shortcuts.c 40.8 KB
Newer Older
1
2
/* See LICENSE file for license and copyright information */

3
4
5
6
#include <girara/session.h>
#include <girara/settings.h>
#include <girara/datastructures.h>
#include <girara/shortcuts.h>
7
#include <girara/utils.h>
Moritz Lipp's avatar
Moritz Lipp committed
8
#include <gtk/gtk.h>
9
#include <glib/gi18n.h>
Moritz Lipp's avatar
Moritz Lipp committed
10
11

#include "callbacks.h"
12
#include "shortcuts.h"
13
#include "document.h"
Moritz Lipp's avatar
Moritz Lipp committed
14
#include "zathura.h"
15
#include "render.h"
16
#include "utils.h"
Moritz Lipp's avatar
Moritz Lipp committed
17
#include "page.h"
Moritz Lipp's avatar
Moritz Lipp committed
18
#include "print.h"
19
#include "page-widget.h"
20
#include "adjustment.h"
21

22
23
24
25
26
27
28
29
#ifndef MIN
#define MIN(a,b) (((a)<(b))?(a):(b))
#endif

#ifndef MAX
#define MAX(a,b) (((a)>(b))?(a):(b))
#endif

30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
/* Helper function; see sc_display_link and sc_follow. */
static bool
draw_links(zathura_t* zathura)
{
  /* set pages to draw links */
  bool show_links = false;
  unsigned int page_offset = 0;
  unsigned int number_of_pages = zathura_document_get_number_of_pages(zathura->document);
  for (unsigned int page_id = 0; page_id < number_of_pages; page_id++) {
    zathura_page_t* page = zathura_document_get_page(zathura->document, page_id);
    if (page == NULL) {
      continue;
    }

    GtkWidget* page_widget = zathura_page_get_widget(zathura, page);
Marwan Tanager's avatar
Marwan Tanager committed
45
    g_object_set(page_widget, "draw-search-results", FALSE, NULL);
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
    if (zathura_page_get_visibility(page) == true) {
      g_object_set(page_widget, "draw-links", TRUE, NULL);

      int number_of_links = 0;
      g_object_get(page_widget, "number-of-links", &number_of_links, NULL);
      if (number_of_links != 0) {
        show_links = true;
      }
      g_object_set(page_widget, "offset-links", page_offset, NULL);
      page_offset += number_of_links;
    } else {
      g_object_set(page_widget, "draw-links", FALSE, NULL);
    }
  }
  return show_links;
}

Moritz Lipp's avatar
Moritz Lipp committed
63
bool
64
sc_abort(girara_session_t* session, girara_argument_t* UNUSED(argument),
Moritz Lipp's avatar
Moritz Lipp committed
65
         girara_event_t* UNUSED(event), unsigned int UNUSED(t))
66
{
Moritz Lipp's avatar
Moritz Lipp committed
67
  g_return_val_if_fail(session != NULL, false);
68
69
70
  g_return_val_if_fail(session->global.data != NULL, false);
  zathura_t* zathura = session->global.data;

71
72
73
  bool clear_search = true;
  girara_setting_get(session, "abort-clear-search", &clear_search);

Moritz Lipp's avatar
Moritz Lipp committed
74
  if (zathura->document != NULL) {
75
    unsigned int number_of_pages = zathura_document_get_number_of_pages(zathura->document);
76
77
    for (unsigned int page_id = 0; page_id < number_of_pages; ++page_id) {
      zathura_page_t* page = zathura_document_get_page(zathura->document, page_id);
Moritz Lipp's avatar
Moritz Lipp committed
78
79
80
81
      if (page == NULL) {
        continue;
      }

Marwan Tanager's avatar
Marwan Tanager committed
82
83
      GtkWidget* page_widget = zathura_page_get_widget(zathura, page);
      g_object_set(page_widget, "draw-links", FALSE, NULL);
84
      if (clear_search == true) {
Marwan Tanager's avatar
Marwan Tanager committed
85
        g_object_set(page_widget, "draw-search-results", FALSE, NULL);
86
      }
87
88
    }
  }
Moritz Lipp's avatar
Moritz Lipp committed
89

Moritz Lipp's avatar
Moritz Lipp committed
90
  girara_mode_set(session, session->modes.normal);
Moritz Lipp's avatar
Moritz Lipp committed
91
  girara_sc_abort(session, NULL, NULL, 0);
Moritz Lipp's avatar
Moritz Lipp committed
92

Moritz Lipp's avatar
Moritz Lipp committed
93
  return false;
94
95
}

96
97
bool
sc_adjust_window(girara_session_t* session, girara_argument_t* argument,
Moritz Lipp's avatar
Moritz Lipp committed
98
                 girara_event_t* UNUSED(event), unsigned int UNUSED(t))
99
{
100
101
102
103
  g_return_val_if_fail(session != NULL, false);
  g_return_val_if_fail(session->global.data != NULL, false);
  zathura_t* zathura = session->global.data;
  g_return_val_if_fail(argument != NULL, false);
Moritz Lipp's avatar
Moritz Lipp committed
104

105
  zathura_document_set_adjust_mode(zathura->document, argument->n);
106
  adjust_view(zathura);
Moritz Lipp's avatar
Moritz Lipp committed
107

108
  return false;
109
110
}

Moritz Lipp's avatar
Moritz Lipp committed
111
bool
Moritz Lipp's avatar
Moritz Lipp committed
112
sc_change_mode(girara_session_t* session, girara_argument_t* argument,
Moritz Lipp's avatar
Moritz Lipp committed
113
               girara_event_t* UNUSED(event), unsigned int UNUSED(t))
114
{
Moritz Lipp's avatar
Moritz Lipp committed
115
116
117
118
  g_return_val_if_fail(session != NULL, false);

  girara_mode_set(session, argument->n);

Moritz Lipp's avatar
Moritz Lipp committed
119
  return false;
120
121
}

122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
bool
sc_display_link(girara_session_t* session, girara_argument_t* UNUSED(argument),
                girara_event_t* UNUSED(event), unsigned int UNUSED(t))
{
  g_return_val_if_fail(session != NULL, false);
  g_return_val_if_fail(session->global.data != NULL, false);
  zathura_t* zathura = session->global.data;

  if (zathura->document == NULL || zathura->ui.session == NULL) {
    return false;
  }

  bool show_links = draw_links(zathura);

  /* ask for input */
  if (show_links) {
138
    zathura_document_set_adjust_mode(zathura->document, ZATHURA_ADJUST_INPUTBAR);
139
140
141
142
143
144
145
146
    girara_dialog(zathura->ui.session, "Display link:", FALSE, NULL,
        (girara_callback_inputbar_activate_t) cb_sc_display_link,
        zathura->ui.session);
  }

  return false;
}

