1 /* SPDX-License-Identifier: Zlib */
2
3 #include <girara/session.h>
4 #include <girara/settings.h>
5 #include <girara/datastructures.h>
6 #include <girara/shortcuts.h>
7 #include <girara/utils.h>
8 #include <gtk/gtk.h>
9 #include <glib/gi18n.h>
10
11 #include "callbacks.h"
12 #include "shortcuts.h"
13 #include "document.h"
14 #include "zathura.h"
15 #include "render.h"
16 #include "utils.h"
17 #include "page.h"
18 #include "print.h"
19 #include "page-widget.h"
20 #include "adjustment.h"
21 #include <math.h>
22
23 /* Helper function; see sc_display_link and sc_follow. */
24 static bool
draw_links(zathura_t * zathura)25 draw_links(zathura_t* zathura)
26 {
27 /* set pages to draw links */
28 bool show_links = false;
29 unsigned int page_offset = 0;
30 const unsigned int number_of_pages = zathura_document_get_number_of_pages(zathura->document);
31 for (unsigned int page_id = 0; page_id < number_of_pages; page_id++) {
32 zathura_page_t* page = zathura_document_get_page(zathura->document, page_id);
33 if (page == NULL) {
34 continue;
35 }
36
37 GtkWidget* page_widget = zathura_page_get_widget(zathura, page);
38 GObject* obj_page_widget = G_OBJECT(page_widget);
39 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 if (number_of_links != 0) {
46 show_links = true;
47 }
48 g_object_set(obj_page_widget, "offset-links", page_offset, NULL);
49 page_offset += number_of_links;
50 } else {
51 g_object_set(obj_page_widget, "draw-links", FALSE, NULL);
52 }
53 }
54 return show_links;
55 }
56
57 bool
sc_abort(girara_session_t * session,girara_argument_t * UNUSED (argument),girara_event_t * UNUSED (event),unsigned int UNUSED (t))58 sc_abort(girara_session_t* session, girara_argument_t* UNUSED(argument),
59 girara_event_t* UNUSED(event), unsigned int UNUSED(t))
60 {
61 g_return_val_if_fail(session != NULL, false);
62 g_return_val_if_fail(session->global.data != NULL, false);
63 zathura_t* zathura = session->global.data;
64
65 bool clear_search = true;
66 girara_setting_get(session, "abort-clear-search", &clear_search);
67
68 if (zathura->document != NULL) {
69 const unsigned int number_of_pages = zathura_document_get_number_of_pages(zathura->document);
70 for (unsigned int page_id = 0; page_id < number_of_pages; ++page_id) {
71 zathura_page_t* page = zathura_document_get_page(zathura->document, page_id);
72 if (page == NULL) {
73 continue;
74 }
75
76 GtkWidget* page_widget = zathura_page_get_widget(zathura, page);
77 GObject* obj_page_widget = G_OBJECT(page_widget);
78 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 }
84
85 /* Setting the mode back here has not worked for ages. We need another way to
86 * do this. Let's disable this for now.
87 */
88 /* girara_mode_set(session, session->modes.normal); */
89 girara_sc_abort(session, NULL, NULL, 0);
90
91 return false;
92 }
93
94 bool
sc_adjust_window(girara_session_t * session,girara_argument_t * argument,girara_event_t * UNUSED (event),unsigned int UNUSED (t))95 sc_adjust_window(girara_session_t* session, girara_argument_t* argument,
96 girara_event_t* UNUSED(event), unsigned int UNUSED(t))
97 {
98 g_return_val_if_fail(session != NULL, false);
99 g_return_val_if_fail(session->global.data != NULL, false);
100 zathura_t* zathura = session->global.data;
101 g_return_val_if_fail(argument != NULL, false);
102
103 if (argument->n < ZATHURA_ADJUST_NONE || argument->n >= ZATHURA_ADJUST_MODE_NUMBER) {
104 girara_error("Invalid adjust mode: %d", argument->n);
105 girara_notify(session, GIRARA_ERROR, _("Invalid adjust mode: %d"), argument->n);
106 } else {
107 girara_debug("Setting adjust mode to: %d", argument->n);
108
109 zathura_document_set_adjust_mode(zathura->document, argument->n);
110 adjust_view(zathura);
111 }
112
113 return false;
114 }
115
116 bool
sc_change_mode(girara_session_t * session,girara_argument_t * argument,girara_event_t * UNUSED (event),unsigned int UNUSED (t))117 sc_change_mode(girara_session_t* session, girara_argument_t* argument,
118 girara_event_t* UNUSED(event), unsigned int UNUSED(t))
119 {
120 g_return_val_if_fail(session != NULL, false);
121
122 girara_mode_set(session, argument->n);
123
124 return false;
125 }
126
127 bool
sc_display_link(girara_session_t * session,girara_argument_t * UNUSED (argument),girara_event_t * UNUSED (event),unsigned int UNUSED (t))128 sc_display_link(girara_session_t* session, girara_argument_t* UNUSED(argument),
129 girara_event_t* UNUSED(event), unsigned int UNUSED(t))
130 {
131 g_return_val_if_fail(session != NULL, false);
132 g_return_val_if_fail(session->global.data != NULL, false);
133 zathura_t* zathura = session->global.data;
134
135 if (zathura->document == NULL || zathura->ui.session == NULL) {
136 return false;
137 }
138
139 bool show_links = draw_links(zathura);
140
141 /* ask for input */
142 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 zathura->ui.session);
147 }
148
149 return false;
150 }
151
152 bool
sc_focus_inputbar(girara_session_t * session,girara_argument_t * argument,girara_event_t * UNUSED (event),unsigned int UNUSED (t))153 sc_focus_inputbar(girara_session_t* session, girara_argument_t* argument, girara_event_t* UNUSED(event), unsigned int UNUSED(t))
154 {
155 g_return_val_if_fail(session != NULL, false);
156 g_return_val_if_fail(session->gtk.inputbar_entry != NULL, false);
157 g_return_val_if_fail(session->global.data != NULL, false);
158 zathura_t* zathura = session->global.data;
159 g_return_val_if_fail(argument != NULL, false);
160
161 zathura_document_set_adjust_mode(zathura->document, ZATHURA_ADJUST_INPUTBAR);
162
163 if (gtk_widget_get_visible(GTK_WIDGET(session->gtk.inputbar)) == false) {
164 gtk_widget_show(GTK_WIDGET(session->gtk.inputbar));
165 }
166
167 if (gtk_widget_get_visible(GTK_WIDGET(session->gtk.notification_area)) == true) {
168 gtk_widget_hide(GTK_WIDGET(session->gtk.notification_area));
169 }
170
171 gtk_widget_grab_focus(GTK_WIDGET(session->gtk.inputbar_entry));
172
173 if (argument->data != NULL) {
174 gtk_entry_set_text(session->gtk.inputbar_entry, (char*) argument->data);
175
176 /* append filepath */
177 if (argument->n == APPEND_FILEPATH && zathura->document != NULL) {
178 const char* file_path = zathura_document_get_path(zathura->document);
179 if (file_path == NULL) {
180 return false;
181 }
182
183 char* path = g_path_get_dirname(file_path);
184 char* escaped = girara_escape_string(path);
185 char* tmp = g_strdup_printf("%s%s/", (char*) argument->data, (g_strcmp0(path, "/") == 0) ? "" : escaped);
186 g_free(path);
187 g_free(escaped);
188
189 gtk_entry_set_text(session->gtk.inputbar_entry, tmp);
190 g_free(tmp);
191 }
192
193 GdkAtom* selection = get_selection(zathura);
194
195 /* we save the X clipboard that will be clear by "grab_focus" */
196 gchar* x_clipboard_text = NULL;
197
198 if (selection != NULL) {
199 x_clipboard_text = gtk_clipboard_wait_for_text(gtk_clipboard_get(*selection));
200 }
201
202 gtk_editable_set_position(GTK_EDITABLE(session->gtk.inputbar_entry), -1);
203
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 g_free(x_clipboard_text);
208 }
209
210 g_free(selection);
211 }
212
213 return true;
214 }
215
216 bool
sc_follow(girara_session_t * session,girara_argument_t * UNUSED (argument),girara_event_t * UNUSED (event),unsigned int UNUSED (t))217 sc_follow(girara_session_t* session, girara_argument_t* UNUSED(argument),
218 girara_event_t* UNUSED(event), unsigned int UNUSED(t))
219 {
220 g_return_val_if_fail(session != NULL, false);
221 g_return_val_if_fail(session->global.data != NULL, false);
222 zathura_t* zathura = session->global.data;
223
224 if (zathura->document == NULL || zathura->ui.session == NULL) {
225 return false;
226 }
227
228 bool show_links = draw_links(zathura);
229
230 /* ask for input */
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);
234 }
235
236 return false;
237 }
238
239 bool
sc_goto(girara_session_t * session,girara_argument_t * argument,girara_event_t * UNUSED (event),unsigned int t)240 sc_goto(girara_session_t* session, girara_argument_t* argument, girara_event_t* UNUSED(event), unsigned int t)
241 {
242 g_return_val_if_fail(session != NULL, false);
243 g_return_val_if_fail(session->global.data != NULL, false);
244 zathura_t* zathura = session->global.data;
245 g_return_val_if_fail(argument != NULL, false);
246 g_return_val_if_fail(zathura->document != NULL, false);
247
248 zathura_jumplist_add(zathura);
249 if (t != 0) {
250 /* add offset */
251 t += zathura_document_get_page_offset(zathura->document);
252
253 page_set(zathura, t - 1);
254 } else if (argument->n == TOP) {
255 page_set(zathura, 0);
256 } else if (argument->n == BOTTOM) {
257 page_set(zathura, zathura_document_get_number_of_pages(zathura->document) - 1);
258 }
259
260 zathura_jumplist_add(zathura);
261
262 return false;
263 }
264
265 bool
sc_mouse_scroll(girara_session_t * session,girara_argument_t * argument,girara_event_t * event,unsigned int t)266 sc_mouse_scroll(girara_session_t* session, girara_argument_t* argument, girara_event_t* event, unsigned int t)
267 {
268 g_return_val_if_fail(session != NULL, false);
269 g_return_val_if_fail(session->global.data != NULL, false);
270 zathura_t* zathura = session->global.data;
271 g_return_val_if_fail(argument != NULL, false);
272 g_return_val_if_fail(event != NULL, false);
273
274 if (zathura->document == NULL) {
275 return false;
276 }
277
278 GtkAdjustment* x_adj = NULL;
279 GtkAdjustment* y_adj = NULL;
280
281 switch (event->type) {
282 /* scroll */
283 case GIRARA_EVENT_SCROLL_UP:
284 case GIRARA_EVENT_SCROLL_DOWN:
285 case GIRARA_EVENT_SCROLL_LEFT:
286 case GIRARA_EVENT_SCROLL_RIGHT:
287 case GIRARA_EVENT_SCROLL_BIDIRECTIONAL:
288 return sc_scroll(session, argument, event, t);
289
290 /* drag */
291 case GIRARA_EVENT_BUTTON_PRESS:
292 zathura->shortcut.mouse.x = event->x;
293 zathura->shortcut.mouse.y = event->y;
294 break;
295 case GIRARA_EVENT_BUTTON_RELEASE:
296 zathura->shortcut.mouse.x = 0;
297 zathura->shortcut.mouse.y = 0;
298 break;
299 case GIRARA_EVENT_MOTION_NOTIFY:
300 x_adj = gtk_scrolled_window_get_hadjustment(GTK_SCROLLED_WINDOW(session->gtk.view));
301 y_adj = gtk_scrolled_window_get_vadjustment(GTK_SCROLLED_WINDOW(session->gtk.view));
302
303 if (x_adj == NULL || y_adj == NULL) {
304 return false;
305 }
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));
311 break;
312
313 /* unhandled events */
314 default:
315 break;
316 }
317
318 return false;
319 }
320
321 bool
sc_mouse_zoom(girara_session_t * session,girara_argument_t * argument,girara_event_t * event,unsigned int t)322 sc_mouse_zoom(girara_session_t* session, girara_argument_t* argument, girara_event_t* event, unsigned int t)
323 {
324 g_return_val_if_fail(session != NULL, false);
325 g_return_val_if_fail(session->global.data != NULL, false);
326 zathura_t* zathura = session->global.data;
327 g_return_val_if_fail(argument != NULL, false);
328 g_return_val_if_fail(event != NULL, false);
329
330 if (zathura->document == NULL) {
331 return false;
332 }
333
334 /* scroll event */
335 switch (event->type) {
336 case GIRARA_EVENT_SCROLL_UP:
337 argument->n = ZOOM_IN;
338 break;
339 case GIRARA_EVENT_SCROLL_DOWN:
340 argument->n = ZOOM_OUT;
341 break;
342 case GIRARA_EVENT_SCROLL_BIDIRECTIONAL:
343 argument->n = ZOOM_SMOOTH;
344 break;
345 default:
346 return false;
347 }
348
349 return sc_zoom(session, argument, event, t);
350 }
351
352 bool
sc_navigate(girara_session_t * session,girara_argument_t * argument,girara_event_t * UNUSED (event),unsigned int t)353 sc_navigate(girara_session_t* session, girara_argument_t* argument,
354 girara_event_t* UNUSED(event), unsigned int t)
355 {
356 g_return_val_if_fail(session != NULL, false);
357 g_return_val_if_fail(session->global.data != NULL, false);
358 zathura_t* zathura = session->global.data;
359 g_return_val_if_fail(argument != NULL, false);
360 g_return_val_if_fail(zathura->document != NULL, false);
361
362 int number_of_pages = zathura_document_get_number_of_pages(zathura->document);
363 int new_page = zathura_document_get_current_page_number(zathura->document);
364
365 bool scroll_wrap = false;
366 girara_setting_get(session, "scroll-wrap", &scroll_wrap);
367
368 bool columns_per_row_offset = false;
369 girara_setting_get(session, "advance-pages-per-row", &columns_per_row_offset);
370
371 int offset = 1;
372 if (columns_per_row_offset == true) {
373 girara_setting_get(session, "pages-per-row", &offset);
374 }
375
376 t = (t == 0) ? (unsigned int) offset : t;
377 if (argument->n == NEXT) {
378 if (scroll_wrap == false) {
379 new_page = new_page + t;
380 } else {
381 new_page = (new_page + t) % number_of_pages;
382 }
383 } else if (argument->n == PREVIOUS) {
384 if (scroll_wrap == false) {
385 new_page = new_page - t;
386 } else {
387 new_page = (new_page + number_of_pages - t) % number_of_pages;
388 }
389 }
390
391 if (!scroll_wrap) {
392 if (new_page <= 0) {
393 new_page = 0;
394 } else if (new_page >= number_of_pages) {
395 new_page = number_of_pages - 1;
396 }
397 }
398
399 page_set(zathura, new_page);
400
401 return false;
402 }
403
404 bool
sc_print(girara_session_t * session,girara_argument_t * UNUSED (argument),girara_event_t * UNUSED (event),unsigned int UNUSED (t))405 sc_print(girara_session_t* session, girara_argument_t* UNUSED(argument),
406 girara_event_t* UNUSED(event), unsigned int UNUSED(t))
407 {
408 g_return_val_if_fail(session != NULL, false);
409 g_return_val_if_fail(session->global.data != NULL, false);
410 zathura_t* zathura = session->global.data;
411
412 if (zathura->document == NULL) {
413 girara_notify(session, GIRARA_ERROR, _("No document opened."));
414 return false;
415 }
416
417 print(zathura);
418
419 return true;
420 }
421
422 bool
sc_recolor(girara_session_t * session,girara_argument_t * UNUSED (argument),girara_event_t * UNUSED (event),unsigned int UNUSED (t))423 sc_recolor(girara_session_t* session, girara_argument_t* UNUSED(argument),
424 girara_event_t* UNUSED(event), unsigned int UNUSED(t))
425 {
426 g_return_val_if_fail(session != NULL, false);
427
428 bool value = false;
429 girara_setting_get(session, "recolor", &value);
430 value = !value;
431 girara_setting_set(session, "recolor", &value);
432
433 return false;
434 }
435
436 bool
sc_reload(girara_session_t * session,girara_argument_t * UNUSED (argument),girara_event_t * UNUSED (event),unsigned int UNUSED (t))437 sc_reload(girara_session_t* session, girara_argument_t* UNUSED(argument),
438 girara_event_t* UNUSED(event), unsigned int UNUSED(t))
439 {
440 g_return_val_if_fail(session != NULL, false);
441 g_return_val_if_fail(session->global.data != NULL, false);
442 zathura_t* zathura = session->global.data;
443
444 if (zathura->file_monitor.monitor == NULL) {
445 return false;
446 }
447
448 /* close current document */
449 document_close(zathura, true);
450
451 /* reopen document */
452 document_open(
453 zathura, zathura_filemonitor_get_filepath(zathura->file_monitor.monitor),
454 NULL, zathura->file_monitor.password, ZATHURA_PAGE_NUMBER_UNSPECIFIED);
455
456 return false;
457 }
458
459 bool
sc_rotate(girara_session_t * session,girara_argument_t * argument,girara_event_t * UNUSED (event),unsigned int t)460 sc_rotate(girara_session_t* session, girara_argument_t* argument,
461 girara_event_t* UNUSED(event), unsigned int t)
462 {
463 g_return_val_if_fail(session != NULL, false);
464 g_return_val_if_fail(session->global.data != NULL, false);
465 zathura_t* zathura = session->global.data;
466 g_return_val_if_fail(zathura->document != NULL, false);
467
468 const unsigned int page_number = zathura_document_get_current_page_number(zathura->document);
469
470 int angle = 90;
471 if (argument != NULL && argument->n == ROTATE_CCW) {
472 angle = 270;
473 }
474
475 /* update rotate value */
476 t = (t == 0) ? 1 : t;
477 unsigned int rotation = zathura_document_get_rotation(zathura->document);
478 zathura_document_set_rotation(zathura->document, (rotation + angle * t) % 360);
479
480 /* update scale */
481 girara_argument_t new_argument = { zathura_document_get_adjust_mode(zathura->document), NULL };
482 sc_adjust_window(zathura->ui.session, &new_argument, NULL, 0);
483
484 /* render all pages again */
485 render_all(zathura);
486
487 page_set(zathura, page_number);
488
489 return false;
490 }
491
492 bool
sc_scroll(girara_session_t * session,girara_argument_t * argument,girara_event_t * event,unsigned int t)493 sc_scroll(girara_session_t* session, girara_argument_t* argument,
494 girara_event_t* event, unsigned int t)
495 {
496 g_return_val_if_fail(session != NULL, false);
497 g_return_val_if_fail(session->global.data != NULL, false);
498 zathura_t* zathura = session->global.data;
499 g_return_val_if_fail(argument != NULL, false);
500 if (zathura->document == NULL) {
501 return false;
502 }
503
504 /* if TOP or BOTTOM, go there and we are done */
505 if (argument->n == TOP) {
506 position_set(zathura, -1, 0);
507 return false;
508 } else if (argument->n == BOTTOM) {
509 position_set(zathura, -1, 1.0);
510 return false;
511 }
512
513 /* Retrieve current page and position */
514 const unsigned int page_id = zathura_document_get_current_page_number(zathura->document);
515 double pos_x = zathura_document_get_position_x(zathura->document);
516 double pos_y = zathura_document_get_position_y(zathura->document);
517
518 /* If PAGE_TOP or PAGE_BOTTOM, go there and we are done */
519 if (argument->n == PAGE_TOP) {
520 double dontcare = 0.5;
521 page_number_to_position(zathura->document, page_id, dontcare, 0.0, &dontcare, &pos_y);
522 position_set(zathura, pos_x, pos_y);
523 return false;
524 } else if (argument->n == PAGE_BOTTOM) {
525 double dontcare = 0.5;
526 page_number_to_position(zathura->document, page_id, dontcare, 1.0, &dontcare, &pos_y);
527 position_set(zathura, pos_x, pos_y);
528 return false;
529 }
530
531 if (t == 0) {
532 t = 1;
533 }
534
535 unsigned int view_width = 0;
536 unsigned int view_height = 0;
537 zathura_document_get_viewport_size(zathura->document, &view_height, &view_width);
538
539 unsigned int doc_width = 0;
540 unsigned int doc_height = 0;
541 zathura_document_get_document_size(zathura->document, &doc_height, &doc_width);
542
543 float scroll_step = 40;
544 girara_setting_get(session, "scroll-step", &scroll_step);
545 float scroll_hstep = -1;
546 girara_setting_get(session, "scroll-hstep", &scroll_hstep);
547 if (scroll_hstep < 0) {
548 scroll_hstep = scroll_step;
549 }
550 float scroll_full_overlap = 0.0;
551 girara_setting_get(session, "scroll-full-overlap", &scroll_full_overlap);
552 bool scroll_page_aware = false;
553 girara_setting_get(session, "scroll-page-aware", &scroll_page_aware);
554
555 bool scroll_wrap = false;
556 girara_setting_get(session, "scroll-wrap", &scroll_wrap);
557
558 /* compute the direction of scrolling */
559 double direction = 1.0;
560 if ((argument->n == LEFT) || (argument->n == FULL_LEFT) || (argument->n == HALF_LEFT) ||
561 (argument->n == UP) || (argument->n == FULL_UP) || (argument->n == HALF_UP)) {
562 direction = -1.0;
563 }
564
565 const double vstep = (double)view_height / (double)doc_height;
566 const double hstep = (double)view_width / (double)doc_width;
567
568 /* compute new position */
569 switch (argument->n) {
570 case FULL_UP:
571 case FULL_DOWN:
572 pos_y += direction * (1.0 - scroll_full_overlap) * vstep;
573 break;
574
575 case FULL_LEFT:
576 case FULL_RIGHT:
577 pos_x += direction * (1.0 - scroll_full_overlap) * hstep;
578 break;
579
580 case HALF_UP:
581 case HALF_DOWN:
582 pos_y += direction * 0.5 * vstep;
583 break;
584
585 case HALF_LEFT:
586 case HALF_RIGHT:
587 pos_x += direction * 0.5 * hstep;
588 break;
589
590 case UP:
591 case DOWN:
592 pos_y += direction * t * scroll_step / (double)doc_height;
593 break;
594
595 case LEFT:
596 case RIGHT:
597 pos_x += direction * t * scroll_hstep / (double)doc_width;
598 break;
599
600 case BIDIRECTIONAL: {
601 pos_x += event->x * t * scroll_hstep / (double)doc_width;
602 pos_y += event->y * t * scroll_step / (double)doc_height;
603 break;
604 }
605 }
606
607 /* handle boundaries */
608 const double end_x = 0.5 * (double)view_width / (double)doc_width;
609 const double end_y = 0.5 * (double)view_height / (double)doc_height;
610
611 const double new_x = scroll_wrap ? 1.0 - end_x : end_x;
612 const double new_y = scroll_wrap ? 1.0 - end_y : end_y;
613
614 if (pos_x < end_x) {
615 pos_x = new_x;
616 } else if (pos_x > 1.0 - end_x) {
617 pos_x = 1 - new_x;
618 }
619
620 if (pos_y < end_y) {
621 pos_y = new_y;
622 } else if (pos_y > 1.0 - end_y) {
623 pos_y = 1 - new_y;
624 }
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 switch(argument->n) {
631 case FULL_LEFT:
632 case HALF_LEFT:
633 page_number_to_position(zathura->document, new_page_id, 1.0, 0.0, &pos_x, &dummy);
634 break;
635
636 case FULL_RIGHT:
637 case HALF_RIGHT:
638 page_number_to_position(zathura->document, new_page_id, 0.0, 0.0, &pos_x, &dummy);
639 break;
640
641 case FULL_UP:
642 case HALF_UP:
643 page_number_to_position(zathura->document, new_page_id, 0.0, 1.0, &dummy, &pos_y);
644 break;
645
646 case FULL_DOWN:
647 case HALF_DOWN:
648 page_number_to_position(zathura->document, new_page_id, 0.0, 0.0, &dummy, &pos_y);
649 break;
650 }
651 }
652
653 position_set(zathura, pos_x, pos_y);
654 return false;
655 }
656
657
658 bool
sc_jumplist(girara_session_t * session,girara_argument_t * argument,girara_event_t * UNUSED (event),unsigned int UNUSED (t))659 sc_jumplist(girara_session_t* session, girara_argument_t* argument,
660 girara_event_t* UNUSED(event), unsigned int UNUSED(t))
661 {
662 g_return_val_if_fail(session != NULL, false);
663 g_return_val_if_fail(session->global.data != NULL, false);
664 zathura_t* zathura = session->global.data;
665 g_return_val_if_fail(argument != NULL, false);
666 g_return_val_if_fail(zathura->document != NULL, false);
667
668 /* if no jumps in the jumplist */
669 if (zathura->jumplist.size == 0) {
670 return true;
671 }
672
673 double x = zathura_document_get_position_x(zathura->document);
674 double y = zathura_document_get_position_y(zathura->document);
675
676 zathura_jump_t* jump = NULL;
677 zathura_jump_t* prev_jump = zathura_jumplist_current(zathura);
678 bool go_to_current = false;
679
680 if (zathura_jumplist_has_next(zathura) == false || zathura_jumplist_has_previous(zathura) == false) {
681 if (x == prev_jump->x && y == prev_jump->y) {
682 go_to_current = false;
683 } else {
684 go_to_current = true;
685 }
686 }
687
688 switch(argument->n) {
689 case FORWARD:
690 if (go_to_current == true && zathura_jumplist_has_previous(zathura) == false) {
691 jump = zathura_jumplist_current(zathura);
692 } else {
693 zathura_jumplist_forward(zathura);
694 jump = zathura_jumplist_current(zathura);
695 }
696 break;
697 case BACKWARD:
698 if (go_to_current == true && zathura_jumplist_has_next(zathura) == false) {
699 jump = zathura_jumplist_current(zathura);
700 } else {
701 zathura_jumplist_backward(zathura);
702 jump = zathura_jumplist_current(zathura);
703 }
704 break;
705 }
706
707 if (jump == prev_jump) {
708 if ((zathura_jumplist_has_previous(zathura) == false && argument->n == BACKWARD) ||
709 (zathura_jumplist_has_next(zathura) == false && argument->n == FORWARD)) {
710 jump = NULL;
711 }
712 }
713
714 if (jump != NULL) {
715 page_set(zathura, jump->page);
716 position_set(zathura, jump->x, jump->y);
717 }
718
719 return false;
720 }
721
722
723 bool
sc_bisect(girara_session_t * session,girara_argument_t * argument,girara_event_t * UNUSED (event),unsigned int t)724 sc_bisect(girara_session_t* session, girara_argument_t* argument,
725 girara_event_t* UNUSED(event), unsigned int t)
726 {
727 g_return_val_if_fail(session != NULL, false);
728 g_return_val_if_fail(session->global.data != NULL, false);
729 zathura_t* zathura = session->global.data;
730 g_return_val_if_fail(argument != NULL, false);
731 g_return_val_if_fail(zathura->document != NULL, false);
732
733 const unsigned int num_pages = zathura_document_get_number_of_pages(zathura->document);
734 const unsigned int cur_page = zathura_document_get_current_page_number(zathura->document);
735
736 /* process arguments */
737 int direction;
738 if (t > 0 && t <= num_pages) {
739 /* bisect between cur_page and t */
740 t -= 1;
741 if (t == cur_page) {
742 /* nothing to do */
743 return false;
744 }
745 else if (t > cur_page) {
746 zathura->bisect.start = cur_page;
747 zathura->bisect.end = t;
748 direction = BACKWARD;
749 } else {
750 zathura->bisect.start = t;
751 zathura->bisect.end = cur_page;
752 direction = FORWARD;
753 }
754 } else {
755 direction = argument->n;
756
757 /* setup initial bisect range */
758 zathura_jump_t* jump = zathura_jumplist_current(zathura);
759 if (jump == NULL) {
760 girara_debug("bisecting between first and last page because there are no jumps");
761 zathura->bisect.start = 0;
762 zathura->bisect.end = num_pages - 1;
763 } else if (jump->page != cur_page || jump->page != zathura->bisect.last_jump) {
764 girara_debug("last jump doesn't match up, starting new bisecting");
765 zathura->bisect.start = 0;
766 zathura->bisect.end = num_pages - 1;
767
768 unsigned int prev_page;
769 if (direction == FORWARD) {
770 prev_page = num_pages - 1;
771 } else {
772 prev_page = 0;
773 }
774
775 /* check if we have previous jumps */
776 if (zathura_jumplist_has_previous(zathura) == true) {
777 zathura_jumplist_backward(zathura);
778 jump = zathura_jumplist_current(zathura);
779 if (jump != NULL) {
780 prev_page = jump->page;
781 }
782 zathura_jumplist_forward(zathura);
783 }
784
785 zathura->bisect.start = MIN(prev_page, cur_page);
786 zathura->bisect.end = MAX(prev_page, cur_page);
787 zathura->bisect.last_jump = cur_page;
788 }
789 }
790
791 girara_debug("bisecting between %d and %d, at %d", zathura->bisect.start, zathura->bisect.end, cur_page);
792 if (zathura->bisect.start == zathura->bisect.end) {
793 /* nothing to do */
794 return false;
795 }
796
797 unsigned int next_page = cur_page;
798 unsigned int next_start = zathura->bisect.start;
799 unsigned int next_end = zathura->bisect.end;
800
801 /* here we have next_start <= next_page <= next_end */
802
803 /* bisect step */
804 switch(direction) {
805 case FORWARD:
806 if (cur_page != zathura->bisect.end) {
807 next_page = (cur_page + zathura->bisect.end) / 2;
808 if (next_page == cur_page) {
809 ++next_page;
810 }
811 next_start = cur_page;
812 }
813 break;
814
815 case BACKWARD:
816 if (cur_page != zathura->bisect.start) {
817 next_page = (cur_page + zathura->bisect.start) / 2;
818 if (next_page == cur_page) {
819 --next_page;
820 }
821 next_end = cur_page;
822 }
823 break;
824 }
825
826 if (next_page == cur_page) {
827 /* nothing to do */
828 return false;
829 }
830
831 girara_debug("bisecting between %d and %d, jumping to %d", zathura->bisect.start, zathura->bisect.end, next_page);
832 zathura->bisect.last_jump = next_page;
833 zathura->bisect.start = next_start;
834 zathura->bisect.end = next_end;
835
836 zathura_jumplist_add(zathura);
837 page_set(zathura, next_page);
838 zathura_jumplist_add(zathura);
839
840 return false;
841 }
842
843
844 bool
sc_search(girara_session_t * session,girara_argument_t * argument,girara_event_t * UNUSED (event),unsigned int UNUSED (t))845 sc_search(girara_session_t* session, girara_argument_t* argument,
846 girara_event_t* UNUSED(event), unsigned int UNUSED(t))
847 {
848 g_return_val_if_fail(session != NULL, false);
849 g_return_val_if_fail(session->global.data != NULL, false);
850 zathura_t* zathura = session->global.data;
851 g_return_val_if_fail(argument != NULL, false);
852 g_return_val_if_fail(zathura->document != NULL, false);
853
854 const unsigned int num_pages = zathura_document_get_number_of_pages(zathura->document);
855 const unsigned int cur_page = zathura_document_get_current_page_number(zathura->document);
856 GtkWidget* cur_page_widget = zathura_page_get_widget(zathura, zathura_document_get_page(zathura->document, cur_page));
857 bool nohlsearch = false;
858 bool first_time_after_abort = false;
859
860 girara_setting_get(session, "nohlsearch", &nohlsearch);
861 if (nohlsearch == false) {
862 gboolean draw = FALSE;
863 g_object_get(G_OBJECT(cur_page_widget), "draw-search-results", &draw, NULL);
864
865 if (draw == false) {
866 first_time_after_abort = true;
867 }
868
869 document_draw_search_results(zathura, true);
870 }
871
872 int diff = argument->n == FORWARD ? 1 : -1;
873 if (zathura->global.search_direction == BACKWARD) {
874 diff = -diff;
875 }
876
877 zathura_page_t* target_page = NULL;
878 int target_idx = 0;
879
880 for (unsigned int page_id = 0; page_id < num_pages; ++page_id) {
881 int tmp = cur_page + diff * page_id;
882 zathura_page_t* page = zathura_document_get_page(zathura->document, (tmp + num_pages) % num_pages);
883 if (page == NULL) {
884 continue;
885 }
886
887 GtkWidget* page_widget = zathura_page_get_widget(zathura, page);
888
889 int num_search_results = 0, current = -1;
890 g_object_get(G_OBJECT(page_widget), "search-current", ¤t, "search-length", &num_search_results, NULL);
891 if (num_search_results == 0 || current == -1) {
892 continue;
893 }
894
895 if (first_time_after_abort == true || (tmp + num_pages) % num_pages != cur_page) {
896 target_page = page;
897 target_idx = diff == 1 ? 0 : num_search_results - 1;
898 break;
899 }
900
901 if (diff == 1 && current < num_search_results - 1) {
902 /* the next result is on the same page */
903 target_page = page;
904 target_idx = current + 1;
905 } else if (diff == -1 && current > 0) {
906 target_page = page;
907 target_idx = current - 1;
908 } else {
909 /* the next result is on a different page */
910 g_object_set(G_OBJECT(page_widget), "search-current", -1, NULL);
911
912 for (int npage_id = 1; page_id < num_pages; ++npage_id) {
913 int ntmp = cur_page + diff * (page_id + npage_id);
914 zathura_page_t* npage = zathura_document_get_page(zathura->document, (ntmp + 2*num_pages) % num_pages);
915 GtkWidget* npage_page_widget = zathura_page_get_widget(zathura, npage);
916 g_object_get(G_OBJECT(npage_page_widget), "search-length", &num_search_results, NULL);
917 if (num_search_results != 0) {
918 target_page = npage;
919 target_idx = diff == 1 ? 0 : num_search_results - 1;
920 break;
921 }
922 }
923 }
924
925 break;
926 }
927
928 if (target_page != NULL) {
929 girara_list_t* results = NULL;
930 GtkWidget* page_widget = zathura_page_get_widget(zathura, target_page);
931 GObject* obj_page_widget = G_OBJECT(page_widget);
932 g_object_set(obj_page_widget, "search-current", target_idx, NULL);
933 g_object_get(obj_page_widget, "search-results", &results, NULL);
934
935 /* Need to adjust rectangle to page scale and orientation */
936 zathura_rectangle_t* rect = girara_list_nth(results, target_idx);
937 zathura_rectangle_t rectangle = recalc_rectangle(target_page, *rect);
938
939 bool search_hadjust = true;
940 girara_setting_get(session, "search-hadjust", &search_hadjust);
941
942 /* compute the position of the center of the page */
943 double pos_x = 0;
944 double pos_y = 0;
945 page_number_to_position(zathura->document, zathura_page_get_index(target_page),
946 0.5, 0.5, &pos_x, &pos_y);
947
948 /* correction to center the current result */
949 /* NOTE: rectangle is in viewport units, already scaled and rotated */
950 unsigned int cell_height = 0;
951 unsigned int cell_width = 0;
952 zathura_document_get_cell_size(zathura->document, &cell_height, &cell_width);
953
954 unsigned int doc_height = 0;
955 unsigned int doc_width = 0;
956 zathura_document_get_document_size(zathura->document, &doc_height, &doc_width);
957
958 /* compute the center of the rectangle, which will be aligned to the center
959 of the viewport */
960 double center_x = (rectangle.x1 + rectangle.x2) / 2;
961 double center_y = (rectangle.y1 + rectangle.y2) / 2;
962
963 pos_y += (center_y - (double)cell_height/2) / (double)doc_height;
964 if (search_hadjust == true) {
965 pos_x += (center_x - (double)cell_width/2) / (double)doc_width;
966 }
967
968 /* move to position */
969 zathura_jumplist_add(zathura);
970 position_set(zathura, pos_x, pos_y);
971 zathura_jumplist_add(zathura);
972 } else if (target_page == NULL && argument->data != NULL) {
973 const char* input = argument->data;
974 girara_notify(session, GIRARA_ERROR, _("Pattern not found: %s"), input);
975 }
976
977 return false;
978 }
979
980 bool
sc_navigate_index(girara_session_t * session,girara_argument_t * argument,girara_event_t * UNUSED (event),unsigned int UNUSED (t))981 sc_navigate_index(girara_session_t* session, girara_argument_t* argument,
982 girara_event_t* UNUSED(event), unsigned int UNUSED(t))
983 {
984 g_return_val_if_fail(session != NULL, false);
985 g_return_val_if_fail(session->global.data != NULL, false);
986 zathura_t* zathura = session->global.data;
987 g_return_val_if_fail(argument != NULL, false);
988 g_return_val_if_fail(zathura->document != NULL, false);
989
990 if(zathura->ui.index == NULL) {
991 return false;
992 }
993
994 GtkTreeView *tree_view = gtk_container_get_children(GTK_CONTAINER(zathura->ui.index))->data;
995 GtkTreePath *path;
996
997 gtk_tree_view_get_cursor(tree_view, &path, NULL);
998 if (path == NULL) {
999 return false;
1000 }
1001
1002 GtkTreeModel *model = gtk_tree_view_get_model(tree_view);
1003 GtkTreeIter iter;
1004 GtkTreeIter child_iter;
1005
1006 gboolean is_valid_path = TRUE;
1007
1008 switch(argument->n) {
1009 case TOP:
1010 /* go to the first node */
1011 gtk_tree_path_free(path);
1012 path = gtk_tree_path_new_first();
1013 break;
1014 case BOTTOM:
1015 /* go to the last visiible node */
1016 gtk_tree_path_free(path);
1017 path = gtk_tree_path_new_from_indices(gtk_tree_model_iter_n_children(model, NULL) - 1, -1);
1018 gtk_tree_model_get_iter(model, &iter, path);
1019 while (gtk_tree_model_iter_has_child(model, &iter) == TRUE &&
1020 gtk_tree_view_row_expanded(tree_view, path) == TRUE) {
1021 gtk_tree_path_append_index(path, gtk_tree_model_iter_n_children(model, &iter) - 1);
1022 }
1023 break;
1024 case UP:
1025 if (gtk_tree_path_prev(path) == FALSE) {
1026 /* For some reason gtk_tree_path_up returns TRUE although we're not
1027 * moving anywhere. */
1028 is_valid_path = gtk_tree_path_up(path) && (gtk_tree_path_get_depth(path) > 0);
1029 } else { /* row above */
1030 while (gtk_tree_view_row_expanded(tree_view, path)) {
1031 gtk_tree_model_get_iter(model, &iter, path);
1032 /* select last child */
1033 gtk_tree_model_iter_nth_child(model, &child_iter, &iter,
1034 gtk_tree_model_iter_n_children(model, &iter)-1);
1035 gtk_tree_path_free(path);
1036 path = gtk_tree_model_get_path(model, &child_iter);
1037 }
1038 }
1039 break;
1040 case COLLAPSE:
1041 if (gtk_tree_view_collapse_row(tree_view, path) == FALSE
1042 && gtk_tree_path_get_depth(path) > 1) {
1043 gtk_tree_path_up(path);
1044 gtk_tree_view_collapse_row(tree_view, path);
1045 }
1046 break;
1047 case DOWN:
1048 if (gtk_tree_view_row_expanded(tree_view, path) == TRUE) {
1049 gtk_tree_path_down(path);
1050 } else {
1051 do {
1052 gtk_tree_model_get_iter(model, &iter, path);
1053 if (gtk_tree_model_iter_next(model, &iter)) {
1054 gtk_tree_path_free(path);
1055 path = gtk_tree_model_get_path(model, &iter);
1056 break;
1057 }
1058 } while((is_valid_path = (gtk_tree_path_get_depth(path) > 1))
1059 && gtk_tree_path_up(path));
1060 }
1061 break;
1062 case EXPAND:
1063 if (gtk_tree_view_expand_row(tree_view, path, FALSE)) {
1064 gtk_tree_path_down(path);
1065 }
1066 break;
1067 case EXPAND_ALL:
1068 gtk_tree_view_expand_all(tree_view);
1069 break;
1070 case COLLAPSE_ALL:
1071 gtk_tree_view_collapse_all(tree_view);
1072 gtk_tree_path_free(path);
1073 path = gtk_tree_path_new_first();
1074 gtk_tree_view_set_cursor(tree_view, path, NULL, FALSE);
1075 break;
1076 case TOGGLE:
1077 gtk_tree_model_get_iter(model, &iter, path);
1078 if (gtk_tree_model_iter_has_child(model, &iter) == TRUE) {
1079 if (gtk_tree_view_row_expanded(tree_view, path) == TRUE) {
1080 gtk_tree_view_collapse_row(tree_view, path);
1081 } else {
1082 gtk_tree_view_expand_row(tree_view, path, FALSE);
1083 }
1084 }
1085 break;
1086 case SELECT:
1087 cb_index_row_activated(tree_view, path, NULL, zathura);
1088 gtk_tree_path_free(path);
1089 return false;
1090 }
1091
1092 if (is_valid_path == TRUE) {
1093 gtk_tree_view_set_cursor(tree_view, path, NULL, FALSE);
1094 }
1095
1096 gtk_tree_path_free(path);
1097
1098 return false;
1099 }
1100
1101 bool
sc_toggle_index(girara_session_t * session,girara_argument_t * UNUSED (argument),girara_event_t * UNUSED (event),unsigned int UNUSED (t))1102 sc_toggle_index(girara_session_t* session, girara_argument_t* UNUSED(argument),
1103 girara_event_t* UNUSED(event), unsigned int UNUSED(t))
1104 {
1105 g_return_val_if_fail(session != NULL, false);
1106 g_return_val_if_fail(session->global.data != NULL, false);
1107 zathura_t* zathura = session->global.data;
1108 if (zathura->document == NULL) {
1109 return false;
1110 }
1111
1112 girara_tree_node_t* document_index = NULL;
1113 GtkWidget* treeview = NULL;
1114 GtkTreeModel* model = NULL;
1115 GtkCellRenderer* renderer = NULL;
1116 GtkCellRenderer* renderer2 = NULL;
1117
1118 if (zathura->ui.index == NULL) {
1119 /* create new index widget */
1120 zathura->ui.index = gtk_scrolled_window_new(NULL, NULL);
1121
1122 if (zathura->ui.index == NULL) {
1123 goto error_ret;
1124 }
1125
1126 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(zathura->ui.index),
1127 GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
1128
1129 /* create index */
1130 document_index = zathura_document_index_generate(zathura->document, NULL);
1131 if (document_index == NULL) {
1132 girara_notify(session, GIRARA_WARNING, _("This document does not contain any index"));
1133 goto error_free;
1134 }
1135
1136 model = GTK_TREE_MODEL(gtk_tree_store_new(3, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_POINTER));
1137 if (model == NULL) {
1138 goto error_free;
1139 }
1140
1141 treeview = gtk_tree_view_new_with_model(model);
1142 if (treeview == NULL) {
1143 goto error_free;
1144 }
1145
1146 gtk_style_context_add_class(gtk_widget_get_style_context(treeview),
1147 "indexmode");
1148
1149 g_object_unref(model);
1150
1151 renderer = gtk_cell_renderer_text_new();
1152 if (renderer == NULL) {
1153 goto error_free;
1154 }
1155
1156 renderer2 = gtk_cell_renderer_text_new();
1157 if (renderer2 == NULL) {
1158 goto error_free;
1159 }
1160
1161 document_index_build(model, NULL, document_index);
1162 girara_node_free(document_index);
1163
1164 /* setup widget */
1165 gtk_tree_view_insert_column_with_attributes(GTK_TREE_VIEW (treeview), 0, "Title", renderer, "markup", 0, NULL);
1166 gtk_tree_view_insert_column_with_attributes(GTK_TREE_VIEW (treeview), 1, "Target", renderer2, "text", 1, NULL);
1167
1168 gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(treeview), FALSE);
1169 g_object_set(G_OBJECT(renderer), "ellipsize", PANGO_ELLIPSIZE_END, NULL);
1170 g_object_set(G_OBJECT(gtk_tree_view_get_column(GTK_TREE_VIEW(treeview), 0)), "expand", TRUE, NULL);
1171 gtk_tree_view_column_set_alignment(gtk_tree_view_get_column(GTK_TREE_VIEW(treeview), 1), 1.0f);
1172 gtk_tree_view_set_cursor(GTK_TREE_VIEW(treeview), gtk_tree_path_new_first(), NULL, FALSE);
1173 g_signal_connect(G_OBJECT(treeview), "row-activated", G_CALLBACK(cb_index_row_activated), zathura);
1174
1175 gtk_container_add(GTK_CONTAINER(zathura->ui.index), treeview);
1176 gtk_widget_show(treeview);
1177 }
1178
1179 if (gtk_widget_get_visible(GTK_WIDGET(zathura->ui.index))) {
1180 girara_set_view(session, zathura->ui.page_widget);
1181 gtk_widget_hide(GTK_WIDGET(zathura->ui.index));
1182 girara_mode_set(zathura->ui.session, zathura->modes.normal);
1183
1184 /* refresh view */
1185 refresh_view(zathura);
1186 } else {
1187 /* save current position to the jumplist */
1188 zathura_jumplist_add(zathura);
1189
1190 girara_set_view(session, zathura->ui.index);
1191 gtk_widget_show(GTK_WIDGET(zathura->ui.index));
1192 girara_mode_set(zathura->ui.session, zathura->modes.index);
1193 }
1194
1195 return false;
1196
1197 error_free:
1198
1199 if (zathura->ui.index != NULL) {
1200 g_object_ref_sink(zathura->ui.index);
1201 zathura->ui.index = NULL;
1202 }
1203
1204 if (document_index != NULL) {
1205 girara_node_free(document_index);
1206 }
1207
1208 error_ret:
1209
1210 return false;
1211 }
1212
1213 bool
sc_toggle_page_mode(girara_session_t * session,girara_argument_t * UNUSED (argument),girara_event_t * UNUSED (event),unsigned int UNUSED (t))1214 sc_toggle_page_mode(girara_session_t* session, girara_argument_t*
1215 UNUSED(argument), girara_event_t* UNUSED(event), unsigned int UNUSED(t))
1216 {
1217 g_return_val_if_fail(session != NULL, false);
1218 g_return_val_if_fail(session->global.data != NULL, false);
1219 zathura_t* zathura = session->global.data;
1220
1221 if (zathura->document == NULL) {
1222 girara_notify(session, GIRARA_WARNING, _("No document opened."));
1223 return false;
1224 }
1225
1226 unsigned int page_id = zathura_document_get_current_page_number(zathura->document);
1227
1228 int pages_per_row = 1;
1229 girara_setting_get(zathura->ui.session, "pages-per-row", &pages_per_row);
1230
1231 int value = 1;
1232 if (pages_per_row == 1) {
1233 value = zathura->shortcut.toggle_page_mode.pages;
1234 } else {
1235 zathura->shortcut.toggle_page_mode.pages = pages_per_row;
1236 }
1237
1238 girara_setting_set(zathura->ui.session, "pages-per-row", &value);
1239 adjust_view(zathura);
1240
1241 page_set(zathura, page_id);
1242 render_all(zathura);
1243 refresh_view(zathura);
1244
1245 return true;
1246 }
1247
1248 bool
sc_toggle_fullscreen(girara_session_t * session,girara_argument_t * UNUSED (argument),girara_event_t * UNUSED (event),unsigned int UNUSED (t))1249 sc_toggle_fullscreen(girara_session_t* session, girara_argument_t*
1250 UNUSED(argument), girara_event_t* UNUSED(event), unsigned int UNUSED(t))
1251 {
1252 g_return_val_if_fail(session != NULL, false);
1253 g_return_val_if_fail(session->global.data != NULL, false);
1254 zathura_t* zathura = session->global.data;
1255
1256 if (zathura->document == NULL) {
1257 girara_notify(session, GIRARA_WARNING, _("No document opened."));
1258 return false;
1259 }
1260
1261 const girara_mode_t old_mode = girara_mode_get(session);
1262 if (old_mode == zathura->modes.fullscreen) {
1263 gtk_window_unfullscreen(GTK_WINDOW(session->gtk.window));
1264 refresh_view(zathura);
1265 girara_mode_set(session, zathura->modes.normal);
1266 } else if (old_mode == zathura->modes.normal) {
1267 gtk_window_fullscreen(GTK_WINDOW(session->gtk.window));
1268 refresh_view(zathura);
1269 girara_mode_set(session, zathura->modes.fullscreen);
1270 }
1271
1272 return false;
1273 }
1274
1275 bool
sc_toggle_presentation(girara_session_t * session,girara_argument_t * UNUSED (argument),girara_event_t * UNUSED (event),unsigned int UNUSED (t))1276 sc_toggle_presentation(girara_session_t* session, girara_argument_t*
1277 UNUSED(argument), girara_event_t* UNUSED(event), unsigned int UNUSED(t))
1278 {
1279 g_return_val_if_fail(session != NULL, false);
1280 g_return_val_if_fail(session->global.data != NULL, false);
1281 zathura_t* zathura = session->global.data;
1282
1283 if (zathura->document == NULL) {
1284 girara_notify(session, GIRARA_WARNING, _("No document opened."));
1285 return false;
1286 }
1287
1288 const girara_mode_t old_mode = girara_mode_get(session);
1289 if (old_mode == zathura->modes.presentation) {
1290 /* reset pages per row */
1291 girara_setting_set(session, "pages-per-row", &zathura->shortcut.toggle_presentation_mode.pages);
1292
1293 /* reset first page column */
1294 if (zathura->shortcut.toggle_presentation_mode.first_page_column_list != NULL) {
1295 girara_setting_set(session, "first-page-column", zathura->shortcut.toggle_presentation_mode.first_page_column_list);
1296 }
1297
1298 /* show status bar */
1299 gtk_widget_show(GTK_WIDGET(session->gtk.statusbar));
1300
1301 /* set full screen */
1302 gtk_window_unfullscreen(GTK_WINDOW(session->gtk.window));
1303
1304 /* reset zoom */
1305 zathura_document_set_zoom(zathura->document, zathura->shortcut.toggle_presentation_mode.zoom);
1306 render_all(zathura);
1307 refresh_view(zathura);
1308
1309 /* set mode */
1310 girara_mode_set(session, zathura->modes.normal);
1311 } else if (old_mode == zathura->modes.normal) {
1312 /* backup pages per row */
1313 girara_setting_get(session, "pages-per-row", &zathura->shortcut.toggle_presentation_mode.pages);
1314
1315 /* backup first page column */
1316 g_free(zathura->shortcut.toggle_presentation_mode.first_page_column_list);
1317 zathura->shortcut.toggle_presentation_mode.first_page_column_list = NULL;
1318 /* this will leak. we need to move the values somewhere else */
1319 girara_setting_get(session, "first-page-column", &zathura->shortcut.toggle_presentation_mode.first_page_column_list);
1320
1321 /* set single view */
1322 int int_value = 1;
1323 girara_setting_set(session, "pages-per-row", &int_value);
1324
1325 /* back up zoom */
1326 zathura->shortcut.toggle_presentation_mode.zoom = zathura_document_get_zoom(zathura->document);
1327
1328 /* adjust window */
1329 girara_argument_t argument = { ZATHURA_ADJUST_BESTFIT, NULL };
1330 sc_adjust_window(session, &argument, NULL, 0);
1331
1332 /* hide status and inputbar */
1333 gtk_widget_hide(GTK_WIDGET(session->gtk.inputbar));
1334 gtk_widget_hide(GTK_WIDGET(session->gtk.statusbar));
1335
1336 /* set full screen */
1337 gtk_window_fullscreen(GTK_WINDOW(session->gtk.window));
1338 refresh_view(zathura);
1339
1340 /* set mode */
1341 girara_mode_set(session, zathura->modes.presentation);
1342 }
1343
1344 return false;
1345 }
1346
1347 bool
sc_quit(girara_session_t * session,girara_argument_t * UNUSED (argument),girara_event_t * UNUSED (event),unsigned int UNUSED (t))1348 sc_quit(girara_session_t* session, girara_argument_t* UNUSED(argument),
1349 girara_event_t* UNUSED(event), unsigned int UNUSED(t))
1350 {
1351 g_return_val_if_fail(session != NULL, false);
1352
1353 girara_argument_t arg = { GIRARA_HIDE, NULL };
1354 girara_isc_completion(session, &arg, NULL, 0);
1355
1356 cb_destroy(NULL, NULL);
1357
1358 return false;
1359 }
1360
1361 bool
sc_zoom(girara_session_t * session,girara_argument_t * argument,girara_event_t * event,unsigned int t)1362 sc_zoom(girara_session_t* session, girara_argument_t* argument, girara_event_t*
1363 event, unsigned int t)
1364 {
1365 g_return_val_if_fail(session != NULL, false);
1366 g_return_val_if_fail(session->global.data != NULL, false);
1367 zathura_t* zathura = session->global.data;
1368 g_return_val_if_fail(argument != NULL, false);
1369 g_return_val_if_fail(zathura->document != NULL, false);
1370
1371 zathura_document_set_adjust_mode(zathura->document, ZATHURA_ADJUST_NONE);
1372
1373 /* retrieve zoom step value */
1374 int value = 1;
1375 girara_setting_get(zathura->ui.session, "zoom-step", &value);
1376
1377 const int nt = (t == 0) ? 1 : t;
1378 const double zoom_step = 1.0 + value / 100.0 * nt;
1379 const double old_zoom = zathura_document_get_zoom(zathura->document);
1380
1381 /* specify new zoom value */
1382 if (argument->n == ZOOM_IN) {
1383 girara_debug("Increasing zoom by %0.2f.", zoom_step - 1.0);
1384 zathura_document_set_zoom(zathura->document, old_zoom * zoom_step);
1385 } else if (argument->n == ZOOM_OUT) {
1386 girara_debug("Decreasing zoom by %0.2f.", zoom_step - 1.0);
1387 zathura_document_set_zoom(zathura->document, old_zoom / zoom_step);
1388 } else if (argument->n == ZOOM_SPECIFIC) {
1389 if (t == 0) {
1390 girara_debug("Setting zoom to 1.");
1391 zathura_document_set_zoom(zathura->document, 1.0);
1392 } else {
1393 girara_debug("Setting zoom to %0.2f.", t / 100.0);
1394 zathura_document_set_zoom(zathura->document, t / 100.0);
1395 }
1396 } else if (argument->n == ZOOM_SMOOTH) {
1397 const double dy = (event != NULL) ? event->y : 1.0;
1398 const double z = pow(zoom_step, -dy);
1399 girara_debug("Increasing zoom by %0.2f.", z - 1.0);
1400 zathura_document_set_zoom(zathura->document, old_zoom * z);
1401 } else {
1402 girara_debug("Setting zoom to 1.");
1403 zathura_document_set_zoom(zathura->document, 1.0);
1404 }
1405
1406 /* zoom limitations */
1407 const double zoom = zathura_document_get_zoom(zathura->document);
1408 zathura_document_set_zoom(zathura->document, zathura_correct_zoom_value(session, zoom));
1409
1410 const double new_zoom = zathura_document_get_zoom(zathura->document);
1411 if (fabs(new_zoom - old_zoom) <= DBL_EPSILON) {
1412 girara_debug("New and old zoom level are too close: %0.2f vs. %0.2f", new_zoom, old_zoom);
1413 return false;
1414 }
1415
1416 girara_debug("Re-rendering with new zoom level %0.2f.", new_zoom);
1417 render_all(zathura);
1418 refresh_view(zathura);
1419
1420 return false;
1421 }
1422
1423 bool
sc_exec(girara_session_t * session,girara_argument_t * argument,girara_event_t * event,unsigned int t)1424 sc_exec(girara_session_t* session, girara_argument_t* argument, girara_event_t* event, unsigned int t)
1425 {
1426 g_return_val_if_fail(session != NULL, false);
1427 g_return_val_if_fail(session->global.data != NULL, false);
1428 zathura_t* zathura = session->global.data;
1429
1430 if (argument == NULL || argument->data == NULL) {
1431 return false;
1432 }
1433
1434 if (zathura->document != NULL) {
1435 const char* path = zathura_document_get_path(zathura->document);
1436
1437 girara_argument_t new_argument = *argument;
1438
1439 char* r = girara_replace_substring(argument->data, "$FILE", path);
1440 if (r == NULL) {
1441 return false;
1442 }
1443
1444 char* s = girara_replace_substring(r, "%", path);
1445 g_free(r);
1446
1447 if (s == NULL) {
1448 return false;
1449 }
1450
1451 new_argument.data = s;
1452 const bool ret = girara_sc_exec(session, &new_argument, event, t);
1453 g_free(s);
1454 return ret;
1455 }
1456
1457 return girara_sc_exec(session, argument, event, t);
1458 }
1459
1460 bool
sc_nohlsearch(girara_session_t * session,girara_argument_t * UNUSED (argument),girara_event_t * UNUSED (event),unsigned int UNUSED (t))1461 sc_nohlsearch(girara_session_t* session, girara_argument_t* UNUSED(argument), girara_event_t* UNUSED(event), unsigned int UNUSED(t))
1462 {
1463 g_return_val_if_fail(session != NULL, false);
1464 g_return_val_if_fail(session->global.data != NULL, false);
1465 zathura_t* zathura = session->global.data;
1466
1467 document_draw_search_results(zathura, false);
1468 render_all(zathura);
1469
1470 return false;
1471 }
1472