shortcuts.c 43.6 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
#include <math.h>
22

23
24
25
26
27
28
29
/* 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;
Sebastian Ramacher's avatar
Sebastian Ramacher committed
30
  const unsigned int number_of_pages = zathura_document_get_number_of_pages(zathura->document);
31
32
33
34
35
36
37
  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);
38
39
    GObject* obj_page_widget = G_OBJECT(page_widget);
    g_object_set(obj_page_widget, "draw-search-results", FALSE, NULL);
40
    if (zathura_page_get_visibility(page) == true) {
41
      g_object_set(obj_page_widget, "draw-links", TRUE, NULL);
42
43

      int number_of_links = 0;
44
      g_object_get(obj_page_widget, "number-of-links", &number_of_links, NULL);
45
46
47
      if (number_of_links != 0) {
        show_links = true;
      }
48
      g_object_set(obj_page_widget, "offset-links", page_offset, NULL);
49
50
      page_offset += number_of_links;
    } else {
51
      g_object_set(obj_page_widget, "draw-links", FALSE, NULL);
52
53
54
55
56
    }
  }
  return show_links;
}

Moritz Lipp's avatar
Moritz Lipp committed
57
bool
58
sc_abort(girara_session_t* session, girara_argument_t* UNUSED(argument),
Moritz Lipp's avatar
Moritz Lipp committed
59
         girara_event_t* UNUSED(event), unsigned int UNUSED(t))
60
{
Moritz Lipp's avatar
Moritz Lipp committed
61
  g_return_val_if_fail(session != NULL, false);
62
63
64
  g_return_val_if_fail(session->global.data != NULL, false);
  zathura_t* zathura = session->global.data;

65
66
67
  bool clear_search = true;
  girara_setting_get(session, "abort-clear-search", &clear_search);

Moritz Lipp's avatar
Moritz Lipp committed
68
  if (zathura->document != NULL) {
Sebastian Ramacher's avatar
Sebastian Ramacher committed
69
    const unsigned int number_of_pages = zathura_document_get_number_of_pages(zathura->document);
70
71
    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
72
73
74
75
      if (page == NULL) {
        continue;
      }

Marwan Tanager's avatar
Marwan Tanager committed
76
      GtkWidget* page_widget = zathura_page_get_widget(zathura, page);
77
78
      GObject* obj_page_widget = G_OBJECT(page_widget);
      g_object_set(obj_page_widget, "draw-links", FALSE, NULL);
79
      if (clear_search == true) {
80
        g_object_set(obj_page_widget, "draw-search-results", FALSE, NULL);
81
      }
82
83
    }
  }
Moritz Lipp's avatar
Moritz Lipp committed
84

85
86
87
88
  /* Setting the mode back here has not worked for ages. We need another way to
   * do this. Let's disable this for now.
   */
  /* girara_mode_set(session, session->modes.normal); */
Moritz Lipp's avatar
Moritz Lipp committed
89
  girara_sc_abort(session, NULL, NULL, 0);
Moritz Lipp's avatar
Moritz Lipp committed
90

Moritz Lipp's avatar
Moritz Lipp committed
91
  return false;
92
93
}

94
95
bool
sc_adjust_window(girara_session_t* session, girara_argument_t* argument,
Moritz Lipp's avatar
Moritz Lipp committed
96
                 girara_event_t* UNUSED(event), unsigned int UNUSED(t))
97
{
98
99
100
101
  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
102

103
104
105
106
107
108
109
110
111
  if (argument->n < ZATHURA_ADJUST_NONE || argument->n >= ZATHURA_ADJUST_MODE_NUMBER) {
    girara_error("Invalid adjust mode: %d", argument->n);
    girara_notify(session, GIRARA_ERROR, _("Invalid adjust mode: %d"), argument->n);
  } else {
    girara_debug("Setting adjust mode to: %d", argument->n);

    zathura_document_set_adjust_mode(zathura->document, argument->n);
    adjust_view(zathura);
  }
Moritz Lipp's avatar
Moritz Lipp committed
112

113
  return false;
114
115
}

Moritz Lipp's avatar
Moritz Lipp committed
116
bool
Moritz Lipp's avatar
Moritz Lipp committed
117
sc_change_mode(girara_session_t* session, girara_argument_t* argument,
Moritz Lipp's avatar
Moritz Lipp committed
118
               girara_event_t* UNUSED(event), unsigned int UNUSED(t))