147
148
149
150
151
152
153
154
155
bool
sc_focus_inputbar(girara_session_t* session, girara_argument_t* argument, girara_event_t* UNUSED(event), unsigned int UNUSED(t))
{
  g_return_val_if_fail(session != NULL, false);
  g_return_val_if_fail(session->gtk.inputbar_entry != NULL, false);
  g_return_val_if_fail(session->global.data != NULL, false);
  zathura_t* zathura = session->global.data;
  g_return_val_if_fail(argument != NULL, false);

156
157
  zathura_document_set_adjust_mode(zathura->document, ZATHURA_ADJUST_INPUTBAR);

158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
  if (gtk_widget_get_visible(GTK_WIDGET(session->gtk.inputbar)) == false) {
    gtk_widget_show(GTK_WIDGET(session->gtk.inputbar));
  }

  if (gtk_widget_get_visible(GTK_WIDGET(session->gtk.notification_area)) == true) {
    gtk_widget_hide(GTK_WIDGET(session->gtk.notification_area));
  }

  gtk_widget_grab_focus(GTK_WIDGET(session->gtk.inputbar_entry));

  if (argument->data != NULL) {
    gtk_entry_set_text(session->gtk.inputbar_entry, (char*) argument->data);

    /* append filepath */
    if (argument->n == APPEND_FILEPATH && zathura->document != NULL) {
173
174
175
176
      const char* file_path = zathura_document_get_path(zathura->document);
      if (file_path == NULL) {
        return false;
      }
177

178
179
180
181
182
      char* path = g_path_get_dirname(file_path);
      char* escaped = girara_escape_string(path);
      char* tmp  = g_strdup_printf("%s%s/", (char*) argument->data, (g_strcmp0(path, "/") == 0) ? "" : escaped);
      g_free(path);
      g_free(escaped);
183
184
185
186
187

      gtk_entry_set_text(session->gtk.inputbar_entry, tmp);
      g_free(tmp);
    }

188
189
    GdkAtom* selection = get_selection(zathura);

190
    /* we save the X clipboard that will be clear by "grab_focus" */
191
    gchar* x_clipboard_text = NULL;
192
193
194
195

    if (selection != NULL) {
      x_clipboard_text = gtk_clipboard_wait_for_text(gtk_clipboard_get(*selection));
    }
196
197
198

    gtk_editable_set_position(GTK_EDITABLE(session->gtk.inputbar_entry), -1);

199
    if (x_clipboard_text != NULL && selection != NULL) {
200
      /* we reset the X clipboard with saved text */
201
      gtk_clipboard_set_text(gtk_clipboard_get(*selection), x_clipboard_text, -1);
202
203
      g_free(x_clipboard_text);
    }
204
205

    g_free(selection);
206
207
208
209
210
  }

  return true;
}

Moritz Lipp's avatar
Moritz Lipp committed
211
bool
212
sc_follow(girara_session_t* session, girara_argument_t* UNUSED(argument),
Moritz Lipp's avatar
Moritz Lipp committed
213
          girara_event_t* UNUSED(event), unsigned int UNUSED(t))
214
{
Moritz Lipp's avatar
Moritz Lipp committed
215
  g_return_val_if_fail(session != NULL, false);
Moritz Lipp's avatar
Moritz Lipp committed
216
217
218
  g_return_val_if_fail(session->global.data != NULL, false);
  zathura_t* zathura = session->global.data;

Moritz Lipp's avatar
Moritz Lipp committed
219
  if (zathura->document == NULL || zathura->ui.session == NULL) {
Moritz Lipp's avatar
Moritz Lipp committed
220
221
222
    return false;
  }

223
  bool show_links = draw_links(zathura);
Moritz Lipp's avatar
Moritz Lipp committed
224

Moritz Lipp's avatar
Moritz Lipp committed
225
  /* ask for input */
Moritz Lipp's avatar
Moritz Lipp committed
226
  if (show_links == true) {
227
    zathura_document_set_adjust_mode(zathura->document, ZATHURA_ADJUST_INPUTBAR);
Moritz Lipp's avatar
Moritz Lipp committed
228
    girara_dialog(zathura->ui.session, "Follow link:", FALSE, NULL, (girara_callback_inputbar_activate_t) cb_sc_follow, zathura->ui.session);
Moritz Lipp's avatar
Moritz Lipp committed
229
  }
Moritz Lipp's avatar
Moritz Lipp committed
230

Moritz Lipp's avatar
Moritz Lipp committed
231
232
  return false;
}
233

Moritz Lipp's avatar
Moritz Lipp committed
234
bool
Moritz Lipp's avatar
Moritz Lipp committed
235
sc_goto(girara_session_t* session, girara_argument_t* argument, girara_event_t* UNUSED(event), unsigned int t)
Moritz Lipp's avatar
Moritz Lipp committed
236
{
Moritz Lipp's avatar
Moritz Lipp committed
237
238
239
240
241
  g_return_val_if_fail(session != NULL, false);
  g_return_val_if_fail(session->global.data != NULL, false);
  zathura_t* zathura = session->global.data;
  g_return_val_if_fail(argument != NULL, false);
  g_return_val_if_fail(zathura->document != NULL, false);
242

243
  zathura_jumplist_add(zathura);
Moritz Lipp's avatar
Moritz Lipp committed
244
  if (t != 0) {
245
    /* add offset */
Moritz Lipp's avatar
Moritz Lipp committed
246
    t += zathura_document_get_page_offset(zathura->document);
247

Moritz Lipp's avatar
Moritz Lipp committed
248
    page_set(zathura, t - 1);
Moritz Lipp's avatar
Moritz Lipp committed
249
  } else if (argument->n == TOP) {
Moritz Lipp's avatar
Moritz Lipp committed
250
    page_set(zathura, 0);
Moritz Lipp's avatar
Moritz Lipp committed
251
  } else if (argument->n == BOTTOM) {
252
    page_set(zathura, zathura_document_get_number_of_pages(zathura->document) - 1);
253
254
  }

255
256
  zathura_jumplist_add(zathura);

Moritz Lipp's avatar
Moritz Lipp committed
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
  return false;
}

