callbacks.c 18.8 KB
Newer Older
Sebastian Ramacher's avatar
Sebastian Ramacher committed
1 2 3
/* See LICENSE file for license and copyright information */

#include "callbacks.h"
Sebastian Ramacher's avatar
Sebastian Ramacher committed
4

Sebastian Ramacher's avatar
Sebastian Ramacher committed
5
#include "datastructures.h"
6
#include "input-history.h"
Sebastian Ramacher's avatar
Sebastian Ramacher committed
7
#include "internal.h"
Sebastian Ramacher's avatar
Sebastian Ramacher committed
8 9
#include "session.h"
#include "shortcuts.h"
Sebastian Ramacher's avatar
Sebastian Ramacher committed
10 11
#include "utils.h"

12
#include <glib/gi18n-lib.h>
Sebastian Ramacher's avatar
Sebastian Ramacher committed
13
#include <string.h>
Sebastian Ramacher's avatar
Sebastian Ramacher committed
14

15
static const guint ALL_ACCELS_MASK = GDK_CONTROL_MASK | GDK_SHIFT_MASK | GDK_MOD1_MASK;
16 17
static const guint MOUSE_MASK = GDK_CONTROL_MASK | GDK_SHIFT_MASK | GDK_MOD1_MASK |
  GDK_BUTTON1_MASK | GDK_BUTTON2_MASK | GDK_BUTTON3_MASK | GDK_BUTTON4_MASK | GDK_BUTTON5_MASK;
18

19 20
static bool
clean_mask(guint hardware_keycode, GdkModifierType state, gint group, guint* clean, guint* keyval)
Sebastian Ramacher's avatar
Sebastian Ramacher committed
21
{
22
  GdkModifierType consumed = 0;
Moritz Lipp's avatar
Moritz Lipp committed
23 24
  if ((gdk_keymap_translate_keyboard_state(
        gdk_keymap_get_default(),
25 26 27
        hardware_keycode,
        state, group,
        keyval,
Moritz Lipp's avatar
Moritz Lipp committed
28 29 30 31 32
        NULL,
        NULL,
        &consumed)
      ) == FALSE) {
    return false;
33
  }
34 35 36 37

  if (clean != NULL) {
    *clean = state & ~consumed & ALL_ACCELS_MASK;
  }
38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72

  /* numpad numbers */
  switch (*keyval) {
    case GDK_KEY_KP_0:
      *keyval = GDK_KEY_0;
      break;
    case GDK_KEY_KP_1:
      *keyval = GDK_KEY_1;
      break;
    case GDK_KEY_KP_2:
      *keyval = GDK_KEY_2;
      break;
    case GDK_KEY_KP_3:
      *keyval = GDK_KEY_3;
      break;
    case GDK_KEY_KP_4:
      *keyval = GDK_KEY_4;
      break;
    case GDK_KEY_KP_5:
      *keyval = GDK_KEY_5;
      break;
    case GDK_KEY_KP_6:
      *keyval = GDK_KEY_6;
      break;
    case GDK_KEY_KP_7:
      *keyval = GDK_KEY_7;
      break;
    case GDK_KEY_KP_8:
      *keyval = GDK_KEY_8;
      break;
    case GDK_KEY_KP_9:
      *keyval = GDK_KEY_9;
      break;
  }

73 74 75 76
  return true;
}

