girara
|
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 }