bool
sc_mouse_scroll(girara_session_t* session, girara_argument_t* argument, girara_event_t* event, unsigned int t)
{
  g_return_val_if_fail(session != NULL, false);
  g_return_val_if_fail(session->global.data != NULL, false);
  zathura_t* zathura = session->global.data;
  g_return_val_if_fail(argument != NULL, false);
  g_return_val_if_fail(event != NULL, false);

  if (zathura->document == NULL) {
    return false;
  }

Moritz Lipp's avatar
Moritz Lipp committed
273
274
275
276
277
278
279
  static int x = 0;
  static int y = 0;

  GtkAdjustment* x_adj = NULL;
  GtkAdjustment* y_adj = NULL;

  switch (event->type) {
Moritz Lipp's avatar
Moritz Lipp committed
280
      /* scroll */
Moritz Lipp's avatar
Moritz Lipp committed
281
282
283
284
285
286
    case GIRARA_EVENT_SCROLL_UP:
    case GIRARA_EVENT_SCROLL_DOWN:
    case GIRARA_EVENT_SCROLL_LEFT:
    case GIRARA_EVENT_SCROLL_RIGHT:
      return sc_scroll(session, argument, NULL, t);

Moritz Lipp's avatar
Moritz Lipp committed
287
      /* drag */
Moritz Lipp's avatar
Moritz Lipp committed
288
289
290
291
292
293
294
295
296
297
    case GIRARA_EVENT_BUTTON_PRESS:
      x = event->x;
      y = event->y;
      break;
    case GIRARA_EVENT_BUTTON_RELEASE:
      x = 0;
      y = 0;
      break;
    case GIRARA_EVENT_MOTION_NOTIFY:
      x_adj = gtk_scrolled_window_get_hadjustment(GTK_SCROLLED_WINDOW(session->gtk.view));
Moritz Lipp's avatar
Moritz Lipp committed
298
      y_adj = gtk_scrolled_window_get_vadjustment(GTK_SCROLLED_WINDOW(session->gtk.view));
Moritz Lipp's avatar
Moritz Lipp committed
299
300
301
302

      if (x_adj == NULL || y_adj == NULL) {
        return false;
      }
Moritz Lipp's avatar
Moritz Lipp committed
303

304
305
306
307
      zathura_adjustment_set_value(x_adj,
          gtk_adjustment_get_value(x_adj) - (event->x - x));
      zathura_adjustment_set_value(y_adj,
          gtk_adjustment_get_value(y_adj) - (event->y - y));
308
      zathura->global.update_page_number = true;
Moritz Lipp's avatar
Moritz Lipp committed
309
310
      break;

Moritz Lipp's avatar
Moritz Lipp committed
311
      /* unhandled events */
Moritz Lipp's avatar
Moritz Lipp committed
312
313
    default:
      break;
Moritz Lipp's avatar
Moritz Lipp committed
314
315
  }

Moritz Lipp's avatar
Moritz Lipp committed
316
  return false;
317
318
}

Moritz Lipp's avatar
Moritz Lipp committed
319
320
321
322
323
324
325
326
327
328
329
330
331
332
bool
sc_mouse_zoom(girara_session_t* session, girara_argument_t* argument, girara_event_t* event, unsigned int t)
{
  g_return_val_if_fail(session != NULL, false);
  g_return_val_if_fail(session->global.data != NULL, false);
  zathura_t* zathura = session->global.data;
  g_return_val_if_fail(argument != NULL, false);
  g_return_val_if_fail(event != NULL, false);

  if (zathura->document == NULL) {
    return false;
  }

  /* scroll event */
333
334
335
336
337
338
339
340
341
  switch (event->type) {
    case GIRARA_EVENT_SCROLL_UP:
      argument->n = ZOOM_IN;
      break;
    case GIRARA_EVENT_SCROLL_DOWN:
      argument->n = ZOOM_OUT;
      break;
    default:
      return false;
Moritz Lipp's avatar
Moritz Lipp committed
342
343
  }

344
  return sc_zoom(session, argument, NULL, t);
345
346
}

Moritz Lipp's avatar
Moritz Lipp committed
347
bool
Moritz Lipp's avatar
Moritz Lipp committed
348
sc_navigate(girara_session_t* session, girara_argument_t* argument,
Moritz Lipp's avatar
Moritz Lipp committed
349
            girara_event_t* UNUSED(event), unsigned int t)
350
{
Moritz Lipp's avatar
Moritz Lipp committed
351
352
353
354
355
  g_return_val_if_fail(session != NULL, false);
  g_return_val_if_fail(session->global.data != NULL, false);
  zathura_t* zathura = session->global.data;
  g_return_val_if_fail(argument != NULL, false);
  g_return_val_if_fail(zathura->document != NULL, false);
Moritz Lipp's avatar
Moritz Lipp committed
356

357
358
  int number_of_pages = zathura_document_get_number_of_pages(zathura->document);
  int new_page        = zathura_document_get_current_page_number(zathura->document);
Moritz Lipp's avatar
Moritz Lipp committed
359

360
361
362
  bool scroll_wrap = false;
  girara_setting_get(session, "scroll-wrap", &scroll_wrap);

363
364
365
366
367
368
369
370
  bool columns_per_row_offset = false;
  girara_setting_get(session, "advance-pages-per-row", &columns_per_row_offset);

  int offset = 1;
  if (columns_per_row_offset == true) {
    girara_setting_get(session, "pages-per-row", &offset);
  }

Moritz Lipp's avatar
Moritz Lipp committed
371
  t = (t == 0) ? (unsigned int) offset : t;
Moritz Lipp's avatar
Moritz Lipp committed
372
  if (argument->n == NEXT) {
Benoît Knecht's avatar
Benoît Knecht committed
373
    if (scroll_wrap == false) {
374
375
376
377
      new_page = new_page + t;
    } else {
      new_page = (new_page + t) % number_of_pages;
    }
Moritz Lipp's avatar
Moritz Lipp committed
378
  } else if (argument->n == PREVIOUS) {
Benoît Knecht's avatar
Benoît Knecht committed
379
    if (scroll_wrap == false) {
380
381
382
383
384
385
      new_page = new_page - t;
    } else {
      new_page = (new_page + number_of_pages - t) % number_of_pages;
    }
  }

Benoît Knecht's avatar
Benoît Knecht committed
386
  if ((new_page < 0 || new_page >= number_of_pages) && !scroll_wrap) {
387
    return false;
Moritz Lipp's avatar
Moritz Lipp committed
388
389
  }

390
  page_set(zathura, new_page);
Moritz Lipp's avatar
Moritz Lipp committed
391

Moritz Lipp's avatar
Moritz Lipp committed
392
  return false;
393
394
}