119
{
Moritz Lipp's avatar
Moritz Lipp committed
120
121
122
123
  g_return_val_if_fail(session != NULL, false);

  girara_mode_set(session, argument->n);

Moritz Lipp's avatar
Moritz Lipp committed
124
  return false;
125
126
}

127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
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) {
143
    zathura_document_set_adjust_mode(zathura->document, ZATHURA_ADJUST_INPUTBAR);
144
    girara_dialog(zathura->ui.session, "Display link:", FALSE, NULL,
145
        cb_sc_display_link,
146
147
148
149
150
151
        zathura->ui.session);
  }

  return false;
}

152
153
154
155
156
157
158
159
160
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);

161
162
  zathura_document_set_adjust_mode(zathura->document, ZATHURA_ADJUST_INPUTBAR);

163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
  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) {
178
179
180
181
      const char* file_path = zathura_document_get_path(zathura->document);
      if (file_path == NULL) {
        return false;
      }
182

183
184
185
186
187
      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);
188
189
190
191
192

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

193
194
    GdkAtom* selection = get_selection(zathura);

195
    /* we save the X clipboard that will be clear by "grab_focus" */
196
    gchar* x_clipboard_text = NULL;
197
198
199
200

    if (selection != NULL) {
      x_clipboard_text = gtk_clipboard_wait_for_text(gtk_clipboard_get(*selection));
    }
201
202
203

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

204
    if (x_clipboard_text != NULL && selection != NULL) {
205
      /* we reset the X clipboard with saved text */
206
      gtk_clipboard_set_text(gtk_clipboard_get(*selection), x_clipboard_text, -1);
207
208
      g_free(x_clipboard_text);
    }
209
210

    g_free(selection);
211
212
213
214
215
  }

  return true;
}

Moritz Lipp's avatar
Moritz Lipp committed
216
bool
217
sc_follow(girara_session_t* session, girara_argument_t* UNUSED(argument),
Moritz Lipp's avatar
Moritz Lipp committed
218
          girara_event_t* UNUSED(event), unsigned int UNUSED(t))
219
{
Moritz Lipp's avatar
Moritz Lipp committed
220
  g_return_val_if_fail(session != NULL, false);
Moritz Lipp's avatar
Moritz Lipp committed
221
222
223
  g_return_val_if_fail(session->global.data != NULL, false);
  zathura_t* zathura = session->global.data;

Moritz Lipp's avatar
Moritz Lipp committed
224
  if (zathura->document == NULL || zathura->ui.session == NULL) {
Moritz Lipp's avatar
Moritz Lipp committed
225
226
227
    return false;
  }

228
  bool show_links = draw_links(zathura);
Moritz Lipp's avatar
Moritz Lipp committed
229

Moritz Lipp's avatar
Moritz Lipp committed
230
  /* ask for input */
Moritz Lipp's avatar
Moritz Lipp committed
231
  if (show_links == true) {
232
    zathura_document_set_adjust_mode(zathura->document, ZATHURA_ADJUST_INPUTBAR);
233
    girara_dialog(zathura->ui.session, "Follow link:", FALSE, NULL, cb_sc_follow, zathura->ui.session);
Moritz Lipp's avatar
Moritz Lipp committed
234
  }
Moritz Lipp's avatar
Moritz Lipp committed
235

Moritz Lipp's avatar
Moritz Lipp committed
236
237
  return false;
}
238

Moritz Lipp's avatar
Moritz Lipp committed
239
bool
Moritz Lipp's avatar
Moritz Lipp committed
240
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
241
{
Moritz Lipp's avatar
Moritz Lipp committed
242
243
244
245
246
  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);
247

248
  zathura_jumplist_add(zathura);
Moritz Lipp's avatar
Moritz Lipp committed
249
  if (t != 0) {
250
    /* add offset */
Moritz Lipp's avatar
Moritz Lipp committed
251
    t += zathura_document_get_page_offset(zathura->document);
252

Moritz Lipp's avatar
Moritz Lipp committed
253
    page_set(zathura, t - 1);
Moritz Lipp's avatar
Moritz Lipp committed
254
  } else if (argument->n == TOP) {
Moritz Lipp's avatar
Moritz Lipp committed
255
    page_set(zathura, 0);
Moritz Lipp's avatar
Moritz Lipp committed
256
  } else if (argument->n == BOTTOM) {
257
    page_set(zathura, zathura_document_get_number_of_pages(zathura->document) - 1);
258
259
  }

260
261
  zathura_jumplist_add(zathura);

