1 /*
2 * This program is free software; you can redistribute it and/or
3 * modify it under the terms of the GNU General Public
4 * License as published by the Free Software Foundation; either
5 * version 2 of the License, or (at your option) any later version.
6 *
7 * This software is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
10 * General Public License for more details.
11 *
12 * You should have received a copy of the GNU General Public License
13 * along with this program. If not, see <http://www.gnu.org/licenses/>.
14 */
15
16 #ifdef HAVE_CONFIG_H
17 # include <config.h>
18 #endif
19
20 #include <math.h>
21 #include <string.h>
22 #include <gtk/gtk.h>
23 #include <libgnomecanvas/libgnomecanvas.h>
24 #include <gdk/gdkkeysyms.h>
25 #include <time.h>
26
27 #include "xournal.h"
28 #include "xo-interface.h"
29 #include "xo-support.h"
30 #include "xo-callbacks.h"
31 #include "xo-misc.h"
32 #include "xo-file.h"
33 #include "xo-paint.h"
34 #include "xo-shapes.h"
35 #include "xo-image.h"
36 #include "xo-selection.h"
37
38 // some global constants
39
40 guint predef_colors_rgba[COLOR_MAX] =
41 { 0x000000ff, 0x3333ccff, 0xff0000ff, 0x008000ff,
42 0x808080ff, 0x00c0ffff, 0x00ff00ff, 0xff00ffff,
43 0xff8000ff, 0xffff00ff, 0xffffffff };
44
45 guint predef_bgcolors_rgba[COLOR_MAX] = // meaningless ones set to white
46 { 0xffffffff, 0xa0e8ffff, 0xffc0d4ff, 0x80ffc0ff,
47 0xffffffff, 0xa0e8ffff, 0x80ffc0ff, 0xffc0d4ff,
48 0xffc080ff, 0xffff80ff, 0xffffffff };
49
50 double predef_thickness[NUM_STROKE_TOOLS][THICKNESS_MAX] =
51 { { 0.42, 0.85, 1.41, 2.26, 5.67 }, // pen thicknesses = 0.15, 0.3, 0.5, 0.8, 2 mm
52 { 2.83, 2.83, 8.50, 19.84, 19.84 }, // eraser thicknesses = 1, 3, 7 mm
53 { 2.83, 2.83, 8.50, 19.84, 19.84 }, // highlighter thicknesses = 1, 3, 7 mm
54 };
55
56 // my own basename() replacement; allows windows filenames even on linux
57
xo_basename(gchar * s,gboolean xplatform)58 gchar *xo_basename(gchar *s, gboolean xplatform)
59 {
60 gchar *p;
61
62 p = strrchr(s, G_DIR_SEPARATOR);
63 if (p == NULL && G_DIR_SEPARATOR != '/') p = strrchr(s, '/');
64 if (xplatform && p == NULL && G_DIR_SEPARATOR != '\\') p = strrchr(s, '\\');
65 if (p != NULL) return p+1; // dir separator found
66 if (xplatform || G_DIR_SEPARATOR == '\\') { // windows drive letters
67 if (g_ascii_isalpha(s[0]) && s[1]==':') return s+2;
68 }
69 return s; // whole string
70 }
71
72 // candidate xoj filename for save, save-as, autosave, etc.
73
candidate_save_filename(void)74 gchar *candidate_save_filename(void)
75 {
76 time_t curtime;
77 char stime[30];
78
79 if (ui.filename != NULL) return g_strdup(ui.filename);
80 if (bgpdf.status!=STATUS_NOT_INIT && bgpdf.file_domain == DOMAIN_ABSOLUTE
81 && bgpdf.filename != NULL)
82 return g_strdup_printf("%s.xoj", bgpdf.filename->s);
83 curtime = time(NULL);
84 strftime(stime, 30, "%Y-%m-%d-Note-%H-%M.xoj", localtime(&curtime));
85 if (ui.default_path!=NULL)
86 return g_strdup_printf("%s%c%s", ui.default_path, G_DIR_SEPARATOR, stime);
87 else return g_strdup(stime);
88 }
89
90 // some manipulation functions
91
new_page(struct Page * template)92 struct Page *new_page(struct Page *template)
93 {
94 struct Page *pg = (struct Page *) g_memdup(template, sizeof(struct Page));
95 struct Layer *l = g_new(struct Layer, 1);
96
97 l->items = NULL;
98 l->nitems = 0;
99 pg->layers = g_list_append(NULL, l);
100 pg->nlayers = 1;
101 if (template->bg->type != BG_SOLID && !ui.new_page_bg_from_pdf)
102 pg->bg = (struct Background *)g_memdup(ui.default_page.bg, sizeof(struct Background));
103 else
104 pg->bg = (struct Background *)g_memdup(template->bg, sizeof(struct Background));
105 pg->bg->canvas_item = NULL;
106 if (pg->bg->type == BG_PIXMAP || pg->bg->type == BG_PDF) {
107 g_object_ref(pg->bg->pixbuf);
108 refstring_ref(pg->bg->filename);
109 }
110 pg->group = (GnomeCanvasGroup *) gnome_canvas_item_new(
111 gnome_canvas_root(canvas), gnome_canvas_clipgroup_get_type(), NULL);
112 make_page_clipbox(pg);
113 update_canvas_bg(pg);
114 l->group = (GnomeCanvasGroup *) gnome_canvas_item_new(
115 pg->group, gnome_canvas_group_get_type(), NULL);
116
117 return pg;
118 }
119
120 /* Create a page from a background.
121 Note: bg should be an UNREFERENCED background.
122 If needed, first duplicate it and increase the refcount of the pixbuf.
123 */
new_page_with_bg(struct Background * bg,double width,double height)124 struct Page *new_page_with_bg(struct Background *bg, double width, double height)
125 {
126 struct Page *pg = g_new(struct Page, 1);
127 struct Layer *l = g_new(struct Layer, 1);
128
129 l->items = NULL;
130 l->nitems = 0;
131 pg->layers = g_list_append(NULL, l);
132 pg->nlayers = 1;
133 pg->bg = bg;
134 pg->bg->canvas_item = NULL;
135 pg->height = height;
136 pg->width = width;
137 pg->group = (GnomeCanvasGroup *) gnome_canvas_item_new(
138 gnome_canvas_root(canvas), gnome_canvas_clipgroup_get_type(), NULL);
139 make_page_clipbox(pg);
140 update_canvas_bg(pg);
141 l->group = (GnomeCanvasGroup *) gnome_canvas_item_new(
142 pg->group, gnome_canvas_group_get_type(), NULL);
143
144 return pg;
145 }
146
147 // change the current page if necessary for pointer at pt
set_current_page(gdouble * pt)148 void set_current_page(gdouble *pt)
149 {
150 gboolean page_change;
151 struct Page *tmppage;
152
153 page_change = FALSE;
154 tmppage = ui.cur_page;
155 if (ui.view_continuous == VIEW_MODE_CONTINUOUS) {
156 while (pt[1] < - VIEW_CONTINUOUS_SKIP) {
157 if (ui.pageno == 0) break;
158 page_change = TRUE;
159 ui.pageno--;
160 tmppage = g_list_nth_data(journal.pages, ui.pageno);
161 pt[1] += tmppage->height + VIEW_CONTINUOUS_SKIP;
162 }
163 while (pt[1] > tmppage->height + VIEW_CONTINUOUS_SKIP) {
164 if (ui.pageno == journal.npages-1) break;
165 pt[1] -= tmppage->height + VIEW_CONTINUOUS_SKIP;
166 page_change = TRUE;
167 ui.pageno++;
168 tmppage = g_list_nth_data(journal.pages, ui.pageno);
169 }
170 }
171 if (ui.view_continuous == VIEW_MODE_HORIZONTAL) {
172 while (pt[0] < - VIEW_CONTINUOUS_SKIP) {
173 if (ui.pageno == 0) break;
174 page_change = TRUE;
175 ui.pageno--;
176 tmppage = g_list_nth_data(journal.pages, ui.pageno);
177 pt[0] += tmppage->width + VIEW_CONTINUOUS_SKIP;
178 }
179 while (pt[0] > tmppage->width + VIEW_CONTINUOUS_SKIP) {
180 if (ui.pageno == journal.npages-1) break;
181 pt[0] -= tmppage->width + VIEW_CONTINUOUS_SKIP;
182 page_change = TRUE;
183 ui.pageno++;
184 tmppage = g_list_nth_data(journal.pages, ui.pageno);
185 }
186 }
187 if (page_change) do_switch_page(ui.pageno, FALSE, FALSE);
188 }
189
realloc_cur_path(int n)190 void realloc_cur_path(int n)
191 {
192 if (n <= ui.cur_path_storage_alloc) return;
193 ui.cur_path_storage_alloc = n+100;
194 ui.cur_path.coords = g_realloc(ui.cur_path.coords, 2*(n+100)*sizeof(double));
195 }
196
realloc_cur_widths(int n)197 void realloc_cur_widths(int n)
198 {
199 if (n <= ui.cur_widths_storage_alloc) return;
200 ui.cur_widths_storage_alloc = n+100;
201 ui.cur_widths = g_realloc(ui.cur_widths, (n+100)*sizeof(double));
202 }
203
204 // undo utility functions
205
prepare_new_undo(void)206 void prepare_new_undo(void)
207 {
208 struct UndoItem *u;
209 // add a new UndoItem on the stack
210 u = (struct UndoItem *)g_malloc(sizeof(struct UndoItem));
211 u->next = undo;
212 u->multiop = 0;
213 undo = u;
214 ui.saved = FALSE;
215 ui.need_autosave = TRUE;
216 clear_redo_stack();
217 }
218
clear_redo_stack(void)219 void clear_redo_stack(void)
220 {
221 struct UndoItem *u;
222 GList *list, *repl;
223 struct UndoErasureData *erasure;
224 struct Item *it;
225
226 /* Warning: the redo items might reference items from past redo entries,
227 which have been destroyed before them. Be careful! As a rule, it's
228 safe to destroy data which has been created at the current history step,
229 it's unsafe to refer to any data from previous history steps */
230
231 while (redo!=NULL) {
232 if (redo->type == ITEM_STROKE) {
233 gnome_canvas_points_free(redo->item->path);
234 if (redo->item->brush.variable_width) g_free(redo->item->widths);
235 g_free(redo->item);
236 /* the strokes are unmapped, so there are no associated canvas items */
237 }
238 else if (redo->type == ITEM_TEXT) {
239 g_free(redo->item->text);
240 g_free(redo->item->font_name);
241 g_free(redo->item);
242 }
243 else if (redo->type == ITEM_IMAGE) {
244 g_object_unref(redo->item->image);
245 g_free(redo->item->image_png);
246 g_free(redo->item);
247 }
248 else if (redo->type == ITEM_ERASURE || redo->type == ITEM_RECOGNIZER) {
249 for (list = redo->erasurelist; list!=NULL; list=list->next) {
250 erasure = (struct UndoErasureData *)list->data;
251 for (repl = erasure->replacement_items; repl!=NULL; repl=repl->next) {
252 it = (struct Item *)repl->data;
253 gnome_canvas_points_free(it->path);
254 if (it->brush.variable_width) g_free(it->widths);
255 g_free(it);
256 }
257 g_list_free(erasure->replacement_items);
258 g_free(erasure);
259 }
260 g_list_free(redo->erasurelist);
261 }
262 else if (redo->type == ITEM_NEW_BG_ONE || redo->type == ITEM_NEW_BG_RESIZE
263 || redo->type == ITEM_NEW_DEFAULT_BG) {
264 if (redo->bg->type == BG_PIXMAP || redo->bg->type == BG_PDF) {
265 if (redo->bg->pixbuf!=NULL) g_object_unref(redo->bg->pixbuf);
266 refstring_unref(redo->bg->filename);
267 }
268 g_free(redo->bg);
269 }
270 else if (redo->type == ITEM_NEW_PAGE) {
271 redo->page->group = NULL;
272 delete_page(redo->page);
273 }
274 else if (redo->type == ITEM_MOVESEL || redo->type == ITEM_REPAINTSEL) {
275 g_list_free(redo->itemlist); g_list_free(redo->auxlist);
276 }
277 else if (redo->type == ITEM_RESIZESEL) {
278 g_list_free(redo->itemlist);
279 }
280 else if (redo->type == ITEM_PASTE) {
281 for (list = redo->itemlist; list!=NULL; list=list->next) {
282 it = (struct Item *)list->data;
283 if (it->type == ITEM_STROKE) {
284 gnome_canvas_points_free(it->path);
285 if (it->brush.variable_width) g_free(it->widths);
286 }
287 g_free(it);
288 }
289 g_list_free(redo->itemlist);
290 }
291 else if (redo->type == ITEM_NEW_LAYER) {
292 g_free(redo->layer);
293 }
294 else if (redo->type == ITEM_TEXT_EDIT || redo->type == ITEM_TEXT_ATTRIB) {
295 g_free(redo->str);
296 if (redo->type == ITEM_TEXT_ATTRIB) g_free(redo->brush);
297 }
298
299 u = redo;
300 redo = redo->next;
301 g_free(u);
302 }
303 update_undo_redo_enabled();
304 }
305
clear_undo_stack(void)306 void clear_undo_stack(void)
307 {
308 struct UndoItem *u;
309 GList *list;
310 struct UndoErasureData *erasure;
311
312 while (undo!=NULL) {
313 // for strokes, items are already in the journal, so we don't free them
314 // for erasures, we need to free the dead items
315 if (undo->type == ITEM_ERASURE || undo->type == ITEM_RECOGNIZER) {
316 for (list = undo->erasurelist; list!=NULL; list=list->next) {
317 erasure = (struct UndoErasureData *)list->data;
318 if (erasure->item->type == ITEM_STROKE) {
319 gnome_canvas_points_free(erasure->item->path);
320 if (erasure->item->brush.variable_width) g_free(erasure->item->widths);
321 }
322 if (erasure->item->type == ITEM_TEXT)
323 { g_free(erasure->item->text); g_free(erasure->item->font_name); }
324 if (erasure->item->type == ITEM_IMAGE) {
325 g_object_unref(erasure->item->image);
326 g_free(erasure->item->image_png);
327 }
328 g_free(erasure->item);
329 g_list_free(erasure->replacement_items);
330 g_free(erasure);
331 }
332 g_list_free(undo->erasurelist);
333 }
334 else if (undo->type == ITEM_NEW_BG_ONE || undo->type == ITEM_NEW_BG_RESIZE
335 || undo->type == ITEM_NEW_DEFAULT_BG) {
336 if (undo->bg->type == BG_PIXMAP || undo->bg->type == BG_PDF) {
337 if (undo->bg->pixbuf!=NULL) g_object_unref(undo->bg->pixbuf);
338 refstring_unref(undo->bg->filename);
339 }
340 g_free(undo->bg);
341 }
342 else if (undo->type == ITEM_MOVESEL || undo->type == ITEM_REPAINTSEL) {
343 g_list_free(undo->itemlist); g_list_free(undo->auxlist);
344 }
345 else if (undo->type == ITEM_RESIZESEL) {
346 g_list_free(undo->itemlist);
347 }
348 else if (undo->type == ITEM_PASTE) {
349 g_list_free(undo->itemlist);
350 }
351 else if (undo->type == ITEM_DELETE_LAYER) {
352 undo->layer->group = NULL;
353 delete_layer(undo->layer);
354 }
355 else if (undo->type == ITEM_DELETE_PAGE) {
356 undo->page->group = NULL;
357 delete_page(undo->page);
358 }
359 else if (undo->type == ITEM_TEXT_EDIT || undo->type == ITEM_TEXT_ATTRIB) {
360 g_free(undo->str);
361 if (undo->type == ITEM_TEXT_ATTRIB) g_free(undo->brush);
362 }
363
364 u = undo;
365 undo = undo->next;
366 g_free(u);
367 }
368 update_undo_redo_enabled();
369 }
370
371 // free data structures
372
delete_journal(struct Journal * j)373 void delete_journal(struct Journal *j)
374 {
375 while (j->pages!=NULL) {
376 delete_page((struct Page *)j->pages->data);
377 j->pages = g_list_delete_link(j->pages, j->pages);
378 }
379 }
380
delete_page(struct Page * pg)381 void delete_page(struct Page *pg)
382 {
383 struct Layer *l;
384
385 while (pg->layers!=NULL) {
386 l = (struct Layer *)pg->layers->data;
387 l->group = NULL;
388 delete_layer(l);
389 pg->layers = g_list_delete_link(pg->layers, pg->layers);
390 }
391 if (pg->group!=NULL) gtk_object_destroy(GTK_OBJECT(pg->group));
392 // this also destroys the background's canvas items
393 if (pg->bg->type == BG_PIXMAP || pg->bg->type == BG_PDF) {
394 if (pg->bg->pixbuf != NULL) g_object_unref(pg->bg->pixbuf);
395 if (pg->bg->filename != NULL) refstring_unref(pg->bg->filename);
396 }
397 g_free(pg->bg);
398 g_free(pg);
399 }
400
delete_layer(struct Layer * l)401 void delete_layer(struct Layer *l)
402 {
403 struct Item *item;
404
405 while (l->items!=NULL) {
406 item = (struct Item *)l->items->data;
407 if (item->type == ITEM_STROKE && item->path != NULL) {
408 gnome_canvas_points_free(item->path);
409 if (item->brush.variable_width) g_free(item->widths);
410 }
411 if (item->type == ITEM_TEXT) {
412 g_free(item->font_name); g_free(item->text);
413 }
414 if (item->type == ITEM_IMAGE) {
415 g_object_unref(item->image);
416 g_free(item->image_png);
417 }
418 // don't need to delete the canvas_item, as it's part of the group destroyed below
419 g_free(item);
420 l->items = g_list_delete_link(l->items, l->items);
421 }
422 if (l->group!= NULL) gtk_object_destroy(GTK_OBJECT(l->group));
423 g_free(l);
424 }
425
426 // referenced strings
427
new_refstring(const char * s)428 struct Refstring *new_refstring(const char *s)
429 {
430 struct Refstring *rs = g_new(struct Refstring, 1);
431 rs->nref = 1;
432 if (s!=NULL) rs->s = g_strdup(s);
433 else rs->s = NULL;
434 rs->aux = NULL;
435 return rs;
436 }
437
refstring_ref(struct Refstring * rs)438 struct Refstring *refstring_ref(struct Refstring *rs)
439 {
440 rs->nref++;
441 return rs;
442 }
443
refstring_unref(struct Refstring * rs)444 void refstring_unref(struct Refstring *rs)
445 {
446 rs->nref--;
447 if (rs->nref == 0) {
448 if (rs->s!=NULL) g_free(rs->s);
449 if (rs->aux!=NULL) g_free(rs->aux);
450 g_free(rs);
451 }
452 }
453
454
455 // some helper functions
456
finite_sized(double x)457 int finite_sized(double x) // detect unrealistic coordinate values
458 {
459 return (finite(x) && x<1E8 && x>-1E8);
460 }
461
462
get_pointer_coords(GdkEvent * event,gdouble * ret)463 void get_pointer_coords(GdkEvent *event, gdouble *ret)
464 {
465 double x, y;
466 gdk_event_get_coords(event, &x, &y);
467 gnome_canvas_window_to_world(canvas, x, y, ret, ret+1);
468 ret[0] -= ui.cur_page->hoffset;
469 ret[1] -= ui.cur_page->voffset;
470 }
471
get_current_pointer_coords(gdouble * ret)472 void get_current_pointer_coords(gdouble *ret)
473 {
474 gint wx, wy, sx, sy;
475
476 gtk_widget_get_pointer((GtkWidget *)canvas, &wx, &wy);
477 gnome_canvas_get_scroll_offsets(canvas, &sx, &sy);
478 gnome_canvas_window_to_world(canvas, (double)(wx + sx), (double)(wy + sy), ret, ret+1);
479 ret[0] -= ui.cur_page->hoffset;
480 ret[1] -= ui.cur_page->voffset;
481 }
482
fix_xinput_coords(GdkEvent * event)483 void fix_xinput_coords(GdkEvent *event)
484 {
485 double *axes, *px, *py, axis_width;
486 GdkDevice *device;
487 int wx, wy, sx, sy, ix, iy;
488
489 if (event->type == GDK_BUTTON_PRESS || event->type == GDK_BUTTON_RELEASE) {
490 axes = event->button.axes;
491 px = &(event->button.x);
492 py = &(event->button.y);
493 device = event->button.device;
494 }
495 else if (event->type == GDK_MOTION_NOTIFY) {
496 axes = event->motion.axes;
497 px = &(event->motion.x);
498 py = &(event->motion.y);
499 device = event->motion.device;
500 }
501 else return; // nothing we know how to do
502
503 gnome_canvas_get_scroll_offsets(canvas, &sx, &sy);
504
505 #ifdef ENABLE_XINPUT_BUGFIX
506 // fix broken events with the core pointer's location
507 if (!finite_sized(axes[0]) || !finite_sized(axes[1]) || axes[0]==0. || axes[1]==0.) {
508 gdk_window_get_pointer(GTK_WIDGET(canvas)->window, &ix, &iy, NULL);
509 *px = ix + sx;
510 *py = iy + sy;
511 }
512 else {
513 gdk_window_get_origin(GTK_WIDGET(canvas)->window, &wx, &wy);
514 axis_width = device->axes[0].max - device->axes[0].min;
515 if (axis_width>EPSILON)
516 *px = (axes[0]/axis_width)*ui.screen_width + sx - wx;
517 axis_width = device->axes[1].max - device->axes[1].min;
518 if (axis_width>EPSILON)
519 *py = (axes[1]/axis_width)*ui.screen_height + sy - wy;
520 }
521 #else
522 if (!finite_sized(*px) || !finite_sized(*py) || *px==0. || *py==0.) {
523 gdk_window_get_pointer(GTK_WIDGET(canvas)->window, &ix, &iy, NULL);
524 *px = ix + sx;
525 *py = iy + sy;
526 }
527 else {
528 /* with GTK+ 2.16 or earlier, the event comes from the parent gdkwindow
529 and so needs to be adjusted for scrolling */
530 if (gtk_major_version == 2 && gtk_minor_version <= 16) {
531 *px += sx;
532 *py += sy;
533 }
534 /* with GTK+ 2.17, events come improperly translated, and the event's
535 GdkWindow isn't even the same for ButtonDown as for MotionNotify... */
536 if (gtk_major_version == 2 && gtk_minor_version == 17) { // GTK+ 2.17 issues !!
537 gdk_window_get_position(GTK_WIDGET(canvas)->window, &wx, &wy);
538 *px += sx - wx;
539 *py += sy - wy;
540 }
541 }
542 #endif
543 }
544
get_pressure_multiplier(GdkEvent * event)545 double get_pressure_multiplier(GdkEvent *event)
546 {
547 double *axes;
548 double rawpressure;
549 GdkDevice *device;
550
551 if (event->type == GDK_MOTION_NOTIFY) {
552 axes = event->motion.axes;
553 device = event->motion.device;
554 }
555 else {
556 axes = event->button.axes;
557 device = event->button.device;
558 }
559
560 if (device == gdk_device_get_core_pointer()
561 || device->num_axes <= 2) return 1.0;
562
563 rawpressure = axes[2]/(device->axes[2].max - device->axes[2].min);
564 if (!finite_sized(rawpressure)) return 1.0;
565
566 if (rawpressure <= 0.) rawpressure = 0.;
567 if (rawpressure >= 1.0) rawpressure = 1.0;
568 return ((1-rawpressure)*ui.width_minimum_multiplier + rawpressure*ui.width_maximum_multiplier);
569 }
570
571
emergency_enable_xinput(GdkInputMode mode)572 void emergency_enable_xinput(GdkInputMode mode)
573 {
574 GList *dev_list;
575 GdkDevice *dev;
576
577 #ifdef INPUT_DEBUG
578 printf("DEBUG: Emergency xinput enable/disable: %d\n", mode);
579 #endif
580 gdk_flush();
581 gdk_error_trap_push();
582 for (dev_list = gdk_devices_list(); dev_list != NULL; dev_list = dev_list->next) {
583 dev = GDK_DEVICE(dev_list->data);
584 gdk_device_set_mode(dev, mode);
585 }
586 gdk_flush();
587 gdk_error_trap_pop();
588 }
589
update_item_bbox(struct Item * item)590 void update_item_bbox(struct Item *item)
591 {
592 int i;
593 gdouble *p, h, w;
594
595 if (item->type == ITEM_STROKE) {
596 item->bbox.left = item->bbox.right = item->path->coords[0];
597 item->bbox.top = item->bbox.bottom = item->path->coords[1];
598 for (i=1, p=item->path->coords+2; i<item->path->num_points; i++, p+=2)
599 {
600 if (p[0] < item->bbox.left) item->bbox.left = p[0];
601 if (p[0] > item->bbox.right) item->bbox.right = p[0];
602 if (p[1] < item->bbox.top) item->bbox.top = p[1];
603 if (p[1] > item->bbox.bottom) item->bbox.bottom = p[1];
604 }
605 }
606 if (item->type == ITEM_TEXT && item->canvas_item!=NULL) {
607 h=0.; w=0.;
608 g_object_get(item->canvas_item, "text_width", &w, "text_height", &h, NULL);
609 item->bbox.right = item->bbox.left + w;
610 item->bbox.bottom = item->bbox.top + h;
611 }
612 }
613
make_page_clipbox(struct Page * pg)614 void make_page_clipbox(struct Page *pg)
615 {
616 GnomeCanvasPathDef *pg_clip;
617
618 pg_clip = gnome_canvas_path_def_new_sized(4);
619 gnome_canvas_path_def_moveto(pg_clip, 0., 0.);
620 gnome_canvas_path_def_lineto(pg_clip, 0., pg->height);
621 gnome_canvas_path_def_lineto(pg_clip, pg->width, pg->height);
622 gnome_canvas_path_def_lineto(pg_clip, pg->width, 0.);
623 gnome_canvas_path_def_closepath(pg_clip);
624 gnome_canvas_item_set(GNOME_CANVAS_ITEM(pg->group), "path", pg_clip, NULL);
625 gnome_canvas_path_def_unref(pg_clip);
626 }
627
make_canvas_item_one(GnomeCanvasGroup * group,struct Item * item)628 void make_canvas_item_one(GnomeCanvasGroup *group, struct Item *item)
629 {
630 PangoFontDescription *font_desc;
631 GnomeCanvasPoints points;
632 GtkWidget *dialog;
633 int j;
634
635 if (item->type == ITEM_STROKE) {
636 if (!item->brush.variable_width)
637 item->canvas_item = gnome_canvas_item_new(group,
638 gnome_canvas_line_get_type(), "points", item->path,
639 "cap-style", GDK_CAP_ROUND, "join-style", GDK_JOIN_ROUND,
640 "fill-color-rgba", item->brush.color_rgba,
641 "width-units", item->brush.thickness, NULL);
642 else {
643 item->canvas_item = gnome_canvas_item_new(group,
644 gnome_canvas_group_get_type(), NULL);
645 points.num_points = 2;
646 points.ref_count = 1;
647 for (j = 0; j < item->path->num_points-1; j++) {
648 points.coords = item->path->coords+2*j;
649 gnome_canvas_item_new((GnomeCanvasGroup *) item->canvas_item,
650 gnome_canvas_line_get_type(), "points", &points,
651 "cap-style", GDK_CAP_ROUND, "join-style", GDK_JOIN_ROUND,
652 "fill-color-rgba", item->brush.color_rgba,
653 "width-units", item->widths[j], NULL);
654 }
655 }
656 }
657 if (item->type == ITEM_TEXT) {
658 #ifdef WIN32 // fontconfig cache generation takes forever, show hourglass
659 if (!ui.warned_generate_fontconfig) {
660 dialog = gtk_message_dialog_new(GTK_WINDOW(winMain), GTK_DIALOG_DESTROY_WITH_PARENT,
661 GTK_MESSAGE_OTHER, GTK_BUTTONS_NONE, _("Generating fontconfig library cache, please be patient..."));
662 gtk_window_set_title(GTK_WINDOW(dialog), _("Generating fontconfig cache..."));
663 gtk_widget_show_all(dialog);
664 set_cursor_busy(TRUE);
665 }
666 #endif
667 font_desc = pango_font_description_from_string(item->font_name);
668 pango_font_description_set_absolute_size(font_desc,
669 item->font_size*ui.zoom*PANGO_SCALE);
670 item->canvas_item = gnome_canvas_item_new(group,
671 gnome_canvas_text_get_type(),
672 "x", item->bbox.left, "y", item->bbox.top, "anchor", GTK_ANCHOR_NW,
673 "font-desc", font_desc, "fill-color-rgba", item->brush.color_rgba,
674 "text", item->text, NULL);
675 update_item_bbox(item);
676 #ifdef WIN32 // done
677 if (!ui.warned_generate_fontconfig) {
678 ui.warned_generate_fontconfig = TRUE;
679 gtk_widget_destroy(dialog);
680 set_cursor_busy(FALSE);
681 }
682 #endif
683 }
684 if (item->type == ITEM_IMAGE) {
685 item->canvas_item = gnome_canvas_item_new(group,
686 gnome_canvas_pixbuf_get_type(),
687 "pixbuf", item->image,
688 "x", item->bbox.left, "y", item->bbox.top,
689 "width", item->bbox.right - item->bbox.left,
690 "height", item->bbox.bottom - item->bbox.top,
691 "width-set", TRUE, "height-set", TRUE,
692 NULL);
693 }
694 }
695
make_canvas_items(void)696 void make_canvas_items(void)
697 {
698 struct Page *pg;
699 struct Layer *l;
700 struct Item *item;
701 GList *pagelist, *layerlist, *itemlist;
702
703 for (pagelist = journal.pages; pagelist!=NULL; pagelist = pagelist->next) {
704 pg = (struct Page *)pagelist->data;
705 if (pg->group == NULL) {
706 pg->group = (GnomeCanvasGroup *) gnome_canvas_item_new(
707 gnome_canvas_root(canvas), gnome_canvas_clipgroup_get_type(), NULL);
708 make_page_clipbox(pg);
709 }
710 if (pg->bg->canvas_item == NULL) update_canvas_bg(pg);
711 for (layerlist = pg->layers; layerlist!=NULL; layerlist = layerlist->next) {
712 l = (struct Layer *)layerlist->data;
713 if (l->group == NULL)
714 l->group = (GnomeCanvasGroup *) gnome_canvas_item_new(
715 pg->group, gnome_canvas_group_get_type(), NULL);
716 for (itemlist = l->items; itemlist!=NULL; itemlist = itemlist->next) {
717 item = (struct Item *)itemlist->data;
718 if (item->canvas_item == NULL)
719 make_canvas_item_one(l->group, item);
720 }
721 }
722 }
723 }
724
update_canvas_bg(struct Page * pg)725 void update_canvas_bg(struct Page *pg)
726 {
727 GnomeCanvasGroup *group;
728 GnomeCanvasPoints *seg;
729 GdkPixbuf *scaled_pix;
730 double *pt;
731 double x, y;
732 int w, h;
733 gboolean is_well_scaled;
734
735 if (pg->bg->canvas_item != NULL)
736 gtk_object_destroy(GTK_OBJECT(pg->bg->canvas_item));
737 pg->bg->canvas_item = NULL;
738
739 if (pg->bg->type == BG_SOLID)
740 {
741 pg->bg->canvas_item = gnome_canvas_item_new(pg->group,
742 gnome_canvas_group_get_type(), NULL);
743 group = GNOME_CANVAS_GROUP(pg->bg->canvas_item);
744 lower_canvas_item_to(pg->group, pg->bg->canvas_item, NULL);
745 gnome_canvas_item_new(group, gnome_canvas_rect_get_type(),
746 "x1", 0., "x2", pg->width, "y1", 0., "y2", pg->height,
747 "fill-color-rgba", pg->bg->color_rgba, NULL);
748 if (pg->bg->ruling == RULING_NONE) return;
749 seg = gnome_canvas_points_new(2);
750 pt = seg->coords;
751 if (pg->bg->ruling == RULING_GRAPH) {
752 pt[1] = 0; pt[3] = pg->height;
753 for (x=RULING_GRAPHSPACING; x<pg->width-1; x+=RULING_GRAPHSPACING) {
754 pt[0] = pt[2] = x;
755 gnome_canvas_item_new(group, gnome_canvas_line_get_type(),
756 "points", seg, "fill-color-rgba", RULING_COLOR,
757 "width-units", RULING_THICKNESS, NULL);
758 }
759 pt[0] = 0; pt[2] = pg->width;
760 for (y=RULING_GRAPHSPACING; y<pg->height-1; y+=RULING_GRAPHSPACING) {
761 pt[1] = pt[3] = y;
762 gnome_canvas_item_new(group, gnome_canvas_line_get_type(),
763 "points", seg, "fill-color-rgba", RULING_COLOR,
764 "width-units", RULING_THICKNESS, NULL);
765 }
766 gnome_canvas_points_free(seg);
767 return;
768 }
769 pt[0] = 0; pt[2] = pg->width;
770 for (y=RULING_TOPMARGIN; y<pg->height-1; y+=RULING_SPACING) {
771 pt[1] = pt[3] = y;
772 gnome_canvas_item_new(group, gnome_canvas_line_get_type(),
773 "points", seg, "fill-color-rgba", RULING_COLOR,
774 "width-units", RULING_THICKNESS, NULL);
775 }
776 if (pg->bg->ruling == RULING_LINED) {
777 pt[0] = pt[2] = RULING_LEFTMARGIN;
778 pt[1] = 0; pt[3] = pg->height;
779 gnome_canvas_item_new(group, gnome_canvas_line_get_type(),
780 "points", seg, "fill-color-rgba", RULING_MARGIN_COLOR,
781 "width-units", RULING_THICKNESS, NULL);
782 }
783 gnome_canvas_points_free(seg);
784 return;
785 }
786
787 if (pg->bg->type == BG_PIXMAP)
788 {
789 pg->bg->pixbuf_scale = 0;
790 pg->bg->canvas_item = gnome_canvas_item_new(pg->group,
791 gnome_canvas_pixbuf_get_type(),
792 "pixbuf", pg->bg->pixbuf,
793 "width", pg->width, "height", pg->height,
794 "width-set", TRUE, "height-set", TRUE,
795 NULL);
796 lower_canvas_item_to(pg->group, pg->bg->canvas_item, NULL);
797 }
798
799 if (pg->bg->type == BG_PDF)
800 {
801 if (pg->bg->pixbuf == NULL) return;
802 is_well_scaled = (fabs(pg->bg->pixel_width - pg->width*ui.zoom) < 2.
803 && fabs(pg->bg->pixel_height - pg->height*ui.zoom) < 2.);
804 if (is_well_scaled)
805 pg->bg->canvas_item = gnome_canvas_item_new(pg->group,
806 gnome_canvas_pixbuf_get_type(),
807 "pixbuf", pg->bg->pixbuf,
808 "width-in-pixels", TRUE, "height-in-pixels", TRUE,
809 NULL);
810 else
811 pg->bg->canvas_item = gnome_canvas_item_new(pg->group,
812 gnome_canvas_pixbuf_get_type(),
813 "pixbuf", pg->bg->pixbuf,
814 "width", pg->width, "height", pg->height,
815 "width-set", TRUE, "height-set", TRUE,
816 NULL);
817 lower_canvas_item_to(pg->group, pg->bg->canvas_item, NULL);
818 }
819 }
820
is_visible(struct Page * pg)821 gboolean is_visible(struct Page *pg)
822 {
823 GtkAdjustment *adj;
824 double top, bottom;
825
826 switch (ui.view_continuous) {
827 case VIEW_MODE_ONE_PAGE:
828 return (pg == ui.cur_page);
829 case VIEW_MODE_CONTINUOUS:
830 adj = gtk_layout_get_vadjustment(GTK_LAYOUT(canvas));
831 top = adj->value/ui.zoom;
832 bottom = (adj->value + adj->page_size) / ui.zoom;
833 return (MAX(top, pg->voffset) < MIN(bottom, pg->voffset+pg->height));
834 case VIEW_MODE_HORIZONTAL:
835 adj = gtk_layout_get_hadjustment(GTK_LAYOUT(canvas));
836 top = adj->value/ui.zoom;
837 bottom = (adj->value + adj->page_size) / ui.zoom;
838 return (MAX(top, pg->hoffset) < MIN(bottom, pg->hoffset+pg->width));
839 }
840 // uh? not a known case
841 return FALSE;
842 }
843
rescale_bg_pixmaps(void)844 void rescale_bg_pixmaps(void)
845 {
846 GList *pglist;
847 struct Page *pg;
848 GdkPixbuf *pix;
849 gboolean is_well_scaled;
850 gdouble zoom_to_request;
851
852 for (pglist = journal.pages; pglist!=NULL; pglist = pglist->next) {
853 pg = (struct Page *)pglist->data;
854 // in progressive mode we scale only visible pages
855 if (ui.progressive_bg && !is_visible(pg)) continue;
856
857 if (pg->bg->type == BG_PIXMAP && pg->bg->canvas_item!=NULL) {
858 g_object_get(G_OBJECT(pg->bg->canvas_item), "pixbuf", &pix, NULL);
859 if (pix!=pg->bg->pixbuf)
860 gnome_canvas_item_set(pg->bg->canvas_item, "pixbuf", pg->bg->pixbuf, NULL);
861 pg->bg->pixbuf_scale = 0;
862 }
863 if (pg->bg->type == BG_PDF) {
864 // make pixmap scale to correct size if current one is wrong
865 is_well_scaled = (fabs(pg->bg->pixel_width - pg->width*ui.zoom) < 2.
866 && fabs(pg->bg->pixel_height - pg->height*ui.zoom) < 2.);
867 if (pg->bg->canvas_item != NULL && !is_well_scaled) {
868 g_object_get(pg->bg->canvas_item, "width-in-pixels", &is_well_scaled, NULL);
869 if (is_well_scaled)
870 gnome_canvas_item_set(pg->bg->canvas_item,
871 "width", pg->width, "height", pg->height,
872 "width-in-pixels", FALSE, "height-in-pixels", FALSE,
873 "width-set", TRUE, "height-set", TRUE,
874 NULL);
875 }
876 // request an asynchronous update to a better pixmap if needed
877 zoom_to_request = MIN(ui.zoom, MAX_SAFE_RENDER_DPI/72.0);
878 if (pg->bg->pixbuf_scale == zoom_to_request) continue;
879 if (add_bgpdf_request(pg->bg->file_page_seq, zoom_to_request))
880 pg->bg->pixbuf_scale = zoom_to_request;
881 }
882 }
883 }
884
have_intersect(struct BBox * a,struct BBox * b)885 gboolean have_intersect(struct BBox *a, struct BBox *b)
886 {
887 return (MAX(a->top, b->top) <= MIN(a->bottom, b->bottom)) &&
888 (MAX(a->left, b->left) <= MIN(a->right, b->right));
889 }
890
891 /* In libgnomecanvas 2.10.0, the lower/raise functions fail to update
892 correctly the end of the group's item list. We try to work around this.
893 DON'T USE gnome_canvas_item_raise/lower directly !! */
894
lower_canvas_item_to(GnomeCanvasGroup * g,GnomeCanvasItem * item,GnomeCanvasItem * after)895 void lower_canvas_item_to(GnomeCanvasGroup *g, GnomeCanvasItem *item, GnomeCanvasItem *after)
896 {
897 int i1, i2;
898
899 i1 = g_list_index(g->item_list, item);
900 if (i1 == -1) return;
901
902 if (after == NULL) i2 = -1;
903 else i2 = g_list_index(g->item_list, after);
904
905 if (i1 < i2) gnome_canvas_item_raise(item, i2-i1);
906 if (i1 > i2+1) gnome_canvas_item_lower(item, i1-i2-1);
907
908 // BUGFIX for libgnomecanvas
909 g->item_list_end = g_list_last(g->item_list);
910 }
911
rgb_to_gdkcolor(guint rgba,GdkColor * color)912 void rgb_to_gdkcolor(guint rgba, GdkColor *color)
913 {
914 color->pixel = 0;
915 color->red = ((rgba>>24)&0xff)*0x101;
916 color->green = ((rgba>>16)&0xff)*0x101;
917 color->blue = ((rgba>>8)&0xff)*0x101;
918 }
919
gdkcolor_to_rgba(GdkColor gdkcolor,guint16 alpha)920 guint32 gdkcolor_to_rgba(GdkColor gdkcolor, guint16 alpha)
921 {
922 guint32 rgba = ((gdkcolor.red & 0xff00) << 16) |
923 ((gdkcolor.green & 0xff00) << 8) |
924 ((gdkcolor.blue & 0xff00) ) |
925 ((alpha & 0xff00) >> 8);
926
927 return rgba;
928 }
929
930 // some interface functions
931
update_thickness_buttons(void)932 void update_thickness_buttons(void)
933 {
934 if (ui.selection!=NULL || ui.toolno[ui.cur_mapping] >= NUM_STROKE_TOOLS) {
935 gtk_toggle_tool_button_set_active(
936 GTK_TOGGLE_TOOL_BUTTON(GET_COMPONENT("buttonThicknessOther")), TRUE);
937 } else
938 switch (ui.cur_brush->thickness_no) {
939 case THICKNESS_FINE:
940 gtk_toggle_tool_button_set_active(
941 GTK_TOGGLE_TOOL_BUTTON(GET_COMPONENT("buttonFine")), TRUE);
942 break;
943 case THICKNESS_MEDIUM:
944 gtk_toggle_tool_button_set_active(
945 GTK_TOGGLE_TOOL_BUTTON(GET_COMPONENT("buttonMedium")), TRUE);
946 break;
947 case THICKNESS_THICK:
948 gtk_toggle_tool_button_set_active(
949 GTK_TOGGLE_TOOL_BUTTON(GET_COMPONENT("buttonThick")), TRUE);
950 break;
951 default:
952 gtk_toggle_tool_button_set_active(
953 GTK_TOGGLE_TOOL_BUTTON(GET_COMPONENT("buttonThicknessOther")), TRUE);
954 }
955 }
956
update_color_buttons(void)957 void update_color_buttons(void)
958 {
959 GdkColor gdkcolor;
960 GtkColorButton *colorbutton;
961
962 if (ui.selection!=NULL || (ui.toolno[ui.cur_mapping] != TOOL_PEN
963 && ui.toolno[ui.cur_mapping] != TOOL_HIGHLIGHTER && ui.toolno[ui.cur_mapping] != TOOL_TEXT)) {
964 gtk_toggle_tool_button_set_active(
965 GTK_TOGGLE_TOOL_BUTTON(GET_COMPONENT("buttonColorOther")), TRUE);
966 } else
967 switch (ui.cur_brush->color_no) {
968 case COLOR_BLACK:
969 gtk_toggle_tool_button_set_active(
970 GTK_TOGGLE_TOOL_BUTTON(GET_COMPONENT("buttonBlack")), TRUE);
971 break;
972 case COLOR_BLUE:
973 gtk_toggle_tool_button_set_active(
974 GTK_TOGGLE_TOOL_BUTTON(GET_COMPONENT("buttonBlue")), TRUE);
975 break;
976 case COLOR_RED:
977 gtk_toggle_tool_button_set_active(
978 GTK_TOGGLE_TOOL_BUTTON(GET_COMPONENT("buttonRed")), TRUE);
979 break;
980 case COLOR_GREEN:
981 gtk_toggle_tool_button_set_active(
982 GTK_TOGGLE_TOOL_BUTTON(GET_COMPONENT("buttonGreen")), TRUE);
983 break;
984 case COLOR_GRAY:
985 gtk_toggle_tool_button_set_active(
986 GTK_TOGGLE_TOOL_BUTTON(GET_COMPONENT("buttonGray")), TRUE);
987 break;
988 case COLOR_LIGHTBLUE:
989 gtk_toggle_tool_button_set_active(
990 GTK_TOGGLE_TOOL_BUTTON(GET_COMPONENT("buttonLightBlue")), TRUE);
991 break;
992 case COLOR_LIGHTGREEN:
993 gtk_toggle_tool_button_set_active(
994 GTK_TOGGLE_TOOL_BUTTON(GET_COMPONENT("buttonLightGreen")), TRUE);
995 break;
996 case COLOR_MAGENTA:
997 gtk_toggle_tool_button_set_active(
998 GTK_TOGGLE_TOOL_BUTTON(GET_COMPONENT("buttonMagenta")), TRUE);
999 break;
1000 case COLOR_ORANGE:
1001 gtk_toggle_tool_button_set_active(
1002 GTK_TOGGLE_TOOL_BUTTON(GET_COMPONENT("buttonOrange")), TRUE);
1003 break;
1004 case COLOR_YELLOW:
1005 gtk_toggle_tool_button_set_active(
1006 GTK_TOGGLE_TOOL_BUTTON(GET_COMPONENT("buttonYellow")), TRUE);
1007 break;
1008 case COLOR_WHITE:
1009 gtk_toggle_tool_button_set_active(
1010 GTK_TOGGLE_TOOL_BUTTON(GET_COMPONENT("buttonWhite")), TRUE);
1011 break;
1012 default:
1013 gtk_toggle_tool_button_set_active(
1014 GTK_TOGGLE_TOOL_BUTTON(GET_COMPONENT("buttonColorOther")), TRUE);
1015 }
1016
1017 colorbutton = GTK_COLOR_BUTTON(GET_COMPONENT("buttonColorChooser"));
1018 if ((ui.toolno[ui.cur_mapping] != TOOL_PEN &&
1019 ui.toolno[ui.cur_mapping] != TOOL_HIGHLIGHTER &&
1020 ui.toolno[ui.cur_mapping] != TOOL_TEXT))
1021 gdkcolor.red = gdkcolor.blue = gdkcolor.green = 0;
1022 else rgb_to_gdkcolor(ui.cur_brush->color_rgba, &gdkcolor);
1023 gtk_color_button_set_color(colorbutton, &gdkcolor);
1024 if (ui.toolno[ui.cur_mapping] == TOOL_HIGHLIGHTER) {
1025 gtk_color_button_set_alpha(colorbutton,
1026 (ui.cur_brush->color_rgba&0xff)*0x101);
1027 gtk_color_button_set_use_alpha(colorbutton, TRUE);
1028 } else {
1029 gtk_color_button_set_alpha(colorbutton, 0xffff);
1030 gtk_color_button_set_use_alpha(colorbutton, FALSE);
1031 }
1032 }
1033
update_tool_buttons(void)1034 void update_tool_buttons(void)
1035 {
1036 switch(ui.toolno[ui.cur_mapping]) {
1037 case TOOL_PEN:
1038 gtk_toggle_tool_button_set_active(
1039 GTK_TOGGLE_TOOL_BUTTON(GET_COMPONENT("buttonPen")), TRUE);
1040 break;
1041 case TOOL_ERASER:
1042 gtk_toggle_tool_button_set_active(
1043 GTK_TOGGLE_TOOL_BUTTON(GET_COMPONENT("buttonEraser")), TRUE);
1044 break;
1045 case TOOL_HIGHLIGHTER:
1046 gtk_toggle_tool_button_set_active(
1047 GTK_TOGGLE_TOOL_BUTTON(GET_COMPONENT("buttonHighlighter")), TRUE);
1048 break;
1049 case TOOL_TEXT:
1050 gtk_toggle_tool_button_set_active(
1051 GTK_TOGGLE_TOOL_BUTTON(GET_COMPONENT("buttonText")), TRUE);
1052 break;
1053 case TOOL_IMAGE:
1054 gtk_toggle_tool_button_set_active(
1055 GTK_TOGGLE_TOOL_BUTTON(GET_COMPONENT("buttonImage")), TRUE);
1056 break;
1057 case TOOL_SELECTREGION:
1058 gtk_toggle_tool_button_set_active(
1059 GTK_TOGGLE_TOOL_BUTTON(GET_COMPONENT("buttonSelectRegion")), TRUE);
1060 break;
1061 case TOOL_SELECTRECT:
1062 gtk_toggle_tool_button_set_active(
1063 GTK_TOGGLE_TOOL_BUTTON(GET_COMPONENT("buttonSelectRectangle")), TRUE);
1064 break;
1065 case TOOL_VERTSPACE:
1066 gtk_toggle_tool_button_set_active(
1067 GTK_TOGGLE_TOOL_BUTTON(GET_COMPONENT("buttonVerticalSpace")), TRUE);
1068 break;
1069 case TOOL_HAND:
1070 gtk_toggle_tool_button_set_active(
1071 GTK_TOGGLE_TOOL_BUTTON(GET_COMPONENT("buttonHand")), TRUE);
1072 break;
1073 }
1074
1075 gtk_toggle_tool_button_set_active(
1076 GTK_TOGGLE_TOOL_BUTTON(GET_COMPONENT("buttonRuler")),
1077 ui.toolno[ui.cur_mapping]<NUM_STROKE_TOOLS && ui.cur_brush->ruler);
1078 gtk_toggle_tool_button_set_active(
1079 GTK_TOGGLE_TOOL_BUTTON(GET_COMPONENT("buttonReco")),
1080 ui.toolno[ui.cur_mapping]<NUM_STROKE_TOOLS && ui.cur_brush->recognizer);
1081
1082 update_thickness_buttons();
1083 update_color_buttons();
1084 }
1085
update_tool_menu(void)1086 void update_tool_menu(void)
1087 {
1088 switch(ui.toolno[0]) {
1089 case TOOL_PEN:
1090 gtk_check_menu_item_set_active(
1091 GTK_CHECK_MENU_ITEM(GET_COMPONENT("toolsPen")), TRUE);
1092 break;
1093 case TOOL_ERASER:
1094 gtk_check_menu_item_set_active(
1095 GTK_CHECK_MENU_ITEM(GET_COMPONENT("toolsEraser")), TRUE);
1096 break;
1097 case TOOL_HIGHLIGHTER:
1098 gtk_check_menu_item_set_active(
1099 GTK_CHECK_MENU_ITEM(GET_COMPONENT("toolsHighlighter")), TRUE);
1100 break;
1101 case TOOL_TEXT:
1102 gtk_check_menu_item_set_active(
1103 GTK_CHECK_MENU_ITEM(GET_COMPONENT("toolsText")), TRUE);
1104 break;
1105 case TOOL_IMAGE:
1106 gtk_check_menu_item_set_active(
1107 GTK_CHECK_MENU_ITEM(GET_COMPONENT("toolsImage")), TRUE);
1108 break;
1109 case TOOL_SELECTREGION:
1110 gtk_check_menu_item_set_active(
1111 GTK_CHECK_MENU_ITEM(GET_COMPONENT("toolsSelectRegion")), TRUE);
1112 break;
1113 case TOOL_SELECTRECT:
1114 gtk_check_menu_item_set_active(
1115 GTK_CHECK_MENU_ITEM(GET_COMPONENT("toolsSelectRectangle")), TRUE);
1116 break;
1117 case TOOL_VERTSPACE:
1118 gtk_check_menu_item_set_active(
1119 GTK_CHECK_MENU_ITEM(GET_COMPONENT("toolsVerticalSpace")), TRUE);
1120 break;
1121 case TOOL_HAND:
1122 gtk_check_menu_item_set_active(
1123 GTK_CHECK_MENU_ITEM(GET_COMPONENT("toolsHand")), TRUE);
1124 break;
1125 }
1126
1127 gtk_check_menu_item_set_active(
1128 GTK_CHECK_MENU_ITEM(GET_COMPONENT("toolsRuler")),
1129 ui.toolno[0]<NUM_STROKE_TOOLS && ui.brushes[0][ui.toolno[0]].ruler);
1130 gtk_check_menu_item_set_active(
1131 GTK_CHECK_MENU_ITEM(GET_COMPONENT("toolsReco")),
1132 ui.toolno[0]<NUM_STROKE_TOOLS && ui.brushes[0][ui.toolno[0]].recognizer);
1133 }
1134
update_ruler_indicator(void)1135 void update_ruler_indicator(void)
1136 {
1137 gtk_toggle_tool_button_set_active(
1138 GTK_TOGGLE_TOOL_BUTTON(GET_COMPONENT("buttonRuler")),
1139 ui.toolno[ui.cur_mapping]<NUM_STROKE_TOOLS && ui.cur_brush->ruler);
1140 gtk_toggle_tool_button_set_active(
1141 GTK_TOGGLE_TOOL_BUTTON(GET_COMPONENT("buttonReco")),
1142 ui.toolno[ui.cur_mapping]<NUM_STROKE_TOOLS && ui.cur_brush->recognizer);
1143 gtk_check_menu_item_set_active(
1144 GTK_CHECK_MENU_ITEM(GET_COMPONENT("toolsRuler")),
1145 ui.toolno[0]<NUM_STROKE_TOOLS && ui.brushes[0][ui.toolno[0]].ruler);
1146 gtk_check_menu_item_set_active(
1147 GTK_CHECK_MENU_ITEM(GET_COMPONENT("toolsReco")),
1148 ui.toolno[0]<NUM_STROKE_TOOLS && ui.brushes[0][ui.toolno[0]].recognizer);
1149 }
1150
update_color_menu(void)1151 void update_color_menu(void)
1152 {
1153 if (ui.selection!=NULL || (ui.toolno[ui.cur_mapping] != TOOL_PEN
1154 && ui.toolno[ui.cur_mapping] != TOOL_HIGHLIGHTER && ui.toolno[ui.cur_mapping] != TOOL_TEXT)) {
1155 gtk_check_menu_item_set_active(
1156 GTK_CHECK_MENU_ITEM(GET_COMPONENT("colorNA")), TRUE);
1157 } else
1158 switch (ui.cur_brush->color_no) {
1159 case COLOR_BLACK:
1160 gtk_check_menu_item_set_active(
1161 GTK_CHECK_MENU_ITEM(GET_COMPONENT("colorBlack")), TRUE);
1162 break;
1163 case COLOR_BLUE:
1164 gtk_check_menu_item_set_active(
1165 GTK_CHECK_MENU_ITEM(GET_COMPONENT("colorBlue")), TRUE);
1166 break;
1167 case COLOR_RED:
1168 gtk_check_menu_item_set_active(
1169 GTK_CHECK_MENU_ITEM(GET_COMPONENT("colorRed")), TRUE);
1170 break;
1171 case COLOR_GREEN:
1172 gtk_check_menu_item_set_active(
1173 GTK_CHECK_MENU_ITEM(GET_COMPONENT("colorGreen")), TRUE);
1174 break;
1175 case COLOR_GRAY:
1176 gtk_check_menu_item_set_active(
1177 GTK_CHECK_MENU_ITEM(GET_COMPONENT("colorGray")), TRUE);
1178 break;
1179 case COLOR_LIGHTBLUE:
1180 gtk_check_menu_item_set_active(
1181 GTK_CHECK_MENU_ITEM(GET_COMPONENT("colorLightBlue")), TRUE);
1182 break;
1183 case COLOR_LIGHTGREEN:
1184 gtk_check_menu_item_set_active(
1185 GTK_CHECK_MENU_ITEM(GET_COMPONENT("colorLightGreen")), TRUE);
1186 break;
1187 case COLOR_MAGENTA:
1188 gtk_check_menu_item_set_active(
1189 GTK_CHECK_MENU_ITEM(GET_COMPONENT("colorMagenta")), TRUE);
1190 break;
1191 case COLOR_ORANGE:
1192 gtk_check_menu_item_set_active(
1193 GTK_CHECK_MENU_ITEM(GET_COMPONENT("colorOrange")), TRUE);
1194 break;
1195 case COLOR_YELLOW:
1196 gtk_check_menu_item_set_active(
1197 GTK_CHECK_MENU_ITEM(GET_COMPONENT("colorYellow")), TRUE);
1198 break;
1199 case COLOR_WHITE:
1200 gtk_check_menu_item_set_active(
1201 GTK_CHECK_MENU_ITEM(GET_COMPONENT("colorWhite")), TRUE);
1202 break;
1203 default:
1204 gtk_check_menu_item_set_active(
1205 GTK_CHECK_MENU_ITEM(GET_COMPONENT("colorNA")), TRUE);
1206 }
1207 }
1208
update_pen_props_menu(void)1209 void update_pen_props_menu(void)
1210 {
1211 switch(ui.brushes[0][TOOL_PEN].thickness_no) {
1212 case THICKNESS_VERYFINE:
1213 gtk_check_menu_item_set_active(
1214 GTK_CHECK_MENU_ITEM(GET_COMPONENT("penthicknessVeryFine")), TRUE);
1215 break;
1216 case THICKNESS_FINE:
1217 gtk_check_menu_item_set_active(
1218 GTK_CHECK_MENU_ITEM(GET_COMPONENT("penthicknessFine")), TRUE);
1219 break;
1220 case THICKNESS_MEDIUM:
1221 gtk_check_menu_item_set_active(
1222 GTK_CHECK_MENU_ITEM(GET_COMPONENT("penthicknessMedium")), TRUE);
1223 break;
1224 case THICKNESS_THICK:
1225 gtk_check_menu_item_set_active(
1226 GTK_CHECK_MENU_ITEM(GET_COMPONENT("penthicknessThick")), TRUE);
1227 break;
1228 case THICKNESS_VERYTHICK:
1229 gtk_check_menu_item_set_active(
1230 GTK_CHECK_MENU_ITEM(GET_COMPONENT("penthicknessVeryThick")), TRUE);
1231 break;
1232 }
1233 }
1234
update_eraser_props_menu(void)1235 void update_eraser_props_menu(void)
1236 {
1237 switch (ui.brushes[0][TOOL_ERASER].thickness_no) {
1238 case THICKNESS_FINE:
1239 gtk_check_menu_item_set_active(
1240 GTK_CHECK_MENU_ITEM(GET_COMPONENT("eraserFine")), TRUE);
1241 break;
1242 case THICKNESS_MEDIUM:
1243 gtk_check_menu_item_set_active(
1244 GTK_CHECK_MENU_ITEM(GET_COMPONENT("eraserMedium")), TRUE);
1245 break;
1246 case THICKNESS_THICK:
1247 gtk_check_menu_item_set_active(
1248 GTK_CHECK_MENU_ITEM(GET_COMPONENT("eraserThick")), TRUE);
1249 break;
1250 }
1251
1252 gtk_check_menu_item_set_active(
1253 GTK_CHECK_MENU_ITEM(GET_COMPONENT("eraserStandard")),
1254 ui.brushes[0][TOOL_ERASER].tool_options == TOOLOPT_ERASER_STANDARD);
1255 gtk_check_menu_item_set_active(
1256 GTK_CHECK_MENU_ITEM(GET_COMPONENT("eraserWhiteout")),
1257 ui.brushes[0][TOOL_ERASER].tool_options == TOOLOPT_ERASER_WHITEOUT);
1258 gtk_check_menu_item_set_active(
1259 GTK_CHECK_MENU_ITEM(GET_COMPONENT("eraserDeleteStrokes")),
1260 ui.brushes[0][TOOL_ERASER].tool_options == TOOLOPT_ERASER_STROKES);
1261 }
1262
update_highlighter_props_menu(void)1263 void update_highlighter_props_menu(void)
1264 {
1265 switch (ui.brushes[0][TOOL_HIGHLIGHTER].thickness_no) {
1266 case THICKNESS_FINE:
1267 gtk_check_menu_item_set_active(
1268 GTK_CHECK_MENU_ITEM(GET_COMPONENT("highlighterFine")), TRUE);
1269 break;
1270 case THICKNESS_MEDIUM:
1271 gtk_check_menu_item_set_active(
1272 GTK_CHECK_MENU_ITEM(GET_COMPONENT("highlighterMedium")), TRUE);
1273 break;
1274 case THICKNESS_THICK:
1275 gtk_check_menu_item_set_active(
1276 GTK_CHECK_MENU_ITEM(GET_COMPONENT("highlighterThick")), TRUE);
1277 break;
1278 }
1279 }
1280
update_mappings_menu_linkings(void)1281 void update_mappings_menu_linkings(void)
1282 {
1283 switch (ui.linked_brush[1]) {
1284 case BRUSH_LINKED:
1285 gtk_check_menu_item_set_active(
1286 GTK_CHECK_MENU_ITEM(GET_COMPONENT("button2LinkBrush")), TRUE);
1287 break;
1288 case BRUSH_COPIED:
1289 gtk_check_menu_item_set_active(
1290 GTK_CHECK_MENU_ITEM(GET_COMPONENT("button2CopyBrush")), TRUE);
1291 break;
1292 case BRUSH_STATIC:
1293 gtk_check_menu_item_set_active(
1294 GTK_CHECK_MENU_ITEM(GET_COMPONENT("button2NABrush")), TRUE);
1295 break;
1296 }
1297 switch (ui.linked_brush[2]) {
1298 case BRUSH_LINKED:
1299 gtk_check_menu_item_set_active(
1300 GTK_CHECK_MENU_ITEM(GET_COMPONENT("button3LinkBrush")), TRUE);
1301 break;
1302 case BRUSH_COPIED:
1303 gtk_check_menu_item_set_active(
1304 GTK_CHECK_MENU_ITEM(GET_COMPONENT("button3CopyBrush")), TRUE);
1305 break;
1306 case BRUSH_STATIC:
1307 gtk_check_menu_item_set_active(
1308 GTK_CHECK_MENU_ITEM(GET_COMPONENT("button3NABrush")), TRUE);
1309 break;
1310 }
1311 }
1312
update_mappings_menu(void)1313 void update_mappings_menu(void)
1314 {
1315 gtk_widget_set_sensitive(GET_COMPONENT("optionsButtonMappings"), ui.use_xinput);
1316 gtk_widget_set_sensitive(GET_COMPONENT("optionsPressureSensitive"), ui.use_xinput);
1317 gtk_widget_set_sensitive(GET_COMPONENT("optionsTouchAsHandTool"), ui.use_xinput);
1318 gtk_widget_set_sensitive(GET_COMPONENT("optionsPenDisablesTouch"), ui.use_xinput);
1319 gtk_widget_set_sensitive(GET_COMPONENT("optionsDesignateTouchscreen"), ui.use_xinput);
1320 gtk_check_menu_item_set_active(
1321 GTK_CHECK_MENU_ITEM(GET_COMPONENT("optionsButtonMappings")), ui.use_erasertip);
1322 gtk_check_menu_item_set_active(
1323 GTK_CHECK_MENU_ITEM(GET_COMPONENT("optionsTouchAsHandTool")), ui.touch_as_handtool);
1324 gtk_check_menu_item_set_active(
1325 GTK_CHECK_MENU_ITEM(GET_COMPONENT("optionsPenDisablesTouch")), ui.pen_disables_touch);
1326 gtk_check_menu_item_set_active(
1327 GTK_CHECK_MENU_ITEM(GET_COMPONENT("optionsPressureSensitive")), ui.pressure_sensitivity);
1328
1329 switch(ui.toolno[1]) {
1330 case TOOL_PEN:
1331 gtk_check_menu_item_set_active(
1332 GTK_CHECK_MENU_ITEM(GET_COMPONENT("button2Pen")), TRUE);
1333 break;
1334 case TOOL_ERASER:
1335 gtk_check_menu_item_set_active(
1336 GTK_CHECK_MENU_ITEM(GET_COMPONENT("button2Eraser")), TRUE);
1337 break;
1338 case TOOL_HIGHLIGHTER:
1339 gtk_check_menu_item_set_active(
1340 GTK_CHECK_MENU_ITEM(GET_COMPONENT("button2Highlighter")), TRUE);
1341 break;
1342 case TOOL_TEXT:
1343 gtk_check_menu_item_set_active(
1344 GTK_CHECK_MENU_ITEM(GET_COMPONENT("button2Text")), TRUE);
1345 break;
1346 case TOOL_IMAGE:
1347 gtk_check_menu_item_set_active(
1348 GTK_CHECK_MENU_ITEM(GET_COMPONENT("button2Image")), TRUE);
1349 break;
1350 case TOOL_SELECTREGION:
1351 gtk_check_menu_item_set_active(
1352 GTK_CHECK_MENU_ITEM(GET_COMPONENT("button2SelectRegion")), TRUE);
1353 break;
1354 case TOOL_SELECTRECT:
1355 gtk_check_menu_item_set_active(
1356 GTK_CHECK_MENU_ITEM(GET_COMPONENT("button2SelectRectangle")), TRUE);
1357 break;
1358 case TOOL_VERTSPACE:
1359 gtk_check_menu_item_set_active(
1360 GTK_CHECK_MENU_ITEM(GET_COMPONENT("button2VerticalSpace")), TRUE);
1361 break;
1362 }
1363 switch(ui.toolno[2]) {
1364 case TOOL_PEN:
1365 gtk_check_menu_item_set_active(
1366 GTK_CHECK_MENU_ITEM(GET_COMPONENT("button3Pen")), TRUE);
1367 break;
1368 case TOOL_ERASER:
1369 gtk_check_menu_item_set_active(
1370 GTK_CHECK_MENU_ITEM(GET_COMPONENT("button3Eraser")), TRUE);
1371 break;
1372 case TOOL_HIGHLIGHTER:
1373 gtk_check_menu_item_set_active(
1374 GTK_CHECK_MENU_ITEM(GET_COMPONENT("button3Highlighter")), TRUE);
1375 break;
1376 case TOOL_TEXT:
1377 gtk_check_menu_item_set_active(
1378 GTK_CHECK_MENU_ITEM(GET_COMPONENT("button3Text")), TRUE);
1379 break;
1380 case TOOL_IMAGE:
1381 gtk_check_menu_item_set_active(
1382 GTK_CHECK_MENU_ITEM(GET_COMPONENT("button3Image")), TRUE);
1383 break;
1384 case TOOL_SELECTREGION:
1385 gtk_check_menu_item_set_active(
1386 GTK_CHECK_MENU_ITEM(GET_COMPONENT("button3SelectRegion")), TRUE);
1387 break;
1388 case TOOL_SELECTRECT:
1389 gtk_check_menu_item_set_active(
1390 GTK_CHECK_MENU_ITEM(GET_COMPONENT("button3SelectRectangle")), TRUE);
1391 break;
1392 case TOOL_VERTSPACE:
1393 gtk_check_menu_item_set_active(
1394 GTK_CHECK_MENU_ITEM(GET_COMPONENT("button3VerticalSpace")), TRUE);
1395 break;
1396 }
1397 update_mappings_menu_linkings();
1398 }
1399
do_switch_page(int pg,gboolean rescroll,gboolean refresh_all)1400 void do_switch_page(int pg, gboolean rescroll, gboolean refresh_all)
1401 {
1402 int i, cx, cy;
1403 struct Layer *layer;
1404 GList *list;
1405
1406 ui.pageno = pg;
1407
1408 /* re-show all the layers of the old page */
1409 if (ui.cur_page != NULL)
1410 for (i=0, list = ui.cur_page->layers; list!=NULL; i++, list = list->next) {
1411 layer = (struct Layer *)list->data;
1412 if (layer->group!=NULL)
1413 gnome_canvas_item_show(GNOME_CANVAS_ITEM(layer->group));
1414 }
1415
1416 ui.cur_page = g_list_nth_data(journal.pages, ui.pageno);
1417 ui.layerno = ui.cur_page->nlayers-1;
1418 ui.cur_layer = (struct Layer *)(g_list_last(ui.cur_page->layers)->data);
1419 update_page_stuff();
1420 if (ui.progressive_bg) rescale_bg_pixmaps();
1421
1422 if (rescroll) { // scroll and force a refresh
1423 gnome_canvas_get_scroll_offsets(canvas, &cx, &cy);
1424 if (ui.view_continuous == VIEW_MODE_HORIZONTAL)
1425 cx = ui.cur_page->hoffset*ui.zoom;
1426 else
1427 cy = ui.cur_page->voffset*ui.zoom;
1428 gnome_canvas_scroll_to(canvas, cx, cy);
1429
1430 if (refresh_all)
1431 gnome_canvas_set_pixels_per_unit(canvas, ui.zoom);
1432 else if (!ui.view_continuous)
1433 gnome_canvas_item_move(GNOME_CANVAS_ITEM(ui.cur_page->group), 0., 0.);
1434 }
1435 }
1436
update_page_stuff(void)1437 void update_page_stuff(void)
1438 {
1439 gchar tmp[10];
1440 GtkComboBox *layerbox;
1441 int i;
1442 GList *pglist;
1443 GtkSpinButton *spin;
1444 struct Page *pg;
1445 double vertpos, maxwidth, horizpos, maxheight;
1446
1447 // move the page groups to their rightful locations or hide them
1448 if (ui.view_continuous == VIEW_MODE_CONTINUOUS) {
1449 vertpos = 0.;
1450 maxwidth = 0.;
1451 for (i=0, pglist = journal.pages; pglist!=NULL; i++, pglist = pglist->next) {
1452 pg = (struct Page *)pglist->data;
1453 if (pg->group!=NULL) {
1454 pg->hoffset = 0.; pg->voffset = vertpos;
1455 gnome_canvas_item_set(GNOME_CANVAS_ITEM(pg->group),
1456 "x", pg->hoffset, "y", pg->voffset, NULL);
1457 gnome_canvas_item_show(GNOME_CANVAS_ITEM(pg->group));
1458 }
1459 vertpos += pg->height + VIEW_CONTINUOUS_SKIP;
1460 if (pg->width > maxwidth) maxwidth = pg->width;
1461 }
1462 vertpos -= VIEW_CONTINUOUS_SKIP;
1463 gnome_canvas_set_scroll_region(canvas, 0, 0, maxwidth, vertpos);
1464 }
1465 else if (ui.view_continuous == VIEW_MODE_HORIZONTAL) {
1466 horizpos = 0.;
1467 maxheight = 0.;
1468 for (i=0, pglist = journal.pages; pglist!=NULL; i++, pglist = pglist->next) {
1469 pg = (struct Page *)pglist->data;
1470 if (pg->group!=NULL) {
1471 pg->hoffset = horizpos; pg->voffset = 0.;
1472 gnome_canvas_item_set(GNOME_CANVAS_ITEM(pg->group),
1473 "x", pg->hoffset, "y", pg->voffset, NULL);
1474 gnome_canvas_item_show(GNOME_CANVAS_ITEM(pg->group));
1475 }
1476 horizpos += pg->width + VIEW_CONTINUOUS_SKIP;
1477 if (pg->height > maxheight) maxheight = pg->height;
1478 }
1479 horizpos -= VIEW_CONTINUOUS_SKIP;
1480 gnome_canvas_set_scroll_region(canvas, 0, 0, horizpos, maxheight);
1481 }
1482 else { // VIEW_MODE_ONE_PAGE
1483 for (pglist = journal.pages; pglist!=NULL; pglist = pglist->next) {
1484 pg = (struct Page *)pglist->data;
1485 if (pg == ui.cur_page && pg->group!=NULL) {
1486 pg->hoffset = 0.; pg->voffset = 0.;
1487 gnome_canvas_item_set(GNOME_CANVAS_ITEM(pg->group),
1488 "x", pg->hoffset, "y", pg->voffset, NULL);
1489 gnome_canvas_item_show(GNOME_CANVAS_ITEM(pg->group));
1490 } else {
1491 if (pg->group!=NULL) gnome_canvas_item_hide(GNOME_CANVAS_ITEM(pg->group));
1492 }
1493 }
1494 gnome_canvas_set_scroll_region(canvas, 0, 0, ui.cur_page->width, ui.cur_page->height);
1495 }
1496
1497 // update the page / layer info at bottom of screen
1498
1499 spin = GTK_SPIN_BUTTON(GET_COMPONENT("spinPageNo"));
1500 ui.in_update_page_stuff = TRUE; // avoid a bad retroaction
1501 gtk_spin_button_set_range(spin, 1, journal.npages+1);
1502 /* npages+1 will be used to create a new page at end */
1503 gtk_spin_button_set_value(spin, ui.pageno+1);
1504 g_snprintf(tmp, 10, _(" of %d"), journal.npages);
1505 gtk_label_set_text(GTK_LABEL(GET_COMPONENT("labelNumpages")), tmp);
1506
1507 layerbox = GTK_COMBO_BOX(GET_COMPONENT("comboLayer"));
1508 if (ui.layerbox_length == 0) {
1509 gtk_combo_box_prepend_text(layerbox, _("Background"));
1510 ui.layerbox_length++;
1511 }
1512 while (ui.layerbox_length > ui.cur_page->nlayers+1) {
1513 gtk_combo_box_remove_text(layerbox, 0);
1514 ui.layerbox_length--;
1515 }
1516 while (ui.layerbox_length < ui.cur_page->nlayers+1) {
1517 g_snprintf(tmp, 10, _("Layer %d"), ui.layerbox_length++);
1518 gtk_combo_box_prepend_text(layerbox, tmp);
1519 }
1520 gtk_combo_box_set_active(layerbox, ui.cur_page->nlayers-1-ui.layerno);
1521 ui.in_update_page_stuff = FALSE;
1522
1523 gtk_container_forall(GTK_CONTAINER(layerbox), unset_flags, (gpointer)GTK_CAN_FOCUS);
1524
1525 // update the paper-style menu radio buttons
1526
1527 if (ui.view_continuous == VIEW_MODE_CONTINUOUS)
1528 gtk_check_menu_item_set_active(
1529 GTK_CHECK_MENU_ITEM(GET_COMPONENT("viewContinuous")), TRUE);
1530 else if (ui.view_continuous == VIEW_MODE_HORIZONTAL)
1531 gtk_check_menu_item_set_active(
1532 GTK_CHECK_MENU_ITEM(GET_COMPONENT("viewHorizontal")), TRUE);
1533 else
1534 gtk_check_menu_item_set_active(
1535 GTK_CHECK_MENU_ITEM(GET_COMPONENT("viewOnePage")), TRUE);
1536
1537 if (ui.cur_page->bg->type == BG_SOLID && !ui.bg_apply_all_pages) {
1538 switch (ui.cur_page->bg->color_no) {
1539 case COLOR_WHITE:
1540 gtk_check_menu_item_set_active(
1541 GTK_CHECK_MENU_ITEM(GET_COMPONENT("papercolorWhite")), TRUE);
1542 break;
1543 case COLOR_YELLOW:
1544 gtk_check_menu_item_set_active(
1545 GTK_CHECK_MENU_ITEM(GET_COMPONENT("papercolorYellow")), TRUE);
1546 break;
1547 case COLOR_RED:
1548 gtk_check_menu_item_set_active(
1549 GTK_CHECK_MENU_ITEM(GET_COMPONENT("papercolorPink")), TRUE);
1550 break;
1551 case COLOR_ORANGE:
1552 gtk_check_menu_item_set_active(
1553 GTK_CHECK_MENU_ITEM(GET_COMPONENT("papercolorOrange")), TRUE);
1554 break;
1555 case COLOR_BLUE:
1556 gtk_check_menu_item_set_active(
1557 GTK_CHECK_MENU_ITEM(GET_COMPONENT("papercolorBlue")), TRUE);
1558 break;
1559 case COLOR_GREEN:
1560 gtk_check_menu_item_set_active(
1561 GTK_CHECK_MENU_ITEM(GET_COMPONENT("papercolorGreen")), TRUE);
1562 break;
1563 default:
1564 gtk_check_menu_item_set_active(
1565 GTK_CHECK_MENU_ITEM(GET_COMPONENT("papercolorNA")), TRUE);
1566 break;
1567 }
1568 switch (ui.cur_page->bg->ruling) {
1569 case RULING_NONE:
1570 gtk_check_menu_item_set_active(
1571 GTK_CHECK_MENU_ITEM(GET_COMPONENT("paperstylePlain")), TRUE);
1572 break;
1573 case RULING_LINED:
1574 gtk_check_menu_item_set_active(
1575 GTK_CHECK_MENU_ITEM(GET_COMPONENT("paperstyleLined")), TRUE);
1576 break;
1577 case RULING_RULED:
1578 gtk_check_menu_item_set_active(
1579 GTK_CHECK_MENU_ITEM(GET_COMPONENT("paperstyleRuled")), TRUE);
1580 break;
1581 case RULING_GRAPH:
1582 gtk_check_menu_item_set_active(
1583 GTK_CHECK_MENU_ITEM(GET_COMPONENT("paperstyleGraph")), TRUE);
1584 break;
1585 }
1586 } else {
1587 gtk_check_menu_item_set_active(
1588 GTK_CHECK_MENU_ITEM(GET_COMPONENT("papercolorNA")), TRUE);
1589 gtk_check_menu_item_set_active(
1590 GTK_CHECK_MENU_ITEM(GET_COMPONENT("paperstyleNA")), TRUE);
1591 }
1592
1593 // enable/disable the page/layer menu items and toolbar buttons
1594
1595 gtk_widget_set_sensitive(GET_COMPONENT("journalPaperColor"),
1596 ui.cur_page->bg->type == BG_SOLID || ui.bg_apply_all_pages);
1597 gtk_widget_set_sensitive(GET_COMPONENT("journalSetAsDefault"),
1598 ui.cur_page->bg->type == BG_SOLID);
1599
1600 gtk_widget_set_sensitive(GET_COMPONENT("viewFirstPage"), ui.pageno!=0);
1601 gtk_widget_set_sensitive(GET_COMPONENT("viewPreviousPage"), ui.pageno!=0);
1602 gtk_widget_set_sensitive(GET_COMPONENT("viewNextPage"), TRUE);
1603 gtk_widget_set_sensitive(GET_COMPONENT("viewLastPage"), ui.pageno!=journal.npages-1);
1604 gtk_widget_set_sensitive(GET_COMPONENT("buttonFirstPage"), ui.pageno!=0);
1605 gtk_widget_set_sensitive(GET_COMPONENT("buttonPreviousPage"), ui.pageno!=0);
1606 gtk_widget_set_sensitive(GET_COMPONENT("buttonNextPage"), TRUE);
1607 gtk_widget_set_sensitive(GET_COMPONENT("buttonLastPage"), ui.pageno!=journal.npages-1);
1608
1609 gtk_widget_set_sensitive(GET_COMPONENT("viewShowLayer"), ui.layerno!=ui.cur_page->nlayers-1);
1610 gtk_widget_set_sensitive(GET_COMPONENT("viewHideLayer"), ui.layerno>=0);
1611
1612 gtk_widget_set_sensitive(GET_COMPONENT("editPaste"), ui.cur_layer!=NULL);
1613 gtk_widget_set_sensitive(GET_COMPONENT("buttonPaste"), ui.cur_layer!=NULL);
1614 }
1615
update_toolbar_and_menu(void)1616 void update_toolbar_and_menu(void)
1617 {
1618 update_tool_buttons(); // takes care of other toolbar buttons as well
1619 update_tool_menu();
1620 update_color_menu();
1621 update_pen_props_menu();
1622 update_eraser_props_menu();
1623 update_highlighter_props_menu();
1624 update_mappings_menu();
1625
1626 gtk_toggle_tool_button_set_active(
1627 GTK_TOGGLE_TOOL_BUTTON(GET_COMPONENT("buttonFullscreen")), ui.fullscreen);
1628 gtk_check_menu_item_set_active(
1629 GTK_CHECK_MENU_ITEM(GET_COMPONENT("viewFullscreen")), ui.fullscreen);
1630 }
1631
update_file_name(char * filename)1632 void update_file_name(char *filename)
1633 {
1634 gchar tmp[100], *p;
1635 if (ui.filename != NULL) g_free(ui.filename);
1636 ui.filename = filename;
1637 if (filename == NULL) {
1638 gtk_window_set_title(GTK_WINDOW (winMain), _("Xournal"));
1639 return;
1640 }
1641 p = xo_basename(filename, FALSE);
1642 g_snprintf(tmp, 100, _("Xournal - %s"), p);
1643 gtk_window_set_title(GTK_WINDOW (winMain), tmp);
1644 new_mru_entry(filename);
1645
1646 if (p!=filename) {
1647 if (ui.default_path!=NULL) g_free(ui.default_path);
1648 ui.default_path = g_path_get_dirname(filename);
1649 }
1650 }
1651
update_undo_redo_enabled(void)1652 void update_undo_redo_enabled(void)
1653 {
1654 gtk_widget_set_sensitive(GET_COMPONENT("editUndo"), undo!=NULL);
1655 gtk_widget_set_sensitive(GET_COMPONENT("editRedo"), redo!=NULL);
1656 gtk_widget_set_sensitive(GET_COMPONENT("buttonUndo"), undo!=NULL);
1657 gtk_widget_set_sensitive(GET_COMPONENT("buttonRedo"), redo!=NULL);
1658 }
1659
update_copy_paste_enabled(void)1660 void update_copy_paste_enabled(void)
1661 {
1662 gtk_widget_set_sensitive(GET_COMPONENT("editCut"), ui.selection!=NULL);
1663 gtk_widget_set_sensitive(GET_COMPONENT("editCopy"), ui.selection!=NULL);
1664 gtk_widget_set_sensitive(GET_COMPONENT("editPaste"), ui.cur_item_type!=ITEM_TEXT);
1665 gtk_widget_set_sensitive(GET_COMPONENT("editDelete"), ui.selection!=NULL);
1666 gtk_widget_set_sensitive(GET_COMPONENT("buttonCut"), ui.selection!=NULL);
1667 gtk_widget_set_sensitive(GET_COMPONENT("buttonCopy"), ui.selection!=NULL);
1668 gtk_widget_set_sensitive(GET_COMPONENT("buttonPaste"), ui.cur_item_type!=ITEM_TEXT);
1669 }
1670
update_mapping_linkings(int toolno)1671 void update_mapping_linkings(int toolno)
1672 {
1673 int i;
1674
1675 for (i = 1; i<=NUM_BUTTONS; i++) {
1676 if (ui.linked_brush[i] == BRUSH_LINKED) {
1677 if (toolno >= 0 && toolno < NUM_STROKE_TOOLS)
1678 g_memmove(&(ui.brushes[i][toolno]), &(ui.brushes[0][toolno]), sizeof(struct Brush));
1679 }
1680 if (ui.linked_brush[i] == BRUSH_COPIED && toolno == ui.toolno[i]) {
1681 ui.linked_brush[i] = BRUSH_STATIC;
1682 if (i==1 || i==2) update_mappings_menu_linkings();
1683 }
1684 }
1685 }
1686
set_cur_color(int color_no,guint color_rgba)1687 void set_cur_color(int color_no, guint color_rgba)
1688 {
1689 int which_mapping, tool;
1690
1691 if (ui.toolno[ui.cur_mapping] == TOOL_HIGHLIGHTER) tool = TOOL_HIGHLIGHTER;
1692 else tool = TOOL_PEN;
1693 if (ui.cur_mapping>0 && ui.linked_brush[ui.cur_mapping]!=BRUSH_LINKED)
1694 which_mapping = ui.cur_mapping;
1695 else which_mapping = 0;
1696
1697 ui.brushes[which_mapping][tool].color_no = color_no;
1698 if (tool == TOOL_HIGHLIGHTER && (color_rgba & 0xff) == 0xff)
1699 ui.brushes[which_mapping][tool].color_rgba = color_rgba & ui.hiliter_alpha_mask;
1700 else
1701 ui.brushes[which_mapping][tool].color_rgba = color_rgba;
1702 update_mapping_linkings(tool);
1703 }
1704
recolor_temp_text(int color_no,guint color_rgba)1705 void recolor_temp_text(int color_no, guint color_rgba)
1706 {
1707 GdkColor gdkcolor;
1708
1709 if (ui.cur_item_type!=ITEM_TEXT) return;
1710 if (ui.cur_item->text!=NULL && ui.cur_item->brush.color_rgba != color_rgba) {
1711 prepare_new_undo();
1712 undo->type = ITEM_TEXT_ATTRIB;
1713 undo->item = ui.cur_item;
1714 undo->str = g_strdup(ui.cur_item->font_name);
1715 undo->val_x = ui.cur_item->font_size;
1716 undo->brush = (struct Brush *)g_memdup(&(ui.cur_item->brush), sizeof(struct Brush));
1717 }
1718 ui.cur_item->brush.color_no = color_no;
1719 ui.cur_item->brush.color_rgba = color_rgba;
1720 rgb_to_gdkcolor(color_rgba, &gdkcolor);
1721 gtk_widget_modify_text(ui.cur_item->widget, GTK_STATE_NORMAL, &gdkcolor);
1722 gtk_widget_grab_focus(ui.cur_item->widget);
1723 }
1724
process_color_activate(GtkMenuItem * menuitem,int color_no,guint color_rgba)1725 void process_color_activate(GtkMenuItem *menuitem, int color_no, guint color_rgba)
1726 {
1727 if (GTK_OBJECT_TYPE(menuitem) == GTK_TYPE_RADIO_MENU_ITEM) {
1728 if (!gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM (menuitem)))
1729 return;
1730 }
1731 else if (GTK_OBJECT_TYPE(menuitem) == GTK_TYPE_RADIO_TOOL_BUTTON) {
1732 if (!gtk_toggle_tool_button_get_active(GTK_TOGGLE_TOOL_BUTTON (menuitem)))
1733 return;
1734 }
1735
1736 if (ui.cur_mapping != 0 && !ui.button_switch_mapping) return; // not user-generated
1737
1738 if (ui.cur_item_type == ITEM_TEXT)
1739 recolor_temp_text(color_no, color_rgba);
1740
1741 if (ui.selection != NULL) {
1742 recolor_selection(color_no, color_rgba);
1743 update_color_buttons();
1744 update_color_menu();
1745 }
1746
1747 if (ui.toolno[ui.cur_mapping] != TOOL_PEN && ui.toolno[ui.cur_mapping] != TOOL_HIGHLIGHTER
1748 && ui.toolno[ui.cur_mapping] != TOOL_TEXT) {
1749 if (ui.selection != NULL) return;
1750 ui.cur_mapping = 0;
1751 end_text();
1752 ui.toolno[ui.cur_mapping] = TOOL_PEN;
1753 ui.cur_brush = &(ui.brushes[ui.cur_mapping][TOOL_PEN]);
1754 update_tool_buttons();
1755 update_tool_menu();
1756 }
1757
1758 set_cur_color(color_no, color_rgba);
1759 update_color_buttons();
1760 update_color_menu();
1761 update_cursor();
1762 }
1763
process_thickness_activate(GtkMenuItem * menuitem,int tool,int val)1764 void process_thickness_activate(GtkMenuItem *menuitem, int tool, int val)
1765 {
1766 int which_mapping;
1767
1768 if (GTK_OBJECT_TYPE(menuitem) == GTK_TYPE_RADIO_MENU_ITEM) {
1769 if (!gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM (menuitem)))
1770 return;
1771 } else {
1772 if (!gtk_toggle_tool_button_get_active(GTK_TOGGLE_TOOL_BUTTON (menuitem)))
1773 return;
1774 }
1775
1776 if (ui.cur_mapping != 0 && !ui.button_switch_mapping) return; // not user-generated
1777
1778 if (ui.selection != NULL && GTK_OBJECT_TYPE(menuitem) != GTK_TYPE_RADIO_MENU_ITEM) {
1779 rethicken_selection(val);
1780 update_thickness_buttons();
1781 }
1782
1783 if (tool >= NUM_STROKE_TOOLS) {
1784 update_thickness_buttons(); // undo illegal button selection
1785 return;
1786 }
1787
1788 if (ui.cur_mapping>0 && ui.linked_brush[ui.cur_mapping]!=BRUSH_LINKED)
1789 which_mapping = ui.cur_mapping;
1790 else which_mapping = 0;
1791 if (ui.brushes[which_mapping][tool].thickness_no == val) return;
1792 end_text();
1793 ui.brushes[which_mapping][tool].thickness_no = val;
1794 ui.brushes[which_mapping][tool].thickness = predef_thickness[tool][val];
1795 update_mapping_linkings(tool);
1796
1797 update_thickness_buttons();
1798 if (tool == TOOL_PEN) update_pen_props_menu();
1799 if (tool == TOOL_ERASER) update_eraser_props_menu();
1800 if (tool == TOOL_HIGHLIGHTER) update_highlighter_props_menu();
1801 update_cursor();
1802 }
1803
process_papercolor_activate(GtkMenuItem * menuitem,int color,guint rgba)1804 void process_papercolor_activate(GtkMenuItem *menuitem, int color, guint rgba)
1805 {
1806 struct Page *pg;
1807 GList *pglist;
1808 gboolean hasdone;
1809
1810 if (GTK_OBJECT_TYPE(menuitem) == GTK_TYPE_RADIO_MENU_ITEM) {
1811 if (!gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM (menuitem)))
1812 return;
1813 }
1814
1815 if ((ui.cur_page->bg->type != BG_SOLID) || ui.bg_apply_all_pages || color == COLOR_OTHER)
1816 gtk_check_menu_item_set_active(
1817 GTK_CHECK_MENU_ITEM(GET_COMPONENT("papercolorNA")), TRUE);
1818
1819 pg = ui.cur_page;
1820 hasdone = FALSE;
1821 for (pglist = journal.pages; pglist!=NULL; pglist = pglist->next) {
1822 if (ui.bg_apply_all_pages) pg = (struct Page *)pglist->data;
1823 if (pg->bg->type == BG_SOLID && pg->bg->color_rgba != rgba) {
1824 prepare_new_undo();
1825 if (hasdone) undo->multiop |= MULTIOP_CONT_UNDO;
1826 undo->multiop |= MULTIOP_CONT_REDO;
1827 hasdone = TRUE;
1828 undo->type = ITEM_NEW_BG_ONE;
1829 undo->page = pg;
1830 undo->bg = (struct Background *)g_memdup(pg->bg, sizeof(struct Background));
1831 undo->bg->canvas_item = NULL;
1832
1833 pg->bg->color_no = color;
1834 pg->bg->color_rgba = rgba;
1835 update_canvas_bg(pg);
1836 }
1837 if (!ui.bg_apply_all_pages) break;
1838 }
1839 if (hasdone) undo->multiop -= MULTIOP_CONT_REDO;
1840 }
1841
process_paperstyle_activate(GtkMenuItem * menuitem,int style)1842 void process_paperstyle_activate(GtkMenuItem *menuitem, int style)
1843 {
1844 struct Page *pg;
1845 GList *pglist;
1846 gboolean hasdone, must_upd;
1847
1848 if (!gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM (menuitem)))
1849 return;
1850
1851 if (ui.bg_apply_all_pages)
1852 gtk_check_menu_item_set_active(
1853 GTK_CHECK_MENU_ITEM(GET_COMPONENT("paperstyleNA")), TRUE);
1854
1855 pg = ui.cur_page;
1856 hasdone = FALSE;
1857 must_upd = FALSE;
1858 for (pglist = journal.pages; pglist!=NULL; pglist = pglist->next) {
1859 if (ui.bg_apply_all_pages) pg = (struct Page *)pglist->data;
1860 if (pg->bg->type != BG_SOLID || pg->bg->ruling != style) {
1861 prepare_new_undo();
1862 undo->type = ITEM_NEW_BG_ONE;
1863 if (hasdone) undo->multiop |= MULTIOP_CONT_UNDO;
1864 undo->multiop |= MULTIOP_CONT_REDO;
1865 hasdone = TRUE;
1866 undo->page = pg;
1867 undo->bg = (struct Background *)g_memdup(pg->bg, sizeof(struct Background));
1868 undo->bg->canvas_item = NULL;
1869
1870 if (pg->bg->type != BG_SOLID) {
1871 pg->bg->type = BG_SOLID;
1872 pg->bg->color_no = COLOR_WHITE;
1873 pg->bg->color_rgba = predef_bgcolors_rgba[COLOR_WHITE];
1874 pg->bg->filename = NULL;
1875 pg->bg->pixbuf = NULL;
1876 must_upd = TRUE;
1877 }
1878 pg->bg->ruling = style;
1879 update_canvas_bg(pg);
1880 }
1881 if (!ui.bg_apply_all_pages) break;
1882 }
1883 if (hasdone) undo->multiop -= MULTIOP_CONT_REDO;
1884 if (must_upd) update_page_stuff();
1885 }
1886
1887 #ifndef GTK_STOCK_DISCARD
1888 #define GTK_STOCK_DISCARD GTK_STOCK_NO
1889 #endif
1890
ok_to_close(void)1891 gboolean ok_to_close(void)
1892 {
1893 GtkWidget *dialog;
1894 GtkResponseType response;
1895
1896 if (ui.saved) return TRUE;
1897 dialog = gtk_message_dialog_new(GTK_WINDOW (winMain), GTK_DIALOG_DESTROY_WITH_PARENT,
1898 GTK_MESSAGE_WARNING, GTK_BUTTONS_NONE, _("Save changes to '%s'?"),
1899 (ui.filename!=NULL) ? ui.filename:_("Untitled"));
1900 gtk_dialog_add_button(GTK_DIALOG (dialog), GTK_STOCK_DISCARD, GTK_RESPONSE_NO);
1901 gtk_dialog_add_button(GTK_DIALOG (dialog), GTK_STOCK_SAVE, GTK_RESPONSE_YES);
1902 gtk_dialog_add_button(GTK_DIALOG (dialog), GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL);
1903 gtk_dialog_set_default_response(GTK_DIALOG (dialog), GTK_RESPONSE_YES);
1904 response = wrapper_gtk_dialog_run(GTK_DIALOG (dialog));
1905 gtk_widget_destroy(dialog);
1906 if (response == GTK_RESPONSE_CANCEL || response == GTK_RESPONSE_DELETE_EVENT)
1907 return FALSE; // aborted
1908 if (response == GTK_RESPONSE_YES) {
1909 on_fileSave_activate(NULL, NULL);
1910 if (!ui.saved) return FALSE; // if save failed, then we abort
1911 }
1912 return TRUE;
1913 }
1914
1915 // send the focus back to the appropriate widget
1916
reset_focus(void)1917 void reset_focus(void)
1918 {
1919 if (ui.cur_item_type == ITEM_TEXT)
1920 gtk_widget_grab_focus(ui.cur_item->widget);
1921 else
1922 gtk_widget_grab_focus(GTK_WIDGET(canvas));
1923 }
1924
1925 // selection / clipboard stuff
1926
reset_selection(void)1927 void reset_selection(void)
1928 {
1929 if (ui.selection == NULL) return;
1930 if (ui.selection->canvas_item != NULL)
1931 gtk_object_destroy(GTK_OBJECT(ui.selection->canvas_item));
1932 g_list_free(ui.selection->items);
1933 g_free(ui.selection);
1934 ui.selection = NULL;
1935 update_copy_paste_enabled();
1936 update_color_menu();
1937 update_thickness_buttons();
1938 update_color_buttons();
1939 update_font_button();
1940 update_cursor();
1941 }
1942
move_journal_items_by(GList * itemlist,double dx,double dy,struct Layer * l1,struct Layer * l2,GList * depths)1943 void move_journal_items_by(GList *itemlist, double dx, double dy,
1944 struct Layer *l1, struct Layer *l2, GList *depths)
1945 {
1946 struct Item *item;
1947 GnomeCanvasItem *refitem;
1948 GList *link;
1949 int i;
1950 double *pt;
1951
1952 while (itemlist!=NULL) {
1953 item = (struct Item *)itemlist->data;
1954 if (item->type == ITEM_STROKE)
1955 for (pt=item->path->coords, i=0; i<item->path->num_points; i++, pt+=2)
1956 { pt[0] += dx; pt[1] += dy; }
1957 if (item->type == ITEM_STROKE || item->type == ITEM_TEXT ||
1958 item->type == ITEM_TEMP_TEXT || item->type == ITEM_IMAGE) {
1959 item->bbox.left += dx;
1960 item->bbox.right += dx;
1961 item->bbox.top += dy;
1962 item->bbox.bottom += dy;
1963 }
1964 if (l1 != l2) {
1965 // find out where to insert
1966 if (depths != NULL) {
1967 if (depths->data == NULL) link = l2->items;
1968 else {
1969 link = g_list_find(l2->items, depths->data);
1970 if (link != NULL) link = link->next;
1971 }
1972 } else link = NULL;
1973 l2->items = g_list_insert_before(l2->items, link, item);
1974 l2->nitems++;
1975 l1->items = g_list_remove(l1->items, item);
1976 l1->nitems--;
1977 }
1978 if (depths != NULL) { // also raise/lower the canvas items
1979 if (item->canvas_item!=NULL) {
1980 if (depths->data == NULL) link = NULL;
1981 else link = g_list_find(l2->items, depths->data);
1982 if (link != NULL) refitem = ((struct Item *)(link->data))->canvas_item;
1983 else refitem = NULL;
1984 lower_canvas_item_to(l2->group, item->canvas_item, refitem);
1985 }
1986 depths = depths->next;
1987 }
1988 itemlist = itemlist->next;
1989 }
1990 }
1991
resize_journal_items_by(GList * itemlist,double scaling_x,double scaling_y,double offset_x,double offset_y)1992 void resize_journal_items_by(GList *itemlist, double scaling_x, double scaling_y,
1993 double offset_x, double offset_y)
1994 {
1995 struct Item *item;
1996 GList *list;
1997 double mean_scaling, temp;
1998 double *pt, *wid;
1999 GnomeCanvasGroup *group;
2000 int i;
2001
2002 /* geometric mean of x and y scalings = rescaling for stroke widths
2003 and for text font sizes */
2004 mean_scaling = sqrt(fabs(scaling_x * scaling_y));
2005
2006 for (list = itemlist; list != NULL; list = list->next) {
2007 item = (struct Item *)list->data;
2008 if (item->type == ITEM_STROKE) {
2009 item->brush.thickness = item->brush.thickness * mean_scaling;
2010 for (i=0, pt=item->path->coords; i<item->path->num_points; i++, pt+=2) {
2011 pt[0] = pt[0]*scaling_x + offset_x;
2012 pt[1] = pt[1]*scaling_y + offset_y;
2013 }
2014 if (item->brush.variable_width)
2015 for (i=0, wid=item->widths; i<item->path->num_points-1; i++, wid++)
2016 *wid = *wid * mean_scaling;
2017
2018 item->bbox.left = item->bbox.left*scaling_x + offset_x;
2019 item->bbox.right = item->bbox.right*scaling_x + offset_x;
2020 item->bbox.top = item->bbox.top*scaling_y + offset_y;
2021 item->bbox.bottom = item->bbox.bottom*scaling_y + offset_y;
2022 if (item->bbox.left > item->bbox.right) {
2023 temp = item->bbox.left;
2024 item->bbox.left = item->bbox.right;
2025 item->bbox.right = temp;
2026 }
2027 if (item->bbox.top > item->bbox.bottom) {
2028 temp = item->bbox.top;
2029 item->bbox.top = item->bbox.bottom;
2030 item->bbox.bottom = temp;
2031 }
2032 }
2033 if (item->type == ITEM_TEXT) {
2034 /* must scale about NW corner -- all other points of the text box
2035 are font- and zoom-dependent, so scaling about center of text box
2036 couldn't be undone properly. FIXME? */
2037 item->font_size *= mean_scaling;
2038 item->bbox.left = item->bbox.left*scaling_x + offset_x;
2039 item->bbox.top = item->bbox.top*scaling_y + offset_y;
2040 }
2041 if (item->type == ITEM_IMAGE) {
2042 item->bbox.left = item->bbox.left*scaling_x + offset_x;
2043 item->bbox.right = item->bbox.right*scaling_x + offset_x;
2044 item->bbox.top = item->bbox.top*scaling_y + offset_y;
2045 item->bbox.bottom = item->bbox.bottom*scaling_y + offset_y;
2046 if (item->bbox.left > item->bbox.right) {
2047 temp = item->bbox.left;
2048 item->bbox.left = item->bbox.right;
2049 item->bbox.right = temp;
2050 }
2051 if (item->bbox.top > item->bbox.bottom) {
2052 temp = item->bbox.top;
2053 item->bbox.top = item->bbox.bottom;
2054 item->bbox.bottom = temp;
2055 }
2056 }
2057 // redraw the item
2058 if (item->canvas_item!=NULL) {
2059 group = (GnomeCanvasGroup *) item->canvas_item->parent;
2060 gtk_object_destroy(GTK_OBJECT(item->canvas_item));
2061 make_canvas_item_one(group, item);
2062 }
2063 }
2064 }
2065
2066 // Switch between button mappings
2067
2068 /* NOTE ABOUT BUTTON MAPPINGS: ui.cur_mapping is 0 except while a canvas
2069 click event is being processed ... or if ui.button_switch_mapping is
2070 enabled and mappings are switched (but even then, canvas should have
2071 a pointer grab from the initial click that switched the mapping) */
2072
switch_mapping(int m)2073 void switch_mapping(int m)
2074 {
2075 if (ui.cur_mapping == m) return;
2076
2077 ui.cur_mapping = m;
2078 if (ui.toolno[m] < NUM_STROKE_TOOLS)
2079 ui.cur_brush = &(ui.brushes[m][ui.toolno[m]]);
2080 if (ui.toolno[m] == TOOL_TEXT)
2081 ui.cur_brush = &(ui.brushes[m][TOOL_PEN]);
2082 if (m==0) ui.which_unswitch_button = 0;
2083
2084 update_tool_buttons();
2085 update_color_menu();
2086 update_cursor();
2087 }
2088
process_mapping_activate(GtkMenuItem * menuitem,int m,int tool)2089 void process_mapping_activate(GtkMenuItem *menuitem, int m, int tool)
2090 {
2091 if (!gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(menuitem))) return;
2092 if (ui.cur_mapping!=0 && !ui.button_switch_mapping) return;
2093 if (ui.toolno[m] == tool) return;
2094 switch_mapping(0);
2095 end_text();
2096
2097 ui.toolno[m] = tool;
2098 if (ui.linked_brush[m] == BRUSH_COPIED) {
2099 ui.linked_brush[m] = BRUSH_STATIC;
2100 update_mappings_menu_linkings();
2101 }
2102 }
2103
2104 // update the ordering of components in the main vbox
2105
2106 const char *vbox_component_names[VBOX_MAIN_NITEMS]=
2107 {"scrolledwindowMain", "menubar", "toolbarMain", "toolbarPen", "hbox1"};
2108
update_vbox_order(int * order)2109 void update_vbox_order(int *order)
2110 {
2111 int i, j;
2112 GtkWidget *child;
2113 GtkBox *vboxMain = GTK_BOX(GET_COMPONENT("vboxMain"));
2114 gboolean present[VBOX_MAIN_NITEMS];
2115
2116 for (i=0; i<VBOX_MAIN_NITEMS; i++) present[i] = FALSE;
2117 j=0;
2118 for (i=0; i<VBOX_MAIN_NITEMS; i++) {
2119 if (order[i]<0 || order[i]>=VBOX_MAIN_NITEMS) continue;
2120 present[order[i]] = TRUE;
2121 child = GET_COMPONENT(vbox_component_names[order[i]]);
2122 gtk_box_reorder_child(vboxMain, child, j++);
2123 gtk_widget_show(child);
2124 }
2125 for (i=1; i<VBOX_MAIN_NITEMS; i++) // hide others, but not the drawing area!
2126 if (!present[i]) gtk_widget_hide(GET_COMPONENT(vbox_component_names[i]));
2127 }
2128
make_cur_font_name(void)2129 gchar *make_cur_font_name(void)
2130 {
2131 gchar *str;
2132 struct Item *it;
2133
2134 if (ui.cur_item_type == ITEM_TEXT)
2135 str = g_strdup_printf("%s %.1f", ui.cur_item->font_name, ui.cur_item->font_size);
2136 else if (ui.selection!=NULL && ui.selection->items!=NULL &&
2137 ui.selection->items->next==NULL &&
2138 (it=(struct Item*)ui.selection->items->data)->type == ITEM_TEXT)
2139 str = g_strdup_printf("%s %.1f", it->font_name, it->font_size);
2140 else
2141 str = g_strdup_printf("%s %.1f", ui.font_name, ui.font_size);
2142 return str;
2143 }
2144
update_font_button(void)2145 void update_font_button(void)
2146 {
2147 gchar *str;
2148
2149 str = make_cur_font_name();
2150 gtk_font_button_set_font_name(GTK_FONT_BUTTON(GET_COMPONENT("fontButton")), str);
2151 g_free(str);
2152 }
2153
can_accel(GtkWidget * widget,guint id,gpointer data)2154 gboolean can_accel(GtkWidget *widget, guint id, gpointer data)
2155 {
2156 return GTK_WIDGET_SENSITIVE(widget);
2157 }
2158
can_accel_except_text(GtkWidget * widget,guint id,gpointer data)2159 gboolean can_accel_except_text(GtkWidget *widget, guint id, gpointer data)
2160 {
2161 if (ui.cur_item_type == ITEM_TEXT) {
2162 g_signal_stop_emission_by_name(widget, "can-activate-accel");
2163 return FALSE;
2164 }
2165 return GTK_WIDGET_SENSITIVE(widget);
2166 }
2167
allow_all_accels(void)2168 void allow_all_accels(void)
2169 {
2170 g_signal_connect((gpointer) GET_COMPONENT("fileNew"),
2171 "can-activate-accel", G_CALLBACK(can_accel), NULL);
2172 g_signal_connect((gpointer) GET_COMPONENT("fileOpen"),
2173 "can-activate-accel", G_CALLBACK(can_accel), NULL);
2174 g_signal_connect((gpointer) GET_COMPONENT("fileSave"),
2175 "can-activate-accel", G_CALLBACK(can_accel), NULL);
2176 g_signal_connect((gpointer) GET_COMPONENT("filePrint"),
2177 "can-activate-accel", G_CALLBACK(can_accel), NULL);
2178 g_signal_connect((gpointer) GET_COMPONENT("filePrintPDF"),
2179 "can-activate-accel", G_CALLBACK(can_accel), NULL);
2180 g_signal_connect((gpointer) GET_COMPONENT("fileQuit"),
2181 "can-activate-accel", G_CALLBACK(can_accel), NULL);
2182 g_signal_connect((gpointer) GET_COMPONENT("editUndo"),
2183 "can-activate-accel", G_CALLBACK(can_accel), NULL);
2184 g_signal_connect((gpointer) GET_COMPONENT("editRedo"),
2185 "can-activate-accel", G_CALLBACK(can_accel), NULL);
2186 g_signal_connect((gpointer) GET_COMPONENT("editCut"),
2187 "can-activate-accel", G_CALLBACK(can_accel), NULL);
2188 g_signal_connect((gpointer) GET_COMPONENT("editCopy"),
2189 "can-activate-accel", G_CALLBACK(can_accel), NULL);
2190 g_signal_connect((gpointer) GET_COMPONENT("editPaste"),
2191 "can-activate-accel", G_CALLBACK(can_accel), NULL);
2192 g_signal_connect((gpointer) GET_COMPONENT("editDelete"),
2193 "can-activate-accel", G_CALLBACK(can_accel), NULL);
2194 g_signal_connect((gpointer) GET_COMPONENT("viewFullscreen"),
2195 "can-activate-accel", G_CALLBACK(can_accel), NULL);
2196 g_signal_connect((gpointer) GET_COMPONENT("viewZoomIn"),
2197 "can-activate-accel", G_CALLBACK(can_accel), NULL);
2198 g_signal_connect((gpointer) GET_COMPONENT("viewZoomOut"),
2199 "can-activate-accel", G_CALLBACK(can_accel), NULL);
2200 g_signal_connect((gpointer) GET_COMPONENT("viewNormalSize"),
2201 "can-activate-accel", G_CALLBACK(can_accel), NULL);
2202 g_signal_connect((gpointer) GET_COMPONENT("viewPageWidth"),
2203 "can-activate-accel", G_CALLBACK(can_accel), NULL);
2204 g_signal_connect((gpointer) GET_COMPONENT("viewFirstPage"),
2205 "can-activate-accel", G_CALLBACK(can_accel), NULL);
2206 g_signal_connect((gpointer) GET_COMPONENT("viewPreviousPage"),
2207 "can-activate-accel", G_CALLBACK(can_accel_except_text), NULL);
2208 g_signal_connect((gpointer) GET_COMPONENT("viewNextPage"),
2209 "can-activate-accel", G_CALLBACK(can_accel_except_text), NULL);
2210 g_signal_connect((gpointer) GET_COMPONENT("viewLastPage"),
2211 "can-activate-accel", G_CALLBACK(can_accel), NULL);
2212 g_signal_connect((gpointer) GET_COMPONENT("toolsPen"),
2213 "can-activate-accel", G_CALLBACK(can_accel), NULL);
2214 g_signal_connect((gpointer) GET_COMPONENT("toolsEraser"),
2215 "can-activate-accel", G_CALLBACK(can_accel), NULL);
2216 g_signal_connect((gpointer) GET_COMPONENT("toolsHighlighter"),
2217 "can-activate-accel", G_CALLBACK(can_accel), NULL);
2218 g_signal_connect((gpointer) GET_COMPONENT("toolsText"),
2219 "can-activate-accel", G_CALLBACK(can_accel), NULL);
2220 g_signal_connect((gpointer) GET_COMPONENT("toolsSelectRegion"),
2221 "can-activate-accel", G_CALLBACK(can_accel), NULL);
2222 g_signal_connect((gpointer) GET_COMPONENT("toolsSelectRectangle"),
2223 "can-activate-accel", G_CALLBACK(can_accel), NULL);
2224 g_signal_connect((gpointer) GET_COMPONENT("toolsVerticalSpace"),
2225 "can-activate-accel", G_CALLBACK(can_accel), NULL);
2226 g_signal_connect((gpointer) GET_COMPONENT("toolsHand"),
2227 "can-activate-accel", G_CALLBACK(can_accel), NULL);
2228 g_signal_connect((gpointer) GET_COMPONENT("toolsTextFont"),
2229 "can-activate-accel", G_CALLBACK(can_accel), NULL);
2230 g_signal_connect((gpointer) GET_COMPONENT("toolsRuler"),
2231 "can-activate-accel", G_CALLBACK(can_accel), NULL);
2232 g_signal_connect((gpointer) GET_COMPONENT("toolsReco"),
2233 "can-activate-accel", G_CALLBACK(can_accel), NULL);
2234 }
2235
add_scroll_bindings(void)2236 void add_scroll_bindings(void)
2237 {
2238 GtkBindingSet *binding_set;
2239
2240 binding_set = gtk_binding_set_by_class(
2241 G_OBJECT_GET_CLASS(GET_COMPONENT("scrolledwindowMain")));
2242 gtk_binding_entry_add_signal(binding_set, GDK_Up, 0,
2243 "scroll_child", 2, GTK_TYPE_SCROLL_TYPE, GTK_SCROLL_STEP_BACKWARD,
2244 G_TYPE_BOOLEAN, FALSE);
2245 gtk_binding_entry_add_signal(binding_set, GDK_KP_Up, 0,
2246 "scroll_child", 2, GTK_TYPE_SCROLL_TYPE, GTK_SCROLL_STEP_BACKWARD,
2247 G_TYPE_BOOLEAN, FALSE);
2248 gtk_binding_entry_add_signal(binding_set, GDK_Down, 0,
2249 "scroll_child", 2, GTK_TYPE_SCROLL_TYPE, GTK_SCROLL_STEP_FORWARD,
2250 G_TYPE_BOOLEAN, FALSE);
2251 gtk_binding_entry_add_signal(binding_set, GDK_KP_Down, 0,
2252 "scroll_child", 2, GTK_TYPE_SCROLL_TYPE, GTK_SCROLL_STEP_FORWARD,
2253 G_TYPE_BOOLEAN, FALSE);
2254 gtk_binding_entry_add_signal(binding_set, GDK_Left, 0,
2255 "scroll_child", 2, GTK_TYPE_SCROLL_TYPE, GTK_SCROLL_STEP_BACKWARD,
2256 G_TYPE_BOOLEAN, TRUE);
2257 gtk_binding_entry_add_signal(binding_set, GDK_KP_Left, 0,
2258 "scroll_child", 2, GTK_TYPE_SCROLL_TYPE, GTK_SCROLL_STEP_BACKWARD,
2259 G_TYPE_BOOLEAN, TRUE);
2260 gtk_binding_entry_add_signal(binding_set, GDK_Right, 0,
2261 "scroll_child", 2, GTK_TYPE_SCROLL_TYPE, GTK_SCROLL_STEP_FORWARD,
2262 G_TYPE_BOOLEAN, TRUE);
2263 gtk_binding_entry_add_signal(binding_set, GDK_KP_Right, 0,
2264 "scroll_child", 2, GTK_TYPE_SCROLL_TYPE, GTK_SCROLL_STEP_FORWARD,
2265 G_TYPE_BOOLEAN, TRUE);
2266 // make space and shift-space scroll down/up by a page
2267 gtk_binding_entry_add_signal(binding_set, GDK_space, 0,
2268 "scroll_child", 2, GTK_TYPE_SCROLL_TYPE, GTK_SCROLL_PAGE_DOWN,
2269 G_TYPE_BOOLEAN, TRUE);
2270 gtk_binding_entry_add_signal(binding_set, GDK_space, GDK_SHIFT_MASK,
2271 "scroll_child", 2, GTK_TYPE_SCROLL_TYPE, GTK_SCROLL_PAGE_UP,
2272 G_TYPE_BOOLEAN, TRUE);
2273 }
2274
is_event_within_textview(GdkEventButton * event)2275 gboolean is_event_within_textview(GdkEventButton *event)
2276 {
2277 double pt[2];
2278
2279 if (ui.cur_item_type!=ITEM_TEXT) return FALSE;
2280 get_pointer_coords((GdkEvent *)event, pt);
2281 if (pt[0]<ui.cur_item->bbox.left || pt[0]>ui.cur_item->bbox.right) return FALSE;
2282 if (pt[1]<ui.cur_item->bbox.top || pt[1]>ui.cur_item->bbox.bottom) return FALSE;
2283 return TRUE;
2284 }
2285
hide_unimplemented(void)2286 void hide_unimplemented(void)
2287 {
2288 gtk_widget_hide(GET_COMPONENT("filePrintOptions"));
2289 gtk_widget_hide(GET_COMPONENT("journalFlatten"));
2290 gtk_widget_hide(GET_COMPONENT("helpIndex"));
2291
2292 /* config file only works with glib 2.6 and beyond */
2293 if (glib_minor_version<6) {
2294 gtk_widget_hide(GET_COMPONENT("optionsAutoSavePrefs"));
2295 gtk_widget_hide(GET_COMPONENT("optionsSavePreferences"));
2296 }
2297 /* gtkprint only works with gtk+ 2.10 and beyond */
2298 if (gtk_check_version(2, 10, 0)) {
2299 gtk_widget_hide(GET_COMPONENT("filePrint"));
2300 }
2301
2302 /* screenshot feature doesn't work yet in Win32 */
2303 #ifndef GDK_WINDOWING_X11
2304 gtk_widget_hide(GET_COMPONENT("journalScreenshot"));
2305 #endif
2306 }
2307
2308 // toggle fullscreen mode
do_fullscreen(gboolean active)2309 void do_fullscreen(gboolean active)
2310 {
2311 end_text();
2312 ui.fullscreen = active;
2313 gtk_check_menu_item_set_active(
2314 GTK_CHECK_MENU_ITEM(GET_COMPONENT("viewFullscreen")), ui.fullscreen);
2315 gtk_toggle_tool_button_set_active(
2316 GTK_TOGGLE_TOOL_BUTTON(GET_COMPONENT("buttonFullscreen")), ui.fullscreen);
2317
2318 if (ui.fullscreen) {
2319 #ifdef WIN32
2320 gtk_window_get_size(GTK_WINDOW(winMain), &ui.pre_fullscreen_width, &ui.pre_fullscreen_height);
2321 gtk_widget_set_size_request(GTK_WIDGET(winMain), gdk_screen_width(),
2322 gdk_screen_height());
2323 #endif
2324 gtk_window_fullscreen(GTK_WINDOW(winMain));
2325 }
2326 else {
2327 #ifdef WIN32
2328 gtk_widget_set_size_request(GTK_WIDGET(winMain), -1, -1);
2329 gtk_window_resize(GTK_WINDOW(winMain), ui.pre_fullscreen_width,
2330 ui.pre_fullscreen_height);
2331 #endif
2332 gtk_window_unfullscreen(GTK_WINDOW(winMain));
2333 }
2334
2335 update_vbox_order(ui.vertical_order[ui.fullscreen?1:0]);
2336 }
2337
2338 /* attempt to work around GTK+ 2.16/2.17 bugs where random interface
2339 elements receive XInput events that they can't handle properly */
2340
2341 // prevent interface items from getting bogus XInput events
2342
filter_extended_events(GtkWidget * widget,GdkEvent * event,gpointer user_data)2343 gboolean filter_extended_events (GtkWidget *widget, GdkEvent *event,
2344 gpointer user_data)
2345 {
2346 if (event->type == GDK_MOTION_NOTIFY &&
2347 event->motion.device != gdk_device_get_core_pointer())
2348 return TRUE;
2349 if ((event->type == GDK_BUTTON_PRESS || event->type == GDK_2BUTTON_PRESS ||
2350 event->type == GDK_3BUTTON_PRESS || event->type == GDK_BUTTON_RELEASE) &&
2351 event->button.device != gdk_device_get_core_pointer())
2352 return TRUE;
2353 return FALSE;
2354 }
2355
2356 /* Code to turn an extended input event into a core event and send it to
2357 a different GdkWindow -- e.g. could be used when a click in a text edit box
2358 gets sent to the canvas instead due to incorrect event translation.
2359 We now turn off xinput altogether while editing text under GTK+ 2.17, so
2360 this isn't needed any more... but could become useful again someday!
2361 */
2362
2363 /*
2364 gboolean fix_extended_events (GtkWidget *widget, GdkEvent *event,
2365 gpointer user_data)
2366 {
2367 int ix, iy;
2368 GdkWindow *window;
2369
2370 if (user_data) window = (GdkWindow *)user_data;
2371 else window = widget->window;
2372
2373 if (event->type == GDK_MOTION_NOTIFY &&
2374 event->motion.device != gdk_device_get_core_pointer()) {
2375 // printf("fixing motion\n");
2376 gdk_window_get_pointer(window, &ix, &iy, NULL);
2377 event->motion.x = ix; event->motion.y = iy;
2378 event->motion.device = gdk_device_get_core_pointer();
2379 g_object_unref(event->motion.window);
2380 event->motion.window = g_object_ref(window);
2381 gtk_widget_event(widget, event);
2382 return TRUE;
2383 }
2384 if ((event->type == GDK_BUTTON_PRESS || event->type == GDK_BUTTON_RELEASE) &&
2385 event->button.device != gdk_device_get_core_pointer()) {
2386 // printf("fixing button from pos = %f, %f\n", event->button.x, event->button.y);
2387 gdk_window_get_pointer(window, &ix, &iy, NULL);
2388 event->button.x = ix; event->button.y = iy;
2389 event->button.device = gdk_device_get_core_pointer();
2390 g_object_unref(event->button.window);
2391 event->button.window = g_object_ref(window);
2392 // printf("fixing button to pos = %f, %f\n", event->button.x, event->button.y);
2393 gtk_widget_event(widget, event);
2394 return TRUE;
2395 }
2396 return FALSE;
2397 }
2398 */
2399
2400
2401 /* When enter is pressed into page spinbox, send focus back to canvas. */
2402
handle_activate_signal(GtkWidget * widget,gpointer user_data)2403 gboolean handle_activate_signal(GtkWidget *widget, gpointer user_data)
2404 {
2405 reset_focus();
2406 return FALSE;
2407 }
2408
2409 /* recursively unset widget flags */
2410
unset_flags(GtkWidget * w,gpointer flag)2411 void unset_flags(GtkWidget *w, gpointer flag)
2412 {
2413 GTK_WIDGET_UNSET_FLAGS(w, (GtkWidgetFlags)flag);
2414 if(GTK_IS_CONTAINER(w))
2415 gtk_container_forall(GTK_CONTAINER(w), unset_flags, flag);
2416 }
2417
2418 /* reset focus when a key or button press event reaches someone, or when the
2419 page-number spin button should relinquish control... */
2420
intercept_activate_events(GtkWidget * w,GdkEvent * ev,gpointer data)2421 gboolean intercept_activate_events(GtkWidget *w, GdkEvent *ev, gpointer data)
2422 {
2423 if (w == GET_COMPONENT("hbox1")) {
2424 /* the event won't be processed since the hbox1 doesn't know what to do with it,
2425 so we might as well kill it and avoid confusing ourselves when it gets
2426 propagated further ... */
2427 return TRUE;
2428 }
2429 if (w == GET_COMPONENT("spinPageNo")) {
2430 /* we let the spin button take care of itself, and don't steal its focus,
2431 unless the user presses Esc or Tab (in those cases we intervene) */
2432 if (ev->type != GDK_KEY_PRESS) return FALSE;
2433 if (ev->key.keyval == GDK_Escape)
2434 gtk_spin_button_set_value(GTK_SPIN_BUTTON(w), ui.pageno+1); // abort
2435 else if (ev->key.keyval != GDK_Tab && ev->key.keyval != GDK_ISO_Left_Tab)
2436 return FALSE; // let the spin button process it
2437 }
2438
2439 // otherwise, we want to make sure the canvas or text item gets focus back...
2440 reset_focus();
2441 return FALSE;
2442 }
2443
install_focus_hooks(GtkWidget * w,gpointer data)2444 void install_focus_hooks(GtkWidget *w, gpointer data)
2445 {
2446 if (w == NULL) return;
2447 g_signal_connect(w, "key-press-event", G_CALLBACK(intercept_activate_events), data);
2448 g_signal_connect(w, "button-press-event", G_CALLBACK(intercept_activate_events), data);
2449 if (GTK_IS_MENU_ITEM(w)) {
2450 g_signal_connect(w, "activate", G_CALLBACK(intercept_activate_events), data);
2451 install_focus_hooks(gtk_menu_item_get_submenu(GTK_MENU_ITEM(w)), data);
2452 }
2453 if(GTK_IS_CONTAINER(w))
2454 gtk_container_forall(GTK_CONTAINER(w), install_focus_hooks, data);
2455 }
2456
2457 // wrapper for missing poppler functions (defunct poppler-gdk api)
2458
2459 static void
wrapper_copy_cairo_surface_to_pixbuf(cairo_surface_t * surface,GdkPixbuf * pixbuf)2460 wrapper_copy_cairo_surface_to_pixbuf (cairo_surface_t *surface,
2461 GdkPixbuf *pixbuf)
2462 {
2463 int cairo_width, cairo_height, cairo_rowstride;
2464 unsigned char *pixbuf_data, *dst, *cairo_data;
2465 int pixbuf_rowstride, pixbuf_n_channels;
2466 unsigned int *src;
2467 int x, y;
2468
2469 cairo_width = cairo_image_surface_get_width (surface);
2470 cairo_height = cairo_image_surface_get_height (surface);
2471 cairo_rowstride = cairo_image_surface_get_stride (surface);
2472 cairo_data = cairo_image_surface_get_data (surface);
2473
2474 pixbuf_data = gdk_pixbuf_get_pixels (pixbuf);
2475 pixbuf_rowstride = gdk_pixbuf_get_rowstride (pixbuf);
2476 pixbuf_n_channels = gdk_pixbuf_get_n_channels (pixbuf);
2477
2478 if (cairo_width > gdk_pixbuf_get_width (pixbuf))
2479 cairo_width = gdk_pixbuf_get_width (pixbuf);
2480 if (cairo_height > gdk_pixbuf_get_height (pixbuf))
2481 cairo_height = gdk_pixbuf_get_height (pixbuf);
2482 for (y = 0; y < cairo_height; y++)
2483 {
2484 src = (unsigned int *) (cairo_data + y * cairo_rowstride);
2485 dst = pixbuf_data + y * pixbuf_rowstride;
2486 for (x = 0; x < cairo_width; x++)
2487 {
2488 dst[0] = (*src >> 16) & 0xff;
2489 dst[1] = (*src >> 8) & 0xff;
2490 dst[2] = (*src >> 0) & 0xff;
2491 if (pixbuf_n_channels == 4)
2492 dst[3] = (*src >> 24) & 0xff;
2493 dst += pixbuf_n_channels;
2494 src++;
2495 }
2496 }
2497 }
2498
2499 void
wrapper_poppler_page_render_to_pixbuf(PopplerPage * page,int src_x,int src_y,int src_width,int src_height,double scale,int rotation,GdkPixbuf * pixbuf)2500 wrapper_poppler_page_render_to_pixbuf (PopplerPage *page,
2501 int src_x, int src_y,
2502 int src_width, int src_height,
2503 double scale,
2504 int rotation,
2505 GdkPixbuf *pixbuf)
2506 {
2507 cairo_t *cr;
2508 cairo_surface_t *surface;
2509
2510 surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32,
2511 src_width, src_height);
2512 cr = cairo_create (surface);
2513 cairo_save (cr);
2514 switch (rotation) {
2515 case 90:
2516 cairo_translate (cr, src_x + src_width, -src_y);
2517 break;
2518 case 180:
2519 cairo_translate (cr, src_x + src_width, src_y + src_height);
2520 break;
2521 case 270:
2522 cairo_translate (cr, -src_x, src_y + src_height);
2523 break;
2524 default:
2525 cairo_translate (cr, -src_x, -src_y);
2526 }
2527
2528 if (scale != 1.0)
2529 cairo_scale (cr, scale, scale);
2530
2531 if (rotation != 0)
2532 cairo_rotate (cr, rotation * G_PI / 180.0);
2533
2534 poppler_page_render (page, cr);
2535 cairo_restore (cr);
2536
2537 cairo_set_operator (cr, CAIRO_OPERATOR_DEST_OVER);
2538 cairo_set_source_rgb (cr, 1., 1., 1.);
2539 cairo_paint (cr);
2540
2541 cairo_destroy (cr);
2542
2543 wrapper_copy_cairo_surface_to_pixbuf (surface, pixbuf);
2544 cairo_surface_destroy (surface);
2545 }
2546
2547 // wrapper for gtk_dialog_run that disables xinput (bug #159)
2548
wrapper_gtk_dialog_run(GtkDialog * dialog)2549 gint wrapper_gtk_dialog_run(GtkDialog *dialog)
2550 {
2551 gint response;
2552
2553 if (!gtk_check_version(2, 17, 0))
2554 emergency_enable_xinput(GDK_MODE_DISABLED);
2555 response = gtk_dialog_run(dialog);
2556 return response;
2557 }
2558