Moritz Lipp's avatar
Moritz Lipp committed
395
396
bool
sc_print(girara_session_t* session, girara_argument_t* UNUSED(argument),
Moritz Lipp's avatar
Moritz Lipp committed
397
         girara_event_t* UNUSED(event), unsigned int UNUSED(t))
Moritz Lipp's avatar
Moritz Lipp committed
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
{
  g_return_val_if_fail(session != NULL, false);
  g_return_val_if_fail(session->global.data != NULL, false);
  zathura_t* zathura = session->global.data;

  if (zathura->document == NULL) {
    girara_notify(session, GIRARA_ERROR, _("No document opened."));
    return false;
  }

  print(zathura);

  return true;
}

Moritz Lipp's avatar
Moritz Lipp committed
413
bool
414
sc_recolor(girara_session_t* session, girara_argument_t* UNUSED(argument),
Moritz Lipp's avatar
Moritz Lipp committed
415
           girara_event_t* UNUSED(event), unsigned int UNUSED(t))
416
{
Moritz Lipp's avatar
Moritz Lipp committed
417
  g_return_val_if_fail(session != NULL, false);
Moritz Lipp's avatar
Moritz Lipp committed
418

Moritz Lipp's avatar
Moritz Lipp committed
419
420
421
422
  bool value = false;
  girara_setting_get(session, "recolor", &value);
  value = !value;
  girara_setting_set(session, "recolor", &value);
Moritz Lipp's avatar
Moritz Lipp committed
423

Moritz Lipp's avatar
Moritz Lipp committed
424
  return false;
425
426
}

Moritz Lipp's avatar
Moritz Lipp committed
427
bool
428
sc_reload(girara_session_t* session, girara_argument_t* UNUSED(argument),
Moritz Lipp's avatar
Moritz Lipp committed
429
          girara_event_t* UNUSED(event), unsigned int UNUSED(t))
430
{
Moritz Lipp's avatar
Moritz Lipp committed
431
  g_return_val_if_fail(session != NULL, false);
Moritz Lipp's avatar
Moritz Lipp committed
432
433
434
  g_return_val_if_fail(session->global.data != NULL, false);
  zathura_t* zathura = session->global.data;

Moritz Lipp's avatar
Moritz Lipp committed
435
  if (zathura->file_monitor.file_path == NULL) {
Moritz Lipp's avatar
Moritz Lipp committed
436
437
438
439
    return false;
  }

  /* close current document */
Moritz Lipp's avatar
Moritz Lipp committed
440
  document_close(zathura, true);
Moritz Lipp's avatar
Moritz Lipp committed
441
442

  /* reopen document */
443
444
445
  document_open(zathura, zathura->file_monitor.file_path,
                zathura->file_monitor.password,
                ZATHURA_PAGE_NUMBER_UNSPECIFIED);
Moritz Lipp's avatar
Moritz Lipp committed
446

Moritz Lipp's avatar
Moritz Lipp committed
447
  return false;
448
449
}

Moritz Lipp's avatar
Moritz Lipp committed
450
bool
451
sc_rotate(girara_session_t* session, girara_argument_t* argument,
Moritz Lipp's avatar
Moritz Lipp committed
452
          girara_event_t* UNUSED(event), unsigned int t)
453
{
Moritz Lipp's avatar
Moritz Lipp committed
454
455
456
457
  g_return_val_if_fail(session != NULL, false);
  g_return_val_if_fail(session->global.data != NULL, false);
  zathura_t* zathura = session->global.data;
  g_return_val_if_fail(zathura->document != NULL, false);
Moritz Lipp's avatar
Moritz Lipp committed
458

459
  unsigned int page_number = zathura_document_get_current_page_number(zathura->document);
460

461
462
463
464
465
  int angle = 90;
  if (argument != NULL && argument->n == ROTATE_CCW) {
    angle = 270;
  }

Moritz Lipp's avatar
Moritz Lipp committed
466
  /* update rotate value */
Moritz Lipp's avatar
Moritz Lipp committed
467
  t = (t == 0) ? 1 : t;
468
  unsigned int rotation = zathura_document_get_rotation(zathura->document);
Moritz Lipp's avatar
Moritz Lipp committed
469
  zathura_document_set_rotation(zathura->document, (rotation + angle * t) % 360);
Moritz Lipp's avatar
Moritz Lipp committed
470

471
472
473
474
  /* update scale */
  girara_argument_t new_argument = { zathura_document_get_adjust_mode(zathura->document), NULL };
  sc_adjust_window(zathura->ui.session, &new_argument, NULL, 0);

Moritz Lipp's avatar
Moritz Lipp committed
475
  /* render all pages again */
476
  render_all(zathura);
Moritz Lipp's avatar
Moritz Lipp committed
477

478
  page_set(zathura, page_number);
479

Moritz Lipp's avatar
Moritz Lipp committed
480
  return false;
481
482
}

Moritz Lipp's avatar
Moritz Lipp committed
483
bool
Moritz Lipp's avatar
Moritz Lipp committed
484
sc_scroll(girara_session_t* session, girara_argument_t* argument,
Sebastian Ramacher's avatar
CS    
Sebastian Ramacher committed
485
          girara_event_t* UNUSED(event), unsigned int t)