Moritz Lipp's avatar
Moritz Lipp committed
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
  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
278
279
280
281
  GtkAdjustment* x_adj = NULL;
  GtkAdjustment* y_adj = NULL;

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

Moritz Lipp's avatar
Moritz Lipp committed
290
      /* drag */
Moritz Lipp's avatar
Moritz Lipp committed
291
    case GIRARA_EVENT_BUTTON_PRESS:
292
293
      zathura->shortcut.mouse.x = event->x;
      zathura->shortcut.mouse.y = event->y;
Moritz Lipp's avatar
Moritz Lipp committed
294
295
      break;
    case GIRARA_EVENT_BUTTON_RELEASE:
296
297
      zathura->shortcut.mouse.x = 0;
      zathura->shortcut.mouse.y = 0;
Moritz Lipp's avatar
Moritz Lipp committed
298
299
300
      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
301
      y_adj = gtk_scrolled_window_get_vadjustment(GTK_SCROLLED_WINDOW(session->gtk.view));
Moritz Lipp's avatar
Moritz Lipp committed
302
303
304
305

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

307
      zathura_adjustment_set_value(x_adj,
308
          gtk_adjustment_get_value(x_adj) - (event->x - zathura->shortcut.mouse.x));
309
      zathura_adjustment_set_value(y_adj,
310
          gtk_adjustment_get_value(y_adj) - (event->y - zathura->shortcut.mouse.y));
Moritz Lipp's avatar
Moritz Lipp committed
311
312
      break;

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

Moritz Lipp's avatar
Moritz Lipp committed
318
  return false;
319
320
}

Moritz Lipp's avatar
Moritz Lipp committed
321
322
323
324
325
326
327
328
329
330
331
332
333
334
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 */
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;
342
343
344
    case GIRARA_EVENT_SCROLL_BIDIRECTIONAL:
      argument->n = ZOOM_SMOOTH;
      break;
345
346
    default:
      return false;
Moritz Lipp's avatar
Moritz Lipp committed
347
348
  }

349
  return sc_zoom(session, argument, event, t);
350
351
}

Moritz Lipp's avatar
Moritz Lipp committed
352
bool
Moritz Lipp's avatar
Moritz Lipp committed
353
sc_navigate(girara_session_t* session, girara_argument_t* argument,
Moritz Lipp's avatar
Moritz Lipp committed
354
            girara_event_t* UNUSED(event), unsigned int t)
355
{
Moritz Lipp's avatar
Moritz Lipp committed
356
357
358
359
360
  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
361

362
363
  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
364

365
366
367
  bool scroll_wrap = false;
  girara_setting_get(session, "scroll-wrap", &scroll_wrap);

368
369
370
371
372
373
374
375
  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
376
  t = (t == 0) ? (unsigned int) offset : t;
Moritz Lipp's avatar
Moritz Lipp committed
377
  if (argument->n == NEXT) {
Benoît Knecht's avatar
Benoît Knecht committed
378
    if (scroll_wrap == false) {
379
380
381
382
      new_page = new_page + t;
    } else {
      new_page = (new_page + t) % number_of_pages;
    }
Moritz Lipp's avatar
Moritz Lipp committed
383
  } else if (argument->n == PREVIOUS) {
Benoît Knecht's avatar
Benoît Knecht committed
384
    if (scroll_wrap == false) {
385
386
387
388
389
390
      new_page = new_page - t;
    } else {
      new_page = (new_page + number_of_pages - t) % number_of_pages;
    }
  }

391
392
393
394
395
396
  if (!scroll_wrap) {
    if (new_page <= 0) {
      new_page = 0;
    } else if (new_page >= number_of_pages) {
      new_page = number_of_pages - 1;
    }
Moritz Lipp's avatar
Moritz Lipp committed
397
398
  }

399
  page_set(zathura, new_page);
Moritz Lipp's avatar
Moritz Lipp committed
400

Moritz Lipp's avatar
Moritz Lipp committed
401
  return false;
402
403
}

Moritz Lipp's avatar
Moritz Lipp committed
404
405
bool
sc_print(girara_session_t* session, girara_argument_t* UNUSED(argument),
Moritz Lipp's avatar
Moritz Lipp committed
406
         girara_event_t* UNUSED(event), unsigned int UNUSED(t))
