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 #include "input-history.h"
10 
11 #include <string.h>
12 #include <gtk/gtk.h>
13 
14 static void girara_toggle_widget_visibility(GtkWidget* widget);
15 static bool simulate_key_press(girara_session_t* session, int state, int key);
16 
17 bool
18 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)
19 {
20  g_return_val_if_fail(session != NULL, false);
21  g_return_val_if_fail(buffer || key || modifier, false);
22  g_return_val_if_fail(function != NULL, false);
23 
24  girara_argument_t argument = {argument_n, (argument_data != NULL) ?
25  g_strdup(argument_data) : NULL};
26 
27  /* search for existing binding */
28  bool found_existing_shortcut = false;
29  GIRARA_LIST_FOREACH(session->bindings.shortcuts, girara_shortcut_t*, iter, shortcuts_it)
30  if (((shortcuts_it->mask == modifier && shortcuts_it->key == key && (modifier != 0 || key != 0)) ||
31  (buffer && shortcuts_it->buffered_command && !strcmp(shortcuts_it->buffered_command, buffer)))
32  && ((shortcuts_it->mode == mode) || (mode == 0)))
33  {
34  if (shortcuts_it->argument.data != NULL) {
35  g_free(shortcuts_it->argument.data);
36  }
37 
38  shortcuts_it->function = function;
39  shortcuts_it->argument = argument;
40  found_existing_shortcut = true;
41 
42  if (mode != 0) {
44  return true;
45  }
46  }
47  GIRARA_LIST_FOREACH_END(session->bindings.shortcuts, girara_shortcut_t*, iter, shortcuts_it);
48 
49  if (found_existing_shortcut == true) {
50  return true;
51  }
52 
53  /* add new shortcut */
54  girara_shortcut_t* shortcut = g_slice_new(girara_shortcut_t);
55 
56  shortcut->mask = modifier;
57  shortcut->key = key;
58  shortcut->buffered_command = buffer;
59  shortcut->function = function;
60  shortcut->mode = mode;
61  shortcut->argument = argument;
62  girara_list_append(session->bindings.shortcuts, shortcut);
63 
64  return true;
65 }
66 
67 bool
68 girara_shortcut_remove(girara_session_t* session, guint modifier, guint key, const char* buffer, girara_mode_t mode)
69 {
70  g_return_val_if_fail(session != NULL, false);
71  g_return_val_if_fail(buffer || key || modifier, false);
72 
73  /* search for existing binding */
74  GIRARA_LIST_FOREACH(session->bindings.shortcuts, girara_shortcut_t*, iter, shortcuts_it)
75  if (((shortcuts_it->mask == modifier && shortcuts_it->key == key && (modifier != 0 || key != 0)) ||
76  (buffer && shortcuts_it->buffered_command && !strcmp(shortcuts_it->buffered_command, buffer)))
77  && shortcuts_it->mode == mode)
78  {
79  girara_list_remove(session->bindings.shortcuts, shortcuts_it);
81  return true;
82  }
83  GIRARA_LIST_FOREACH_END(session->bindings.shortcuts, girara_shortcut_t*, iter, shortcuts_it);
84 
85  return false;
86 }
87 
88 void
89 girara_shortcut_free(girara_shortcut_t* shortcut)
90 {
91  g_return_if_fail(shortcut != NULL);
92  g_free(shortcut->argument.data);
93  g_slice_free(girara_shortcut_t, shortcut);
94 }
95 
96 bool
97 girara_inputbar_shortcut_add(girara_session_t* session, guint modifier, guint key, girara_shortcut_function_t function, int argument_n, void* argument_data)
98 {
99  g_return_val_if_fail(session != NULL, false);
100  g_return_val_if_fail(function != NULL, false);
101 
102  girara_argument_t argument = {argument_n, argument_data};
103 
104  /* search for existing special command */
105  GIRARA_LIST_FOREACH(session->bindings.inputbar_shortcuts, girara_inputbar_shortcut_t*, iter, inp_sh_it)
106  if (inp_sh_it->mask == modifier && inp_sh_it->key == key) {
107  inp_sh_it->function = function;
108  inp_sh_it->argument = argument;
109 
111  return true;
112  }
113  GIRARA_LIST_FOREACH_END(session->bindings.inputbar_shortcuts, girara_inputbar_shortcut_t*, iter, inp_sh_it);
114 
115  /* create new inputbar shortcut */
116  girara_inputbar_shortcut_t* inputbar_shortcut = g_slice_new(girara_inputbar_shortcut_t);
117 
118  inputbar_shortcut->mask = modifier;
119  inputbar_shortcut->key = key;
120  inputbar_shortcut->function = function;
121  inputbar_shortcut->argument = argument;
122 
123  girara_list_append(session->bindings.inputbar_shortcuts, inputbar_shortcut);
124  return true;
125 }
126 
127 bool
128 girara_inputbar_shortcut_remove(girara_session_t* session, guint modifier, guint key)
129 {
130  g_return_val_if_fail(session != NULL, false);
131 
132  /* search for existing special command */
133  GIRARA_LIST_FOREACH(session->bindings.inputbar_shortcuts, girara_inputbar_shortcut_t*, iter, inp_sh_it)
134  if (inp_sh_it->mask == modifier && inp_sh_it->key == key) {
135  girara_list_remove(session->bindings.inputbar_shortcuts, inp_sh_it);
137  return true;
138  }
139  GIRARA_LIST_FOREACH_END(session->bindings.inputbar_shortcuts, girara_inputbar_shortcut_t*, iter, inp_sh_it);
140 
141  return true;
142 }
143 
144 void
145 girara_inputbar_shortcut_free(girara_inputbar_shortcut_t* inputbar_shortcut)
146 {
147  g_slice_free(girara_inputbar_shortcut_t, inputbar_shortcut);
148 }
149 
150 bool
151 girara_isc_abort(girara_session_t* session, girara_argument_t* UNUSED(argument), girara_event_t* UNUSED(event), unsigned int UNUSED(t))
152 {
153  g_return_val_if_fail(session != NULL, false);
154 
155  /* hide completion */
156  girara_argument_t arg = { GIRARA_HIDE, NULL };
157  girara_isc_completion(session, &arg, NULL, 0);
158 
159  /* clear inputbar */
160  gtk_editable_delete_text(GTK_EDITABLE(session->gtk.inputbar_entry), 0, -1);
161 
162  /* grab view */
163  gtk_widget_grab_focus(GTK_WIDGET(session->gtk.view));
164 
165  /* hide inputbar */
166  gtk_widget_hide(GTK_WIDGET(session->gtk.inputbar_dialog));
167  if (session->global.autohide_inputbar == true) {
168  gtk_widget_hide(GTK_WIDGET(session->gtk.inputbar));
169  }
170 
171  /* Begin from the last command when navigating through history */
172  girara_input_history_reset(session->command_history);
173 
174  /* reset custom functions */
175  session->signals.inputbar_custom_activate = NULL;
176  session->signals.inputbar_custom_key_press_event = NULL;
177  gtk_entry_set_visibility(session->gtk.inputbar_entry, TRUE);
178 
179  return true;
180 }
181 
182 bool
183 girara_isc_string_manipulation(girara_session_t* session, girara_argument_t* argument, girara_event_t* UNUSED(event), unsigned int UNUSED(t))
184 {
185  g_return_val_if_fail(session != NULL, false);
186 
187  gchar *separator = NULL;
188  girara_setting_get(session, "word-separator", &separator);
189  gchar *input = gtk_editable_get_chars(GTK_EDITABLE(session->gtk.inputbar_entry), 0, -1);
190  int length = strlen(input);
191  int pos = gtk_editable_get_position(GTK_EDITABLE(session->gtk.inputbar_entry));
192  int i;
193 
194  switch (argument->n) {
196  if (pos == 1 && (input[0] == ':' || input[0] == '/')) {
197  break;
198  }
199  if (pos == 0) {
200  break;
201  }
202 
203  i = pos - 1;
204 
205  /* remove trailing spaces */
206  for (; i >= 0 && input[i] == ' '; i--);
207 
208  /* find the beginning of the word */
209  while ((i == (pos - 1)) || ((i > 0) && !strchr(separator, input[i]))) {
210  i--;
211  }
212 
213  gtk_editable_delete_text(GTK_EDITABLE(session->gtk.inputbar_entry), i + 1, pos);
214  gtk_editable_set_position(GTK_EDITABLE(session->gtk.inputbar_entry), i + 1);
215  break;
217  if (length != 1 && pos == 1 && (input[0] == ':' || input[0] == '/')) {
218  break;
219  }
220  if (length == 1 && pos == 1) {
221  girara_isc_abort(session, argument, NULL, 0);
222  }
223  gtk_editable_delete_text(GTK_EDITABLE(session->gtk.inputbar_entry), pos - 1, pos);
224  break;
226  gtk_editable_delete_text(GTK_EDITABLE(session->gtk.inputbar_entry), 1, pos);
227  break;
228  case GIRARA_NEXT_CHAR:
229  gtk_editable_set_position(GTK_EDITABLE(session->gtk.inputbar_entry), pos + 1);
230  break;
232  gtk_editable_set_position(GTK_EDITABLE(session->gtk.inputbar_entry), (pos == 1) ? 1 : pos - 1);
233  break;
235  if (length != 1 && pos == 0 && (input[0] == ':' || input[0] == '/')){
236  break;
237  }
238  if(length == 1 && pos == 0) {
239  girara_isc_abort(session, argument, NULL, 0);
240  }
241  gtk_editable_delete_text(GTK_EDITABLE(session->gtk.inputbar_entry), pos, pos + 1);
242  break;
244  gtk_editable_delete_text(GTK_EDITABLE(session->gtk.inputbar_entry), pos, length);
245  break;
246  case GIRARA_GOTO_START:
247  gtk_editable_set_position(GTK_EDITABLE(session->gtk.inputbar_entry), 1);
248  break;
249  case GIRARA_GOTO_END:
250  gtk_editable_set_position(GTK_EDITABLE(session->gtk.inputbar_entry), -1);
251  break;
252  }
253 
254  g_free(separator);
255  g_free(input);
256 
257  return false;
258 }
259 
260 bool
261 girara_isc_command_history(girara_session_t* session, girara_argument_t*
262  argument, girara_event_t* UNUSED(event), unsigned int UNUSED(t))
263 {
264  g_return_val_if_fail(session != NULL, false);
265 
266  char* temp = gtk_editable_get_chars(GTK_EDITABLE(session->gtk.inputbar_entry), 0, -1);
267  const char* command = argument->n == GIRARA_NEXT ?
268  girara_input_history_next(session->command_history, temp) :
269  girara_input_history_previous(session->command_history, temp);
270  g_free(temp);
271 
272  if (command != NULL) {
273  gtk_entry_set_text(session->gtk.inputbar_entry, command);
274  gtk_widget_grab_focus(GTK_WIDGET(session->gtk.inputbar_entry));
275  gtk_editable_set_position(GTK_EDITABLE(session->gtk.inputbar_entry), -1);
276  }
277 
278  return true;
279 }
280 
281 /* default shortcut implementation */
282 bool
283 girara_sc_focus_inputbar(girara_session_t* session, girara_argument_t* argument, girara_event_t* UNUSED(event), unsigned int UNUSED(t))
284 {
285  g_return_val_if_fail(session != NULL, false);
286  g_return_val_if_fail(session->gtk.inputbar_entry != NULL, false);
287 
288  if (gtk_widget_get_visible(GTK_WIDGET(session->gtk.inputbar)) == false) {
289  gtk_widget_show(GTK_WIDGET(session->gtk.inputbar));
290  }
291 
292  if (gtk_widget_get_visible(GTK_WIDGET(session->gtk.notification_area)) == true) {
293  gtk_widget_hide(GTK_WIDGET(session->gtk.notification_area));
294  }
295 
296  gtk_widget_grab_focus(GTK_WIDGET(session->gtk.inputbar_entry));
297 
298  if (argument != NULL && argument->data != NULL) {
299  gtk_entry_set_text(session->gtk.inputbar_entry, (char*) argument->data);
300 
301  /* we save the X clipboard that will be clear by "grab_focus" */
302  gchar* x_clipboard_text = gtk_clipboard_wait_for_text(gtk_clipboard_get(GDK_SELECTION_PRIMARY));
303 
304  gtk_editable_set_position(GTK_EDITABLE(session->gtk.inputbar_entry), -1);
305 
306  if (x_clipboard_text != NULL) {
307  /* we reset the X clipboard with saved text */
308  gtk_clipboard_set_text(gtk_clipboard_get(GDK_SELECTION_PRIMARY), x_clipboard_text, -1);
309  g_free(x_clipboard_text);
310  }
311  }
312 
313  return true;
314 }
315 
316 bool
317 girara_sc_abort(girara_session_t* session, girara_argument_t* UNUSED(argument), girara_event_t* UNUSED(event), unsigned int UNUSED(t))
318 {
319  g_return_val_if_fail(session != NULL, false);
320 
321  girara_isc_abort(session, NULL, NULL, 0);
322 
323  gtk_widget_hide(GTK_WIDGET(session->gtk.notification_area));
324 
325  if (session->global.autohide_inputbar == false) {
326  gtk_widget_show(GTK_WIDGET(session->gtk.inputbar));
327  }
328 
329  return false;
330 }
331 
332 bool
333 girara_sc_quit(girara_session_t* session, girara_argument_t* UNUSED(argument), girara_event_t* UNUSED(event), unsigned int UNUSED(t))
334 {
335  g_return_val_if_fail(session != NULL, false);
336 
337  girara_argument_t arg = { GIRARA_HIDE, NULL };
338  girara_isc_completion(session, &arg, NULL, 0);
339 
340  gtk_main_quit();
341 
342  return false;
343 }
344 
345 bool
346 girara_sc_tab_close(girara_session_t* session, girara_argument_t* UNUSED(argument), girara_event_t* UNUSED(event), unsigned int UNUSED(t))
347 {
348  g_return_val_if_fail(session != NULL, false);
349 
350  girara_tab_t* tab = girara_tab_current_get(session);
351 
352  if (tab != NULL) {
353  girara_tab_remove(session, tab);
354  }
355 
356  return false;
357 }
358 
359 bool
360 girara_sc_tab_navigate(girara_session_t* session, girara_argument_t* argument, girara_event_t* UNUSED(event), unsigned int t)
361 {
362  g_return_val_if_fail(session != NULL, false);
363 
364  unsigned int number_of_tabs = girara_get_number_of_tabs(session);
365  if (number_of_tabs == 0)
366  return false;
367 
368  unsigned int current_tab = girara_tab_position_get(session, girara_tab_current_get(session));
369  unsigned int step = (argument->n == GIRARA_PREVIOUS) ? -1 : 1;
370  unsigned int new_tab = (current_tab + step) % number_of_tabs;
371 
372  if (t != 0 && t <= number_of_tabs) {
373  new_tab = t - 1;
374  }
375 
376  girara_tab_t* tab = girara_tab_get(session, new_tab);
377 
378  if (tab != NULL) {
379  girara_tab_current_set(session, tab);
380  }
381 
382  girara_tab_update(session);
383 
384  return false;
385 }
386 
387 bool
388 girara_sc_tab_navigate_next(girara_session_t* session,
389  girara_argument_t* argument,
390  girara_event_t* event, unsigned int t)
391 {
392  argument->n = GIRARA_NEXT;
393  return girara_sc_tab_navigate(session, argument, event, t);
394 }
395 
396 bool
397 girara_sc_tab_navigate_prev(girara_session_t* session,
398  girara_argument_t* argument,
399  girara_event_t* event, unsigned int t)
400 {
401  argument->n = GIRARA_PREVIOUS;
402  return girara_sc_tab_navigate(session, argument, event, t);
403 }
404 
405 static void
406 girara_toggle_widget_visibility(GtkWidget* widget)
407 {
408  if (widget == NULL) {
409  return;
410  }
411 
412  if (gtk_widget_get_visible(widget)) {
413  gtk_widget_hide(widget);
414  } else {
415  gtk_widget_show(widget);
416  }
417 }
418 
419 bool
420 girara_sc_toggle_inputbar(girara_session_t* session, girara_argument_t* UNUSED(argument), girara_event_t* UNUSED(event), unsigned int UNUSED(t))
421 {
422  g_return_val_if_fail(session != NULL, false);
423 
424  girara_toggle_widget_visibility(GTK_WIDGET(session->gtk.inputbar));
425 
426  return true;
427 }
428 
429 bool
430 girara_sc_toggle_statusbar(girara_session_t* session, girara_argument_t* UNUSED(argument), girara_event_t* UNUSED(event), unsigned int UNUSED(t))
431 {
432  g_return_val_if_fail(session != NULL, false);
433 
434  girara_toggle_widget_visibility(GTK_WIDGET(session->gtk.statusbar));
435 
436  return true;
437 }
438 
439 bool
440 girara_sc_toggle_tabbar(girara_session_t* session, girara_argument_t* UNUSED(argument), girara_event_t* UNUSED(event), unsigned int UNUSED(t))
441 {
442  g_return_val_if_fail(session != NULL, false);
443 
444  girara_toggle_widget_visibility(GTK_WIDGET(session->gtk.tabbar));
445 
446  return true;
447 }
448 
449 bool
450 girara_sc_set(girara_session_t* session, girara_argument_t* argument, girara_event_t* UNUSED(event), unsigned int UNUSED(t))
451 {
452  g_return_val_if_fail(session != NULL, false);
453 
454  if (argument == NULL || argument->data == NULL) {
455  return false;
456  }
457 
458  /* create argument list */
459  girara_list_t* argument_list = girara_list_new();
460  if (argument_list == NULL) {
461  return false;
462  }
463 
464  gchar** argv = NULL;
465  gint argc = 0;
466 
467  girara_list_set_free_function(argument_list, g_free);
468  if (g_shell_parse_argv((const gchar*) argument->data, &argc, &argv, NULL) != FALSE) {
469  for(int i = 0; i < argc; i++) {
470  char* argument = g_strdup(argv[i]);
471  girara_list_append(argument_list, (void*) argument);
472  }
473  } else {
474  girara_list_free(argument_list);
475  return false;
476  }
477 
478  /* call set */
479  girara_cmd_set(session, argument_list);
480 
481  /* cleanup */
482  girara_list_free(argument_list);
483 
484  return false;
485 }
486 
487 bool
488 girara_sc_feedkeys(girara_session_t* session, girara_argument_t* argument,
489  girara_event_t* UNUSED(event), unsigned int t)
490 {
491  if (session == NULL || argument == NULL) {
492  return false;
493  }
494 
495  typedef struct gdk_keyboard_button_s {
496  char* identifier;
497  int keyval;
498  } gdk_keyboard_button_t;
499 
500  static const gdk_keyboard_button_t gdk_keyboard_buttons[] = {
501  {"BackSpace", GDK_KEY_BackSpace},
502  {"CapsLock", GDK_KEY_Caps_Lock},
503  {"Down", GDK_KEY_Down},
504  {"Esc", GDK_KEY_Escape},
505  {"F10", GDK_KEY_F10},
506  {"F11", GDK_KEY_F11},
507  {"F12", GDK_KEY_F12},
508  {"F1", GDK_KEY_F1},
509  {"F2", GDK_KEY_F2},
510  {"F3", GDK_KEY_F3},
511  {"F4", GDK_KEY_F4},
512  {"F5", GDK_KEY_F5},
513  {"F6", GDK_KEY_F6},
514  {"F7", GDK_KEY_F7},
515  {"F8", GDK_KEY_F8},
516  {"F9", GDK_KEY_F9},
517  {"Left", GDK_KEY_Left},
518  {"PageDown", GDK_KEY_Page_Down},
519  {"PageUp", GDK_KEY_Page_Up},
520  {"Home", GDK_KEY_Home},
521  {"End", GDK_KEY_End},
522  {"Return", GDK_KEY_Return},
523  {"Right", GDK_KEY_Right},
524  {"Space", GDK_KEY_space},
525  {"Super", GDK_KEY_Super_L},
526  {"Tab", GDK_KEY_Tab},
527  {"ShiftTab", GDK_KEY_ISO_Left_Tab},
528  {"Up", GDK_KEY_Up}
529  };
530 
531  char* input = (char*) argument->data;
532  unsigned int input_length = strlen(input);
533 
534  t = (t == 0) ? 1 : t;
535  for (unsigned int c = 0; c < t; c++) {
536  for (unsigned i = 0; i < input_length; i++) {
537  int state = 0;
538  int keyval = input[i];
539 
540  /* possible special button */
541  if ((input_length - i) >= 3 && input[i] == '<') {
542  char* end = strchr(input + i, '>');
543  if (end == NULL) {
544  goto single_key;
545  }
546 
547  int length = end - (input + i) - 1;
548  char* tmp = g_strndup(input + i + 1, length);
549  bool found = false;
550 
551  /* Multi key shortcut */
552  if (length > 2 && tmp[1] == '-') {
553  switch (tmp[0]) {
554  case 'S':
555  state = GDK_SHIFT_MASK;
556  break;
557  case 'A':
558  state = GDK_MOD1_MASK;
559  break;
560  case 'C':
561  state = GDK_CONTROL_MASK;
562  break;
563  default:
564  break;
565  }
566 
567  if (length == 3) {
568  keyval = tmp[2];
569  found = true;
570  } else {
571  for (unsigned int i = 0; i < LENGTH(gdk_keyboard_buttons); i++) {
572  if (g_strcmp0(tmp + 2, gdk_keyboard_buttons[i].identifier) == 0) {
573  keyval = gdk_keyboard_buttons[i].keyval;
574  found = true;
575  break;
576  }
577  }
578  }
579  /* Possible special key */
580  } else {
581  for (unsigned int i = 0; i < LENGTH(gdk_keyboard_buttons); i++) {
582  if (g_strcmp0(tmp, gdk_keyboard_buttons[i].identifier) == 0) {
583  keyval = gdk_keyboard_buttons[i].keyval;
584  found = true;
585  break;
586  }
587  }
588  }
589 
590  g_free(tmp);
591 
592  /* parsed special key */
593  if (found == true) {
594  i += length + 1;
595  }
596  }
597 
598 single_key:
599 
600  update_state_by_keyval(&state, keyval);
601  simulate_key_press(session, state, keyval);
602  }
603  }
604 
605  return true;
606 }
607 
608 bool
609 girara_shortcut_mapping_add(girara_session_t* session, const char* identifier, girara_shortcut_function_t function)
610 {
611  g_return_val_if_fail(session != NULL, false);
612 
613  if (function == NULL || identifier == NULL) {
614  return false;
615  }
616 
617  GIRARA_LIST_FOREACH(session->config.shortcut_mappings, girara_shortcut_mapping_t*, iter, data)
618  if (strcmp(data->identifier, identifier) == 0) {
619  data->function = function;
621  return true;
622  }
623  GIRARA_LIST_FOREACH_END(session->config.shortcut_mappings, girara_shortcut_mapping_t*, iter, data);
624 
625  /* add new config handle */
626  girara_shortcut_mapping_t* mapping = g_slice_new(girara_shortcut_mapping_t);
627 
628  mapping->identifier = g_strdup(identifier);
629  mapping->function = function;
630  girara_list_append(session->config.shortcut_mappings, mapping);
631 
632  return true;
633 }
634 
635 void
636 girara_shortcut_mapping_free(girara_shortcut_mapping_t* mapping)
637 {
638  if (mapping == NULL) {
639  return;
640  }
641 
642  g_free(mapping->identifier);
643  g_slice_free(girara_shortcut_mapping_t, mapping);
644 }
645 
646 bool
647 girara_argument_mapping_add(girara_session_t* session, const char* identifier, int value)
648 {
649  g_return_val_if_fail(session != NULL, false);
650 
651  if (identifier == NULL) {
652  return false;
653  }
654 
655  GIRARA_LIST_FOREACH(session->config.argument_mappings, girara_argument_mapping_t*, iter, mapping);
656  if (g_strcmp0(mapping->identifier, identifier) == 0) {
657  mapping->value = value;
659  return true;
660  }
661  GIRARA_LIST_FOREACH_END(session->config.argument_mappings, girara_argument_mapping_t*, iter, mapping);
662 
663  /* add new config handle */
664  girara_argument_mapping_t* mapping = g_slice_new(girara_argument_mapping_t);
665 
666  mapping->identifier = g_strdup(identifier);
667  mapping->value = value;
668  girara_list_append(session->config.argument_mappings, mapping);
669 
670  return true;
671 }
672 
673 void
674 girara_argument_mapping_free(girara_argument_mapping_t* argument_mapping)
675 {
676  if (argument_mapping == NULL) {
677  return;
678  }
679 
680  g_free(argument_mapping->identifier);
681  g_slice_free(girara_argument_mapping_t, argument_mapping);
682 }
683 
684 bool
685 girara_mouse_event_add(girara_session_t* session, guint mask, guint button,
687  event_type, int argument_n, void* argument_data)
688 {
689  g_return_val_if_fail(session != NULL, false);
690  g_return_val_if_fail(function != NULL, false);
691 
692  girara_argument_t argument = {argument_n, argument_data};
693 
694  /* search for existing binding */
695  GIRARA_LIST_FOREACH(session->bindings.mouse_events, girara_mouse_event_t*, iter, me_it)
696  if (me_it->mask == mask && me_it->button == button &&
697  me_it->mode == mode && me_it->event_type == event_type)
698  {
699  me_it->function = function;
700  me_it->argument = argument;
702  return true;
703  }
704  GIRARA_LIST_FOREACH_END(session->bindings.mouse_events, girara_mouse_event_t*, iter, me_it);
705 
706  /* add new mouse event */
707  girara_mouse_event_t* mouse_event = g_slice_new(girara_mouse_event_t);
708 
709  mouse_event->mask = mask;
710  mouse_event->button = button;
711  mouse_event->function = function;
712  mouse_event->mode = mode;
713  mouse_event->event_type = event_type;
714  mouse_event->argument = argument;
715  girara_list_append(session->bindings.mouse_events, mouse_event);
716 
717  return true;
718 }
719 
720 bool
721 girara_mouse_event_remove(girara_session_t* session, guint mask, guint button, girara_mode_t mode)
722 {
723  g_return_val_if_fail(session != NULL, false);
724 
725  /* search for existing binding */
726  GIRARA_LIST_FOREACH(session->bindings.mouse_events, girara_mouse_event_t*, iter, me_it)
727  if (me_it->mask == mask && me_it->button == button &&
728  me_it->mode == mode)
729  {
730  girara_list_remove(session->bindings.mouse_events, me_it);
732  return true;
733  }
734  GIRARA_LIST_FOREACH_END(session->bindings.mouse_events, girara_mouse_event_t*, iter, me_it);
735 
736  return false;
737 }
738 
739 void
740 girara_mouse_event_free(girara_mouse_event_t* mouse_event)
741 {
742  if (mouse_event == NULL) {
743  return;
744  }
745  g_slice_free(girara_mouse_event_t, mouse_event);
746 }
747 
748 static bool
749 simulate_key_press(girara_session_t* session, int state, int key)
750 {
751  if (session == NULL || session->gtk.box == NULL) {
752  return false;
753  }
754 
755  GdkEvent* event = gdk_event_new(GDK_KEY_PRESS);
756 
757  event->key.type = GDK_KEY_PRESS;
758  event->key.window = gtk_widget_get_parent_window(GTK_WIDGET(session->gtk.box));
759  event->key.send_event = false;
760  event->key.time = GDK_CURRENT_TIME;
761  event->key.state = state;
762  event->key.keyval = key;
763 
764  g_object_ref(event->key.window);
765 
766  GdkKeymapKey* keys;
767  gint number_of_keys;
768 
769  if (gdk_keymap_get_entries_for_keyval(gdk_keymap_get_default(),
770  event->key.keyval, &keys, &number_of_keys) == FALSE) {
771  gdk_event_free(event);
772  return false;
773  }
774 
775  event->key.hardware_keycode = keys[0].keycode;
776  event->key.group = keys[0].group;
777 
778  g_free(keys);
779 
780  gdk_event_put(event);
781  gdk_event_free(event);
782 
783  gtk_main_iteration_do(FALSE);
784 
785  return true;
786 }