486
{
Moritz Lipp's avatar
Moritz Lipp committed
487
488
489
490
  g_return_val_if_fail(session != NULL, false);
  g_return_val_if_fail(session->global.data != NULL, false);
  zathura_t* zathura = session->global.data;
  g_return_val_if_fail(argument != NULL, false);
491
492
493
  if (zathura->document == NULL) {
    return false;
  }
Moritz Lipp's avatar
Moritz Lipp committed
494

Sebastian Ramacher's avatar
CS    
Sebastian Ramacher committed
495
  if (t == 0) {
496
497
498
    t = 1;
  }

Moritz Lipp's avatar
Moritz Lipp committed
499
  GtkAdjustment* adjustment = NULL;
500
  if ( (argument->n == LEFT) || (argument->n == FULL_LEFT) || (argument->n == HALF_LEFT) ||
Moritz Lipp's avatar
Moritz Lipp committed
501
       (argument->n == RIGHT) || (argument->n == FULL_RIGHT) || (argument->n == HALF_RIGHT)) {
Moritz Lipp's avatar
Moritz Lipp committed
502
    adjustment = gtk_scrolled_window_get_hadjustment(GTK_SCROLLED_WINDOW(session->gtk.view));
Moritz Lipp's avatar
Moritz Lipp committed
503
  } else {
Moritz Lipp's avatar
Moritz Lipp committed
504
    adjustment = gtk_scrolled_window_get_vadjustment(GTK_SCROLLED_WINDOW(session->gtk.view));
Moritz Lipp's avatar
Moritz Lipp committed
505
  }
Moritz Lipp's avatar
Moritz Lipp committed
506

507
508
509
  gdouble view_size                  = gtk_adjustment_get_page_size(adjustment);
  gdouble value                      = gtk_adjustment_get_value(adjustment);
  gdouble max                        = gtk_adjustment_get_upper(adjustment) - view_size;
510
  zathura->global.update_page_number = true;
511

512
513
  float scroll_step = 40;
  girara_setting_get(session, "scroll-step", &scroll_step);
Julian Orth's avatar
Julian Orth committed
514
515
516
517
518
  float scroll_hstep = -1;
  girara_setting_get(session, "scroll-hstep", &scroll_hstep);
  if (scroll_hstep < 0) {
    scroll_hstep = scroll_step;
  }
519
  float scroll_full_overlap = 0.0;
520
  girara_setting_get(session, "scroll-full-overlap", &scroll_full_overlap);
Jonas Hoersch's avatar
Jonas Hoersch committed
521
522
  bool scroll_page_aware = false;
  girara_setting_get(session, "scroll-page-aware", &scroll_page_aware);
523

524
525
526
  bool scroll_wrap = false;
  girara_setting_get(session, "scroll-wrap", &scroll_wrap);

527
528
529
  int padding = 1;
  girara_setting_get(session, "page-padding", &padding);

530
  gdouble new_value;
Moritz Lipp's avatar
Moritz Lipp committed
531

Moritz Lipp's avatar
Moritz Lipp committed
532
  switch(argument->n) {
Moritz Lipp's avatar
Moritz Lipp committed
533
    case FULL_UP:
534
    case FULL_LEFT:
535
      new_value = value - (1.0 - scroll_full_overlap) * view_size - padding;
Moritz Lipp's avatar
Moritz Lipp committed
536
537
      break;
    case FULL_DOWN:
538
    case FULL_RIGHT:
539
      new_value = value + (1.0 - scroll_full_overlap) * view_size + padding;
Moritz Lipp's avatar
Moritz Lipp committed
540
541
      break;
    case HALF_UP:
542
    case HALF_LEFT:
543
      new_value = value - ((view_size + padding) / 2);
Moritz Lipp's avatar
Moritz Lipp committed
544
545
      break;
    case HALF_DOWN:
546
    case HALF_RIGHT:
547
      new_value = value + ((view_size + padding) / 2);
Moritz Lipp's avatar
Moritz Lipp committed
548
549
      break;
    case LEFT:
550
      new_value = value - scroll_hstep * t;
Julian Orth's avatar
Julian Orth committed
551
      break;
Moritz Lipp's avatar
Moritz Lipp committed
552
    case UP:
553
      new_value = value - scroll_step * t;
Moritz Lipp's avatar
Moritz Lipp committed
554
555
      break;
    case RIGHT:
556
      new_value = value + scroll_hstep * t;
Julian Orth's avatar
Julian Orth committed
557
      break;
Moritz Lipp's avatar
Moritz Lipp committed
558
    case DOWN:
559
      new_value = value + scroll_step * t;
Moritz Lipp's avatar
Moritz Lipp committed
560
561
562
563
564
565
566
567
      break;
    case TOP:
      new_value = 0;
      break;
    case BOTTOM:
      new_value = max;
      break;
    default:
Moritz Lipp's avatar
Moritz Lipp committed
568
      new_value = value;
Moritz Lipp's avatar
Moritz Lipp committed
569
570
  }

571
572
573
574
575
576
577
  if (scroll_wrap == true) {
    if (new_value < 0)
      new_value = max;
    else if (new_value > max)
      new_value = 0;
  }

Sebastian Ramacher's avatar
CS    
Sebastian Ramacher committed
578
  if (scroll_page_aware == true) {
Jonas Hoersch's avatar
Jonas Hoersch committed
579
580
581
582
583
584
585
586
587
588
589
    int page_offset;
    double page_size;

    {
      unsigned int page_id = zathura_document_get_current_page_number(zathura->document);
      zathura_page_t* page = zathura_document_get_page(zathura->document, page_id);
      page_offset_t offset;
      page_calculate_offset(zathura, page, &offset);

      double scale = zathura_document_get_scale(zathura->document);

Sebastian Ramacher's avatar
CS    
Sebastian Ramacher committed
590
591
      if ((argument->n == LEFT) || (argument->n == FULL_LEFT) || (argument->n == HALF_LEFT) ||
          (argument->n == RIGHT) || (argument->n == FULL_RIGHT) || (argument->n == HALF_RIGHT)) {
Jonas Hoersch's avatar
Jonas Hoersch committed
592
593
594
595
596
597
598
599
600
601
        page_offset = offset.x;
        page_size = zathura_page_get_width(page) * scale;
      } else {
        page_offset = offset.y;
        page_size = zathura_page_get_height(page) * scale;
      }

      page_offset -= padding / 2;
      page_size   += padding;
    }
Sebastian Ramacher's avatar
CS    
Sebastian Ramacher committed
602
603
604
605
606

    if ((argument->n == FULL_DOWN) || (argument->n == HALF_DOWN) ||
        (argument->n == FULL_RIGHT) || (argument->n == HALF_RIGHT)) {
      if ((page_offset > value) &&
          (page_offset < value + view_size)) {
Jonas Hoersch's avatar
Jonas Hoersch committed
607
        new_value = page_offset;
Sebastian Ramacher's avatar
CS    
Sebastian Ramacher committed
608
609
      } else if ((page_offset <= value) &&
                 (page_offset + page_size < value + view_size)) {
Jonas Hoersch's avatar
Jonas Hoersch committed
610
        new_value = page_offset + page_size + 1;
Sebastian Ramacher's avatar
CS    
Sebastian Ramacher committed
611
612
      } else if ((page_offset <= value) &&
                 (page_offset + page_size < new_value + view_size)) {
Jonas Hoersch's avatar
Jonas Hoersch committed
613
614
        new_value = page_offset + page_size - view_size + 1;
      }
Sebastian Ramacher's avatar
CS    
Sebastian Ramacher committed
615
616
617
618
    } else if ((argument->n == FULL_UP) || (argument->n == HALF_UP) ||
               (argument->n == FULL_LEFT) || (argument->n == HALF_LEFT)) {
      if ((page_offset + 1 >= value) &&
          (page_offset < value + view_size)) {
Jonas Hoersch's avatar
Jonas Hoersch committed
619
        new_value = page_offset - view_size;
Sebastian Ramacher's avatar
CS    
Sebastian Ramacher committed
620
621
      } else if ((page_offset <= value) &&
                 (page_offset + page_size + 1 < value + view_size)) {
Jonas Hoersch's avatar
Jonas Hoersch committed
622
        new_value = page_offset + page_size - view_size;
Sebastian Ramacher's avatar
CS    
Sebastian Ramacher committed
623
624
      } else if ((page_offset <= value) &&
                 (page_offset > new_value)) {
Jonas Hoersch's avatar
Jonas Hoersch committed
625
626
        new_value = page_offset;
      }
Sebastian Ramacher's avatar
CS    
Sebastian Ramacher committed
627
    }
Jonas Hoersch's avatar
Jonas Hoersch committed
628
629
  }

630
  zathura_adjustment_set_value(adjustment, new_value);
Moritz Lipp's avatar
Moritz Lipp committed
631

Moritz Lipp's avatar
Moritz Lipp committed
632
  return false;
633
634
}