Moritz Lipp's avatar
Moritz Lipp committed
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
{
  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
422
bool
423
sc_recolor(girara_session_t* session, girara_argument_t* UNUSED(argument),
Moritz Lipp's avatar
Moritz Lipp committed
424
           girara_event_t* UNUSED(event), unsigned int UNUSED(t))
425
{
Moritz Lipp's avatar
Moritz Lipp committed
426
  g_return_val_if_fail(session != NULL, false);
Moritz Lipp's avatar
Moritz Lipp committed
427

Moritz Lipp's avatar
Moritz Lipp committed
428
429
430
431
  bool value = false;
  girara_setting_get(session, "recolor", &value);
  value = !value;
  girara_setting_set(session, "recolor", &value);
Moritz Lipp's avatar
Moritz Lipp committed
432

Moritz Lipp's avatar
Moritz Lipp committed
433
  return false;
434
435
}

Moritz Lipp's avatar
Moritz Lipp committed
436
bool
437
sc_reload(girara_session_t* session, girara_argument_t* UNUSED(argument),
Moritz Lipp's avatar
Moritz Lipp committed
438
          girara_event_t* UNUSED(event), unsigned int UNUSED(t))
439
{
Moritz Lipp's avatar
Moritz Lipp committed
440
  g_return_val_if_fail(session != NULL, false);
Moritz Lipp's avatar
Moritz Lipp committed
441
442
443
  g_return_val_if_fail(session->global.data != NULL, false);
  zathura_t* zathura = session->global.data;

444
  if (zathura->file_monitor.monitor == NULL) {
Moritz Lipp's avatar
Moritz Lipp committed
445
446
447
448
    return false;
  }

  /* close current document */
Moritz Lipp's avatar
Moritz Lipp committed
449
  document_close(zathura, true);
Moritz Lipp's avatar
Moritz Lipp committed
450
451

  /* reopen document */
452
453
454
  document_open(
    zathura, zathura_filemonitor_get_filepath(zathura->file_monitor.monitor),
    NULL, zathura->file_monitor.password, ZATHURA_PAGE_NUMBER_UNSPECIFIED);
Moritz Lipp's avatar
Moritz Lipp committed
455

Moritz Lipp's avatar
Moritz Lipp committed
456
  return false;
457
458
}

Moritz Lipp's avatar
Moritz Lipp committed
459
bool
460
sc_rotate(girara_session_t* session, girara_argument_t* argument,
Moritz Lipp's avatar
Moritz Lipp committed
461
          girara_event_t* UNUSED(event), unsigned int t)
462
{
Moritz Lipp's avatar
Moritz Lipp committed
463
464
465
466
  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
467

Sebastian Ramacher's avatar
Sebastian Ramacher committed
468
  const unsigned int page_number = zathura_document_get_current_page_number(zathura->document);
469

470
471
472
473
474
  int angle = 90;
  if (argument != NULL && argument->n == ROTATE_CCW) {
    angle = 270;
  }

Moritz Lipp's avatar
Moritz Lipp committed
475
  /* update rotate value */
Moritz Lipp's avatar
Moritz Lipp committed
476
  t = (t == 0) ? 1 : t;
477
  unsigned int rotation = zathura_document_get_rotation(zathura->document);
Moritz Lipp's avatar
Moritz Lipp committed
478
  zathura_document_set_rotation(zathura->document, (rotation + angle * t) % 360);
Moritz Lipp's avatar
Moritz Lipp committed
479

480
481
482
483
  /* 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
484
  /* render all pages again */
485
  render_all(zathura);
Moritz Lipp's avatar
Moritz Lipp committed
486

487
  page_set(zathura, page_number);
488

Moritz Lipp's avatar
Moritz Lipp committed
489
  return false;
490
491
}

Moritz Lipp's avatar
Moritz Lipp committed
492
bool
Moritz Lipp's avatar
Moritz Lipp committed
493
sc_scroll(girara_session_t* session, girara_argument_t* argument,
Sebastian Ramacher's avatar
Sebastian Ramacher committed
494
          girara_event_t* event, unsigned int t)
495
{
Moritz Lipp's avatar
Moritz Lipp committed
496
497
498
499
  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);
500
501
502
  if (zathura->document == NULL) {
    return false;
  }
Moritz Lipp's avatar
Moritz Lipp committed
503

504
505
506
507
508
509
510
511
512
  /* if TOP or BOTTOM, go there and we are done */
  if (argument->n == TOP) {
    position_set(zathura, -1, 0);
    return false;
  } else if (argument->n == BOTTOM) {
    position_set(zathura, -1, 1.0);
    return false;
  }

513
514
515
516
517
518
519
  /* Retrieve current page and position */
  const unsigned int page_id = zathura_document_get_current_page_number(zathura->document);
  double pos_x = zathura_document_get_position_x(zathura->document);
  double pos_y = zathura_document_get_position_y(zathura->document);

  /* If PAGE_TOP or PAGE_BOTTOM, go there and we are done */
  if (argument->n == PAGE_TOP) {
520
521
522
    double dontcare = 0.5;
    page_number_to_position(zathura->document, page_id, dontcare, 0.0, &dontcare, &pos_y);
    position_set(zathura, pos_x, pos_y);
523
524
    return false;
  } else if (argument->n == PAGE_BOTTOM) {
525
526
527
    double dontcare = 0.5;
    page_number_to_position(zathura->document, page_id, dontcare, 1.0, &dontcare, &pos_y);
    position_set(zathura, pos_x, pos_y);
528
529
530
    return false;
  }

Sebastian Ramacher's avatar
CS    
Sebastian Ramacher committed
531
  if (t == 0) {
532
533
534
    t = 1;
  }

Sebastian Ramacher's avatar
CS    
Sebastian Ramacher committed
535
536
  unsigned int view_width  = 0;
  unsigned int view_height = 0;
537
  zathura_document_get_viewport_size(zathura->document, &view_height, &view_width);
Moritz Lipp's avatar
Moritz Lipp committed
538

Sebastian Ramacher's avatar
CS    
Sebastian Ramacher committed
539
540
  unsigned int doc_width  = 0;
  unsigned int doc_height = 0;
541
  zathura_document_get_document_size(zathura->document, &doc_height, &doc_width);
542

543
544
  float scroll_step = 40;
  girara_setting_get(session, "scroll-step", &scroll_step);
Julian Orth's avatar
Julian Orth committed
545
546
547
548
549
  float scroll_hstep = -1;
  girara_setting_get(session, "scroll-hstep", &scroll_hstep);
  if (scroll_hstep < 0) {
    scroll_hstep = scroll_step;
  }
550
  float scroll_full_overlap = 0.0;
551
  girara_setting_get(session, "scroll-full-overlap", &scroll_full_overlap);
Jonas Hoersch's avatar
Jonas Hoersch committed
552
553
  bool scroll_page_aware = false;
  girara_setting_get(session, "scroll-page-aware", &scroll_page_aware);
554

555
556
557
  bool scroll_wrap = false;
  girara_setting_get(session, "scroll-wrap", &scroll_wrap);

558
  /* compute the direction of scrolling */
559
560
561
  double direction = 1.0;
  if ((argument->n == LEFT) || (argument->n == FULL_LEFT) || (argument->n == HALF_LEFT) ||
      (argument->n == UP) || (argument->n == FULL_UP) || (argument->n == HALF_UP)) {
562
563
564
    direction = -1.0;
  }

565
566
  const double vstep = (double)view_height / (double)doc_height;
  const double hstep = (double)view_width / (double)doc_width;
567
568

  /* compute new position */
569
  switch (argument->n) {
Moritz Lipp's avatar
Moritz Lipp committed
570
571
    case FULL_UP:
    case FULL_DOWN:
572
573
574
575
      pos_y += direction * (1.0 - scroll_full_overlap) * vstep;
      break;

    case FULL_LEFT:
576
    case FULL_RIGHT:
577
      pos_x += direction * (1.0 - scroll_full_overlap) * hstep;
Moritz Lipp's avatar
Moritz Lipp committed
578
      break;
579

Moritz Lipp's avatar
Moritz Lipp committed
580
581
    case HALF_UP:
    case HALF_DOWN:
582
      pos_y += direction * 0.5 * vstep;
Moritz Lipp's avatar
Moritz Lipp committed
583
      break;
584
585
586
587

    case HALF_LEFT:
    case HALF_RIGHT:
      pos_x += direction * 0.5 * hstep;
Julian Orth's avatar
Julian Orth committed
588
      break;
589

Moritz Lipp's avatar
Moritz Lipp committed
590
591
    case UP:
    case DOWN:
592
      pos_y += direction * t * scroll_step / (double)doc_height;
Moritz Lipp's avatar
Moritz Lipp committed
593
      break;
594
595
596
597

    case LEFT:
    case RIGHT:
      pos_x += direction * t * scroll_hstep / (double)doc_width;
Moritz Lipp's avatar
Moritz Lipp committed
598
      break;
599
600

    case BIDIRECTIONAL: {
601
602
      pos_x += event->x * t * scroll_hstep / (double)doc_width;
      pos_y += event->y * t * scroll_step / (double)doc_height;
603
604
      break;
    }
Moritz Lipp's avatar
Moritz Lipp committed
605
606
  }

607
  /* handle boundaries */
608
609
  const double end_x = 0.5 * (double)view_width / (double)doc_width;
  const double end_y = 0.5 * (double)view_height / (double)doc_height;
610

611
612
  const double new_x = scroll_wrap ? 1.0 - end_x : end_x;
  const double new_y = scroll_wrap ? 1.0 - end_y : end_y;
Jonas Hoersch's avatar
Jonas Hoersch committed
613

614
615
616
617
618
  if (pos_x < end_x) {
    pos_x = new_x;
  } else if (pos_x > 1.0 - end_x) {
    pos_x = 1 - new_x;
  }
Jonas Hoersch's avatar
Jonas Hoersch committed
619

620
621
622
623
624
  if (pos_y < end_y) {
    pos_y = new_y;
  } else if (pos_y > 1.0 - end_y) {
    pos_y = 1 - new_y;
  }
Sebastian Ramacher's avatar
CS    
Sebastian Ramacher committed
625

626
  /* snap to the border if we change page */
627
  const unsigned int new_page_id = position_to_page_number(zathura->document, pos_x, pos_y);
628
  if (scroll_page_aware == true && page_id != new_page_id) {
629
    double dummy = 0.0;
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
    switch(argument->n) {
      case FULL_LEFT:
      case HALF_LEFT:
        page_number_to_position(zathura->document, new_page_id, 1.0, 0.0, &pos_x, &dummy);
        break;

      case FULL_RIGHT:
      case HALF_RIGHT:
        page_number_to_position(zathura->document, new_page_id, 0.0, 0.0, &pos_x, &dummy);
        break;

      case FULL_UP:
      case HALF_UP:
        page_number_to_position(zathura->document, new_page_id, 0.0, 1.0, &dummy, &pos_y);
        break;

      case FULL_DOWN:
      case HALF_DOWN:
        page_number_to_position(zathura->document, new_page_id, 0.0, 0.0, &dummy, &pos_y);
        break;
Sebastian Ramacher's avatar
CS    
Sebastian Ramacher committed
650
    }
Jonas Hoersch's avatar
Jonas Hoersch committed
651
652
  }

653
  position_set(zathura, pos_x, pos_y);
Moritz Lipp's avatar
Moritz Lipp committed
654
  return false;
655
656
}