/* callback implementation */
77
gboolean
78 79 80 81 82
girara_callback_view_key_press_event(GtkWidget* UNUSED(widget),
    GdkEventKey* event, girara_session_t* session)
{
  g_return_val_if_fail(session != NULL, FALSE);

83
  guint clean  = 0;
84
  guint keyval = 0;
85

86 87 88
  if (clean_mask(event->hardware_keycode, event->state, event->group, &clean, &keyval) == false) {
    return false;
  }
89

90 91
  girara_session_private_t* session_private = session->private_data;

92
  /* prepare event */
Sebastian Ramacher's avatar
Sebastian Ramacher committed
93
  GIRARA_LIST_FOREACH(session->bindings.shortcuts, girara_shortcut_t*, iter, shortcut)
94
    if (session_private->buffer.command != NULL) {
Sebastian Ramacher's avatar
Sebastian Ramacher committed
95 96
      break;
    }
Moritz Lipp's avatar
Moritz Lipp committed
97 98

    if ( keyval == shortcut->key
99 100
      && (clean == shortcut->mask || (shortcut->key >= 0x21
      && shortcut->key <= 0x7E && clean == GDK_SHIFT_MASK))
Moritz Lipp's avatar
Moritz Lipp committed
101
      && (session->modes.current_mode == shortcut->mode || shortcut->mode == 0)
Moritz Lipp's avatar
Moritz Lipp committed
102
      && shortcut->function != NULL
Sebastian Ramacher's avatar
Sebastian Ramacher committed
103 104
      )
    {
105
      const int t = (session_private->buffer.n > 0) ? session_private->buffer.n : 1;
Sebastian Ramacher's avatar
Sebastian Ramacher committed
106
      for (int i = 0; i < t; i++) {
107
        if (shortcut->function(session, &(shortcut->argument), NULL, session_private->buffer.n) == false) {
Sebastian Ramacher's avatar
Sebastian Ramacher committed
108 109 110 111
          break;
        }
      }

Moritz Lipp's avatar
Moritz Lipp committed
112
      if (session->global.buffer != NULL) {
Sebastian Ramacher's avatar
Sebastian Ramacher committed
113 114 115 116
        g_string_free(session->global.buffer, TRUE);
        session->global.buffer = NULL;
      }

117
      session_private->buffer.n = 0;
Sebastian Ramacher's avatar
Sebastian Ramacher committed
118

Moritz Lipp's avatar
Moritz Lipp committed
119
      if (session->events.buffer_changed != NULL) {
Sebastian Ramacher's avatar
Sebastian Ramacher committed
120 121 122 123 124 125 126 127 128
        session->events.buffer_changed(session);
      }

      girara_list_iterator_free(iter);
      return TRUE;
    }
  GIRARA_LIST_FOREACH_END(session->bindings.shortcuts, girara_shortcut_t*, iter, shortcut);

  /* update buffer */
129
  if (keyval >= 0x21 && keyval <= 0x7E) {
Sebastian Ramacher's avatar
Sebastian Ramacher committed
130
    /* overall buffer */
Moritz Lipp's avatar
Moritz Lipp committed
131
    if (session->global.buffer == NULL) {
Sebastian Ramacher's avatar
Sebastian Ramacher committed
132 133 134
      session->global.buffer = g_string_new("");
    }

135
    session->global.buffer = g_string_append_c(session->global.buffer, keyval);
Sebastian Ramacher's avatar
Sebastian Ramacher committed
136

137 138 139
    if (session_private->buffer.command == NULL && keyval >= 0x30 && keyval <= 0x39) {
      if (((session_private->buffer.n * 10) + (keyval - '0')) < INT_MAX) {
        session_private->buffer.n = (session_private->buffer.n * 10) + (keyval - '0');
Sebastian Ramacher's avatar
Sebastian Ramacher committed
140 141
      }
    } else {
142 143
      if (session_private->buffer.command == NULL) {
        session_private->buffer.command = g_string_new("");
Sebastian Ramacher's avatar
Sebastian Ramacher committed
144 145
      }

146
      session_private->buffer.command = g_string_append_c(session_private->buffer.command, keyval);
Sebastian Ramacher's avatar
Sebastian Ramacher committed
147 148
    }

Moritz Lipp's avatar
Moritz Lipp committed
149
    if (session->events.buffer_changed != NULL) {
Sebastian Ramacher's avatar
Sebastian Ramacher committed
150 151 152 153 154
      session->events.buffer_changed(session);
    }
  }

  /* check for buffer command */
155
  if (session_private->buffer.command != NULL) {
Sebastian Ramacher's avatar
Sebastian Ramacher committed
156 157 158
    bool matching_command = FALSE;

    GIRARA_LIST_FOREACH(session->bindings.shortcuts, girara_shortcut_t*, iter, shortcut)
Moritz Lipp's avatar
Moritz Lipp committed
159
      if (shortcut->buffered_command != NULL) {
Sebastian Ramacher's avatar
Sebastian Ramacher committed
160
        /* buffer could match a command */
161
        if (!strncmp(session_private->buffer.command->str, shortcut->buffered_command, session_private->buffer.command->len)) {
Sebastian Ramacher's avatar
Sebastian Ramacher committed
162
          /* command matches buffer exactly */
163
          if (!strcmp(session_private->buffer.command->str, shortcut->buffered_command)
164
            && (session->modes.current_mode == shortcut->mode || shortcut->mode == 0)) {
165
            g_string_free(session_private->buffer.command, TRUE);
Sebastian Ramacher's avatar
Sebastian Ramacher committed
166
            g_string_free(session->global.buffer,  TRUE);
167
            session_private->buffer.command = NULL;
Sebastian Ramacher's avatar
Sebastian Ramacher committed
168 169
            session->global.buffer  = NULL;

Moritz Lipp's avatar
Moritz Lipp committed
170
            if (session->events.buffer_changed != NULL) {
Sebastian Ramacher's avatar
Sebastian Ramacher committed
171 172 173
              session->events.buffer_changed(session);
            }

174
            int t = (session_private->buffer.n > 0) ? session_private->buffer.n : 1;
Sebastian Ramacher's avatar
Sebastian Ramacher committed
175
            for (int i = 0; i < t; i++) {
176
              if (shortcut->function(session, &(shortcut->argument), NULL, session_private->buffer.n) == false) {
Sebastian Ramacher's avatar
Sebastian Ramacher committed
177 178 179 180
                break;
              }
            }

181
            session_private->buffer.n = 0;
Sebastian Ramacher's avatar
Sebastian Ramacher committed
182 183 184 185 186 187 188 189 190 191
            girara_list_iterator_free(iter);
            return TRUE;
          }

          matching_command = TRUE;
        }
      }
    GIRARA_LIST_FOREACH_END(session->bindings.shortcuts, girara_shortcut_t*, iter, shortcut);

    /* free buffer if buffer will never match a command */
Moritz Lipp's avatar
Moritz Lipp committed
192
    if (matching_command == false) {
193
      g_string_free(session_private->buffer.command, TRUE);
Sebastian Ramacher's avatar
Sebastian Ramacher committed
194
      g_string_free(session->global.buffer,  TRUE);
195
      session_private->buffer.command = NULL;
Sebastian Ramacher's avatar
Sebastian Ramacher committed
196
      session->global.buffer  = NULL;
197
      session_private->buffer.n       = 0;
Sebastian Ramacher's avatar
Sebastian Ramacher committed
198

Moritz Lipp's avatar
Moritz Lipp committed
199
      if (session->events.buffer_changed != NULL) {
Sebastian Ramacher's avatar
Sebastian Ramacher committed
200 201 202 203 204 205 206 207
        session->events.buffer_changed(session);
      }
    }
  }

  return FALSE;
}

