callbacks.c 18 KB
Newer Older
1
/* SPDX-License-Identifier: Zlib */
Sebastian Ramacher's avatar
Sebastian Ramacher committed
2 3

#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
static bool
20
clean_mask(GtkWidget* widget, guint hardware_keycode, GdkModifierType state, gint group, guint* clean, guint* keyval)
Sebastian Ramacher's avatar
Sebastian Ramacher committed
21
{
22
  GdkDisplay* display      = gtk_widget_get_display(widget);
23
  GdkModifierType consumed = 0;
24

Moritz Lipp's avatar
Moritz Lipp committed
25
  if ((gdk_keymap_translate_keyboard_state(
26
        gdk_keymap_get_for_display(display),
27 28 29
        hardware_keycode,
        state, group,
        keyval,
Moritz Lipp's avatar
Moritz Lipp committed
30 31 32 33 34
        NULL,
        NULL,
        &consumed)
      ) == FALSE) {
    return false;
35
  }
36 37 38 39

  if (clean != NULL) {
    *clean = state & ~consumed & ALL_ACCELS_MASK;
  }
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 73 74

  /* 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;
  }

75 76 77 78
  return true;
}

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

85
  guint clean  = 0;
86
  guint keyval = 0;
87

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

92 93
  girara_session_private_t* session_private = session->private_data;

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

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

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

119
      session_private->buffer.n = 0;
Sebastian Ramacher's avatar
Sebastian Ramacher committed
120

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

      girara_list_iterator_free(iter);
      return TRUE;
    }
Sebastian Ramacher's avatar
Sebastian Ramacher committed
128
  );
Sebastian Ramacher's avatar
Sebastian Ramacher committed
129 130

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

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

139 140 141
    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
142 143
      }
    } else {
144 145
      if (session_private->buffer.command == NULL) {
        session_private->buffer.command = g_string_new("");
Sebastian Ramacher's avatar
Sebastian Ramacher committed
146 147
      }

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

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

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

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

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

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

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

          matching_command = TRUE;
        }
      }
Sebastian Ramacher's avatar
Sebastian Ramacher committed
191
    );
Sebastian Ramacher's avatar
Sebastian Ramacher committed
192 193

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

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

  return FALSE;
}

210
gboolean
Moritz Lipp's avatar
Moritz Lipp committed
211 212
girara_callback_view_button_press_event(GtkWidget* UNUSED(widget),
    GdkEventButton* button, girara_session_t* session)
213
{
Moritz Lipp's avatar
Moritz Lipp committed
214 215 216 217
  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
218 219 220 221
  girara_event_t event = {
    .x = button->x,
    .y = button->y
  };
Moritz Lipp's avatar
Moritz Lipp committed
222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237

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

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

241 242
  bool handled = false;

Moritz Lipp's avatar
Moritz Lipp committed
243
  /* search registered mouse events */
244
  GIRARA_LIST_FOREACH_BODY(session->bindings.mouse_events, girara_mouse_event_t*, mouse_event,
Moritz Lipp's avatar
Moritz Lipp committed
245 246
    if (mouse_event->function != NULL
        && button->button == mouse_event->button
247
        && state  == mouse_event->mask
Moritz Lipp's avatar
Moritz Lipp committed
248
        && mouse_event->event_type == event.type
249
        && (session->modes.current_mode == mouse_event->mode || mouse_event->mode == 0)
Moritz Lipp's avatar
Moritz Lipp committed
250
       ) {
251 252 253
      mouse_event->function(session, &(mouse_event->argument), &event, session_private->buffer.n);
      handled = true;
      break;
Moritz Lipp's avatar
Moritz Lipp committed
254
    }
Sebastian Ramacher's avatar
Sebastian Ramacher committed
255
  );
Moritz Lipp's avatar
Moritz Lipp committed
256

257
  return handled;
258 259
}