635
636

bool
637
638
sc_jumplist(girara_session_t* session, girara_argument_t* argument,
            girara_event_t* UNUSED(event), unsigned int UNUSED(t))
639
640
641
642
643
644
{
  g_return_val_if_fail(session != NULL, false);
  g_return_val_if_fail(session->global.data != NULL, false);
  zathura_t* zathura = session->global.data;
  g_return_val_if_fail(argument != NULL, false);
  g_return_val_if_fail(zathura->document != NULL, false);
645
646
647

  /* if no jumps in the jumplist */
  if (zathura->jumplist.size == 0) {
Moritz Lipp's avatar
Moritz Lipp committed
648
    return true;
649
  }
650

651
652
653
654
  GtkAdjustment* hadj = gtk_scrolled_window_get_hadjustment(GTK_SCROLLED_WINDOW(session->gtk.view));
  GtkAdjustment* vadj = gtk_scrolled_window_get_vadjustment(GTK_SCROLLED_WINDOW(session->gtk.view));
  double x = zathura_adjustment_get_ratio(hadj);
  double y = zathura_adjustment_get_ratio(vadj);
655
  zathura_jump_t* jump = NULL;
656
657
658
  zathura_jump_t* prev_jump = zathura_jumplist_current(zathura);
  bool go_to_current = false;

Sebastian Ramacher's avatar
CS    
Sebastian Ramacher committed
659
  if (zathura_jumplist_has_next(zathura) == false || zathura_jumplist_has_previous(zathura) == false) {
660
661
662
663
664
665
666
    if (x == prev_jump->x && y == prev_jump->y) {
      go_to_current = false;
    } else {
      go_to_current = true;
    }
  }

667
668
  switch(argument->n) {
    case FORWARD:
669
670
671
672
673
674
      if (go_to_current == true && zathura_jumplist_has_previous(zathura) == false) {
        jump = zathura_jumplist_current(zathura);
      } else {
        zathura_jumplist_forward(zathura);
        jump = zathura_jumplist_current(zathura);
      }
675
676
      break;
    case BACKWARD:
677
678
679
680
681
682
      if (go_to_current == true && zathura_jumplist_has_next(zathura) == false) {
        jump = zathura_jumplist_current(zathura);
      } else {
        zathura_jumplist_backward(zathura);
        jump = zathura_jumplist_current(zathura);
      }
683
684
685
      break;
  }

686
  if (jump == prev_jump) {
Sebastian Ramacher's avatar
CS    
Sebastian Ramacher committed
687
688
    if ((zathura_jumplist_has_previous(zathura) == false && argument->n == BACKWARD) ||
        (zathura_jumplist_has_next(zathura) == false && argument->n == FORWARD)) {
689
690
691
692
      jump = NULL;
    }
  }

693
  if (jump != NULL) {
694
695
    zathura_adjustment_set_value_from_ratio(hadj, jump->x);
    zathura_adjustment_set_value_from_ratio(vadj, jump->y);
696
697
    zathura_document_set_current_page_number(zathura->document, jump->page);
    statusbar_page_number_update(zathura);
698
}
699
700
701
702

  return false;
}

703
704
705
706
707
708
709
710
711
712
713