208
gboolean
Moritz Lipp's avatar
Moritz Lipp committed
209 210
girara_callback_view_button_press_event(GtkWidget* UNUSED(widget),
    GdkEventButton* button, girara_session_t* session)
211
{
Moritz Lipp's avatar
Moritz Lipp committed
212 213 214 215
  g_return_val_if_fail(session != NULL, false);
  g_return_val_if_fail(button  != NULL, false);

  /* prepare girara event */
Sebastian Ramacher's avatar
Sebastian Ramacher committed
216 217 218 219
  girara_event_t event = {
    .x = button->x,
    .y = button->y
  };
Moritz Lipp's avatar
Moritz Lipp committed
220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235

  switch (button->type) {
    case GDK_BUTTON_PRESS:
      event.type = GIRARA_EVENT_BUTTON_PRESS;
      break;
    case GDK_2BUTTON_PRESS:
      event.type = GIRARA_EVENT_2BUTTON_PRESS;
      break;
    case GDK_3BUTTON_PRESS:
      event.type = GIRARA_EVENT_3BUTTON_PRESS;
      break;
    default: /* do not handle unknown events */
      event.type = GIRARA_EVENT_OTHER;
      break;
  }

236
  const guint state = button->state & MOUSE_MASK;
237
  girara_session_private_t* session_private = session->private_data;
238

Moritz Lipp's avatar
Moritz Lipp committed
239 240 241 242
  /* search registered mouse events */
  GIRARA_LIST_FOREACH(session->bindings.mouse_events, girara_mouse_event_t*, iter, mouse_event)
    if (mouse_event->function != NULL
        && button->button == mouse_event->button
243
        && state  == mouse_event->mask
Moritz Lipp's avatar
Moritz Lipp committed
244
        && mouse_event->event_type == event.type
245
        && (session->modes.current_mode == mouse_event->mode || mouse_event->mode == 0)
Moritz Lipp's avatar
Moritz Lipp committed
246
       ) {
247
        mouse_event->function(session, &(mouse_event->argument), &event, session_private->buffer.n);
Moritz Lipp's avatar
Moritz Lipp committed
248 249 250 251 252 253
        girara_list_iterator_free(iter);
      return true;
    }
  GIRARA_LIST_FOREACH_END(session->bindings.mouse_events, girara_mouse_event_t*, iter, mouse_event);

  return false;
254 255
}