657
658

bool
659
660
sc_jumplist(girara_session_t* session, girara_argument_t* argument,
            girara_event_t* UNUSED(event), unsigned int UNUSED(t))
661
662
663
664
665
666
{
  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);
667
668
669

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

673
674
675
  double x = zathura_document_get_position_x(zathura->document);
  double y = zathura_document_get_position_y(zathura->document);

676
  zathura_jump_t* jump = NULL;
677
678
679
  zathura_jump_t* prev_jump = zathura_jumplist_current(zathura);
  bool go_to_current = false;

Sebastian Ramacher's avatar
CS    
Sebastian Ramacher committed
680
  if (zathura_jumplist_has_next(zathura) == false || zathura_jumplist_has_previous(zathura) == false) {
681
682
683
684
685
686
687
    if (x == prev_jump->x && y == prev_jump->y) {
      go_to_current = false;
    } else {
      go_to_current = true;
    }
  }

688
689
  switch(argument->n) {
    case FORWARD:
690
691
692
693
694
695
      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);
      }
696
697
      break;
    case BACKWARD:
698
699
700
701
702
703
      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);
      }
704
705
706
      break;
  }

707
  if (jump == prev_jump) {
Sebastian Ramacher's avatar
CS    
Sebastian Ramacher committed
708
709
    if ((zathura_jumplist_has_previous(zathura) == false && argument->n == BACKWARD) ||
        (zathura_jumplist_has_next(zathura) == false && argument->n == FORWARD)) {
710
711
712
713
      jump = NULL;
    }
  }

