1 /* SPDX-License-Identifier: Zlib */
2 
3 #include <stdlib.h>
4 #include <string.h>
5 #include <girara/session.h>
6 #include <girara/callbacks.h>
7 #include <girara/datastructures.h>
8 
9 #include "callbacks.h"
10 #include "marks.h"
11 #include "document.h"
12 #include "render.h"
13 #include "utils.h"
14 
15 static void mark_add(zathura_t* zathura, int key);
16 static void mark_evaluate(zathura_t* zathura, int key);
17 static bool cb_marks_view_key_press_event_add(GtkWidget* widget, GdkEventKey*
18     event, girara_session_t* session);
19 static bool cb_marks_view_key_press_event_evaluate(GtkWidget* widget,
20     GdkEventKey* event, girara_session_t* session);
21 
22 struct zathura_mark_s {
23   int key; /**> Marks key */
24   double position_x; /**> Horizontal adjustment */
25   double position_y; /**> Vertical adjustment */
26   unsigned int page; /**> Page number */
27   double zoom; /**> Zoom level */
28 };
29 
30 bool
sc_mark_add(girara_session_t * session,girara_argument_t * UNUSED (argument),girara_event_t * UNUSED (event),unsigned int UNUSED (t))31 sc_mark_add(girara_session_t* session, girara_argument_t* UNUSED(argument),
32             girara_event_t* UNUSED(event), unsigned int UNUSED(t))
33 {
34   g_return_val_if_fail(session != NULL,           FALSE);
35   g_return_val_if_fail(session->gtk.view != NULL, FALSE);
36 
37   /* redirect signal handler */
38   g_signal_handler_disconnect(G_OBJECT(session->gtk.view), session->signals.view_key_pressed);
39   session->signals.view_key_pressed = g_signal_connect(G_OBJECT(session->gtk.view), "key-press-event",
40                                       G_CALLBACK(cb_marks_view_key_press_event_add), session);
41 
42   return true;
43 }
44 
45 bool
sc_mark_evaluate(girara_session_t * session,girara_argument_t * UNUSED (argument),girara_event_t * UNUSED (event),unsigned int UNUSED (t))46 sc_mark_evaluate(girara_session_t* session, girara_argument_t* UNUSED(argument),
47                  girara_event_t* UNUSED(event), unsigned int UNUSED(t))
48 {
49   g_return_val_if_fail(session != NULL,           FALSE);
50   g_return_val_if_fail(session->gtk.view != NULL, FALSE);
51 
52   /* redirect signal handler */
53   g_signal_handler_disconnect(G_OBJECT(session->gtk.view), session->signals.view_key_pressed);
54   session->signals.view_key_pressed = g_signal_connect(G_OBJECT(session->gtk.view), "key-press-event",
55                                       G_CALLBACK(cb_marks_view_key_press_event_evaluate), session);
56 
57   return true;
58 }
59 
60 bool
cb_marks_view_key_press_event_add(GtkWidget * UNUSED (widget),GdkEventKey * event,girara_session_t * session)61 cb_marks_view_key_press_event_add(GtkWidget* UNUSED(widget), GdkEventKey* event,
62                                   girara_session_t* session)
63 {
64   g_return_val_if_fail(session != NULL,              FALSE);
65   g_return_val_if_fail(session->gtk.view != NULL,    FALSE);
66   g_return_val_if_fail(session->global.data != NULL, FALSE);
67   zathura_t* zathura = (zathura_t*) session->global.data;
68 
69   /* reset signal handler */
70   g_signal_handler_disconnect(G_OBJECT(session->gtk.view), session->signals.view_key_pressed);
71   session->signals.view_key_pressed = g_signal_connect(G_OBJECT(session->gtk.view), "key-press-event",
72                                       G_CALLBACK(girara_callback_view_key_press_event), session);
73 
74   /* evaluate key */
75   if (((event->keyval >= '0' && event->keyval <= '9') ||
76        (event->keyval >= 'a' && event->keyval <= 'z') ||
77        (event->keyval >= 'A' && event->keyval <= 'Z')
78        ) == false) {
79     return false;
80   }
81 
82   mark_add(zathura, event->keyval);
83 
84   return true;
85 }
86 
cb_marks_view_key_press_event_evaluate(GtkWidget * UNUSED (widget),GdkEventKey * event,girara_session_t * session)87 bool cb_marks_view_key_press_event_evaluate(GtkWidget* UNUSED(widget), GdkEventKey*
88     event, girara_session_t* session)
89 {
90   g_return_val_if_fail(session != NULL,              FALSE);
91   g_return_val_if_fail(session->gtk.view != NULL,    FALSE);
92   g_return_val_if_fail(session->global.data != NULL, FALSE);
93   zathura_t* zathura = (zathura_t*) session->global.data;
94 
95   /* reset signal handler */
96   g_signal_handler_disconnect(G_OBJECT(session->gtk.view), session->signals.view_key_pressed);
97   session->signals.view_key_pressed = g_signal_connect(G_OBJECT(session->gtk.view), "key-press-event",
98                                       G_CALLBACK(girara_callback_view_key_press_event), session);
99 
100   /* evaluate key */
101   if (((event->keyval >= '0' && event->keyval <= '9') ||
102        (event->keyval >= 'a' && event->keyval <= 'z') ||
103        (event->keyval >= 'A' && event->keyval <= 'Z')
104        ) == false) {
105     return true;
106   }
107 
108   mark_evaluate(zathura, event->keyval);
109 
110   return true;
111 }
112 
113 bool
cmd_marks_add(girara_session_t * session,girara_list_t * argument_list)114 cmd_marks_add(girara_session_t* session, girara_list_t* argument_list)
115 {
116   g_return_val_if_fail(session != NULL, false);
117   g_return_val_if_fail(session->global.data != NULL, false);
118   zathura_t* zathura = (zathura_t*) session->global.data;
119 
120   if (girara_list_size(argument_list) < 1) {
121     return false;
122   }
123 
124   char* key_string = girara_list_nth(argument_list, 0);
125 
126   if (key_string == NULL) {
127     return false;
128   }
129 
130   if (strlen(key_string) != 1) {
131     return false;
132   }
133 
134   char key = key_string[0];
135 
136   if (((key >= 0x41 && key <= 0x5A) || (key >=
137                                         0x61 && key <= 0x7A)) == false) {
138     return false;
139   }
140 
141   mark_add(zathura, key);
142 
143   return false;
144 }
145 
146 bool
cmd_marks_delete(girara_session_t * session,girara_list_t * argument_list)147 cmd_marks_delete(girara_session_t* session, girara_list_t* argument_list)
148 {
149   g_return_val_if_fail(session != NULL, false);
150   g_return_val_if_fail(session->global.data != NULL, false);
151   zathura_t* zathura = (zathura_t*) session->global.data;
152 
153   if (girara_list_size(argument_list) < 1) {
154     return false;
155   }
156 
157   if (girara_list_size(zathura->global.marks) == 0) {
158     return false;
159   }
160 
161   GIRARA_LIST_FOREACH_BODY_WITH_ITER(argument_list, char*, iter, key_string,
162     if (key_string == NULL) {
163       girara_list_iterator_next(iter);
164       continue;
165     }
166 
167     for (unsigned int i = 0; i < strlen(key_string); i++) {
168       char key = key_string[i];
169       if (((key >= 0x41 && key <= 0x5A) || (key >=
170                                             0x61 && key <= 0x7A)) == false) {
171         continue;
172       }
173 
174       /* search for existing mark */
175       girara_list_iterator_t* mark_iter = girara_list_iterator(zathura->global.marks);
176       do {
177         zathura_mark_t* mark = (zathura_mark_t*) girara_list_iterator_data(mark_iter);
178         if (mark == NULL) {
179           continue;
180         }
181 
182         if (mark->key == key) {
183           girara_list_remove(zathura->global.marks, mark);
184           continue;
185         }
186       } while (girara_list_iterator_next(mark_iter) != NULL);
187       girara_list_iterator_free(mark_iter);
188     }
189   );
190 
191   return true;
192 }
193 
194 void
mark_add(zathura_t * zathura,int key)195 mark_add(zathura_t* zathura, int key)
196 {
197   if (zathura == NULL || zathura->document == NULL || zathura->global.marks == NULL) {
198     return;
199   }
200 
201   unsigned int page_id = zathura_document_get_current_page_number(zathura->document);
202   double position_x    = zathura_document_get_position_x(zathura->document);
203   double position_y    = zathura_document_get_position_y(zathura->document);
204 
205   double zoom          = zathura_document_get_zoom(zathura->document);
206 
207   /* search for existing mark */
208   GIRARA_LIST_FOREACH_BODY_WITH_ITER(zathura->global.marks, zathura_mark_t*, iter, mark,
209     if (mark->key == key) {
210       mark->page       = page_id;
211       mark->position_x = position_x;
212       mark->position_y = position_y;
213       mark->zoom       = zoom;
214       girara_list_iterator_free(iter);
215       return;
216     }
217   );
218 
219   /* add new mark */
220   zathura_mark_t* mark = g_try_malloc0(sizeof(zathura_mark_t));
221   if (mark == NULL) {
222     return;
223   }
224 
225   mark->key        = key;
226   mark->page       = page_id;
227   mark->position_x = position_x;
228   mark->position_y = position_y;
229   mark->zoom       = zoom;
230 
231   girara_list_append(zathura->global.marks, mark);
232 }
233 
234 void
mark_evaluate(zathura_t * zathura,int key)235 mark_evaluate(zathura_t* zathura, int key)
236 {
237   if (zathura == NULL || zathura->global.marks == NULL) {
238     return;
239   }
240 
241   /* search for existing mark */
242   GIRARA_LIST_FOREACH_BODY(zathura->global.marks, zathura_mark_t*, mark,
243     if (mark != NULL && mark->key == key) {
244       zathura_document_set_zoom(zathura->document,
245           zathura_correct_zoom_value(zathura->ui.session, mark->zoom));
246       render_all(zathura);
247 
248       zathura_jumplist_add(zathura);
249       page_set(zathura, mark->page);
250       position_set(zathura, mark->position_x, mark->position_y);
251       zathura_jumplist_add(zathura);
252 
253       break;
254     }
255   );
256 }
257 
258 void
mark_free(void * data)259 mark_free(void* data)
260 {
261   if (data == NULL) {
262     return;
263   }
264 
265   zathura_mark_t* mark = (zathura_mark_t*) data;
266 
267   g_free(mark);
268 }
269