256
gboolean
Moritz Lipp's avatar
Moritz Lipp committed
257
girara_callback_view_button_release_event(GtkWidget* UNUSED(widget), GdkEventButton* button, girara_session_t* session)
258
{
Moritz Lipp's avatar
Moritz Lipp committed
259 260 261 262
  g_return_val_if_fail(session != NULL, false);
  g_return_val_if_fail(button  != NULL, false);

  /* prepare girara event */
Sebastian Ramacher's avatar
Sebastian Ramacher committed
263 264 265 266 267
  girara_event_t event = {
    .type = GIRARA_EVENT_BUTTON_RELEASE,
    .x    = button->x,
    .y    = button->y
  };
Moritz Lipp's avatar
Moritz Lipp committed
268

269
  const guint state = button->state & MOUSE_MASK;
270
  girara_session_private_t* session_private = session->private_data;
271

Moritz Lipp's avatar
Moritz Lipp committed
272 273 274 275
  /* search registered mouse events */
  GIRARA_LIST_FOREACH(session->bindings.mouse_events, girara_mouse_event_t*, iter, mouse_event)
    if (mouse_event->function != NULL
        && button->button == mouse_event->button
276
        && state  == mouse_event->mask
Moritz Lipp's avatar
Moritz Lipp committed
277
        && mouse_event->event_type == GIRARA_EVENT_BUTTON_RELEASE
278
        && (session->modes.current_mode == mouse_event->mode || mouse_event->mode == 0)
Moritz Lipp's avatar
Moritz Lipp committed
279
       ) {
280
        mouse_event->function(session, &(mouse_event->argument), &event, session_private->buffer.n);
Moritz Lipp's avatar
Moritz Lipp committed
281 282 283 284 285 286
        girara_list_iterator_free(iter);
      return true;
    }
  GIRARA_LIST_FOREACH_END(session->bindings.mouse_events, girara_mouse_event_t*, iter, mouse_event);

  return false;
287 288
}

