girara
callbacks.c
Go to the documentation of this file.
00001 /* See LICENSE file for license and copyright information */
00002 
00003 #include "callbacks.h"
00004 #include "datastructures.h"
00005 #include "session.h"
00006 #include "shortcuts.h"
00007 #include <string.h>
00008 
00009 #include "internal.h"
00010 #if GTK_MAJOR_VERSION == 2
00011 #include "gtk2-compat.h"
00012 #endif
00013 
00014 static const guint ALL_ACCELS_MASK = GDK_CONTROL_MASK | GDK_SHIFT_MASK | GDK_MOD1_MASK;
00015 static const guint MOUSE_MASK = GDK_CONTROL_MASK | GDK_SHIFT_MASK | GDK_MOD1_MASK |
00016   GDK_BUTTON1_MASK | GDK_BUTTON2_MASK | GDK_BUTTON3_MASK | GDK_BUTTON4_MASK | GDK_BUTTON5_MASK;
00017 
00018 static bool
00019 clean_mask(guint hardware_keycode, GdkModifierType state, gint group, guint* clean, guint* keyval)
00020 {
00021   GdkModifierType consumed = 0;
00022   if ((gdk_keymap_translate_keyboard_state(
00023         gdk_keymap_get_default(),
00024         hardware_keycode,
00025         state, group,
00026         keyval,
00027         NULL,
00028         NULL,
00029         &consumed)
00030       ) == FALSE) {
00031     return false;
00032   }
00033 
00034   if (clean != NULL) {
00035     *clean = state & ~consumed & ALL_ACCELS_MASK;
00036   }
00037   return true;
00038 }
00039 
00040 /* callback implementation */
00041 bool
00042 girara_callback_view_key_press_event(GtkWidget* UNUSED(widget),
00043     GdkEventKey* event, girara_session_t* session)
00044 {
00045   g_return_val_if_fail(session != NULL, FALSE);
00046 
00047   guint clean = 0;
00048   guint keyval = 0;
00049   if (clean_mask(event->hardware_keycode, event->state, event->group, &clean, &keyval) == false) {
00050     return false;
00051   }
00052 
00053   /* prepare event */
00054   GIRARA_LIST_FOREACH(session->bindings.shortcuts, girara_shortcut_t*, iter, shortcut)
00055     if (session->buffer.command != NULL) {
00056       break;
00057     }
00058 
00059     if ( keyval == shortcut->key
00060       && (clean == shortcut->mask || (shortcut->key >= 0x21
00061       && shortcut->key <= 0x7E && clean == GDK_SHIFT_MASK))
00062       && (session->modes.current_mode == shortcut->mode || shortcut->mode == 0)
00063       && shortcut->function != NULL
00064       )
00065     {
00066       int t = (session->buffer.n > 0) ? session->buffer.n : 1;
00067       for (int i = 0; i < t; i++) {
00068         if (shortcut->function(session, &(shortcut->argument), NULL, session->buffer.n) == false) {
00069           break;
00070         }
00071       }
00072 
00073       if (session->global.buffer != NULL) {
00074         g_string_free(session->global.buffer, TRUE);
00075         session->global.buffer = NULL;
00076       }
00077 
00078       session->buffer.n = 0;
00079 
00080       if (session->events.buffer_changed != NULL) {
00081         session->events.buffer_changed(session);
00082       }
00083 
00084       girara_list_iterator_free(iter);
00085       return TRUE;
00086     }
00087   GIRARA_LIST_FOREACH_END(session->bindings.shortcuts, girara_shortcut_t*, iter, shortcut);
00088 
00089   /* update buffer */
00090   if (event->keyval >= 0x21 && event->keyval <= 0x7E) {
00091     /* overall buffer */
00092     if (session->global.buffer == NULL) {
00093       session->global.buffer = g_string_new("");
00094     }
00095 
00096     session->global.buffer = g_string_append_c(session->global.buffer, event->keyval);
00097 
00098     if (session->buffer.command == NULL && event->keyval >= 0x30 && event->keyval <= 0x39) {
00099       if (((session->buffer.n * 10) + (event->keyval - '0')) < INT_MAX) {
00100         session->buffer.n = (session->buffer.n * 10) + (event->keyval - '0');
00101       }
00102     } else {
00103       if (session->buffer.command == NULL) {
00104         session->buffer.command = g_string_new("");
00105       }
00106 
00107       session->buffer.command = g_string_append_c(session->buffer.command, event->keyval);
00108     }
00109 
00110     if (session->events.buffer_changed != NULL) {
00111       session->events.buffer_changed(session);
00112     }
00113   }
00114 
00115   /* check for buffer command */
00116   if (session->buffer.command != NULL) {
00117     bool matching_command = FALSE;
00118 
00119     GIRARA_LIST_FOREACH(session->bindings.shortcuts, girara_shortcut_t*, iter, shortcut)
00120       if (shortcut->buffered_command != NULL) {
00121         /* buffer could match a command */
00122         if (!strncmp(session->buffer.command->str, shortcut->buffered_command, session->buffer.command->len)) {
00123           /* command matches buffer exactly */
00124           if (!strcmp(session->buffer.command->str, shortcut->buffered_command)) {
00125             g_string_free(session->buffer.command, TRUE);
00126             g_string_free(session->global.buffer,  TRUE);
00127             session->buffer.command = NULL;
00128             session->global.buffer  = NULL;
00129 
00130             if (session->events.buffer_changed != NULL) {
00131               session->events.buffer_changed(session);
00132             }
00133 
00134             int t = (session->buffer.n > 0) ? session->buffer.n : 1;
00135             for (int i = 0; i < t; i++) {
00136               if (shortcut->function(session, &(shortcut->argument), NULL, session->buffer.n) == false) {
00137                 break;
00138               }
00139             }
00140 
00141             session->buffer.n = 0;
00142             girara_list_iterator_free(iter);
00143             return TRUE;
00144           }
00145 
00146           matching_command = TRUE;
00147         }
00148       }
00149     GIRARA_LIST_FOREACH_END(session->bindings.shortcuts, girara_shortcut_t*, iter, shortcut);
00150 
00151     /* free buffer if buffer will never match a command */
00152     if (matching_command == false) {
00153       g_string_free(session->buffer.command, TRUE);
00154       g_string_free(session->global.buffer,  TRUE);
00155       session->buffer.command = NULL;
00156       session->global.buffer  = NULL;
00157       session->buffer.n       = 0;
00158 
00159       if (session->events.buffer_changed != NULL) {
00160         session->events.buffer_changed(session);
00161       }
00162     }
00163   }
00164 
00165   return FALSE;
00166 }
00167 
00168 bool
00169 girara_callback_view_button_press_event(GtkWidget* UNUSED(widget),
00170     GdkEventButton* button, girara_session_t* session)
00171 {
00172   g_return_val_if_fail(session != NULL, false);
00173   g_return_val_if_fail(button  != NULL, false);
00174 
00175   /* prepare girara event */
00176   girara_event_t event;
00177 
00178   switch (button->type) {
00179     case GDK_BUTTON_PRESS:
00180       event.type = GIRARA_EVENT_BUTTON_PRESS;
00181       break;
00182     case GDK_2BUTTON_PRESS:
00183       event.type = GIRARA_EVENT_2BUTTON_PRESS;
00184       break;
00185     case GDK_3BUTTON_PRESS:
00186       event.type = GIRARA_EVENT_3BUTTON_PRESS;
00187       break;
00188     default: /* do not handle unknown events */
00189       event.type = GIRARA_EVENT_OTHER;
00190       break;
00191   }
00192 
00193   event.x = button->x;
00194   event.y = button->y;
00195 
00196   const guint state = button->state & MOUSE_MASK;
00197 
00198   /* search registered mouse events */
00199   GIRARA_LIST_FOREACH(session->bindings.mouse_events, girara_mouse_event_t*, iter, mouse_event)
00200     if (mouse_event->function != NULL
00201         && button->button == mouse_event->button
00202         && state  == mouse_event->mask
00203         && mouse_event->event_type == event.type
00204         && (session->modes.current_mode & mouse_event->mode || mouse_event->mode == 0)
00205        ) {
00206         mouse_event->function(session, &(mouse_event->argument), &event, session->buffer.n);
00207         girara_list_iterator_free(iter);
00208       return true;
00209     }
00210   GIRARA_LIST_FOREACH_END(session->bindings.mouse_events, girara_mouse_event_t*, iter, mouse_event);
00211 
00212   return false;
00213 }
00214 
00215 bool
00216 girara_callback_view_button_release_event(GtkWidget* UNUSED(widget), GdkEventButton* button, girara_session_t* session)
00217 {
00218   g_return_val_if_fail(session != NULL, false);
00219   g_return_val_if_fail(button  != NULL, false);
00220 
00221   /* prepare girara event */
00222   girara_event_t event;
00223   event.type = GIRARA_EVENT_BUTTON_RELEASE;
00224   event.x    = button->x;
00225   event.y    = button->y;
00226 
00227   const guint state = button->state & MOUSE_MASK;
00228 
00229   /* search registered mouse events */
00230   GIRARA_LIST_FOREACH(session->bindings.mouse_events, girara_mouse_event_t*, iter, mouse_event)
00231     if (mouse_event->function != NULL
00232         && button->button == mouse_event->button
00233         && state  == mouse_event->mask
00234         && mouse_event->event_type == GIRARA_EVENT_BUTTON_RELEASE
00235         && (session->modes.current_mode & mouse_event->mode || mouse_event->mode == 0)
00236        ) {
00237         mouse_event->function(session, &(mouse_event->argument), &event, session->buffer.n);
00238         girara_list_iterator_free(iter);
00239       return true;
00240     }
00241   GIRARA_LIST_FOREACH_END(session->bindings.mouse_events, girara_mouse_event_t*, iter, mouse_event);
00242 
00243   return false;
00244 }
00245 
00246 bool
00247 girara_callback_view_button_motion_notify_event(GtkWidget* UNUSED(widget), GdkEventMotion* button, girara_session_t* session)
00248 {
00249   g_return_val_if_fail(session != NULL, false);
00250   g_return_val_if_fail(button  != NULL, false);
00251 
00252   /* prepare girara event */
00253   girara_event_t event;
00254   event.type = GIRARA_EVENT_MOTION_NOTIFY;
00255   event.x    = button->x;
00256   event.y    = button->y;
00257 
00258   const guint state = button->state & MOUSE_MASK;
00259 
00260   /* search registered mouse events */
00261   GIRARA_LIST_FOREACH(session->bindings.mouse_events, girara_mouse_event_t*, iter, mouse_event)
00262     if (mouse_event->function != NULL
00263         && state  == mouse_event->mask
00264         && mouse_event->event_type == event.type
00265         && (session->modes.current_mode & mouse_event->mode || mouse_event->mode == 0)
00266        ) {
00267         mouse_event->function(session, &(mouse_event->argument), &event, session->buffer.n);
00268         girara_list_iterator_free(iter);
00269       return true;
00270     }
00271   GIRARA_LIST_FOREACH_END(session->bindings.mouse_events, girara_mouse_event_t*, iter, mouse_event);
00272 
00273   return false;
00274 }
00275 
00276 bool
00277 girara_callback_view_scroll_event(GtkWidget* UNUSED(widget), GdkEventScroll* scroll, girara_session_t* session)
00278 {
00279   g_return_val_if_fail(session != NULL, false);
00280   g_return_val_if_fail(scroll  != NULL, false);
00281 
00282   /* prepare girara event */
00283   girara_event_t event;
00284   event.x    = scroll->x;
00285   event.y    = scroll->y;
00286 
00287   switch (scroll->direction) {
00288     case GDK_SCROLL_UP:
00289       event.type = GIRARA_EVENT_SCROLL_UP;
00290       break;
00291     case GDK_SCROLL_DOWN:
00292       event.type = GIRARA_EVENT_SCROLL_DOWN;
00293       break;
00294     case GDK_SCROLL_LEFT:
00295       event.type = GIRARA_EVENT_SCROLL_LEFT;
00296       break;
00297     case GDK_SCROLL_RIGHT:
00298       event.type = GIRARA_EVENT_SCROLL_RIGHT;
00299       break;
00300     default:
00301       return false;
00302   }
00303 
00304   const guint state = scroll->state & MOUSE_MASK;
00305 
00306   /* search registered mouse events */
00307   /* TODO: Filter correct event */
00308   GIRARA_LIST_FOREACH(session->bindings.mouse_events, girara_mouse_event_t*, iter, mouse_event)
00309     if (mouse_event->function != NULL
00310         && state  == mouse_event->mask
00311         && mouse_event->event_type == event.type
00312         && (session->modes.current_mode & mouse_event->mode || mouse_event->mode == 0)
00313        ) {
00314         mouse_event->function(session, &(mouse_event->argument), &event, session->buffer.n);
00315         girara_list_iterator_free(iter);
00316         return true;
00317     }
00318   GIRARA_LIST_FOREACH_END(session->bindings.mouse_events, girara_mouse_event_t*, iter, mouse_event);
00319 
00320   return false;
00321 }
00322 
00323 bool
00324 girara_callback_inputbar_activate(GtkEntry* entry, girara_session_t* session)
00325 {
00326   g_return_val_if_fail(session != NULL, FALSE);
00327 
00328   /* a custom handler has been installed (e.g. by girara_dialog) */
00329   if (session->signals.inputbar_custom_activate != NULL) {
00330     bool return_value = session->signals.inputbar_custom_activate(entry, session->signals.inputbar_custom_data);
00331 
00332     /* disconnect custom handler */
00333     session->signals.inputbar_custom_activate        = NULL;
00334     session->signals.inputbar_custom_key_press_event = NULL;
00335     session->signals.inputbar_custom_data            = NULL;
00336 
00337     if (session->gtk.inputbar_dialog != NULL && session->gtk.inputbar_entry != NULL) {
00338       gtk_label_set_markup(session->gtk.inputbar_dialog, "");
00339       gtk_widget_hide(GTK_WIDGET(session->gtk.inputbar_dialog));
00340       gtk_widget_hide(GTK_WIDGET(session->gtk.inputbar));
00341       gtk_entry_set_visibility(session->gtk.inputbar_entry, TRUE);
00342       girara_isc_abort(session, NULL, NULL, 0);
00343       return true;
00344     }
00345 
00346     return return_value;
00347   }
00348 
00349   gchar *input = gtk_editable_get_chars(GTK_EDITABLE(entry), 1, -1);
00350   if (input == NULL) {
00351     girara_isc_abort(session, NULL, NULL, 0);
00352     return false;
00353   }
00354 
00355   if (strlen(input) == 0) {
00356     g_free(input);
00357     girara_isc_abort(session, NULL, NULL, 0);
00358     return false;
00359   }
00360 
00361   gchar** argv = NULL;
00362   gint    argc = 0;
00363 
00364   if (g_shell_parse_argv(input, &argc, &argv, NULL) == FALSE) {
00365     g_free(input);
00366     return false;
00367   }
00368 
00369   gchar *cmd = argv[0];
00370 
00371   /* special commands */
00372   char *identifier_s = gtk_editable_get_chars(GTK_EDITABLE(entry), 0, 1);
00373   if (identifier_s == NULL) {
00374     g_free(input);
00375     g_strfreev(argv);
00376     return false;
00377   }
00378 
00379   char identifier = identifier_s[0];
00380   g_free(identifier_s);
00381 
00382   GIRARA_LIST_FOREACH(session->bindings.special_commands, girara_special_command_t*, iter, special_command)
00383     if (special_command->identifier == identifier) {
00384       if (special_command->always != true) {
00385         special_command->function(session, input, &(special_command->argument));
00386       }
00387 
00388       g_free(input);
00389       g_strfreev(argv);
00390 
00391       girara_isc_abort(session, NULL, NULL, 0);
00392 
00393       girara_list_iterator_free(iter);
00394       return true;
00395     }
00396   GIRARA_LIST_FOREACH_END(session->bindings.special_commands, girara_special_command_t*, iter, special_command);
00397 
00398   /* search commands */
00399   GIRARA_LIST_FOREACH(session->bindings.commands, girara_command_t*, iter, command)
00400     if ((g_strcmp0(cmd, command->command) == 0) ||
00401         (g_strcmp0(cmd, command->abbr)    == 0))
00402     {
00403       girara_list_t* argument_list = girara_list_new();
00404       if (argument_list == NULL) {
00405         g_free(input);
00406         g_strfreev(argv);
00407         girara_list_iterator_free(iter);
00408         return false;
00409       }
00410 
00411       girara_list_set_free_function(argument_list, g_free);
00412 
00413       for(int i = 1; i < argc; i++) {
00414         char* argument = g_strdup(argv[i]);
00415         girara_list_append(argument_list, (void*) argument);
00416       }
00417 
00418       command->function(session, argument_list);
00419 
00420       girara_list_free(argument_list);
00421       g_free(input);
00422       g_strfreev(argv);
00423 
00424       girara_isc_abort(session, NULL, NULL, 0);
00425 
00426       gtk_widget_hide(GTK_WIDGET(session->gtk.inputbar));
00427       gtk_widget_hide(GTK_WIDGET(session->gtk.inputbar_dialog));
00428       girara_list_iterator_free(iter);
00429       return true;
00430     }
00431   GIRARA_LIST_FOREACH_END(session->bindings.commands, girara_command_t*, iter, command);
00432 
00433   /* no known command */
00434   girara_isc_abort(session, NULL, NULL, 0);
00435 
00436   return false;
00437 }
00438 
00439 bool
00440 girara_callback_inputbar_key_press_event(GtkWidget* entry, GdkEventKey* event, girara_session_t* session)
00441 {
00442   g_return_val_if_fail(session != NULL, false);
00443 
00444   /* a custom handler has been installed (e.g. by girara_dialog) */
00445   if (session->signals.inputbar_custom_key_press_event != NULL) {
00446     return session->signals.inputbar_custom_key_press_event(entry, event, session);
00447   }
00448 
00449   guint keyval             = 0;
00450   GdkModifierType consumed = 0;
00451 
00452   if (gdk_keymap_translate_keyboard_state(
00453         gdk_keymap_get_default(),
00454         event->hardware_keycode,
00455         event->state,
00456         event->group,
00457         &keyval,
00458         NULL,
00459         NULL,
00460         &consumed
00461       ) == FALSE) {
00462     return false;
00463   }
00464   const guint clean = event->state & ~consumed & ALL_ACCELS_MASK;
00465 
00466   GIRARA_LIST_FOREACH(session->bindings.inputbar_shortcuts, girara_inputbar_shortcut_t*, iter, inputbar_shortcut)
00467     if (inputbar_shortcut->key == keyval
00468      && inputbar_shortcut->mask == clean)
00469     {
00470       if (inputbar_shortcut->function != NULL) {
00471         inputbar_shortcut->function(session, &(inputbar_shortcut->argument), NULL, 0);
00472       }
00473 
00474       girara_list_iterator_free(iter);
00475       return true;
00476     }
00477   GIRARA_LIST_FOREACH_END(session->bindings.inputbar_shortcuts, girara_inputbar_shortcut_t*, iter, inputbar_shortcut);
00478 
00479   if ((session->gtk.results != NULL) &&
00480      (gtk_widget_get_visible(GTK_WIDGET(session->gtk.results)) == TRUE) &&
00481      (event->keyval == GDK_KEY_space))
00482   {
00483     gtk_widget_hide(GTK_WIDGET(session->gtk.results));
00484   }
00485 
00486   return false;
00487 }
00488 
00489 bool
00490 girara_callback_inputbar_changed_event(GtkEditable* entry, girara_session_t* session)
00491 {
00492   g_return_val_if_fail(session != NULL, false);
00493 
00494   /* special commands */
00495   char *identifier_s = gtk_editable_get_chars(entry, 0, 1);
00496   if (identifier_s == NULL) {
00497     return false;
00498   }
00499 
00500   char identifier    = identifier_s[0];
00501   g_free(identifier_s);
00502 
00503   GIRARA_LIST_FOREACH(session->bindings.special_commands, girara_special_command_t*, iter, special_command)
00504     if ((special_command->identifier == identifier) &&
00505        (special_command->always == true))
00506     {
00507       gchar *input  = gtk_editable_get_chars(GTK_EDITABLE(entry), 1, -1);
00508       special_command->function(session, input, &(special_command->argument));
00509       g_free(input);
00510       girara_list_iterator_free(iter);
00511       return false;
00512     }
00513   GIRARA_LIST_FOREACH_END(session->bindings.special_commands, girara_special_command_t*, iter, special_command);
00514 
00515   return false;
00516 }
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Defines