260
gboolean
Moritz Lipp's avatar
Moritz Lipp committed
261
girara_callback_view_button_release_event(GtkWidget* UNUSED(widget), GdkEventButton* button, girara_session_t* session)
262
{
Moritz Lipp's avatar
Moritz Lipp committed
263 264 265 266
  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
267 268 269 270 271
  girara_event_t event = {
    .type = GIRARA_EVENT_BUTTON_RELEASE,
    .x    = button->x,
    .y    = button->y
  };
Moritz Lipp's avatar
Moritz Lipp committed
272

273
  const guint state = button->state & MOUSE_MASK;
274
  girara_session_private_t* session_private = session->private_data;
275
  bool handled = false;
276

Moritz Lipp's avatar
Moritz Lipp committed
277
  /* search registered mouse events */
278
  GIRARA_LIST_FOREACH_BODY(session->bindings.mouse_events, girara_mouse_event_t*, mouse_event,
Moritz Lipp's avatar
Moritz Lipp committed
279 280
    if (mouse_event->function != NULL
        && button->button == mouse_event->button
281
        && state  == mouse_event->mask
Moritz Lipp's avatar
Moritz Lipp committed
282
        && mouse_event->event_type == GIRARA_EVENT_BUTTON_RELEASE
283
        && (session->modes.current_mode == mouse_event->mode || mouse_event->mode == 0)
Moritz Lipp's avatar
Moritz Lipp committed
284
       ) {
285 286 287
      mouse_event->function(session, &(mouse_event->argument), &event, session_private->buffer.n);
      handled = true;
      break;
Moritz Lipp's avatar
Moritz Lipp committed
288
    }
Sebastian Ramacher's avatar
Sebastian Ramacher committed
289
  );
Moritz Lipp's avatar
Moritz Lipp committed
290

291
  return handled;
292 293
}

294
gboolean
Moritz Lipp's avatar
Moritz Lipp committed
295
girara_callback_view_button_motion_notify_event(GtkWidget* UNUSED(widget), GdkEventMotion* button, girara_session_t* session)
296
{
Moritz Lipp's avatar
Moritz Lipp committed
297 298 299 300
  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
301 302 303 304 305
  girara_event_t event = {
    .type = GIRARA_EVENT_MOTION_NOTIFY,
    .x    = button->x,
    .y    = button->y
  };
Moritz Lipp's avatar
Moritz Lipp committed
306

307
  const guint state = button->state & MOUSE_MASK;
308
  girara_session_private_t* session_private = session->private_data;
309
  bool handled = false;
310

Moritz Lipp's avatar
Moritz Lipp committed
311
  /* search registered mouse events */
312
  GIRARA_LIST_FOREACH_BODY(session->bindings.mouse_events, girara_mouse_event_t*, mouse_event,
Moritz Lipp's avatar
Moritz Lipp committed
313
    if (mouse_event->function != NULL
314
        && state  == mouse_event->mask
Moritz Lipp's avatar
Moritz Lipp committed
315
        && mouse_event->event_type == event.type
316
        && (session->modes.current_mode == mouse_event->mode || mouse_event->mode == 0)
Moritz Lipp's avatar
Moritz Lipp committed
317
       ) {
318 319 320
      mouse_event->function(session, &(mouse_event->argument), &event, session_private->buffer.n);
      handled = true;
      break;
Moritz Lipp's avatar
Moritz Lipp committed
321
    }
Sebastian Ramacher's avatar
Sebastian Ramacher committed
322
  );
Moritz Lipp's avatar
Moritz Lipp committed
323

324
  return handled;
325 326
}

327
gboolean
328 329 330 331 332 333
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
334 335 336 337
  girara_event_t event = {
    .x    = scroll->x,
    .y    = scroll->y
  };