289
gboolean
Moritz Lipp's avatar
Moritz Lipp committed
290
girara_callback_view_button_motion_notify_event(GtkWidget* UNUSED(widget), GdkEventMotion* button, girara_session_t* session)
291
{
Moritz Lipp's avatar
Moritz Lipp committed
292 293 294 295
  g_return_val_if_fail(session != NULL, false);
  g_return_val_if_fail(button  != NULL, false);

  /* prepare girara event */
Sebastian Ramacher's avatar
Sebastian Ramacher committed
296 297 298 299 300
  girara_event_t event = {
    .type = GIRARA_EVENT_MOTION_NOTIFY,
    .x    = button->x,
    .y    = button->y
  };
Moritz Lipp's avatar
Moritz Lipp committed
301

302
  const guint state = button->state & MOUSE_MASK;
303
  girara_session_private_t* session_private = session->private_data;
304

Moritz Lipp's avatar
Moritz Lipp committed
305 306 307
  /* search registered mouse events */
  GIRARA_LIST_FOREACH(session->bindings.mouse_events, girara_mouse_event_t*, iter, mouse_event)
    if (mouse_event->function != NULL
308
        && state  == mouse_event->mask
Moritz Lipp's avatar
Moritz Lipp committed
309
        && mouse_event->event_type == event.type
310
        && (session->modes.current_mode == mouse_event->mode || mouse_event->mode == 0)
Moritz Lipp's avatar
Moritz Lipp committed
311
       ) {
312
        mouse_event->function(session, &(mouse_event->argument), &event, session_private->buffer.n);
Moritz Lipp's avatar
Moritz Lipp committed
313 314 315 316 317 318
        girara_list_iterator_free(iter);
      return true;
    }
  GIRARA_LIST_FOREACH_END(session->bindings.mouse_events, girara_mouse_event_t*, iter, mouse_event);

  return false;
319 320
}

321
gboolean
322 323 324 325 326 327
girara_callback_view_scroll_event(GtkWidget* UNUSED(widget), GdkEventScroll* scroll, girara_session_t* session)
{
  g_return_val_if_fail(session != NULL, false);
  g_return_val_if_fail(scroll  != NULL, false);

  /* prepare girara event */
Sebastian Ramacher's avatar
Sebastian Ramacher committed
328 329 330 331
  girara_event_t event = {
    .x    = scroll->x,
    .y    = scroll->y
  };
332 333 334

  switch (scroll->direction) {
    case GDK_SCROLL_UP:
Moritz Lipp's avatar
Moritz Lipp committed
335
      event.type = GIRARA_EVENT_SCROLL_UP;
336 337
      break;
    case GDK_SCROLL_DOWN:
Moritz Lipp's avatar
Moritz Lipp committed
338
      event.type = GIRARA_EVENT_SCROLL_DOWN;
339 340
      break;
    case GDK_SCROLL_LEFT:
Moritz Lipp's avatar
Moritz Lipp committed
341
      event.type = GIRARA_EVENT_SCROLL_LEFT;
342 343
      break;
    case GDK_SCROLL_RIGHT:
Moritz Lipp's avatar
Moritz Lipp committed
344
      event.type = GIRARA_EVENT_SCROLL_RIGHT;
345
      break;
346 347
    case GDK_SCROLL_SMOOTH:
      event.type = GIRARA_EVENT_SCROLL_BIDIRECTIONAL;
348 349
      /* We abuse x and y here. We really need more fields in girara_event_t. */
      gdk_event_get_scroll_deltas((GdkEvent*)scroll, &event.x, &event.y);
350
      break;
351 352 353 354
    default:
      return false;
  }

355
  const guint state = scroll->state & MOUSE_MASK;
356
  girara_session_private_t* session_private = session->private_data;
357

358 359 360 361
  /* search registered mouse events */
  /* TODO: Filter correct event */
  GIRARA_LIST_FOREACH(session->bindings.mouse_events, girara_mouse_event_t*, iter, mouse_event)
    if (mouse_event->function != NULL
362
        && state  == mouse_event->mask
Moritz Lipp's avatar
Moritz Lipp committed
363
        && mouse_event->event_type == event.type
364
        && (session->modes.current_mode == mouse_event->mode || mouse_event->mode == 0)
365
       ) {
366
        mouse_event->function(session, &(mouse_event->argument), &event, session_private->buffer.n);
367 368 369 370 371 372 373 374
        girara_list_iterator_free(iter);
        return true;
    }
  GIRARA_LIST_FOREACH_END(session->bindings.mouse_events, girara_mouse_event_t*, iter, mouse_event);

  return false;
}