714
  if (jump != NULL) {
715
716
717
    page_set(zathura, jump->page);
    position_set(zathura, jump->x, jump->y);
  }
718
719
720
721

  return false;
}

722
723
724
725
726
727
728
729
730
731
732

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

733
734
  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);
735
736
737

  /* process arguments */
  int direction;
738
739
740
741
742
743
744
745
746
747
  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;
748
749
      direction = BACKWARD;
    } else {
750
751
      zathura->bisect.start = t;
      zathura->bisect.end = cur_page;
752
753
754
755
756
      direction = FORWARD;
    }
  } else if (argument != NULL)  {
    direction = argument->n;

Abdó Roig-Maranges's avatar
Abdó Roig-Maranges committed
757
    /* setup initial bisect range */
758
759
760
761
762
763
    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
764
    } else if (jump->page != cur_page || jump->page != zathura->bisect.last_jump) {
Abdó Roig-Maranges's avatar
Abdó Roig-Maranges committed
765
766
767
      girara_debug("last jump doesn't match up, starting new bisecting");
      zathura->bisect.start = 0;
      zathura->bisect.end = num_pages - 1;
768

Abdó Roig-Maranges's avatar
Abdó Roig-Maranges committed
769
770
771
772
773
774
775
776
777
778
779
780
781
      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;
782
        }