338 339 340

  switch (scroll->direction) {
    case GDK_SCROLL_UP:
Moritz Lipp's avatar
Moritz Lipp committed
341
      event.type = GIRARA_EVENT_SCROLL_UP;
342 343
      break;
    case GDK_SCROLL_DOWN:
Moritz Lipp's avatar
Moritz Lipp committed
344
      event.type = GIRARA_EVENT_SCROLL_DOWN;
345 346
      break;
    case GDK_SCROLL_LEFT:
Moritz Lipp's avatar
Moritz Lipp committed
347
      event.type = GIRARA_EVENT_SCROLL_LEFT;
348 349
      break;
    case GDK_SCROLL_RIGHT:
Moritz Lipp's avatar
Moritz Lipp committed
350
      event.type = GIRARA_EVENT_SCROLL_RIGHT;
351
      break;
352 353
    case GDK_SCROLL_SMOOTH:
      event.type = GIRARA_EVENT_SCROLL_BIDIRECTIONAL;
354 355
      /* 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);
356
      break;
357 358 359 360
    default:
      return false;
  }

361
  const guint state = scroll->state & MOUSE_MASK;
362
  girara_session_private_t* session_private = session->private_data;
363
  bool handled = false;
364

365 366
  /* search registered mouse events */
  /* TODO: Filter correct event */
367
  GIRARA_LIST_FOREACH_BODY(session->bindings.mouse_events, girara_mouse_event_t*, mouse_event,
368
    if (mouse_event->function != NULL
369
        && state  == mouse_event->mask
Moritz Lipp's avatar
Moritz Lipp committed
370
        && mouse_event->event_type == event.type
371
        && (session->modes.current_mode == mouse_event->mode || mouse_event->mode == 0)
372
       ) {
373 374 375
      mouse_event->function(session, &(mouse_event->argument), &event, session_private->buffer.n);
      handled = true;
      break;
376
    }
Sebastian Ramacher's avatar
Sebastian Ramacher committed
377
  );
378

379
  return handled;
380 381
}

382
gboolean
Sebastian Ramacher's avatar
Sebastian Ramacher committed
383 384 385 386
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
387 388
  /* 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
389
    bool return_value = session->signals.inputbar_custom_activate(entry, session->signals.inputbar_custom_data);
Moritz Lipp's avatar
Moritz Lipp committed
390 391 392 393

    /* disconnect custom handler */
    session->signals.inputbar_custom_activate        = NULL;
    session->signals.inputbar_custom_key_press_event = NULL;
Moritz Lipp's avatar
Moritz Lipp committed
394
    session->signals.inputbar_custom_data            = NULL;
Moritz Lipp's avatar
Moritz Lipp committed
395 396 397 398

    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
399 400 401
      if (session->global.autohide_inputbar == true) {
        gtk_widget_hide(GTK_WIDGET(session->gtk.inputbar));
      }
Moritz Lipp's avatar
Moritz Lipp committed
402
      gtk_entry_set_visibility(session->gtk.inputbar_entry, TRUE);
403
      girara_isc_abort(session, NULL, NULL, 0);
Moritz Lipp's avatar
Moritz Lipp committed
404 405 406 407 408 409
      return true;
    }

    return return_value;
  }

Moritz Lipp's avatar
Moritz Lipp committed
410 411
  gchar *input = gtk_editable_get_chars(GTK_EDITABLE(entry), 1, -1);
  if (input == NULL) {
412
    girara_isc_abort(session, NULL, NULL, 0);
Sebastian Ramacher's avatar
Sebastian Ramacher committed
413 414 415 416
    return false;
  }

  if (strlen(input) == 0) {
Moritz Lipp's avatar
Moritz Lipp committed
417
    g_free(input);
418
    girara_isc_abort(session, NULL, NULL, 0);
Sebastian Ramacher's avatar
Sebastian Ramacher committed
419 420 421
    return false;
  }

Moritz Lipp's avatar
Moritz Lipp committed
422
  /* append to command history */
423
  const char* command = gtk_entry_get_text(entry);
424
  girara_input_history_append(session->command_history, command);
425

Sebastian Ramacher's avatar
Sebastian Ramacher committed
426 427
  /* special commands */
  char *identifier_s = gtk_editable_get_chars(GTK_EDITABLE(entry), 0, 1);
Moritz Lipp's avatar
Moritz Lipp committed
428 429 430 431
  if (identifier_s == NULL) {
    return false;
  }

Sebastian Ramacher's avatar
Sebastian Ramacher committed
432
  const char identifier = identifier_s[0];
Sebastian Ramacher's avatar
Sebastian Ramacher committed
433 434
  g_free(identifier_s);