bool
sc_bisect(girara_session_t* session, girara_argument_t* argument,
          girara_event_t* UNUSED(event), unsigned int t)
{
  g_return_val_if_fail(session != NULL, false);
  g_return_val_if_fail(session->global.data != NULL, false);
  zathura_t* zathura = session->global.data;
  g_return_val_if_fail(argument != NULL, false);
  g_return_val_if_fail(zathura->document != NULL, false);

714
715
  const unsigned int num_pages = zathura_document_get_number_of_pages(zathura->document);
  const unsigned int cur_page = zathura_document_get_current_page_number(zathura->document);
716
717
718

  /* process arguments */
  int direction;
719
720
721
722
723
724
725
726
727
728
  if (t > 0 && t <= num_pages) {
    /* bisect between cur_page and t */
    t -= 1;
    if (t == cur_page) {
      /* nothing to do */
      return false;
    }
    else if (t > cur_page) {
      zathura->bisect.start = cur_page;
      zathura->bisect.end = t;
729
730
      direction = BACKWARD;
    } else {
731
732
      zathura->bisect.start = t;
      zathura->bisect.end = cur_page;
733
734
735
736
737
      direction = FORWARD;
    }
  } else if (argument != NULL)  {
    direction = argument->n;

Abdó Roig-Maranges's avatar
Abdó Roig-Maranges committed
738
    /* setup initial bisect range */
739
740
741
742
743
744
    zathura_jump_t* jump = zathura_jumplist_current(zathura);
    if (jump == NULL) {
      girara_debug("bisecting between first and last page because there are no jumps");
      zathura->bisect.start = 0;
      zathura->bisect.end = num_pages - 1;

Moritz Lipp's avatar
Moritz Lipp committed
745
    } else if (jump->page != cur_page || jump->page != zathura->bisect.last_jump) {
Abdó Roig-Maranges's avatar
Abdó Roig-Maranges committed
746
747
748
      girara_debug("last jump doesn't match up, starting new bisecting");
      zathura->bisect.start = 0;
      zathura->bisect.end = num_pages - 1;
749

Abdó Roig-Maranges's avatar
Abdó Roig-Maranges committed
750
751
752
753
754
755
756
757
758
759
760
761
762
      unsigned int prev_page;
      if (direction == FORWARD) {
        prev_page = num_pages - 1;
      } else {
        prev_page = 0;
      }

      /* check if we have previous jumps */
      if (zathura_jumplist_has_previous(zathura) == true) {
        zathura_jumplist_backward(zathura);
        jump = zathura_jumplist_current(zathura);
        if (jump != NULL) {
          prev_page = jump->page;
763
        }
Abdó Roig-Maranges's avatar
Abdó Roig-Maranges committed
764
        zathura_jumplist_forward(zathura);
765
      }
Abdó Roig-Maranges's avatar
Abdó Roig-Maranges committed
766
767
768
769

      zathura->bisect.start = MIN(prev_page, cur_page);
      zathura->bisect.end = MAX(prev_page, cur_page);
      zathura->bisect.last_jump = cur_page;
770
    }
771
772
773
774
775
776
777
778
  } else {
    return false;
  }

  girara_debug("bisecting between %d and %d, at %d", zathura->bisect.start, zathura->bisect.end, cur_page);
  if (zathura->bisect.start == zathura->bisect.end) {
    /* nothing to do */
    return false;
779
780
  }

781
782
783
784
  unsigned int next_page = cur_page;
  unsigned int next_start = zathura->bisect.start;
  unsigned int next_end = zathura->bisect.end;

Abdó Roig-Maranges's avatar
Abdó Roig-Maranges committed
785
786
787
  /* here we have next_start <= next_page <= next_end */

  /* bisect step */
788
789
  switch(direction) {
    case FORWARD:
790
791
792
793
      if (cur_page != zathura->bisect.end) {
        next_page = (cur_page + zathura->bisect.end) / 2;
        if (next_page == cur_page) {
          ++next_page;
794
        }
795
        next_start = cur_page;
796
797
798
799
      }
      break;

    case BACKWARD:
800
801
802
803
      if (cur_page != zathura->bisect.start) {
        next_page = (cur_page + zathura->bisect.start) / 2;
        if (next_page == cur_page) {
          --next_page;
804
        }
805
        next_end = cur_page;
806
807
808
      }
      break;
  }
809

810
811
812
813
814
815
816
817
818
819
  if (next_page == cur_page) {
    /* nothing to do */
    return false;
  }

  girara_debug("bisecting between %d and %d, jumping to %d", zathura->bisect.start, zathura->bisect.end, next_page);
  zathura->bisect.last_jump = next_page;
  zathura->bisect.start = next_start;
  zathura->bisect.end = next_end;

Abdó Roig-Maranges's avatar
Abdó Roig-Maranges committed
820
  zathura_jumplist_add(zathura);
821
822
823
  page_set(zathura, next_page);
  zathura_jumplist_add(zathura);

824
825
826
827
  return false;
}


Moritz Lipp's avatar
Moritz Lipp committed
828
bool
Moritz Lipp's avatar
Moritz Lipp committed
829
sc_search(girara_session_t* session, girara_argument_t* argument,
Moritz Lipp's avatar
Moritz Lipp committed
830
          girara_event_t* UNUSED(event), unsigned int UNUSED(t))
831
{
Moritz Lipp's avatar
Moritz Lipp committed
832
833
834
835
836
  g_return_val_if_fail(session != NULL, false);
  g_return_val_if_fail(session->global.data != NULL, false);
  zathura_t* zathura = session->global.data;
  g_return_val_if_fail(argument != NULL, false);
  g_return_val_if_fail(zathura->document != NULL, false);
Moritz Lipp's avatar
Moritz Lipp committed
837

Marwan Tanager's avatar
Marwan Tanager committed
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
  const unsigned int num_pages = zathura_document_get_number_of_pages(zathura->document);
  const unsigned int cur_page  = zathura_document_get_current_page_number(zathura->document);
  GtkWidget *cur_page_widget = zathura_page_get_widget(zathura, zathura_document_get_page(zathura->document, cur_page));
  bool nohlsearch, first_time_after_abort, draw;

  nohlsearch = first_time_after_abort = draw = false;
  girara_setting_get(session, "nohlsearch", &nohlsearch);

  if (nohlsearch == false) {
    g_object_get(cur_page_widget, "draw-search-results", &draw, NULL);

    if (draw == false) {
      first_time_after_abort = true;
    }

    document_draw_search_results(zathura, true);
  }
855

856
  int diff = argument->n == FORWARD ? 1 : -1;
857
858
  if (zathura->global.search_direction == BACKWARD)
    diff = -diff;
859

Sebastian Ramacher's avatar
Sebastian Ramacher committed
860
861
862
  zathura_page_t* target_page = NULL;
  int target_idx = 0;

Marwan Tanager's avatar
Marwan Tanager committed
863
  for (unsigned int page_id = 0; page_id < num_pages; ++page_id) {
864
    int tmp = cur_page + diff * page_id;
865
    zathura_page_t* page = zathura_document_get_page(zathura->document, (tmp + num_pages) % num_pages);
866
867
868
869
    if (page == NULL) {
      continue;
    }

870
    GtkWidget* page_widget = zathura_page_get_widget(zathura, page);
Moritz Lipp's avatar
Moritz Lipp committed
871

872
    int num_search_results = 0, current = -1;
Marwan Tanager's avatar
Marwan Tanager committed
873
    g_object_get(page_widget, "search-current", &current, "search-length", &num_search_results, NULL);
874
875
876
877
    if (num_search_results == 0 || current == -1) {
      continue;
    }

Marwan Tanager's avatar
Marwan Tanager committed
878
    if (first_time_after_abort == true || (tmp + num_pages) % num_pages != cur_page) {
Marwan Tanager's avatar
Marwan Tanager committed
879
880
881
882
883
      target_page = page;
      target_idx = diff == 1 ? 0 : num_search_results - 1;
      break;
    }

884
885
    if (diff == 1 && current < num_search_results - 1) {
      /* the next result is on the same page */
Sebastian Ramacher's avatar
Sebastian Ramacher committed
886
887
      target_page = page;
      target_idx = current + 1;
888
    } else if (diff == -1 && current > 0) {
Sebastian Ramacher's avatar
Sebastian Ramacher committed
889
890
      target_page = page;
      target_idx = current - 1;
891
892
    } else {
      /* the next result is on a different page */
Moritz Lipp's avatar
Moritz Lipp committed
893
      g_object_set(page_widget, "search-current", -1, NULL);
894
895
896

      for (int npage_id = 1; page_id < num_pages; ++npage_id) {
        int ntmp = cur_page + diff * (page_id + npage_id);
897
        zathura_page_t* npage = zathura_document_get_page(zathura->document, (ntmp + 2*num_pages) % num_pages);
898
        GtkWidget* npage_page_widget = zathura_page_get_widget(zathura, npage);
Moritz Lipp's avatar
Moritz Lipp committed
899
        g_object_get(npage_page_widget, "search-length", &num_search_results, NULL);
900
        if (num_search_results != 0) {
Sebastian Ramacher's avatar
Sebastian Ramacher committed
901
902
          target_page = npage;
          target_idx = diff == 1 ? 0 : num_search_results - 1;
903
904
905
906
          break;
        }
      }
    }
907

908
909
    break;
  }
Moritz Lipp's avatar
Moritz Lipp committed
910

Sebastian Ramacher's avatar
Sebastian Ramacher committed
911
912
  if (target_page != NULL) {
    girara_list_t* results = NULL;
913
    GtkWidget* page_widget = zathura_page_get_widget(zathura, target_page);
Moritz Lipp's avatar
Moritz Lipp committed
914
915
    g_object_set(page_widget, "search-current", target_idx, NULL);
    g_object_get(page_widget, "search-results", &results, NULL);
Sebastian Ramacher's avatar
Sebastian Ramacher committed
916
917
918
919

    zathura_rectangle_t* rect = girara_list_nth(results, target_idx);
    zathura_rectangle_t rectangle = recalc_rectangle(target_page, *rect);
    page_offset_t offset;
920
    page_calculate_offset(zathura, target_page, &offset);
921
    zathura_jumplist_add(zathura);
Sebastian Ramacher's avatar
Sebastian Ramacher committed
922

Marwan Tanager's avatar
Marwan Tanager committed
923
924
925
926
    if (zathura_page_get_index(target_page) != cur_page) {
      page_set(zathura, zathura_page_get_index(target_page));
    }

Sebastian Ramacher's avatar
Sebastian Ramacher committed
927
928
    GtkAdjustment* view_vadjustment = gtk_scrolled_window_get_vadjustment(GTK_SCROLLED_WINDOW(zathura->ui.session->gtk.view));
    int y = offset.y - gtk_adjustment_get_page_size(view_vadjustment) / 2 + rectangle.y1;
929
    zathura_adjustment_set_value(view_vadjustment, y);
Julian Orth's avatar
Julian Orth committed
930
931
932
933
934
935

    bool search_hadjust = true;
    girara_setting_get(session, "search-hadjust", &search_hadjust);
    if (search_hadjust == true) {
      GtkAdjustment* view_hadjustment = gtk_scrolled_window_get_hadjustment(GTK_SCROLLED_WINDOW(zathura->ui.session->gtk.view));
      int x = offset.x - gtk_adjustment_get_page_size(view_hadjustment) / 2 + rectangle.x1;
936
      zathura_adjustment_set_value(view_hadjustment, x);
Julian Orth's avatar
Julian Orth committed
937
    }
938
939

    zathura_jumplist_add(zathura);
Sebastian Ramacher's avatar
Sebastian Ramacher committed
940
941
  }

Moritz Lipp's avatar
Moritz Lipp committed
942
  return false;
943
944
}