375
gboolean
Sebastian Ramacher's avatar
Sebastian Ramacher committed
376 377 378 379
girara_callback_inputbar_activate(GtkEntry* entry, girara_session_t* session)
{
  g_return_val_if_fail(session != NULL, FALSE);

Moritz Lipp's avatar
Moritz Lipp committed
380 381
  /* a custom handler has been installed (e.g. by girara_dialog) */
  if (session->signals.inputbar_custom_activate != NULL) {
Moritz Lipp's avatar
Moritz Lipp committed
382
    bool return_value = session->signals.inputbar_custom_activate(entry, session->signals.inputbar_custom_data);
Moritz Lipp's avatar
Moritz Lipp committed
383 384 385 386

    /* disconnect custom handler */
    session->signals.inputbar_custom_activate        = NULL;
    session->signals.inputbar_custom_key_press_event = NULL;
Moritz Lipp's avatar
Moritz Lipp committed
387
    session->signals.inputbar_custom_data            = NULL;
Moritz Lipp's avatar
Moritz Lipp committed
388 389 390 391

    if (session->gtk.inputbar_dialog != NULL && session->gtk.inputbar_entry != NULL) {
      gtk_label_set_markup(session->gtk.inputbar_dialog, "");
      gtk_widget_hide(GTK_WIDGET(session->gtk.inputbar_dialog));
Moritz Lipp's avatar
Moritz Lipp committed
392 393 394
      if (session->global.autohide_inputbar == true) {
        gtk_widget_hide(GTK_WIDGET(session->gtk.inputbar));
      }
Moritz Lipp's avatar
Moritz Lipp committed
395
      gtk_entry_set_visibility(session->gtk.inputbar_entry, TRUE);
396
      girara_isc_abort(session, NULL, NULL, 0);
Moritz Lipp's avatar
Moritz Lipp committed
397 398 399 400 401 402
      return true;
    }

    return return_value;
  }

Moritz Lipp's avatar
Moritz Lipp committed
403 404
  gchar *input = gtk_editable_get_chars(GTK_EDITABLE(entry), 1, -1);
  if (input == NULL) {
405
    girara_isc_abort(session, NULL, NULL, 0);
Sebastian Ramacher's avatar
Sebastian Ramacher committed
406 407 408 409
    return false;
  }

  if (strlen(input) == 0) {
Moritz Lipp's avatar
Moritz Lipp committed
410
    g_free(input);
411
    girara_isc_abort(session, NULL, NULL, 0);
Sebastian Ramacher's avatar
Sebastian Ramacher committed
412 413 414
    return false;
  }

Moritz Lipp's avatar
Moritz Lipp committed
415
  /* append to command history */
416
  const char* command = gtk_entry_get_text(entry);
417
  girara_input_history_append(session->command_history, command);
418

Sebastian Ramacher's avatar
Sebastian Ramacher committed
419 420
  /* special commands */
  char *identifier_s = gtk_editable_get_chars(GTK_EDITABLE(entry), 0, 1);
Moritz Lipp's avatar
Moritz Lipp committed
421 422 423 424
  if (identifier_s == NULL) {
    return false;
  }

Sebastian Ramacher's avatar
Sebastian Ramacher committed
425
  const char identifier = identifier_s[0];
Sebastian Ramacher's avatar
Sebastian Ramacher committed
426 427
  g_free(identifier_s);

Sebastian Ramacher's avatar
Sebastian Ramacher committed
428
  girara_debug("Processing special command with identifier '%c'.", identifier);
Sebastian Ramacher's avatar
Sebastian Ramacher committed
429 430
  GIRARA_LIST_FOREACH(session->bindings.special_commands, girara_special_command_t*, iter, special_command)
    if (special_command->identifier == identifier) {
Sebastian Ramacher's avatar
Sebastian Ramacher committed
431
      girara_debug("Found special command.");
Sebastian Ramacher's avatar
Sebastian Ramacher committed
432 433 434 435
      if (special_command->always != true) {
        special_command->function(session, input, &(special_command->argument));
      }

436
      girara_isc_abort(session, NULL, NULL, 0);
Sebastian Ramacher's avatar
Sebastian Ramacher committed
437 438 439 440 441 442

      girara_list_iterator_free(iter);
      return true;
    }
  GIRARA_LIST_FOREACH_END(session->bindings.special_commands, girara_special_command_t*, iter, special_command);

Sebastian Ramacher's avatar
Sebastian Ramacher committed
443 444 445 446 447 448 449 450 451 452 453 454
  /* parse input */
  gchar** argv = NULL;
  gint    argc = 0;

  if (g_shell_parse_argv(input, &argc, &argv, NULL) == FALSE) {
    girara_debug("Failed to parse argument.");
    g_free(input);
    return false;
  }

  gchar *cmd = argv[0];

Sebastian Ramacher's avatar
Sebastian Ramacher committed
455 456 457
  /* search commands */
  GIRARA_LIST_FOREACH(session->bindings.commands, girara_command_t*, iter, command)
    if ((g_strcmp0(cmd, command->command) == 0) ||
Moritz Lipp's avatar
Moritz Lipp committed
458
        (g_strcmp0(cmd, command->abbr)    == 0))
Sebastian Ramacher's avatar
Sebastian Ramacher committed
459 460 461 462 463 464 465 466 467 468 469 470 471
    {
      girara_list_t* argument_list = girara_list_new();
      if (argument_list == NULL) {
        g_free(input);
        g_strfreev(argv);
        girara_list_iterator_free(iter);
        return false;
      }

      girara_list_set_free_function(argument_list, g_free);

      for(int i = 1; i < argc; i++) {
        char* argument = g_strdup(argv[i]);
Moritz Lipp's avatar
Moritz Lipp committed
472
        girara_list_append(argument_list, (void*) argument);
Sebastian Ramacher's avatar
Sebastian Ramacher committed
473 474 475 476 477 478 479 480
      }

      command->function(session, argument_list);

      girara_list_free(argument_list);
      g_free(input);
      g_strfreev(argv);

481
      girara_isc_abort(session, NULL, NULL, 0);
Sebastian Ramacher's avatar
Sebastian Ramacher committed
482

Moritz Lipp's avatar
Moritz Lipp committed
483 484 485
      if (session->global.autohide_inputbar == true) {
        gtk_widget_hide(GTK_WIDGET(session->gtk.inputbar));
      }
Moritz Lipp's avatar
Moritz Lipp committed
486
      gtk_widget_hide(GTK_WIDGET(session->gtk.inputbar_dialog));
Sebastian Ramacher's avatar
Sebastian Ramacher committed
487 488 489 490 491
      girara_list_iterator_free(iter);
      return true;
    }
  GIRARA_LIST_FOREACH_END(session->bindings.commands, girara_command_t*, iter, command);

Moritz Lipp's avatar
Moritz Lipp committed
492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508
  /* check for unknown command event handler */
  if (session->events.unknown_command != NULL) {
    if (session->events.unknown_command(session, input) == true) {
      g_strfreev(argv);
      g_free(input);
      girara_isc_abort(session, NULL, NULL, 0);

      if (session->global.autohide_inputbar == true) {
        gtk_widget_hide(GTK_WIDGET(session->gtk.inputbar));
      }
      gtk_widget_hide(GTK_WIDGET(session->gtk.inputbar_dialog));

      return true;
    }
  }

  /* unhandled command */
509
  girara_notify(session, GIRARA_ERROR, _("Not a valid command: %s"), cmd);
Moritz Lipp's avatar
Moritz Lipp committed
510
  g_strfreev(argv);
511
  girara_isc_abort(session, NULL, NULL, 0);
Sebastian Ramacher's avatar
Sebastian Ramacher committed
512 513 514 515

  return false;
}