Sebastian Ramacher's avatar
Sebastian Ramacher committed
435
  girara_debug("Processing special command with identifier '%c'.", identifier);
Sebastian Ramacher's avatar
Sebastian Ramacher committed
436
  GIRARA_LIST_FOREACH_BODY_WITH_ITER(session->bindings.special_commands, girara_special_command_t*, iter, special_command,
Sebastian Ramacher's avatar
Sebastian Ramacher committed
437
    if (special_command->identifier == identifier) {
Sebastian Ramacher's avatar
Sebastian Ramacher committed
438
      girara_debug("Found special command.");
Sebastian Ramacher's avatar
Sebastian Ramacher committed
439 440 441 442
      if (special_command->always != true) {
        special_command->function(session, input, &(special_command->argument));
      }

443
      girara_isc_abort(session, NULL, NULL, 0);
Sebastian Ramacher's avatar
Sebastian Ramacher committed
444 445 446 447

      girara_list_iterator_free(iter);
      return true;
    }
Sebastian Ramacher's avatar
Sebastian Ramacher committed
448
  );
Sebastian Ramacher's avatar
Sebastian Ramacher committed
449

Sebastian Ramacher's avatar
Sebastian Ramacher committed
450 451 452 453 454 455 456 457 458 459 460 461
  /* 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
462
  /* search commands */
Sebastian Ramacher's avatar
Sebastian Ramacher committed
463 464 465
  GIRARA_LIST_FOREACH_BODY_WITH_ITER(session->bindings.commands, girara_command_t*, iter, binding_command,
    if ((g_strcmp0(cmd, binding_command->command) == 0) ||
        (g_strcmp0(cmd, binding_command->abbr)    == 0)) {
Sebastian Ramacher's avatar
Sebastian Ramacher committed
466 467 468 469 470 471 472 473 474 475 476 477
      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
478
        girara_list_append(argument_list, (void*) argument);
Sebastian Ramacher's avatar
Sebastian Ramacher committed
479 480
      }

Sebastian Ramacher's avatar
Sebastian Ramacher committed
481
      binding_command->function(session, argument_list);
Sebastian Ramacher's avatar
Sebastian Ramacher committed
482 483 484 485 486

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

487
      girara_isc_abort(session, NULL, NULL, 0);
Sebastian Ramacher's avatar
Sebastian Ramacher committed
488

Moritz Lipp's avatar
Moritz Lipp committed
489 490 491
      if (session->global.autohide_inputbar == true) {
        gtk_widget_hide(GTK_WIDGET(session->gtk.inputbar));
      }
Moritz Lipp's avatar
Moritz Lipp committed
492
      gtk_widget_hide(GTK_WIDGET(session->gtk.inputbar_dialog));
Sebastian Ramacher's avatar
Sebastian Ramacher committed
493 494 495
      girara_list_iterator_free(iter);
      return true;
    }
Sebastian Ramacher's avatar
Sebastian Ramacher committed
496
  );
Sebastian Ramacher's avatar
Sebastian Ramacher committed
497

Moritz Lipp's avatar
Moritz Lipp committed
498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514
  /* 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 */
515
  girara_notify(session, GIRARA_ERROR, _("Not a valid command: %s"), cmd);
Moritz Lipp's avatar
Moritz Lipp committed
516
  g_strfreev(argv);
517
  girara_isc_abort(session, NULL, NULL, 0);
Sebastian Ramacher's avatar
Sebastian Ramacher committed
518 519 520 521

  return false;
}

522
gboolean
Moritz Lipp's avatar
Moritz Lipp committed
523
girara_callback_inputbar_key_press_event(GtkWidget* entry, GdkEventKey* event, girara_session_t* session)
Sebastian Ramacher's avatar
Sebastian Ramacher committed
524 525 526
{
  g_return_val_if_fail(session != NULL, false);

Moritz Lipp's avatar
Moritz Lipp committed
527
  /* a custom handler has been installed (e.g. by girara_dialog) */
528
  gboolean custom_ret = false;
Moritz Lipp's avatar
Moritz Lipp committed
529
  if (session->signals.inputbar_custom_key_press_event != NULL) {
Sebastian Ramacher's avatar
Sebastian Ramacher committed
530
    girara_debug("Running custom key press event handler.");
531 532 533 534
    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
535 536 537
      if (session->global.autohide_inputbar == true) {
        gtk_widget_hide(GTK_WIDGET(session->gtk.inputbar));
      }
538 539
      gtk_widget_hide(GTK_WIDGET(session->gtk.inputbar_dialog));
    }
Moritz Lipp's avatar
Moritz Lipp committed
540 541
  }

