girara
|
00001 /* See LICENSE file for license and copyright information */ 00002 00003 #include "shortcuts.h" 00004 #include "datastructures.h" 00005 #include "internal.h" 00006 #include "session.h" 00007 #include "settings.h" 00008 #include "tabs.h" 00009 00010 #include <string.h> 00011 #include <gtk/gtk.h> 00012 00013 static void girara_toggle_widget_visibility(GtkWidget* widget); 00014 00015 bool 00016 girara_shortcut_add(girara_session_t* session, guint modifier, guint key, const char* buffer, girara_shortcut_function_t function, girara_mode_t mode, int argument_n, void* argument_data) 00017 { 00018 g_return_val_if_fail(session != NULL, false); 00019 g_return_val_if_fail(buffer || key || modifier, false); 00020 g_return_val_if_fail(function != NULL, false); 00021 00022 girara_argument_t argument = {argument_n, (argument_data != NULL) ? 00023 g_strdup(argument_data) : NULL}; 00024 00025 /* search for existing binding */ 00026 bool found_existing_shortcut = false; 00027 GIRARA_LIST_FOREACH(session->bindings.shortcuts, girara_shortcut_t*, iter, shortcuts_it) 00028 if (((shortcuts_it->mask == modifier && shortcuts_it->key == key && (modifier != 0 || key != 0)) || 00029 (buffer && shortcuts_it->buffered_command && !strcmp(shortcuts_it->buffered_command, buffer))) 00030 && ((shortcuts_it->mode == mode) || (mode == 0))) 00031 { 00032 if (shortcuts_it->argument.data != NULL) { 00033 g_free(shortcuts_it->argument.data); 00034 } 00035 00036 shortcuts_it->function = function; 00037 shortcuts_it->argument = argument; 00038 found_existing_shortcut = true; 00039 00040 if (mode != 0) { 00041 girara_list_iterator_free(iter); 00042 return true; 00043 } 00044 } 00045 GIRARA_LIST_FOREACH_END(session->bindings.shortcuts, girara_shortcut_t*, iter, shortcuts_it); 00046 00047 if (found_existing_shortcut == true) { 00048 return true; 00049 } 00050 00051 /* add new shortcut */ 00052 girara_shortcut_t* shortcut = g_slice_new(girara_shortcut_t); 00053 00054 shortcut->mask = modifier; 00055 shortcut->key = key; 00056 shortcut->buffered_command = buffer; 00057 shortcut->function = function; 00058 shortcut->mode = mode; 00059 shortcut->argument = argument; 00060 girara_list_append(session->bindings.shortcuts, shortcut); 00061 00062 return true; 00063 } 00064 00065 bool 00066 girara_shortcut_remove(girara_session_t* session, guint modifier, guint key, const char* buffer, girara_mode_t mode) 00067 { 00068 g_return_val_if_fail(session != NULL, false); 00069 g_return_val_if_fail(buffer || key || modifier, false); 00070 00071 /* search for existing binding */ 00072 GIRARA_LIST_FOREACH(session->bindings.shortcuts, girara_shortcut_t*, iter, shortcuts_it) 00073 if (((shortcuts_it->mask == modifier && shortcuts_it->key == key && (modifier != 0 || key != 0)) || 00074 (buffer && shortcuts_it->buffered_command && !strcmp(shortcuts_it->buffered_command, buffer))) 00075 && shortcuts_it->mode == mode) 00076 { 00077 girara_list_remove(session->bindings.shortcuts, shortcuts_it); 00078 girara_list_iterator_free(iter); 00079 return true; 00080 } 00081 GIRARA_LIST_FOREACH_END(session->bindings.shortcuts, girara_shortcut_t*, iter, shortcuts_it); 00082 00083 return false; 00084 } 00085 00086 void 00087 girara_shortcut_free(girara_shortcut_t* shortcut) 00088 { 00089 g_return_if_fail(shortcut != NULL); 00090 g_free(shortcut->argument.data); 00091 g_slice_free(girara_shortcut_t, shortcut); 00092 } 00093 00094 bool 00095 girara_inputbar_shortcut_add(girara_session_t* session, guint modifier, guint key, girara_shortcut_function_t function, int argument_n, void* argument_data) 00096 { 00097 g_return_val_if_fail(session != NULL, false); 00098 g_return_val_if_fail(function != NULL, false); 00099 00100 girara_argument_t argument = {argument_n, argument_data}; 00101 00102 /* search for existing special command */ 00103 GIRARA_LIST_FOREACH(session->bindings.inputbar_shortcuts, girara_inputbar_shortcut_t*, iter, inp_sh_it) 00104 if (inp_sh_it->mask == modifier && inp_sh_it->key == key) { 00105 inp_sh_it->function = function; 00106 inp_sh_it->argument = argument; 00107 00108 girara_list_iterator_free(iter); 00109 return true; 00110 } 00111 GIRARA_LIST_FOREACH_END(session->bindings.inputbar_shortcuts, girara_inputbar_shortcut_t*, iter, inp_sh_it); 00112 00113 /* create new inputbar shortcut */ 00114 girara_inputbar_shortcut_t* inputbar_shortcut = g_slice_new(girara_inputbar_shortcut_t); 00115 00116 inputbar_shortcut->mask = modifier; 00117 inputbar_shortcut->key = key; 00118 inputbar_shortcut->function = function; 00119 inputbar_shortcut->argument = argument; 00120 00121 girara_list_append(session->bindings.inputbar_shortcuts, inputbar_shortcut); 00122 return true; 00123 } 00124 00125 bool 00126 girara_inputbar_shortcut_remove(girara_session_t* session, guint modifier, guint key) 00127 { 00128 g_return_val_if_fail(session != NULL, false); 00129 00130 /* search for existing special command */ 00131 GIRARA_LIST_FOREACH(session->bindings.inputbar_shortcuts, girara_inputbar_shortcut_t*, iter, inp_sh_it) 00132 if (inp_sh_it->mask == modifier && inp_sh_it->key == key) { 00133 girara_list_remove(session->bindings.inputbar_shortcuts, inp_sh_it); 00134 girara_list_iterator_free(iter); 00135 return true; 00136 } 00137 GIRARA_LIST_FOREACH_END(session->bindings.inputbar_shortcuts, girara_inputbar_shortcut_t*, iter, inp_sh_it); 00138 00139 return true; 00140 } 00141 00142 void 00143 girara_inputbar_shortcut_free(girara_inputbar_shortcut_t* inputbar_shortcut) 00144 { 00145 g_slice_free(girara_inputbar_shortcut_t, inputbar_shortcut); 00146 } 00147 bool 00148 girara_isc_abort(girara_session_t* session, girara_argument_t* UNUSED(argument), girara_event_t* UNUSED(event), unsigned int UNUSED(t)) 00149 { 00150 /* hide completion */ 00151 girara_argument_t arg = { GIRARA_HIDE, NULL }; 00152 girara_isc_completion(session, &arg, NULL, 0); 00153 00154 /* clear inputbar */ 00155 gtk_editable_delete_text(GTK_EDITABLE(session->gtk.inputbar_entry), 0, -1); 00156 00157 /* grab view */ 00158 gtk_widget_grab_focus(GTK_WIDGET(session->gtk.view)); 00159 00160 /* hide inputbar */ 00161 gtk_widget_hide(GTK_WIDGET(session->gtk.inputbar_dialog)); 00162 gtk_widget_hide(GTK_WIDGET(session->gtk.inputbar)); 00163 00164 /* reset custom functions */ 00165 session->signals.inputbar_custom_activate = NULL; 00166 session->signals.inputbar_custom_key_press_event = NULL; 00167 gtk_entry_set_visibility(session->gtk.inputbar_entry, TRUE); 00168 00169 return true; 00170 } 00171 00172 bool 00173 girara_isc_string_manipulation(girara_session_t* session, girara_argument_t* argument, girara_event_t* UNUSED(event), unsigned int UNUSED(t)) 00174 { 00175 gchar *separator = NULL; 00176 girara_setting_get(session, "word-separator", &separator); 00177 gchar *input = gtk_editable_get_chars(GTK_EDITABLE(session->gtk.inputbar_entry), 0, -1); 00178 int length = strlen(input); 00179 int pos = gtk_editable_get_position(GTK_EDITABLE(session->gtk.inputbar_entry)); 00180 int i; 00181 00182 switch (argument->n) { 00183 case GIRARA_DELETE_LAST_WORD: 00184 i = pos - 1; 00185 00186 if (!pos) { 00187 break; 00188 } 00189 00190 /* remove trailing spaces */ 00191 for (; i >= 0 && input[i] == ' '; i--); 00192 00193 /* find the beginning of the word */ 00194 while ((i == (pos - 1)) || ((i > 0) && !strchr(separator, input[i]))) { 00195 i--; 00196 } 00197 00198 gtk_editable_delete_text(GTK_EDITABLE(session->gtk.inputbar_entry), i + 1, pos); 00199 gtk_editable_set_position(GTK_EDITABLE(session->gtk.inputbar_entry), i + 1); 00200 break; 00201 case GIRARA_DELETE_LAST_CHAR: 00202 if ((length - 1) <= 0) { 00203 girara_isc_abort(session, argument, NULL, 0); 00204 } 00205 gtk_editable_delete_text(GTK_EDITABLE(session->gtk.inputbar_entry), pos - 1, pos); 00206 break; 00207 case GIRARA_DELETE_TO_LINE_START: 00208 gtk_editable_delete_text(GTK_EDITABLE(session->gtk.inputbar_entry), 1, pos); 00209 break; 00210 case GIRARA_NEXT_CHAR: 00211 gtk_editable_set_position(GTK_EDITABLE(session->gtk.inputbar_entry), pos + 1); 00212 break; 00213 case GIRARA_PREVIOUS_CHAR: 00214 gtk_editable_set_position(GTK_EDITABLE(session->gtk.inputbar_entry), (pos == 0) ? 0 : pos - 1); 00215 break; 00216 case GIRARA_DELETE_CURR_CHAR: 00217 if((length - 1) <= 0) { 00218 girara_isc_abort(session, argument, NULL, 0); 00219 } 00220 gtk_editable_delete_text(GTK_EDITABLE(session->gtk.inputbar_entry), pos, pos + 1); 00221 break; 00222 case GIRARA_DELETE_TO_LINE_END: 00223 gtk_editable_delete_text(GTK_EDITABLE(session->gtk.inputbar_entry), pos, length); 00224 break; 00225 case GIRARA_GOTO_START: 00226 gtk_editable_set_position(GTK_EDITABLE(session->gtk.inputbar_entry), 1); 00227 break; 00228 case GIRARA_GOTO_END: 00229 gtk_editable_set_position(GTK_EDITABLE(session->gtk.inputbar_entry), -1); 00230 break; 00231 } 00232 00233 g_free(separator); 00234 g_free(input); 00235 00236 return false; 00237 } 00238 00239 /* default shortcut implementation */ 00240 bool 00241 girara_sc_focus_inputbar(girara_session_t* session, girara_argument_t* argument, girara_event_t* UNUSED(event), unsigned int UNUSED(t)) 00242 { 00243 g_return_val_if_fail(session != NULL, false); 00244 g_return_val_if_fail(session->gtk.inputbar_entry != NULL, false); 00245 00246 if (gtk_widget_get_visible(GTK_WIDGET(session->gtk.inputbar)) == false) { 00247 gtk_widget_show(GTK_WIDGET(session->gtk.inputbar)); 00248 } 00249 00250 if (gtk_widget_get_visible(GTK_WIDGET(session->gtk.notification_area)) == true) { 00251 gtk_widget_hide(GTK_WIDGET(session->gtk.notification_area)); 00252 } 00253 00254 gtk_widget_grab_focus(GTK_WIDGET(session->gtk.inputbar_entry)); 00255 00256 if (argument != NULL && argument->data != NULL) { 00257 gtk_entry_set_text(session->gtk.inputbar_entry, (char*) argument->data); 00258 00259 /* we save the X clipboard that will be clear by "grab_focus" */ 00260 gchar* x_clipboard_text = gtk_clipboard_wait_for_text(gtk_clipboard_get(GDK_SELECTION_PRIMARY)); 00261 00262 gtk_editable_set_position(GTK_EDITABLE(session->gtk.inputbar_entry), -1); 00263 00264 if (x_clipboard_text != NULL) { 00265 /* we reset the X clipboard with saved text */ 00266 gtk_clipboard_set_text(gtk_clipboard_get(GDK_SELECTION_PRIMARY), x_clipboard_text, -1); 00267 g_free(x_clipboard_text); 00268 } 00269 } 00270 00271 return true; 00272 } 00273 00274 bool 00275 girara_sc_abort(girara_session_t* session, girara_argument_t* UNUSED(argument), girara_event_t* UNUSED(event), unsigned int UNUSED(t)) 00276 { 00277 g_return_val_if_fail(session != NULL, false); 00278 00279 girara_isc_abort(session, NULL, NULL, 0); 00280 gtk_widget_hide(GTK_WIDGET(session->gtk.notification_area)); 00281 00282 return false; 00283 } 00284 00285 bool 00286 girara_sc_quit(girara_session_t* session, girara_argument_t* UNUSED(argument), girara_event_t* UNUSED(event), unsigned int UNUSED(t)) 00287 { 00288 g_return_val_if_fail(session != NULL, false); 00289 00290 girara_argument_t arg = { GIRARA_HIDE, NULL }; 00291 girara_isc_completion(session, &arg, NULL, 0); 00292 00293 gtk_main_quit(); 00294 00295 return false; 00296 } 00297 00298 bool 00299 girara_sc_tab_close(girara_session_t* session, girara_argument_t* UNUSED(argument), girara_event_t* UNUSED(event), unsigned int UNUSED(t)) 00300 { 00301 g_return_val_if_fail(session != NULL, false); 00302 00303 girara_tab_t* tab = girara_tab_current_get(session); 00304 00305 if (tab != NULL) { 00306 girara_tab_remove(session, tab); 00307 } 00308 00309 return false; 00310 } 00311 00312 bool 00313 girara_sc_tab_navigate(girara_session_t* session, girara_argument_t* argument, girara_event_t* UNUSED(event), unsigned int t) 00314 { 00315 g_return_val_if_fail(session != NULL, false); 00316 00317 unsigned int number_of_tabs = girara_get_number_of_tabs(session); 00318 unsigned int current_tab = girara_tab_position_get(session, girara_tab_current_get(session)); 00319 unsigned int step = (argument->n == GIRARA_PREVIOUS) ? -1 : 1; 00320 unsigned int new_tab = (current_tab + step) % number_of_tabs; 00321 00322 if (t != 0 && t <= number_of_tabs) { 00323 new_tab = t - 1; 00324 } 00325 00326 girara_tab_t* tab = girara_tab_get(session, new_tab); 00327 00328 if (tab != NULL) { 00329 girara_tab_current_set(session, tab); 00330 } 00331 00332 girara_tab_update(session); 00333 00334 return false; 00335 } 00336 00337 static void 00338 girara_toggle_widget_visibility(GtkWidget* widget) 00339 { 00340 if (widget == NULL) { 00341 return; 00342 } 00343 00344 if (gtk_widget_get_visible(widget)) { 00345 gtk_widget_hide(widget); 00346 } else { 00347 gtk_widget_show(widget); 00348 } 00349 } 00350 00351 bool 00352 girara_sc_toggle_inputbar(girara_session_t* session, girara_argument_t* UNUSED(argument), girara_event_t* UNUSED(event), unsigned int UNUSED(t)) 00353 { 00354 g_return_val_if_fail(session != NULL, false); 00355 00356 girara_toggle_widget_visibility(GTK_WIDGET(session->gtk.inputbar)); 00357 00358 return true; 00359 } 00360 00361 bool 00362 girara_sc_toggle_statusbar(girara_session_t* session, girara_argument_t* UNUSED(argument), girara_event_t* UNUSED(event), unsigned int UNUSED(t)) 00363 { 00364 g_return_val_if_fail(session != NULL, false); 00365 00366 girara_toggle_widget_visibility(GTK_WIDGET(session->gtk.statusbar)); 00367 00368 return true; 00369 } 00370 00371 bool 00372 girara_sc_toggle_tabbar(girara_session_t* session, girara_argument_t* UNUSED(argument), girara_event_t* UNUSED(event), unsigned int UNUSED(t)) 00373 { 00374 g_return_val_if_fail(session != NULL, false); 00375 00376 girara_toggle_widget_visibility(GTK_WIDGET(session->gtk.tabbar)); 00377 00378 return true; 00379 } 00380 00381 bool 00382 girara_sc_set(girara_session_t* session, girara_argument_t* argument, girara_event_t* UNUSED(event), unsigned int UNUSED(t)) 00383 { 00384 g_return_val_if_fail(session != NULL, false); 00385 00386 if (argument == NULL || argument->data == NULL) { 00387 return false; 00388 } 00389 00390 /* create argument list */ 00391 girara_list_t* argument_list = girara_list_new(); 00392 if (argument_list == NULL) { 00393 return false; 00394 } 00395 00396 gchar** argv = NULL; 00397 gint argc = 0; 00398 00399 girara_list_set_free_function(argument_list, g_free); 00400 if (g_shell_parse_argv((const gchar*) argument->data, &argc, &argv, NULL) != FALSE) { 00401 for(int i = 0; i < argc; i++) { 00402 char* argument = g_strdup(argv[i]); 00403 girara_list_append(argument_list, (void*) argument); 00404 } 00405 } else { 00406 girara_list_free(argument_list); 00407 return false; 00408 } 00409 00410 /* call set */ 00411 girara_cmd_set(session, argument_list); 00412 00413 /* cleanup */ 00414 girara_list_free(argument_list); 00415 00416 return false; 00417 } 00418 00419 bool girara_shortcut_mapping_add(girara_session_t* session, const char* identifier, girara_shortcut_function_t function) 00420 { 00421 g_return_val_if_fail(session != NULL, false); 00422 00423 if (function == NULL || identifier == NULL) { 00424 return false; 00425 } 00426 00427 GIRARA_LIST_FOREACH(session->config.shortcut_mappings, girara_shortcut_mapping_t*, iter, data) 00428 if (strcmp(data->identifier, identifier) == 0) { 00429 data->function = function; 00430 girara_list_iterator_free(iter); 00431 return true; 00432 } 00433 GIRARA_LIST_FOREACH_END(session->config.shortcut_mappings, girara_shortcut_mapping_t*, iter, data); 00434 00435 /* add new config handle */ 00436 girara_shortcut_mapping_t* mapping = g_slice_new(girara_shortcut_mapping_t); 00437 00438 mapping->identifier = g_strdup(identifier); 00439 mapping->function = function; 00440 girara_list_append(session->config.shortcut_mappings, mapping); 00441 00442 return true; 00443 } 00444 00445 void 00446 girara_shortcut_mapping_free(girara_shortcut_mapping_t* mapping) 00447 { 00448 if (mapping == NULL) { 00449 return; 00450 } 00451 00452 g_free(mapping->identifier); 00453 g_slice_free(girara_shortcut_mapping_t, mapping); 00454 } 00455 00456 bool girara_argument_mapping_add(girara_session_t* session, const char* identifier, int value) 00457 { 00458 g_return_val_if_fail(session != NULL, false); 00459 00460 if (identifier == NULL) { 00461 return false; 00462 } 00463 00464 GIRARA_LIST_FOREACH(session->config.argument_mappings, girara_argument_mapping_t*, iter, mapping); 00465 if (g_strcmp0(mapping->identifier, identifier) == 0) { 00466 mapping->value = value; 00467 girara_list_iterator_free(iter); 00468 return true; 00469 } 00470 GIRARA_LIST_FOREACH_END(session->config.argument_mappings, girara_argument_mapping_t*, iter, mapping); 00471 00472 /* add new config handle */ 00473 girara_argument_mapping_t* mapping = g_slice_new(girara_argument_mapping_t); 00474 00475 mapping->identifier = g_strdup(identifier); 00476 mapping->value = value; 00477 girara_list_append(session->config.argument_mappings, mapping); 00478 00479 return true; 00480 } 00481 00482 void 00483 girara_argument_mapping_free(girara_argument_mapping_t* argument_mapping) 00484 { 00485 if (argument_mapping == NULL) { 00486 return; 00487 } 00488 00489 g_free(argument_mapping->identifier); 00490 g_slice_free(girara_argument_mapping_t, argument_mapping); 00491 } 00492 00493 bool 00494 girara_mouse_event_add(girara_session_t* session, guint mask, guint button, 00495 girara_shortcut_function_t function, girara_mode_t mode, girara_event_type_t 00496 event_type, int argument_n, void* argument_data) 00497 { 00498 g_return_val_if_fail(session != NULL, false); 00499 g_return_val_if_fail(function != NULL, false); 00500 00501 girara_argument_t argument = {argument_n, argument_data}; 00502 00503 /* search for existing binding */ 00504 GIRARA_LIST_FOREACH(session->bindings.mouse_events, girara_mouse_event_t*, iter, me_it) 00505 if (me_it->mask == mask && me_it->button == button && 00506 me_it->mode == mode && me_it->event_type == event_type) 00507 { 00508 me_it->function = function; 00509 me_it->argument = argument; 00510 girara_list_iterator_free(iter); 00511 return true; 00512 } 00513 GIRARA_LIST_FOREACH_END(session->bindings.mouse_events, girara_mouse_event_t*, iter, me_it); 00514 00515 /* add new mouse event */ 00516 girara_mouse_event_t* mouse_event = g_slice_new(girara_mouse_event_t); 00517 00518 mouse_event->mask = mask; 00519 mouse_event->button = button; 00520 mouse_event->function = function; 00521 mouse_event->mode = mode; 00522 mouse_event->event_type = event_type; 00523 mouse_event->argument = argument; 00524 girara_list_append(session->bindings.mouse_events, mouse_event); 00525 00526 return true; 00527 } 00528 00529 bool 00530 girara_mouse_event_remove(girara_session_t* session, guint mask, guint button, girara_mode_t mode) 00531 { 00532 g_return_val_if_fail(session != NULL, false); 00533 00534 /* search for existing binding */ 00535 GIRARA_LIST_FOREACH(session->bindings.mouse_events, girara_mouse_event_t*, iter, me_it) 00536 if (me_it->mask == mask && me_it->button == button && 00537 me_it->mode == mode) 00538 { 00539 girara_list_remove(session->bindings.mouse_events, me_it); 00540 girara_list_iterator_free(iter); 00541 return true; 00542 } 00543 GIRARA_LIST_FOREACH_END(session->bindings.mouse_events, girara_mouse_event_t*, iter, me_it); 00544 00545 return false; 00546 } 00547 00548 void 00549 girara_mouse_event_free(girara_mouse_event_t* mouse_event) 00550 { 00551 if (mouse_event == NULL) { 00552 return; 00553 } 00554 g_slice_free(girara_mouse_event_t, mouse_event); 00555 }