516
gboolean
Moritz Lipp's avatar
Moritz Lipp committed
517
girara_callback_inputbar_key_press_event(GtkWidget* entry, GdkEventKey* event, girara_session_t* session)
Sebastian Ramacher's avatar
Sebastian Ramacher committed
518 519 520
{
  g_return_val_if_fail(session != NULL, false);

Moritz Lipp's avatar
Moritz Lipp committed
521
  /* a custom handler has been installed (e.g. by girara_dialog) */
522
  gboolean custom_ret = false;
Moritz Lipp's avatar
Moritz Lipp committed
523
  if (session->signals.inputbar_custom_key_press_event != NULL) {
Sebastian Ramacher's avatar
Sebastian Ramacher committed
524
    girara_debug("Running custom key press event handler.");
525 526 527 528
    custom_ret = session->signals.inputbar_custom_key_press_event(entry, event, session->signals.inputbar_custom_data);
    if (custom_ret == true) {
      girara_isc_abort(session, NULL, NULL, 0);

Moritz Lipp's avatar
Moritz Lipp committed
529 530 531
      if (session->global.autohide_inputbar == true) {
        gtk_widget_hide(GTK_WIDGET(session->gtk.inputbar));
      }
532 533
      gtk_widget_hide(GTK_WIDGET(session->gtk.inputbar_dialog));
    }
Moritz Lipp's avatar
Moritz Lipp committed
534 535
  }

536 537 538
  guint keyval = 0;
  guint clean  = 0;
  if (clean_mask(event->hardware_keycode, event->state, event->group, &clean, &keyval) == false) {
Sebastian Ramacher's avatar
Sebastian Ramacher committed
539
    girara_debug("clean_mask returned false.");
540 541
    return false;
  }
Sebastian Ramacher's avatar
Sebastian Ramacher committed
542
  girara_debug("Proccessing key %u with mask %x.", keyval, clean);
543

544 545 546 547 548
  if (custom_ret == false) {
    GIRARA_LIST_FOREACH(session->bindings.inputbar_shortcuts, girara_inputbar_shortcut_t*, iter, inputbar_shortcut)
      if (inputbar_shortcut->key == keyval
       && inputbar_shortcut->mask == clean)
      {
Sebastian Ramacher's avatar
Sebastian Ramacher committed
549
        girara_debug("found shortcut for key %u and mask %x", keyval, clean);
550 551 552
        if (inputbar_shortcut->function != NULL) {
          inputbar_shortcut->function(session, &(inputbar_shortcut->argument), NULL, 0);
        }
Sebastian Ramacher's avatar
Sebastian Ramacher committed
553

554 555 556 557 558
        girara_list_iterator_free(iter);
        return true;
      }
    GIRARA_LIST_FOREACH_END(session->bindings.inputbar_shortcuts, girara_inputbar_shortcut_t*, iter, inputbar_shortcut);
  }
Sebastian Ramacher's avatar
Sebastian Ramacher committed
559

560 561
  if ((session->gtk.results != NULL) &&
     (gtk_widget_get_visible(GTK_WIDGET(session->gtk.results)) == TRUE) &&
562
     (keyval == GDK_KEY_space))
563 564 565 566
  {
    gtk_widget_hide(GTK_WIDGET(session->gtk.results));
  }

567
  return custom_ret;
568 569
}