542 543
  guint keyval = 0;
  guint clean  = 0;
544
  if (clean_mask(entry, event->hardware_keycode, event->state, event->group, &clean, &keyval) == false) {
Sebastian Ramacher's avatar
Sebastian Ramacher committed
545
    girara_debug("clean_mask returned false.");
546 547
    return false;
  }
Sebastian Ramacher's avatar
Sebastian Ramacher committed
548
  girara_debug("Proccessing key %u with mask %x.", keyval, clean);
549

550
  if (custom_ret == false) {
Sebastian Ramacher's avatar
Sebastian Ramacher committed
551
    GIRARA_LIST_FOREACH_BODY_WITH_ITER(session->bindings.inputbar_shortcuts, girara_inputbar_shortcut_t*, iter, inputbar_shortcut,
552
      if (inputbar_shortcut->key == keyval
Sebastian Ramacher's avatar
Sebastian Ramacher committed
553
       && inputbar_shortcut->mask == clean) {
Sebastian Ramacher's avatar
Sebastian Ramacher committed
554
        girara_debug("found shortcut for key %u and mask %x", keyval, clean);
555 556 557
        if (inputbar_shortcut->function != NULL) {
          inputbar_shortcut->function(session, &(inputbar_shortcut->argument), NULL, 0);
        }
Sebastian Ramacher's avatar
Sebastian Ramacher committed
558

559 560 561
        girara_list_iterator_free(iter);
        return true;
      }
Sebastian Ramacher's avatar
Sebastian Ramacher committed
562
    );
563
  }
Sebastian Ramacher's avatar
Sebastian Ramacher committed
564

565 566
  if ((session->gtk.results != NULL) &&
     (gtk_widget_get_visible(GTK_WIDGET(session->gtk.results)) == TRUE) &&
567
     (keyval == GDK_KEY_space))
568 569 570 571
  {
    gtk_widget_hide(GTK_WIDGET(session->gtk.results));
  }

572
  return custom_ret;
573 574
}

575
gboolean
576 577 578 579
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
580
  /* special commands */
581
  char *identifier_s = gtk_editable_get_chars(entry, 0, 1);
Moritz Lipp's avatar
Moritz Lipp committed
582 583 584 585
  if (identifier_s == NULL) {
    return false;
  }

Sebastian Ramacher's avatar
Sebastian Ramacher committed
586 587
  char identifier    = identifier_s[0];
  g_free(identifier_s);
588
  bool handled = false;
Sebastian Ramacher's avatar
Sebastian Ramacher committed
589

590
  GIRARA_LIST_FOREACH_BODY(session->bindings.special_commands, girara_special_command_t*, special_command,
Sebastian Ramacher's avatar
Sebastian Ramacher committed
591
    if ((special_command->identifier == identifier) &&
Sebastian Ramacher's avatar
Sebastian Ramacher committed
592
       (special_command->always == true)) {
Sebastian Ramacher's avatar
Sebastian Ramacher committed
593 594 595
      gchar *input  = gtk_editable_get_chars(GTK_EDITABLE(entry), 1, -1);
      special_command->function(session, input, &(special_command->argument));
      g_free(input);
596 597
      handled = true;
      break;
Sebastian Ramacher's avatar
Sebastian Ramacher committed
598
    }
Sebastian Ramacher's avatar
Sebastian Ramacher committed
599
  );
Sebastian Ramacher's avatar
Sebastian Ramacher committed
600

601
  return handled;
Sebastian Ramacher's avatar
Sebastian Ramacher committed
602
}