1 /* SPDX-License-Identifier: Zlib */
2
3 #include <girara/statusbar.h>
4 #include <girara/session.h>
5 #include <girara/settings.h>
6 #include <girara/utils.h>
7 #include <stdlib.h>
8 #include <gtk/gtk.h>
9 #include <string.h>
10 #include <glib/gi18n.h>
11 #include <math.h>
12
13 #include "callbacks.h"
14 #include "links.h"
15 #include "zathura.h"
16 #include "render.h"
17 #include "document.h"
18 #include "utils.h"
19 #include "shortcuts.h"
20 #include "page-widget.h"
21 #include "page.h"
22 #include "adjustment.h"
23 #include "synctex.h"
24 #include "dbus-interface.h"
25
26 gboolean
cb_destroy(GtkWidget * UNUSED (widget),zathura_t * zathura)27 cb_destroy(GtkWidget* UNUSED(widget), zathura_t* zathura)
28 {
29 if (zathura != NULL && zathura->document != NULL) {
30 document_close(zathura, false);
31 }
32
33 gtk_main_quit();
34 return TRUE;
35 }
36
37 void
cb_buffer_changed(girara_session_t * session)38 cb_buffer_changed(girara_session_t* session)
39 {
40 g_return_if_fail(session != NULL);
41 g_return_if_fail(session->global.data != NULL);
42
43 zathura_t* zathura = session->global.data;
44
45 char* buffer = girara_buffer_get(session);
46 if (buffer != NULL) {
47 girara_statusbar_item_set_text(session, zathura->ui.statusbar.buffer, buffer);
48 free(buffer);
49 } else {
50 girara_statusbar_item_set_text(session, zathura->ui.statusbar.buffer, "");
51 }
52 }
53
54 void
update_visible_pages(zathura_t * zathura)55 update_visible_pages(zathura_t* zathura)
56 {
57 const unsigned int number_of_pages = zathura_document_get_number_of_pages(zathura->document);
58
59 for (unsigned int page_id = 0; page_id < number_of_pages; page_id++) {
60 zathura_page_t* page = zathura_document_get_page(zathura->document, page_id);
61 GtkWidget* page_widget = zathura_page_get_widget(zathura, page);
62 ZathuraPage* zathura_page_widget = ZATHURA_PAGE(page_widget);
63
64 if (page_is_visible(zathura->document, page_id) == true) {
65 /* make page visible */
66 if (zathura_page_get_visibility(page) == false) {
67 zathura_page_set_visibility(page, true);
68 zathura_page_widget_update_view_time(zathura_page_widget);
69 zathura_renderer_page_cache_add(zathura->sync.render_thread, zathura_page_get_index(page));
70 }
71
72 } else {
73 /* make page invisible */
74 if (zathura_page_get_visibility(page) == true) {
75 zathura_page_set_visibility(page, false);
76 /* If a page becomes invisible, abort the render request. */
77 zathura_page_widget_abort_render_request(zathura_page_widget);
78 }
79
80 /* reset current search result */
81 girara_list_t* results = NULL;
82 GObject* obj_page_widget = G_OBJECT(page_widget);
83 g_object_get(obj_page_widget, "search-results", &results, NULL);
84 if (results != NULL) {
85 g_object_set(obj_page_widget, "search-current", 0, NULL);
86 }
87 }
88 }
89 }
90
91 void
cb_view_hadjustment_value_changed(GtkAdjustment * adjustment,gpointer data)92 cb_view_hadjustment_value_changed(GtkAdjustment* adjustment, gpointer data)
93 {
94 zathura_t* zathura = data;
95 if (zathura == NULL || zathura->document == NULL) {
96 return;
97 }
98
99 /* Do nothing in index mode */
100 if (girara_mode_get(zathura->ui.session) == zathura->modes.index) {
101 return;
102 }
103
104 update_visible_pages(zathura);
105
106 double position_x = zathura_adjustment_get_ratio(adjustment);
107 double position_y = zathura_document_get_position_y(zathura->document);
108 unsigned int page_id = position_to_page_number(zathura->document, position_x, position_y);
109
110 zathura_document_set_position_x(zathura->document, position_x);
111 zathura_document_set_position_y(zathura->document, position_y);
112 zathura_document_set_current_page_number(zathura->document, page_id);
113
114 statusbar_page_number_update(zathura);
115 }
116
117 void
cb_view_vadjustment_value_changed(GtkAdjustment * adjustment,gpointer data)118 cb_view_vadjustment_value_changed(GtkAdjustment* adjustment, gpointer data)
119 {
120 zathura_t* zathura = data;
121 if (zathura == NULL || zathura->document == NULL) {
122 return;
123 }
124
125 /* Do nothing in index mode */
126 if (girara_mode_get(zathura->ui.session) == zathura->modes.index) {
127 return;
128 }
129
130 update_visible_pages(zathura);
131
132 double position_x = zathura_document_get_position_x(zathura->document);
133 double position_y = zathura_adjustment_get_ratio(adjustment);
134 unsigned int page_id = position_to_page_number(zathura->document, position_x, position_y);
135
136 zathura_document_set_position_x(zathura->document, position_x);
137 zathura_document_set_position_y(zathura->document, position_y);
138 zathura_document_set_current_page_number(zathura->document, page_id);
139
140 statusbar_page_number_update(zathura);
141 }
142
143 static void
cb_view_adjustment_changed(GtkAdjustment * adjustment,zathura_t * zathura,bool width)144 cb_view_adjustment_changed(GtkAdjustment* adjustment, zathura_t* zathura,
145 bool width)
146 {
147 /* Do nothing in index mode */
148 if (girara_mode_get(zathura->ui.session) == zathura->modes.index) {
149 return;
150 }
151
152 const zathura_adjust_mode_t adjust_mode =
153 zathura_document_get_adjust_mode(zathura->document);
154
155 /* Don't scroll, we're focusing the inputbar. */
156 if (adjust_mode == ZATHURA_ADJUST_INPUTBAR) {
157 return;
158 }
159
160 /* Save the viewport size */
161 unsigned int size = (unsigned int)floor(gtk_adjustment_get_page_size(adjustment));
162 if (width == true) {
163 zathura_document_set_viewport_width(zathura->document, size);
164 } else {
165 zathura_document_set_viewport_height(zathura->document, size);
166 }
167
168 /* reset the adjustment, in case bounds have changed */
169 const double ratio = width == true ?
170 zathura_document_get_position_x(zathura->document) :
171 zathura_document_get_position_y(zathura->document);
172 zathura_adjustment_set_value_from_ratio(adjustment, ratio);
173 }
174
175 void
cb_view_hadjustment_changed(GtkAdjustment * adjustment,gpointer data)176 cb_view_hadjustment_changed(GtkAdjustment* adjustment, gpointer data)
177 {
178 zathura_t* zathura = data;
179 g_return_if_fail(zathura != NULL);
180
181 cb_view_adjustment_changed(adjustment, zathura, true);
182 }
183
184 void
cb_view_vadjustment_changed(GtkAdjustment * adjustment,gpointer data)185 cb_view_vadjustment_changed(GtkAdjustment* adjustment, gpointer data)
186 {
187 zathura_t* zathura = data;
188 g_return_if_fail(zathura != NULL);
189
190 cb_view_adjustment_changed(adjustment, zathura, false);
191 }
192
193 void
cb_refresh_view(GtkWidget * GIRARA_UNUSED (view),gpointer data)194 cb_refresh_view(GtkWidget* GIRARA_UNUSED(view), gpointer data)
195 {
196 zathura_t* zathura = data;
197 if (zathura == NULL || zathura->document == NULL) {
198 return;
199 }
200
201 unsigned int page_id = zathura_document_get_current_page_number(zathura->document);
202 zathura_page_t* page = zathura_document_get_page(zathura->document, page_id);
203 if (page == NULL) {
204 return;
205 }
206
207 GtkAdjustment* vadj = gtk_scrolled_window_get_vadjustment(GTK_SCROLLED_WINDOW(zathura->ui.session->gtk.view));
208 GtkAdjustment* hadj = gtk_scrolled_window_get_hadjustment(GTK_SCROLLED_WINDOW(zathura->ui.session->gtk.view));
209
210 double position_x = zathura_document_get_position_x(zathura->document);
211 double position_y = zathura_document_get_position_y(zathura->document);
212
213 zathura_adjustment_set_value_from_ratio(vadj, position_y);
214 zathura_adjustment_set_value_from_ratio(hadj, position_x);
215
216 statusbar_page_number_update(zathura);
217 }
218
219 void
cb_monitors_changed(GdkScreen * screen,gpointer data)220 cb_monitors_changed(GdkScreen* screen, gpointer data)
221 {
222 girara_debug("signal received");
223
224 zathura_t* zathura = data;
225 if (screen == NULL || zathura == NULL) {
226 return;
227 }
228
229 zathura_update_view_ppi(zathura);
230 }
231
232 void
cb_widget_screen_changed(GtkWidget * widget,GdkScreen * previous_screen,gpointer data)233 cb_widget_screen_changed(GtkWidget* widget, GdkScreen* previous_screen, gpointer data)
234 {
235 girara_debug("called");
236
237 zathura_t* zathura = data;
238 if (widget == NULL || zathura == NULL) {
239 return;
240 }
241
242 /* disconnect previous screen handler if present */
243 if (previous_screen != NULL && zathura->signals.monitors_changed_handler > 0) {
244 g_signal_handler_disconnect(previous_screen, zathura->signals.monitors_changed_handler);
245 zathura->signals.monitors_changed_handler = 0;
246 }
247
248 if (gtk_widget_has_screen(widget)) {
249 GdkScreen* screen = gtk_widget_get_screen(widget);
250
251 /* connect to new screen */
252 zathura->signals.monitors_changed_handler = g_signal_connect(G_OBJECT(screen),
253 "monitors-changed", G_CALLBACK(cb_monitors_changed), zathura);
254 }
255
256 zathura_update_view_ppi(zathura);
257 }
258
259 gboolean
cb_widget_configured(GtkWidget * UNUSED (widget),GdkEvent * UNUSED (event),gpointer data)260 cb_widget_configured(GtkWidget* UNUSED(widget), GdkEvent* UNUSED(event), gpointer data)
261 {
262 zathura_t* zathura = data;
263 if (zathura == NULL) {
264 return false;
265 }
266
267 zathura_update_view_ppi(zathura);
268
269 return false;
270 }
271
272 void
cb_scale_factor(GObject * object,GParamSpec * UNUSED (pspec),gpointer data)273 cb_scale_factor(GObject* object, GParamSpec* UNUSED(pspec), gpointer data)
274 {
275 zathura_t* zathura = data;
276 if (zathura == NULL || zathura->document == NULL) {
277 return;
278 }
279
280 int new_factor = gtk_widget_get_scale_factor(GTK_WIDGET(object));
281 if (new_factor == 0) {
282 girara_debug("Ignoring new device scale factor = 0");
283 return;
284 }
285
286 zathura_device_factors_t current = zathura_document_get_device_factors(zathura->document);
287 if (fabs(new_factor - current.x) >= DBL_EPSILON ||
288 fabs(new_factor - current.y) >= DBL_EPSILON) {
289 zathura_document_set_device_factors(zathura->document, new_factor, new_factor);
290 girara_debug("New device scale factor: %d", new_factor);
291 zathura_update_view_ppi(zathura);
292 render_all(zathura);
293 }
294 }
295
296 void
cb_page_layout_value_changed(girara_session_t * session,const char * name,girara_setting_type_t UNUSED (type),const void * value,void * UNUSED (data))297 cb_page_layout_value_changed(girara_session_t* session, const char* name, girara_setting_type_t UNUSED(type), const void* value, void* UNUSED(data))
298 {
299 g_return_if_fail(value != NULL);
300 g_return_if_fail(session != NULL);
301 g_return_if_fail(session->global.data != NULL);
302 zathura_t* zathura = session->global.data;
303
304 /* pages-per-row must not be 0 */
305 if (g_strcmp0(name, "pages-per-row") == 0) {
306 unsigned int pages_per_row = *((const unsigned int*) value);
307 if (pages_per_row == 0) {
308 pages_per_row = 1;
309 girara_setting_set(session, name, &pages_per_row);
310 girara_notify(session, GIRARA_WARNING, _("'%s' must not be 0. Set to 1."), name);
311 return;
312 }
313 }
314
315 if (zathura->document == NULL) {
316 /* no document has been openend yet */
317 return;
318 }
319
320 unsigned int pages_per_row = 1;
321 girara_setting_get(session, "pages-per-row", &pages_per_row);
322
323 /* get list of first_page_column settings */
324 char* first_page_column_list = NULL;
325 girara_setting_get(session, "first-page-column", &first_page_column_list);
326
327 /* find value for first_page_column */
328 unsigned int first_page_column = find_first_page_column(first_page_column_list, pages_per_row);
329 g_free(first_page_column_list);
330
331 unsigned int page_padding = 1;
332 girara_setting_get(zathura->ui.session, "page-padding", &page_padding);
333
334 bool page_right_to_left = false;
335 girara_setting_get(zathura->ui.session, "page-right-to-left", &page_right_to_left);
336
337 page_widget_set_mode(zathura, page_padding, pages_per_row, first_page_column, page_right_to_left);
338 zathura_document_set_page_layout(zathura->document, page_padding, pages_per_row, first_page_column);
339 }
340
341 void
cb_index_row_activated(GtkTreeView * tree_view,GtkTreePath * path,GtkTreeViewColumn * UNUSED (column),void * data)342 cb_index_row_activated(GtkTreeView* tree_view, GtkTreePath* path,
343 GtkTreeViewColumn* UNUSED(column), void* data)
344 {
345 zathura_t* zathura = data;
346 if (tree_view == NULL || zathura == NULL || zathura->ui.session == NULL) {
347 return;
348 }
349
350 GtkTreeModel *model;
351 GtkTreeIter iter;
352
353 g_object_get(G_OBJECT(tree_view), "model", &model, NULL);
354
355 if(gtk_tree_model_get_iter(model, &iter, path)) {
356 zathura_index_element_t* index_element;
357 gtk_tree_model_get(model, &iter, 2, &index_element, -1);
358
359 if (index_element == NULL) {
360 return;
361 }
362
363 sc_toggle_index(zathura->ui.session, NULL, NULL, 0);
364 zathura_link_evaluate(zathura, index_element->link);
365 }
366
367 g_object_unref(model);
368 }
369
370 typedef enum zathura_link_action_e
371 {
372 ZATHURA_LINK_ACTION_FOLLOW,
373 ZATHURA_LINK_ACTION_DISPLAY
374 } zathura_link_action_t;
375
376 static bool
handle_link(GtkEntry * entry,girara_session_t * session,zathura_link_action_t action)377 handle_link(GtkEntry* entry, girara_session_t* session,
378 zathura_link_action_t action)
379 {
380 g_return_val_if_fail(session != NULL, FALSE);
381 g_return_val_if_fail(session->global.data != NULL, FALSE);
382
383 zathura_t* zathura = session->global.data;
384 bool eval = true;
385
386 char* input = gtk_editable_get_chars(GTK_EDITABLE(entry), 0, -1);
387 if (input == NULL || strlen(input) == 0) {
388 eval = false;
389 }
390
391 int index = 0;
392 if (eval == true) {
393 index = atoi(input);
394 if (index == 0 && g_strcmp0(input, "0") != 0) {
395 girara_notify(session, GIRARA_WARNING, _("Invalid input '%s' given."), input);
396 eval = false;
397 }
398 index = index - 1;
399 }
400
401 /* set pages to draw links */
402 bool invalid_index = true;
403 unsigned int number_of_pages = zathura_document_get_number_of_pages(zathura->document);
404 for (unsigned int page_id = 0; page_id < number_of_pages; page_id++) {
405 zathura_page_t* page = zathura_document_get_page(zathura->document, page_id);
406 if (page == NULL || zathura_page_get_visibility(page) == false) {
407 continue;
408 }
409
410 GtkWidget* page_widget = zathura_page_get_widget(zathura, page);
411 g_object_set(G_OBJECT(page_widget), "draw-links", FALSE, NULL);
412
413 if (eval == true) {
414 zathura_link_t* link = zathura_page_widget_link_get(ZATHURA_PAGE(page_widget), index);
415
416 if (link != NULL) {
417 invalid_index = false;
418 switch (action) {
419 case ZATHURA_LINK_ACTION_FOLLOW:
420 zathura_link_evaluate(zathura, link);
421 break;
422 case ZATHURA_LINK_ACTION_DISPLAY:
423 zathura_link_display(zathura, link);
424 break;
425 }
426 }
427 }
428 }
429
430 if (eval == true && invalid_index == true) {
431 girara_notify(session, GIRARA_WARNING, _("Invalid index '%s' given."), input);
432 }
433
434 g_free(input);
435
436 return (eval == TRUE) ? TRUE : FALSE;
437 }
438
439 gboolean
cb_sc_follow(GtkEntry * entry,void * data)440 cb_sc_follow(GtkEntry* entry, void* data)
441 {
442 girara_session_t* session = data;
443 return handle_link(entry, session, ZATHURA_LINK_ACTION_FOLLOW);
444 }
445
446 gboolean
cb_sc_display_link(GtkEntry * entry,void * data)447 cb_sc_display_link(GtkEntry* entry, void* data)
448 {
449 girara_session_t* session = data;
450 return handle_link(entry, session, ZATHURA_LINK_ACTION_DISPLAY);
451 }
452
453 static gboolean
file_monitor_reload(void * data)454 file_monitor_reload(void* data)
455 {
456 sc_reload((girara_session_t*) data, NULL, NULL, 0);
457 return FALSE;
458 }
459
460 void
cb_file_monitor(ZathuraFileMonitor * monitor,girara_session_t * session)461 cb_file_monitor(ZathuraFileMonitor* monitor, girara_session_t* session)
462 {
463 g_return_if_fail(monitor != NULL);
464 g_return_if_fail(session != NULL);
465
466 g_main_context_invoke(NULL, file_monitor_reload, session);
467 }
468
469 static gboolean
password_dialog(gpointer data)470 password_dialog(gpointer data)
471 {
472 zathura_password_dialog_info_t* dialog = data;
473
474 if (dialog != NULL) {
475 girara_dialog(
476 dialog->zathura->ui.session,
477 "Incorrect password. Enter password:",
478 true,
479 NULL,
480 cb_password_dialog,
481 dialog
482 );
483 }
484
485 return FALSE;
486 }
487
488 gboolean
cb_password_dialog(GtkEntry * entry,void * data)489 cb_password_dialog(GtkEntry* entry, void* data)
490 {
491 if (entry == NULL || data == NULL) {
492 goto error_ret;
493 }
494
495 zathura_password_dialog_info_t* dialog = data;
496
497 if (dialog->path == NULL) {
498 free(dialog);
499 goto error_ret;
500 }
501
502 if (dialog->zathura == NULL) {
503 goto error_free;
504 }
505
506 char* input = gtk_editable_get_chars(GTK_EDITABLE(entry), 0, -1);
507
508 /* no or empty password: ask again */
509 if (input == NULL || strlen(input) == 0) {
510 if (input != NULL) {
511 g_free(input);
512 }
513
514 gdk_threads_add_idle(password_dialog, dialog);
515 return false;
516 }
517
518 /* try to open document again */
519 if (document_open(dialog->zathura, dialog->path, dialog->uri, input,
520 ZATHURA_PAGE_NUMBER_UNSPECIFIED) == false) {
521 gdk_threads_add_idle(password_dialog, dialog);
522 } else {
523 g_free(dialog->path);
524 g_free(dialog->uri);
525 free(dialog);
526 }
527
528 g_free(input);
529
530 return true;
531
532 error_free:
533
534 g_free(dialog->path);
535 free(dialog);
536
537 error_ret:
538
539 return false;
540 }
541
542 gboolean
cb_view_resized(GtkWidget * UNUSED (widget),GtkAllocation * UNUSED (allocation),zathura_t * zathura)543 cb_view_resized(GtkWidget* UNUSED(widget), GtkAllocation* UNUSED(allocation), zathura_t* zathura)
544 {
545 if (zathura == NULL || zathura->document == NULL) {
546 return false;
547 }
548
549 /* adjust the scale according to settings. If nothing needs to be resized,
550 it does not trigger the resize event.
551
552 The right viewport size is already in the document object, due to a
553 previous call to adjustment_changed. We don't want to use the allocation in
554 here, because we would have to subtract scrollbars, etc. */
555 adjust_view(zathura);
556
557 return false;
558 }
559
560 void
cb_setting_recolor_change(girara_session_t * session,const char * name,girara_setting_type_t UNUSED (type),const void * value,void * UNUSED (data))561 cb_setting_recolor_change(girara_session_t* session, const char* name,
562 girara_setting_type_t UNUSED(type), const void* value, void* UNUSED(data))
563 {
564 g_return_if_fail(value != NULL);
565 g_return_if_fail(session != NULL);
566 g_return_if_fail(session->global.data != NULL);
567 g_return_if_fail(name != NULL);
568 zathura_t* zathura = session->global.data;
569
570 const bool bool_value = *((const bool*) value);
571
572 if (zathura->sync.render_thread != NULL && zathura_renderer_recolor_enabled(zathura->sync.render_thread) != bool_value) {
573 zathura_renderer_enable_recolor(zathura->sync.render_thread, bool_value);
574 render_all(zathura);
575 }
576 }
577
578 void
cb_setting_recolor_keep_hue_change(girara_session_t * session,const char * name,girara_setting_type_t UNUSED (type),const void * value,void * UNUSED (data))579 cb_setting_recolor_keep_hue_change(girara_session_t* session, const char* name,
580 girara_setting_type_t UNUSED(type), const void* value, void* UNUSED(data))
581 {
582 g_return_if_fail(value != NULL);
583 g_return_if_fail(session != NULL);
584 g_return_if_fail(session->global.data != NULL);
585 g_return_if_fail(name != NULL);
586 zathura_t* zathura = session->global.data;
587
588 const bool bool_value = *((const bool*) value);
589
590 if (zathura->sync.render_thread != NULL && zathura_renderer_recolor_hue_enabled(zathura->sync.render_thread) != bool_value) {
591 zathura_renderer_enable_recolor_hue(zathura->sync.render_thread, bool_value);
592 render_all(zathura);
593 }
594 }
595
596 void
cb_setting_recolor_keep_reverse_video_change(girara_session_t * session,const char * name,girara_setting_type_t UNUSED (type),const void * value,void * UNUSED (data))597 cb_setting_recolor_keep_reverse_video_change(girara_session_t* session, const char* name,
598 girara_setting_type_t UNUSED(type), const void* value, void* UNUSED(data))
599 {
600 g_return_if_fail(value != NULL);
601 g_return_if_fail(session != NULL);
602 g_return_if_fail(session->global.data != NULL);
603 g_return_if_fail(name != NULL);
604 zathura_t* zathura = session->global.data;
605
606 const bool bool_value = *((const bool*) value);
607
608 if (zathura->sync.render_thread != NULL && zathura_renderer_recolor_reverse_video_enabled(zathura->sync.render_thread) != bool_value) {
609 zathura_renderer_enable_recolor_reverse_video(zathura->sync.render_thread, bool_value);
610 render_all(zathura);
611 }
612 }
613
614 bool
cb_unknown_command(girara_session_t * session,const char * input)615 cb_unknown_command(girara_session_t* session, const char* input)
616 {
617 g_return_val_if_fail(session != NULL, false);
618 g_return_val_if_fail(session->global.data != NULL, false);
619 g_return_val_if_fail(input != NULL, false);
620
621 zathura_t* zathura = session->global.data;
622
623 if (zathura->document == NULL) {
624 return false;
625 }
626
627 /* check for number */
628 const size_t size = strlen(input);
629 for (size_t i = 0; i < size; i++) {
630 if (g_ascii_isdigit(input[i]) == FALSE) {
631 return false;
632 }
633 }
634
635 zathura_jumplist_add(zathura);
636 page_set(zathura, atoi(input) - 1);
637 zathura_jumplist_add(zathura);
638
639 return true;
640 }
641
642 void
cb_page_widget_text_selected(ZathuraPage * page,const char * text,void * data)643 cb_page_widget_text_selected(ZathuraPage* page, const char* text, void* data)
644 {
645 g_return_if_fail(page != NULL);
646 g_return_if_fail(text != NULL);
647 g_return_if_fail(data != NULL);
648
649 zathura_t* zathura = data;
650 girara_mode_t mode = girara_mode_get(zathura->ui.session);
651 if (mode != zathura->modes.normal && mode != zathura->modes.fullscreen) {
652 return;
653 }
654
655 GdkAtom* selection = get_selection(zathura);
656
657 /* copy to clipboard */
658 if (selection != NULL) {
659 gtk_clipboard_set_text(gtk_clipboard_get(*selection), text, -1);
660
661 bool notification = true;
662 girara_setting_get(zathura->ui.session, "selection-notification", ¬ification);
663
664 if (notification == true) {
665 char* target = NULL;
666 girara_setting_get(zathura->ui.session, "selection-clipboard", &target);
667
668 char* stripped_text = g_strdelimit(g_strdup(text), "\n\t\r\n", ' ');
669 char* escaped_text = g_markup_printf_escaped(
670 _("Copied selected text to selection %s: %s"), target, stripped_text);
671 g_free(target);
672 g_free(stripped_text);
673
674 girara_notify(zathura->ui.session, GIRARA_INFO, "%s", escaped_text);
675 g_free(escaped_text);
676 }
677 }
678
679 g_free(selection);
680 }
681
682 void
cb_page_widget_image_selected(ZathuraPage * page,GdkPixbuf * pixbuf,void * data)683 cb_page_widget_image_selected(ZathuraPage* page, GdkPixbuf* pixbuf, void* data)
684 {
685 g_return_if_fail(page != NULL);
686 g_return_if_fail(pixbuf != NULL);
687 g_return_if_fail(data != NULL);
688
689 zathura_t* zathura = data;
690 GdkAtom* selection = get_selection(zathura);
691
692 if (selection != NULL) {
693 gtk_clipboard_set_image(gtk_clipboard_get(*selection), pixbuf);
694
695 bool notification = true;
696 girara_setting_get(zathura->ui.session, "selection-notification", ¬ification);
697
698 if (notification == true) {
699 char* target = NULL;
700 girara_setting_get(zathura->ui.session, "selection-clipboard", &target);
701
702 char* escaped_text = g_markup_printf_escaped(
703 _("Copied selected image to selection %s"), target);
704 g_free(target);
705
706 girara_notify(zathura->ui.session, GIRARA_INFO, "%s", escaped_text);
707 }
708
709 g_free(selection);
710 }
711 }
712
713 void
cb_page_widget_link(ZathuraPage * page,void * data)714 cb_page_widget_link(ZathuraPage* page, void* data)
715 {
716 g_return_if_fail(page != NULL);
717
718 bool enter = (bool) data;
719
720 GdkWindow* window = gtk_widget_get_parent_window(GTK_WIDGET(page));
721 GdkDisplay* display = gtk_widget_get_display(GTK_WIDGET(page));
722 GdkCursor* cursor = gdk_cursor_new_for_display(display, enter == true ? GDK_HAND1 : GDK_LEFT_PTR);
723 gdk_window_set_cursor(window, cursor);
724 g_object_unref(cursor);
725 }
726
727 void
cb_page_widget_scaled_button_release(ZathuraPage * page_widget,GdkEventButton * event,void * data)728 cb_page_widget_scaled_button_release(ZathuraPage* page_widget, GdkEventButton* event,
729 void* data)
730 {
731 zathura_t* zathura = data;
732
733 zathura_page_t* page = zathura_page_widget_get_page(page_widget);
734
735 /* set page number (but don't scroll there. it was clicked on, so it's visible) */
736 if (event->button == GDK_BUTTON_PRIMARY) {
737 zathura_document_set_current_page_number(zathura->document, zathura_page_get_index(page));
738 refresh_view(zathura);
739 }
740
741 if (event->button != GDK_BUTTON_PRIMARY || !(event->state & GDK_CONTROL_MASK)) {
742 return;
743 }
744
745 bool synctex = false;
746 girara_setting_get(zathura->ui.session, "synctex", &synctex);
747 if (synctex == false) {
748 return;
749 }
750
751 if (zathura->dbus != NULL) {
752 zathura_dbus_edit(zathura->dbus, zathura_page_get_index(page), event->x, event->y);
753 }
754
755 char* editor = NULL;
756 girara_setting_get(zathura->ui.session, "synctex-editor-command", &editor);
757 if (editor == NULL || *editor == '\0') {
758 girara_debug("No SyncTeX editor specified.");
759 g_free(editor);
760 return;
761 }
762
763 synctex_edit(editor, page, event->x, event->y);
764 g_free(editor);
765 }
766
767 void
cb_window_update_icon(ZathuraRenderRequest * GIRARA_UNUSED (request),cairo_surface_t * surface,void * data)768 cb_window_update_icon(ZathuraRenderRequest* GIRARA_UNUSED(request), cairo_surface_t* surface, void* data)
769 {
770 zathura_t* zathura = data;
771
772 girara_debug("updating window icon");
773 GdkPixbuf* pixbuf = gdk_pixbuf_get_from_surface(surface, 0, 0, cairo_image_surface_get_width(surface), cairo_image_surface_get_height(surface));
774 if (pixbuf == NULL) {
775 girara_error("Unable to convert cairo surface to Gdk Pixbuf.");
776 }
777
778 gtk_window_set_icon(GTK_WINDOW(zathura->ui.session->gtk.window), pixbuf);
779 g_object_unref(pixbuf);
780 }
781