Abdó Roig-Maranges's avatar
Abdó Roig-Maranges committed
783
        zathura_jumplist_forward(zathura);
784
      }
Abdó Roig-Maranges's avatar
Abdó Roig-Maranges committed
785
786
787
788

      zathura->bisect.start = MIN(prev_page, cur_page);
      zathura->bisect.end = MAX(prev_page, cur_page);
      zathura->bisect.last_jump = cur_page;
789
    }
790
791
792
793
794
795
796
797
  } 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;
798
799
  }

800
801
802
803
  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
804
805
806
  /* here we have next_start <= next_page <= next_end */

  /* bisect step */
807
808
  switch(direction) {
    case FORWARD:
809
810
811
812
      if (cur_page != zathura->bisect.end) {
        next_page = (cur_page + zathura->bisect.end) / 2;
        if (next_page == cur_page) {
          ++next_page;
813
        }
814
        next_start = cur_page;
815
816
817
818
      }
      break;

    case BACKWARD:
819
820
821
822
      if (cur_page != zathura->bisect.start) {
        next_page = (cur_page + zathura->bisect.start) / 2;
        if (next_page == cur_page) {
          --next_page;
823
        }
824
        next_end = cur_page;
825
826
827
      }
      break;
  }
828

829
830
831
832
833
834
835
836
837
838
  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
839
  zathura_jumplist_add(zathura);
840
841
842
  page_set(zathura, next_page);
  zathura_jumplist_add(zathura);

843
844
845
846
  return false;
}


Moritz Lipp's avatar
Moritz Lipp committed
847
bool
Moritz Lipp's avatar
Moritz Lipp committed
848
sc_search(girara_session_t* session, girara_argument_t* argument,
Moritz Lipp's avatar
Moritz Lipp committed
849
          girara_event_t* UNUSED(event), unsigned int UNUSED(t))
850
{
Moritz Lipp's avatar
Moritz Lipp committed
851
852
853
854
855
  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
856

Marwan Tanager's avatar
Marwan Tanager committed
857
858
859
  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));
860
861
  bool nohlsearch, first_time_after_abort;
  gboolean draw;
Marwan Tanager's avatar
Marwan Tanager committed
862

863
864
  nohlsearch = first_time_after_abort = false;
  draw = FALSE;
Marwan Tanager's avatar
Marwan Tanager committed
865
866
867
  girara_setting_get(session, "nohlsearch", &nohlsearch);

  if (nohlsearch == false) {
868
    g_object_get(G_OBJECT(cur_page_widget), "draw-search-results", &draw, NULL);
Marwan Tanager's avatar
Marwan Tanager committed
869
870
871
872
873
874
875

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

    document_draw_search_results(zathura, true);
  }
876

877
  int diff = argument->n == FORWARD ? 1 : -1;
878
879
  if (zathura->global.search_direction == BACKWARD)
    diff = -diff;
880

Sebastian Ramacher's avatar
Sebastian Ramacher committed
881
882
883
  zathura_page_t* target_page = NULL;
  int target_idx = 0;

