girara
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Macros
shortcuts.c
Go to the documentation of this file.
1 /* See LICENSE file for license and copyright information */
2 
3 #include "shortcuts.h"
4 #include "datastructures.h"
5 #include "internal.h"
6 #include "session.h"
7 #include "settings.h"
8 #include "tabs.h"
9 
10 #include <string.h>
11 #include <gtk/gtk.h>
12 
13 static void girara_toggle_widget_visibility(GtkWidget* widget);
14 
15 bool
16 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)
17 {
18  g_return_val_if_fail(session != NULL, false);
19  g_return_val_if_fail(buffer || key || modifier, false);
20  g_return_val_if_fail(function != NULL, false);
21 
22  girara_argument_t argument = {argument_n, (argument_data != NULL) ?
23  g_strdup(argument_data) : NULL};
24 
25  /* search for existing binding */
26  bool found_existing_shortcut = false;
27  GIRARA_LIST_FOREACH(session->bindings.shortcuts, girara_shortcut_t*, iter, shortcuts_it)
28  if (((shortcuts_it->mask == modifier && shortcuts_it->key == key && (modifier != 0 || key != 0)) ||
29  (buffer && shortcuts_it->buffered_command && !strcmp(shortcuts_it->buffered_command, buffer)))
30  && ((shortcuts_it->mode == mode) || (mode == 0)))
31  {
32  if (shortcuts_it->argument.data != NULL) {
33  g_free(shortcuts_it->argument.data);
34  }
35 
36  shortcuts_it->function = function;
37  shortcuts_it->argument = argument;
38  found_existing_shortcut = true;
39 
40  if (mode != 0) {
42  return true;
43  }
44  }
45  GIRARA_LIST_FOREACH_END(session->bindings.shortcuts, girara_shortcut_t*, iter, shortcuts_it);
46 
47  if (found_existing_shortcut == true) {
48  return true;
49  }
50 
51  /* add new shortcut */
52  girara_shortcut_t* shortcut = g_slice_new(girara_shortcut_t);
53 
54  shortcut->mask = modifier;
55  shortcut->key = key;
56  shortcut->buffered_command = buffer;
57  shortcut->function = function;
58  shortcut->mode = mode;
59  shortcut->argument = argument;
60  girara_list_append(session->bindings.shortcuts, shortcut);
61 
62  return true;
63 }
64 
65 bool
66 girara_shortcut_remove(girara_session_t* session, guint modifier, guint key, const char* buffer, girara_mode_t mode)
67 {
68  g_return_val_if_fail(session != NULL, false);
69  g_return_val_if_fail(buffer || key || modifier, false);
70 
71  /* search for existing binding */
72  GIRARA_LIST_FOREACH(session->bindings.shortcuts, girara_shortcut_t*, iter, shortcuts_it)
73  if (((shortcuts_it->mask == modifier && shortcuts_it->key == key && (modifier != 0 || key != 0)) ||
74  (buffer && shortcuts_it->buffered_command && !strcmp(shortcuts_it->buffered_command, buffer)))
75  && shortcuts_it->mode == mode)
76  {
77  girara_list_remove(session->bindings.shortcuts, shortcuts_it);
79  return true;
80  }
81  GIRARA_LIST_FOREACH_END(session->bindings.shortcuts, girara_shortcut_t*, iter, shortcuts_it);
82 
83  return false;
84 }
85 
86 void
87 girara_shortcut_free(girara_shortcut_t* shortcut)
88 {
89  g_return_if_fail(shortcut != NULL);
90  g_free(shortcut->argument.data);
91  g_slice_free(girara_shortcut_t, shortcut);
92 }
93 
94 bool
95 girara_inputbar_shortcut_add(girara_session_t* session, guint modifier, guint key, girara_shortcut_function_t function, int argument_n, void* argument_data)
96 {
97  g_return_val_if_fail(session != NULL, false);
98  g_return_val_if_fail(function != NULL, false);
99 
100  girara_argument_t argument = {argument_n, argument_data};
101 
102  /* search for existing special command */
103  GIRARA_LIST_FOREACH(session->bindings.inputbar_shortcuts, girara_inputbar_shortcut_t*, iter, inp_sh_it)
104  if (inp_sh_it->mask == modifier && inp_sh_it->key == key) {
105  inp_sh_it->function = function;
106  inp_sh_it->argument = argument;
107 
109  return true;
110  }
111  GIRARA_LIST_FOREACH_END(session->bindings.inputbar_shortcuts, girara_inputbar_shortcut_t*, iter, inp_sh_it);
112 
113  /* create new inputbar shortcut */
114  girara_inputbar_shortcut_t* inputbar_shortcut = g_slice_new(girara_inputbar_shortcut_t);
115 
116  inputbar_shortcut->mask = modifier;
117  inputbar_shortcut->key = key;
118  inputbar_shortcut->function = function;
119  inputbar_shortcut->argument = argument;
120 
121  girara_list_append(session->bindings.inputbar_shortcuts, inputbar_shortcut);
122  return true;
123 }
124 
125 bool
126 girara_inputbar_shortcut_remove(girara_session_t* session, guint modifier, guint key)
127 {
128  g_return_val_if_fail(session != NULL, false);
129 
130  /* search for existing special command */
131  GIRARA_LIST_FOREACH(session->bindings.inputbar_shortcuts, girara_inputbar_shortcut_t*, iter, inp_sh_it)
132  if (inp_sh_it->mask == modifier && inp_sh_it->key == key) {
133  girara_list_remove(session->bindings.inputbar_shortcuts, inp_sh_it);
135  return true;
136  }
137  GIRARA_LIST_FOREACH_END(session->bindings.inputbar_shortcuts, girara_inputbar_shortcut_t*, iter, inp_sh_it);
138 
139  return true;
140 }
141 
142 void
143 girara_inputbar_shortcut_free(girara_inputbar_shortcut_t* inputbar_shortcut)
144 {
145  g_slice_free(girara_inputbar_shortcut_t, inputbar_shortcut);
146 }
147 bool
148 girara_isc_abort(girara_session_t* session, girara_argument_t* UNUSED(argument), girara_event_t* UNUSED(event), unsigned int UNUSED(t))
149 {
150  /* hide completion */
151  girara_argument_t arg = { GIRARA_HIDE, NULL };
152  girara_isc_completion(session, &arg, NULL, 0);
153 
154  /* clear inputbar */
155  gtk_editable_delete_text(GTK_EDITABLE(session->gtk.inputbar_entry), 0, -1);
156 
157  /* grab view */
158  gtk_widget_grab_focus(GTK_WIDGET(session->gtk.view));
159 
160  /* hide inputbar */
161  gtk_widget_hide(GTK_WIDGET(session->gtk.inputbar_dialog));
162  gtk_widget_hide(GTK_WIDGET(session->gtk.inputbar));
163 
164  /* reset custom functions */
165  session->signals.inputbar_custom_activate = NULL;
166  session->signals.inputbar_custom_key_press_event = NULL;
167  gtk_entry_set_visibility(session->gtk.inputbar_entry, TRUE);
168 
169  return true;
170 }
171 
172 bool
173 girara_isc_string_manipulation(girara_session_t* session, girara_argument_t* argument, girara_event_t* UNUSED(event), unsigned int UNUSED(t))
174 {
175  gchar *separator = NULL;
176  girara_setting_get(session, "word-separator", &separator);
177  gchar *input = gtk_editable_get_chars(GTK_EDITABLE(session->gtk.inputbar_entry), 0, -1);
178  int length = strlen(input);
179  int pos = gtk_editable_get_position(GTK_EDITABLE(session->gtk.inputbar_entry));
180  int i;
181 
182  switch (argument->n) {
184  i = pos - 1;
185 
186  if (!pos) {
187  break;
188  }
189 
190  /* remove trailing spaces */
191  for (; i >= 0 && input[i] == ' '; i--);
192 
193  /* find the beginning of the word */
194  while ((i == (pos - 1)) || ((i > 0) && !strchr(separator, input[i]))) {
195  i--;
196  }
197 
198  gtk_editable_delete_text(GTK_EDITABLE(session->gtk.inputbar_entry), i + 1, pos);
199  gtk_editable_set_position(GTK_EDITABLE(session->gtk.inputbar_entry), i + 1);
200  break;
202  if ((length - 1) <= 0) {
203  girara_isc_abort(session, argument, NULL, 0);
204  }
205  gtk_editable_delete_text(GTK_EDITABLE(session->gtk.inputbar_entry), pos - 1, pos);
206  break;
208  gtk_editable_delete_text(GTK_EDITABLE(session->gtk.inputbar_entry), 1, pos);
209  break;
210  case GIRARA_NEXT_CHAR:
211  gtk_editable_set_position(GTK_EDITABLE(session->gtk.inputbar_entry), pos + 1);
212  break;
214  gtk_editable_set_position(GTK_EDITABLE(session->gtk.inputbar_entry), (pos == 0) ? 0 : pos - 1);
215  break;
217  if((length - 1) <= 0) {
218  girara_isc_abort(session, argument, NULL, 0);
219  }
220  gtk_editable_delete_text(GTK_EDITABLE(session->gtk.inputbar_entry), pos, pos + 1);
221  break;
223  gtk_editable_delete_text(GTK_EDITABLE(session->gtk.inputbar_entry), pos, length);
224  break;
225  case GIRARA_GOTO_START:
226  gtk_editable_set_position(GTK_EDITABLE(session->gtk.inputbar_entry), 1);
227  break;
228  case GIRARA_GOTO_END:
229  gtk_editable_set_position(GTK_EDITABLE(session->gtk.inputbar_entry), -1);
230  break;
231  }
232 
233  g_free(separator);
234  g_free(input);
235 
236  return false;
237 }
238 
239 /* default shortcut implementation */
240 bool
241 girara_sc_focus_inputbar(girara_session_t* session, girara_argument_t* argument, girara_event_t* UNUSED(event), unsigned int UNUSED(t))
242 {
243  g_return_val_if_fail(session != NULL, false);
244  g_return_val_if_fail(session->gtk.inputbar_entry != NULL, false);
245 
246  if (gtk_widget_get_visible(GTK_WIDGET(session->gtk.inputbar)) == false) {
247  gtk_widget_show(GTK_WIDGET(session->gtk.inputbar));
248  }
249 
250  if (gtk_widget_get_visible(GTK_WIDGET(session->gtk.notification_area)) == true) {
251  gtk_widget_hide(GTK_WIDGET(session->gtk.notification_area));
252  }
253 
254  gtk_widget_grab_focus(GTK_WIDGET(session->gtk.inputbar_entry));
255 
256  if (argument != NULL && argument->data != NULL) {
257  gtk_entry_set_text(session->gtk.inputbar_entry, (char*) argument->data);
258 
259  /* we save the X clipboard that will be clear by "grab_focus" */
260  gchar* x_clipboard_text = gtk_clipboard_wait_for_text(gtk_clipboard_get(GDK_SELECTION_PRIMARY));
261 
262  gtk_editable_set_position(GTK_EDITABLE(session->gtk.inputbar_entry), -1);
263 
264  if (x_clipboard_text != NULL) {
265  /* we reset the X clipboard with saved text */
266  gtk_clipboard_set_text(gtk_clipboard_get(GDK_SELECTION_PRIMARY), x_clipboard_text, -1);
267  g_free(x_clipboard_text);
268  }
269  }
270 
271  return true;
272 }
273 
274 bool
275 girara_sc_abort(girara_session_t* session, girara_argument_t* UNUSED(argument), girara_event_t* UNUSED(event), unsigned int UNUSED(t))
276 {
277  g_return_val_if_fail(session != NULL, false);
278 
279  girara_isc_abort(session, NULL, NULL, 0);
280  gtk_widget_hide(GTK_WIDGET(session->gtk.notification_area));
281 
282  return false;
283 }
284 
285 bool
286 girara_sc_quit(girara_session_t* session, girara_argument_t* UNUSED(argument), girara_event_t* UNUSED(event), unsigned int UNUSED(t))
287 {
288  g_return_val_if_fail(session != NULL, false);
289 
290  girara_argument_t arg = { GIRARA_HIDE, NULL };
291  girara_isc_completion(session, &arg, NULL, 0);
292 
293  gtk_main_quit();
294 
295  return false;
296 }
297 
298 bool
299 girara_sc_tab_close(girara_session_t* session, girara_argument_t* UNUSED(argument), girara_event_t* UNUSED(event), unsigned int UNUSED(t))
300 {
301  g_return_val_if_fail(session != NULL, false);
302 
303  girara_tab_t* tab = girara_tab_current_get(session);
304 
305  if (tab != NULL) {
306  girara_tab_remove(session, tab);
307  }
308 
309  return false;
310 }
311 
312 bool
313 girara_sc_tab_navigate(girara_session_t* session, girara_argument_t* argument, girara_event_t* UNUSED(event), unsigned int t)
314 {
315  g_return_val_if_fail(session != NULL, false);
316 
317  unsigned int number_of_tabs = girara_get_number_of_tabs(session);
318  unsigned int current_tab = girara_tab_position_get(session, girara_tab_current_get(session));
319  unsigned int step = (argument->n == GIRARA_PREVIOUS) ? -1 : 1;
320  unsigned int new_tab = (current_tab + step) % number_of_tabs;
321 
322  if (t != 0 && t <= number_of_tabs) {
323  new_tab = t - 1;
324  }
325 
326  girara_tab_t* tab = girara_tab_get(session, new_tab);
327 
328  if (tab != NULL) {
329  girara_tab_current_set(session, tab);
330  }
331 
332  girara_tab_update(session);
333 
334  return false;
335 }
336 
337 static void
338 girara_toggle_widget_visibility(GtkWidget* widget)
339 {
340  if (widget == NULL) {
341  return;
342  }
343 
344  if (gtk_widget_get_visible(widget)) {
345  gtk_widget_hide(widget);
346  } else {
347  gtk_widget_show(widget);
348  }
349 }
350 
351 bool
352 girara_sc_toggle_inputbar(girara_session_t* session, girara_argument_t* UNUSED(argument), girara_event_t* UNUSED(event), unsigned int UNUSED(t))
353 {
354  g_return_val_if_fail(session != NULL, false);
355 
356  girara_toggle_widget_visibility(GTK_WIDGET(session->gtk.inputbar));
357 
358  return true;
359 }
360 
361 bool
362 girara_sc_toggle_statusbar(girara_session_t* session, girara_argument_t* UNUSED(argument), girara_event_t* UNUSED(event), unsigned int UNUSED(t))
363 {
364  g_return_val_if_fail(session != NULL, false);
365 
366  girara_toggle_widget_visibility(GTK_WIDGET(session->gtk.statusbar));
367 
368  return true;
369 }
370 
371 bool
372 girara_sc_toggle_tabbar(girara_session_t* session, girara_argument_t* UNUSED(argument), girara_event_t* UNUSED(event), unsigned int UNUSED(t))
373 {
374  g_return_val_if_fail(session != NULL, false);
375 
376  girara_toggle_widget_visibility(GTK_WIDGET(session->gtk.tabbar));
377 
378  return true;
379 }
380 
381 bool
382 girara_sc_set(girara_session_t* session, girara_argument_t* argument, girara_event_t* UNUSED(event), unsigned int UNUSED(t))
383 {
384  g_return_val_if_fail(session != NULL, false);
385 
386  if (argument == NULL || argument->data == NULL) {
387  return false;
388  }
389 
390  /* create argument list */
391  girara_list_t* argument_list = girara_list_new();
392  if (argument_list == NULL) {
393  return false;
394  }
395 
396  gchar** argv = NULL;
397  gint argc = 0;
398 
399  girara_list_set_free_function(argument_list, g_free);
400  if (g_shell_parse_argv((const gchar*) argument->data, &argc, &argv, NULL) != FALSE) {
401  for(int i = 0; i < argc; i++) {
402  char* argument = g_strdup(argv[i]);
403  girara_list_append(argument_list, (void*) argument);
404  }
405  } else {
406  girara_list_free(argument_list);
407  return false;
408  }
409 
410  /* call set */
411  girara_cmd_set(session, argument_list);
412 
413  /* cleanup */
414  girara_list_free(argument_list);
415 
416  return false;
417 }
418 
419 bool girara_shortcut_mapping_add(girara_session_t* session, const char* identifier, girara_shortcut_function_t function)
420 {
421  g_return_val_if_fail(session != NULL, false);
422 
423  if (function == NULL || identifier == NULL) {
424  return false;
425  }
426 
427  GIRARA_LIST_FOREACH(session->config.shortcut_mappings, girara_shortcut_mapping_t*, iter, data)
428  if (strcmp(data->identifier, identifier) == 0) {
429  data->function = function;
431  return true;
432  }
433  GIRARA_LIST_FOREACH_END(session->config.shortcut_mappings, girara_shortcut_mapping_t*, iter, data);
434 
435  /* add new config handle */
436  girara_shortcut_mapping_t* mapping = g_slice_new(girara_shortcut_mapping_t);
437 
438  mapping->identifier = g_strdup(identifier);
439  mapping->function = function;
440  girara_list_append(session->config.shortcut_mappings, mapping);
441 
442  return true;
443 }
444 
445 void
446 girara_shortcut_mapping_free(girara_shortcut_mapping_t* mapping)
447 {
448  if (mapping == NULL) {
449  return;
450  }
451 
452  g_free(mapping->identifier);
453  g_slice_free(girara_shortcut_mapping_t, mapping);
454 }
455 
456 bool girara_argument_mapping_add(girara_session_t* session, const char* identifier, int value)
457 {
458  g_return_val_if_fail(session != NULL, false);
459 
460  if (identifier == NULL) {
461  return false;
462  }
463 
464  GIRARA_LIST_FOREACH(session->config.argument_mappings, girara_argument_mapping_t*, iter, mapping);
465  if (g_strcmp0(mapping->identifier, identifier) == 0) {
466  mapping->value = value;
468  return true;
469  }
470  GIRARA_LIST_FOREACH_END(session->config.argument_mappings, girara_argument_mapping_t*, iter, mapping);
471 
472  /* add new config handle */
473  girara_argument_mapping_t* mapping = g_slice_new(girara_argument_mapping_t);
474 
475  mapping->identifier = g_strdup(identifier);
476  mapping->value = value;
477  girara_list_append(session->config.argument_mappings, mapping);
478 
479  return true;
480 }
481 
482 void
483 girara_argument_mapping_free(girara_argument_mapping_t* argument_mapping)
484 {
485  if (argument_mapping == NULL) {
486  return;
487  }
488 
489  g_free(argument_mapping->identifier);
490  g_slice_free(girara_argument_mapping_t, argument_mapping);
491 }
492 
493 bool
494 girara_mouse_event_add(girara_session_t* session, guint mask, guint button,
496  event_type, int argument_n, void* argument_data)
497 {
498  g_return_val_if_fail(session != NULL, false);
499  g_return_val_if_fail(function != NULL, false);
500 
501  girara_argument_t argument = {argument_n, argument_data};
502 
503  /* search for existing binding */
504  GIRARA_LIST_FOREACH(session->bindings.mouse_events, girara_mouse_event_t*, iter, me_it)
505  if (me_it->mask == mask && me_it->button == button &&
506  me_it->mode == mode && me_it->event_type == event_type)
507  {
508  me_it->function = function;
509  me_it->argument = argument;
511  return true;
512  }
513  GIRARA_LIST_FOREACH_END(session->bindings.mouse_events, girara_mouse_event_t*, iter, me_it);
514 
515  /* add new mouse event */
516  girara_mouse_event_t* mouse_event = g_slice_new(girara_mouse_event_t);
517 
518  mouse_event->mask = mask;
519  mouse_event->button = button;
520  mouse_event->function = function;
521  mouse_event->mode = mode;
522  mouse_event->event_type = event_type;
523  mouse_event->argument = argument;
524  girara_list_append(session->bindings.mouse_events, mouse_event);
525 
526  return true;
527 }
528 
529 bool
530 girara_mouse_event_remove(girara_session_t* session, guint mask, guint button, girara_mode_t mode)
531 {
532  g_return_val_if_fail(session != NULL, false);
533 
534  /* search for existing binding */
535  GIRARA_LIST_FOREACH(session->bindings.mouse_events, girara_mouse_event_t*, iter, me_it)
536  if (me_it->mask == mask && me_it->button == button &&
537  me_it->mode == mode)
538  {
539  girara_list_remove(session->bindings.mouse_events, me_it);
541  return true;
542  }
543  GIRARA_LIST_FOREACH_END(session->bindings.mouse_events, girara_mouse_event_t*, iter, me_it);
544 
545  return false;
546 }
547 
548 void
549 girara_mouse_event_free(girara_mouse_event_t* mouse_event)
550 {
551  if (mouse_event == NULL) {
552  return;
553  }
554  g_slice_free(girara_mouse_event_t, mouse_event);
555 }