Moritz Lipp's avatar
Moritz Lipp committed
945
bool
946
sc_navigate_index(girara_session_t* session, girara_argument_t* argument,
Moritz Lipp's avatar
Moritz Lipp committed
947
                  girara_event_t* UNUSED(event), unsigned int UNUSED(t))
948
{
Moritz Lipp's avatar
Moritz Lipp committed
949
950
951
952
953
954
  g_return_val_if_fail(session != NULL, false);
  g_return_val_if_fail(session->global.data != NULL, false);
  zathura_t* zathura = session->global.data;
  g_return_val_if_fail(argument != NULL, false);
  g_return_val_if_fail(zathura->document != NULL, false);

Moritz Lipp's avatar
Moritz Lipp committed
955
956
957
958
959
960
961
962
  if(zathura->ui.index == NULL) {
    return false;
  }

  GtkTreeView *tree_view = gtk_container_get_children(GTK_CONTAINER(zathura->ui.index))->data;
  GtkTreePath *path;

  gtk_tree_view_get_cursor(tree_view, &path, NULL);
Moritz Lipp's avatar
Moritz Lipp committed
963
  if (path == NULL) {
Moritz Lipp's avatar
Moritz Lipp committed
964
965
966
967
968
969
970
971
972
973
974
    return false;
  }

  GtkTreeModel *model = gtk_tree_view_get_model(tree_view);
  GtkTreeIter   iter;
  GtkTreeIter   child_iter;

  gboolean is_valid_path = TRUE;

  switch(argument->n) {
    case UP:
975
      if (gtk_tree_path_prev(path) == FALSE) {
976
977
978
        /* For some reason gtk_tree_path_up returns TRUE although we're not
         * moving anywhere. */
        is_valid_path = gtk_tree_path_up(path) && (gtk_tree_path_get_depth(path) > 0);
Moritz Lipp's avatar
Moritz Lipp committed
979
980
981
982
983
      } else { /* row above */
        while(gtk_tree_view_row_expanded(tree_view, path)) {
          gtk_tree_model_get_iter(model, &iter, path);
          /* select last child */
          gtk_tree_model_iter_nth_child(model, &child_iter, &iter,
Moritz Lipp's avatar
Moritz Lipp committed
984
                                        gtk_tree_model_iter_n_children(model, &iter)-1);
Moritz Lipp's avatar
Moritz Lipp committed
985
986
987
988
989
990
          gtk_tree_path_free(path);
          path = gtk_tree_model_get_path(model, &child_iter);
        }
      }
      break;
    case COLLAPSE:
991
      if (gtk_tree_view_collapse_row(tree_view, path) == FALSE
Moritz Lipp's avatar
Moritz Lipp committed
992
          && gtk_tree_path_get_depth(path) > 1) {
Moritz Lipp's avatar
Moritz Lipp committed
993
994
995
996
997
        gtk_tree_path_up(path);
        gtk_tree_view_collapse_row(tree_view, path);
      }
      break;
    case DOWN:
998
      if (gtk_tree_view_row_expanded(tree_view, path) == TRUE) {
Moritz Lipp's avatar
Moritz Lipp committed
999
1000
1001
1002
1003
        gtk_tree_path_down(path);
      } else {
        do {
          gtk_tree_model_get_iter(model, &iter, path);
          if (gtk_tree_model_iter_next(model, &iter)) {
1004
            gtk_tree_path_free(path);
Moritz Lipp's avatar
Moritz Lipp committed
1005
1006
1007
1008
            path = gtk_tree_model_get_path(model, &iter);
            break;