570
gboolean
571 572 573 574
girara_callback_inputbar_changed_event(GtkEditable* entry, girara_session_t* session)
{
  g_return_val_if_fail(session != NULL, false);

Sebastian Ramacher's avatar
Sebastian Ramacher committed
575
  /* special commands */
576
  char *identifier_s = gtk_editable_get_chars(entry, 0, 1);
Moritz Lipp's avatar
Moritz Lipp committed
577 578 579 580
  if (identifier_s == NULL) {
    return false;
  }

Sebastian Ramacher's avatar
Sebastian Ramacher committed
581 582 583 584 585 586 587 588 589 590 591
  char identifier    = identifier_s[0];
  g_free(identifier_s);

  GIRARA_LIST_FOREACH(session->bindings.special_commands, girara_special_command_t*, iter, special_command)
    if ((special_command->identifier == identifier) &&
       (special_command->always == true))
    {
      gchar *input  = gtk_editable_get_chars(GTK_EDITABLE(entry), 1, -1);
      special_command->function(session, input, &(special_command->argument));
      g_free(input);
      girara_list_iterator_free(iter);
592
      return true;
Sebastian Ramacher's avatar
Sebastian Ramacher committed
593 594 595 596 597
    }
  GIRARA_LIST_FOREACH_END(session->bindings.special_commands, girara_special_command_t*, iter, special_command);

  return false;
}