Marwan Tanager's avatar
Marwan Tanager committed
884
  for (unsigned int page_id = 0; page_id < num_pages; ++page_id) {
885
    int tmp = cur_page + diff * page_id;
886
    zathura_page_t* page = zathura_document_get_page(zathura->document, (tmp + num_pages) % num_pages);
887
888
889
890
    if (page == NULL) {
      continue;
    }

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

893
    int num_search_results = 0, current = -1;
894
    g_object_get(G_OBJECT(page_widget), "search-current", &current, "search-length", &num_search_results, NULL);
895
896
897
898
    if (num_search_results == 0 || current == -1) {
      continue;
    }

Marwan Tanager's avatar
Marwan Tanager committed
899
    if (first_time_after_abort == true || (tmp + num_pages) % num_pages != cur_page) {
Marwan Tanager's avatar
Marwan Tanager committed
900
901
902
903
904
      target_page = page;
      target_idx = diff == 1 ? 0 : num_search_results - 1;
      break;
    }

905
906
    if (diff == 1 && current < num_search_results - 1) {
      /* the next result is on the same page */
Sebastian Ramacher's avatar
Sebastian Ramacher committed
907
908
      target_page = page;
      target_idx = current + 1;
909
    } else if (diff == -1 && current > 0) {
Sebastian Ramacher's avatar
Sebastian Ramacher committed
910
911
      target_page = page;
      target_idx = current - 1;
912
913
    } else {
      /* the next result is on a different page */
914
      g_object_set(G_OBJECT(page_widget), "search-current", -1, NULL);
915
916
917

      for (int npage_id = 1; page_id < num_pages; ++npage_id) {
        int ntmp = cur_page + diff * (page_id + npage_id);
918
        zathura_page_t* npage = zathura_document_get_page(zathura->document, (ntmp + 2*num_pages) % num_pages);
919
        GtkWidget* npage_page_widget = zathura_page_get_widget(zathura, npage);
920
        g_object_get(G_OBJECT(npage_page_widget), "search-length", &num_search_results, NULL);
921
        if (num_search_results != 0) {
Sebastian Ramacher's avatar
Sebastian Ramacher committed
922
923
          target_page = npage;
          target_idx = diff == 1 ? 0 : num_search_results - 1;
924
925
926
927
          break;
        }
      }
    }
928

929
930
    break;
  }
Moritz Lipp's avatar
Moritz Lipp committed
931

Sebastian Ramacher's avatar
Sebastian Ramacher committed
932
933
  if (target_page != NULL) {
    girara_list_t* results = NULL;
934
    GtkWidget* page_widget = zathura_page_get_widget(zathura, target_page);
935
936
937
    GObject* obj_page_widget = G_OBJECT(page_widget);
    g_object_set(obj_page_widget, "search-current", target_idx, NULL);
    g_object_get(obj_page_widget, "search-results", &results, NULL);
Sebastian Ramacher's avatar
Sebastian Ramacher committed
938

939
    /* Need to adjust rectangle to page scale and orientation */
Sebastian Ramacher's avatar
Sebastian Ramacher committed
940
941
    zathura_rectangle_t* rect = girara_list_nth(results, target_idx);
    zathura_rectangle_t rectangle = recalc_rectangle(target_page, *rect);
Julian Orth's avatar
Julian Orth committed
942
943
944

    bool search_hadjust = true;
    girara_setting_get(session, "search-hadjust", &search_hadjust);
945
946

    /* compute the position of the center of the page */
Sebastian Ramacher's avatar
CS    
Sebastian Ramacher committed
947
948
    double pos_x = 0;
    double pos_y = 0;
949
950
951
952
953
    page_number_to_position(zathura->document, zathura_page_get_index(target_page),
                            0.5, 0.5, &pos_x, &pos_y);

    /* correction to center the current result                          */
    /* NOTE: rectangle is in viewport units, already scaled and rotated */
Sebastian Ramacher's avatar
CS    
Sebastian Ramacher committed
954
955
    unsigned int cell_height = 0;
    unsigned int cell_width = 0;
956
957
    zathura_document_get_cell_size(zathura->document, &cell_height, &cell_width);

Sebastian Ramacher's avatar
CS    
Sebastian Ramacher committed
958
959
    unsigned int doc_height = 0;
    unsigned int doc_width = 0;
960
961
    zathura_document_get_document_size(zathura->document, &doc_height, &doc_width);

962
963
964
965
    /* compute the center of the rectangle, which will be aligned to the center
       of the viewport */
    double center_x = (rectangle.x1 + rectangle.x2) / 2;
    double center_y = (rectangle.y1 + rectangle.y2) / 2;
966

967
    pos_y += (center_y - (double)cell_height/2) / (double)doc_height;
Julian Orth's avatar
Julian Orth committed
968
    if (search_hadjust == true) {
969
      pos_x += (center_x - (double)cell_width/2) / (double)doc_width;
Julian Orth's avatar
Julian Orth committed
970
    }
971