]> git.donarmstrong.com Git - xournal.git/blob - src/xo-misc.c
Print via gtk-print instead of libgnomeprint
[xournal.git] / src / xo-misc.c
1 #ifdef HAVE_CONFIG_H
2 #  include <config.h>
3 #endif
4
5 #include <math.h>
6 #include <string.h>
7 #include <gtk/gtk.h>
8 #include <libgnomecanvas/libgnomecanvas.h>
9 #include <gdk/gdkkeysyms.h>
10 #include <X11/Xlib.h>
11
12 #include "xournal.h"
13 #include "xo-interface.h"
14 #include "xo-support.h"
15 #include "xo-callbacks.h"
16 #include "xo-misc.h"
17 #include "xo-file.h"
18 #include "xo-paint.h"
19 #include "xo-shapes.h"
20
21 // some global constants
22
23 guint predef_colors_rgba[COLOR_MAX] =
24   { 0x000000ff, 0x3333ccff, 0xff0000ff, 0x008000ff,
25     0x808080ff, 0x00c0ffff, 0x00ff00ff, 0xff00ffff,
26     0xff8000ff, 0xffff00ff, 0xffffffff };
27
28 guint predef_bgcolors_rgba[COLOR_MAX] = // meaningless ones set to white
29   { 0xffffffff, 0xa0e8ffff, 0xffc0d4ff, 0x80ffc0ff,
30     0xffffffff, 0xa0e8ffff, 0x80ffc0ff, 0xffc0d4ff,
31     0xffc080ff, 0xffff80ff, 0xffffffff };
32
33 double predef_thickness[NUM_STROKE_TOOLS][THICKNESS_MAX] =
34   { { 0.42, 0.85, 1.41,  2.26, 5.67 }, // pen thicknesses = 0.15, 0.3, 0.5, 0.8, 2 mm
35     { 2.83, 2.83, 8.50, 19.84, 19.84 }, // eraser thicknesses = 1, 3, 7 mm
36     { 2.83, 2.83, 8.50, 19.84, 19.84 }, // highlighter thicknesses = 1, 3, 7 mm
37   };
38
39 // some manipulation functions
40
41 struct Page *new_page(struct Page *template)
42 {
43   struct Page *pg = (struct Page *) g_memdup(template, sizeof(struct Page));
44   struct Layer *l = g_new(struct Layer, 1);
45   
46   l->items = NULL;
47   l->nitems = 0;
48   pg->layers = g_list_append(NULL, l);
49   pg->nlayers = 1;
50   pg->bg = (struct Background *)g_memdup(template->bg, sizeof(struct Background));
51   pg->bg->canvas_item = NULL;
52   if (pg->bg->type == BG_PIXMAP || pg->bg->type == BG_PDF) {
53     gdk_pixbuf_ref(pg->bg->pixbuf);
54     refstring_ref(pg->bg->filename);
55   }
56   pg->group = (GnomeCanvasGroup *) gnome_canvas_item_new(
57       gnome_canvas_root(canvas), gnome_canvas_clipgroup_get_type(), NULL);
58   make_page_clipbox(pg);
59   update_canvas_bg(pg);
60   l->group = (GnomeCanvasGroup *) gnome_canvas_item_new(
61       pg->group, gnome_canvas_group_get_type(), NULL);
62   
63   return pg;
64 }
65
66 /* Create a page from a background. 
67    Note: bg should be an UNREFERENCED background.
68    If needed, first duplicate it and increase the refcount of the pixbuf.
69 */
70 struct Page *new_page_with_bg(struct Background *bg, double width, double height)
71 {
72   struct Page *pg = g_new(struct Page, 1);
73   struct Layer *l = g_new(struct Layer, 1);
74   
75   l->items = NULL;
76   l->nitems = 0;
77   pg->layers = g_list_append(NULL, l);
78   pg->nlayers = 1;
79   pg->bg = bg;
80   pg->bg->canvas_item = NULL;
81   pg->height = height;
82   pg->width = width;
83   pg->group = (GnomeCanvasGroup *) gnome_canvas_item_new(
84       gnome_canvas_root(canvas), gnome_canvas_clipgroup_get_type(), NULL);
85   make_page_clipbox(pg);
86   update_canvas_bg(pg);
87   l->group = (GnomeCanvasGroup *) gnome_canvas_item_new(
88       pg->group, gnome_canvas_group_get_type(), NULL);
89   
90   return pg;
91 }
92
93 void realloc_cur_path(int n)
94 {
95   if (n <= ui.cur_path_storage_alloc) return;
96   ui.cur_path_storage_alloc = n+10;
97   ui.cur_path.coords = g_realloc(ui.cur_path.coords, 2*(n+10)*sizeof(double));
98 }
99
100 void realloc_cur_widths(int n)
101 {
102   if (n <= ui.cur_widths_storage_alloc) return;
103   ui.cur_widths_storage_alloc = n+10;
104   ui.cur_widths = g_realloc(ui.cur_widths, (n+10)*sizeof(double));
105 }
106
107 // undo utility functions
108
109 void prepare_new_undo(void)
110 {
111   struct UndoItem *u;
112   // add a new UndoItem on the stack  
113   u = (struct UndoItem *)g_malloc(sizeof(struct UndoItem));
114   u->next = undo;
115   u->multiop = 0;
116   undo = u;
117   ui.saved = FALSE;
118   clear_redo_stack();
119 }
120
121 void clear_redo_stack(void)
122 {
123   struct UndoItem *u;  
124   GList *list, *repl;
125   struct UndoErasureData *erasure;
126   struct Item *it;
127
128   /* Warning: the redo items might reference items from past redo entries,
129      which have been destroyed before them. Be careful! As a rule, it's
130      safe to destroy data which has been created at the current history step,
131      it's unsafe to refer to any data from previous history steps */
132   
133   while (redo!=NULL) {
134     if (redo->type == ITEM_STROKE) {
135       gnome_canvas_points_free(redo->item->path);
136       if (redo->item->brush.variable_width) g_free(redo->item->widths);
137       g_free(redo->item);
138       /* the strokes are unmapped, so there are no associated canvas items */
139     }
140     else if (redo->type == ITEM_TEXT) {
141       g_free(redo->item->text);
142       g_free(redo->item->font_name);
143       g_free(redo->item);
144     }
145     else if (redo->type == ITEM_ERASURE || redo->type == ITEM_RECOGNIZER) {
146       for (list = redo->erasurelist; list!=NULL; list=list->next) {
147         erasure = (struct UndoErasureData *)list->data;
148         for (repl = erasure->replacement_items; repl!=NULL; repl=repl->next) {
149           it = (struct Item *)repl->data;
150           gnome_canvas_points_free(it->path);
151           if (it->brush.variable_width) g_free(it->widths);
152           g_free(it);
153         }
154         g_list_free(erasure->replacement_items);
155         g_free(erasure);
156       }
157       g_list_free(redo->erasurelist);
158     }
159     else if (redo->type == ITEM_NEW_BG_ONE || redo->type == ITEM_NEW_BG_RESIZE
160           || redo->type == ITEM_NEW_DEFAULT_BG) {
161       if (redo->bg->type == BG_PIXMAP || redo->bg->type == BG_PDF) {
162         if (redo->bg->pixbuf!=NULL) gdk_pixbuf_unref(redo->bg->pixbuf);
163         refstring_unref(redo->bg->filename);
164       }
165       g_free(redo->bg);
166     }
167     else if (redo->type == ITEM_NEW_PAGE) {
168       redo->page->group = NULL;
169       delete_page(redo->page);
170     }
171     else if (redo->type == ITEM_MOVESEL || redo->type == ITEM_REPAINTSEL) {
172       g_list_free(redo->itemlist); g_list_free(redo->auxlist);
173     }
174     else if (redo->type == ITEM_RESIZESEL) {
175       g_list_free(redo->itemlist);
176     }
177     else if (redo->type == ITEM_PASTE) {
178       for (list = redo->itemlist; list!=NULL; list=list->next) {
179         it = (struct Item *)list->data;
180         if (it->type == ITEM_STROKE) {
181           gnome_canvas_points_free(it->path);
182           if (it->brush.variable_width) g_free(it->widths);
183         }
184         g_free(it);
185       }
186       g_list_free(redo->itemlist);
187     }
188     else if (redo->type == ITEM_NEW_LAYER) {
189       g_free(redo->layer);
190     }
191     else if (redo->type == ITEM_TEXT_EDIT || redo->type == ITEM_TEXT_ATTRIB) {
192       g_free(redo->str);
193       if (redo->type == ITEM_TEXT_ATTRIB) g_free(redo->brush);
194     }
195
196     u = redo;
197     redo = redo->next;
198     g_free(u);
199   }
200   update_undo_redo_enabled();
201 }
202
203 void clear_undo_stack(void)
204 {
205   struct UndoItem *u;
206   GList *list;
207   struct UndoErasureData *erasure;
208   
209   while (undo!=NULL) {
210     // for strokes, items are already in the journal, so we don't free them
211     // for erasures, we need to free the dead items
212     if (undo->type == ITEM_ERASURE || undo->type == ITEM_RECOGNIZER) {
213       for (list = undo->erasurelist; list!=NULL; list=list->next) {
214         erasure = (struct UndoErasureData *)list->data;
215         if (erasure->item->type == ITEM_STROKE) {
216           gnome_canvas_points_free(erasure->item->path);
217           if (erasure->item->brush.variable_width) g_free(erasure->item->widths);
218         }
219         if (erasure->item->type == ITEM_TEXT)
220           { g_free(erasure->item->text); g_free(erasure->item->font_name); }
221         g_free(erasure->item);
222         g_list_free(erasure->replacement_items);
223         g_free(erasure);
224       }
225       g_list_free(undo->erasurelist);
226     }
227     else if (undo->type == ITEM_NEW_BG_ONE || undo->type == ITEM_NEW_BG_RESIZE
228           || undo->type == ITEM_NEW_DEFAULT_BG) {
229       if (undo->bg->type == BG_PIXMAP || undo->bg->type == BG_PDF) {
230         if (undo->bg->pixbuf!=NULL) gdk_pixbuf_unref(undo->bg->pixbuf);
231         refstring_unref(undo->bg->filename);
232       }
233       g_free(undo->bg);
234     }
235     else if (undo->type == ITEM_MOVESEL || undo->type == ITEM_REPAINTSEL) {
236       g_list_free(undo->itemlist); g_list_free(undo->auxlist);
237     }
238     else if (undo->type == ITEM_RESIZESEL) {
239       g_list_free(undo->itemlist);
240     }
241     else if (undo->type == ITEM_PASTE) {
242       g_list_free(undo->itemlist);
243     }
244     else if (undo->type == ITEM_DELETE_LAYER) {
245       undo->layer->group = NULL;
246       delete_layer(undo->layer);
247     }
248     else if (undo->type == ITEM_DELETE_PAGE) {
249       undo->page->group = NULL;
250       delete_page(undo->page);
251     }
252     else if (undo->type == ITEM_TEXT_EDIT || undo->type == ITEM_TEXT_ATTRIB) {
253       g_free(undo->str);
254       if (undo->type == ITEM_TEXT_ATTRIB) g_free(undo->brush);
255     }
256
257     u = undo;
258     undo = undo->next;
259     g_free(u);
260   }
261   update_undo_redo_enabled();
262 }
263
264 // free data structures 
265
266 void delete_journal(struct Journal *j)
267 {
268   while (j->pages!=NULL) {
269     delete_page((struct Page *)j->pages->data);
270     j->pages = g_list_delete_link(j->pages, j->pages);
271   }
272 }
273
274 void delete_page(struct Page *pg)
275 {
276   struct Layer *l;
277   
278   while (pg->layers!=NULL) {
279     l = (struct Layer *)pg->layers->data;
280     l->group = NULL;
281     delete_layer(l);
282     pg->layers = g_list_delete_link(pg->layers, pg->layers);
283   }
284   if (pg->group!=NULL) gtk_object_destroy(GTK_OBJECT(pg->group));
285               // this also destroys the background's canvas items
286   if (pg->bg->type == BG_PIXMAP || pg->bg->type == BG_PDF) {
287     if (pg->bg->pixbuf != NULL) gdk_pixbuf_unref(pg->bg->pixbuf);
288     if (pg->bg->filename != NULL) refstring_unref(pg->bg->filename);
289   }
290   g_free(pg->bg);
291   g_free(pg);
292 }
293
294 void delete_layer(struct Layer *l)
295 {
296   struct Item *item;
297   
298   while (l->items!=NULL) {
299     item = (struct Item *)l->items->data;
300     if (item->type == ITEM_STROKE && item->path != NULL) 
301       gnome_canvas_points_free(item->path);
302     if (item->type == ITEM_TEXT) {
303       g_free(item->font_name); g_free(item->text);
304     }
305     // don't need to delete the canvas_item, as it's part of the group destroyed below
306     g_free(item);
307     l->items = g_list_delete_link(l->items, l->items);
308   }
309   if (l->group!= NULL) gtk_object_destroy(GTK_OBJECT(l->group));
310   g_free(l);
311 }
312
313 // referenced strings
314
315 struct Refstring *new_refstring(const char *s)
316 {
317   struct Refstring *rs = g_new(struct Refstring, 1);
318   rs->nref = 1;
319   if (s!=NULL) rs->s = g_strdup(s);
320   else rs->s = NULL;
321   rs->aux = NULL;
322   return rs;
323 }
324
325 struct Refstring *refstring_ref(struct Refstring *rs)
326 {
327   rs->nref++;
328   return rs;
329 }
330
331 void refstring_unref(struct Refstring *rs)
332 {
333   rs->nref--;
334   if (rs->nref == 0) {
335     if (rs->s!=NULL) g_free(rs->s);
336     if (rs->aux!=NULL) g_free(rs->aux);
337     g_free(rs);
338   }
339 }
340
341
342 // some helper functions
343
344 void get_pointer_coords(GdkEvent *event, gdouble *ret)
345 {
346   double x, y;
347   gdk_event_get_coords(event, &x, &y);
348   gnome_canvas_window_to_world(canvas, x, y, ret, ret+1);
349   ret[0] -= ui.cur_page->hoffset;
350   ret[1] -= ui.cur_page->voffset;
351 }
352
353 void fix_xinput_coords(GdkEvent *event)
354 {
355   double *axes, *px, *py, axis_width;
356   GdkDevice *device;
357   int wx, wy, sx, sy, ix, iy;
358
359   if (event->type == GDK_BUTTON_PRESS || event->type == GDK_BUTTON_RELEASE) {
360     axes = event->button.axes;
361     px = &(event->button.x);
362     py = &(event->button.y);
363     device = event->button.device;
364   }
365   else if (event->type == GDK_MOTION_NOTIFY) {
366     axes = event->motion.axes;
367     px = &(event->motion.x);
368     py = &(event->motion.y);
369     device = event->motion.device;
370   }
371   else return; // nothing we know how to do
372
373   // use canvas window, not event window (else get GTK+ 2.11 bugs!)            
374   gdk_window_get_origin(GTK_WIDGET(canvas)->window, &wx, &wy);  
375   gnome_canvas_get_scroll_offsets(canvas, &sx, &sy);
376
377 #ifdef ENABLE_XINPUT_BUGFIX
378   // fix broken events with the core pointer's location
379   if (!finite(axes[0]) || !finite(axes[1]) || (axes[0]==0. && axes[1]==0.)) {
380     gdk_window_get_pointer(GTK_WIDGET(canvas)->window, &ix, &iy, NULL);
381     *px = ix + sx; 
382     *py = iy + sy;
383   }
384   else {
385     axis_width = device->axes[0].max - device->axes[0].min;
386     if (axis_width>EPSILON)
387       *px = (axes[0]/axis_width)*ui.screen_width + sx - wx;
388     axis_width = device->axes[1].max - device->axes[1].min;
389     if (axis_width>EPSILON)
390       *py = (axes[1]/axis_width)*ui.screen_height + sy - wy;
391   }
392 #endif
393 }
394
395 double get_pressure_multiplier(GdkEvent *event)
396 {
397   double rawpressure;
398   
399   if (event->button.device == gdk_device_get_core_pointer()
400       || event->button.device->num_axes <= 2) return 1.0;
401
402   rawpressure = event->button.axes[2]/(event->button.device->axes[2].max - event->button.device->axes[2].min);
403
404   return ((1-rawpressure)*ui.width_minimum_multiplier + rawpressure*ui.width_maximum_multiplier);
405 }
406
407 void update_item_bbox(struct Item *item)
408 {
409   int i;
410   gdouble *p, h, w;
411   
412   if (item->type == ITEM_STROKE) {
413     item->bbox.left = item->bbox.right = item->path->coords[0];
414     item->bbox.top = item->bbox.bottom = item->path->coords[1];
415     for (i=1, p=item->path->coords+2; i<item->path->num_points; i++, p+=2)
416     {
417       if (p[0] < item->bbox.left) item->bbox.left = p[0];
418       if (p[0] > item->bbox.right) item->bbox.right = p[0];
419       if (p[1] < item->bbox.top) item->bbox.top = p[1];
420       if (p[1] > item->bbox.bottom) item->bbox.bottom = p[1];
421     }
422   }
423   if (item->type == ITEM_TEXT && item->canvas_item!=NULL) {
424     h=0.; w=0.;
425     g_object_get(item->canvas_item, "text_width", &w, "text_height", &h, NULL);
426     item->bbox.right = item->bbox.left + w;
427     item->bbox.bottom = item->bbox.top + h;
428   }
429 }
430
431 void make_page_clipbox(struct Page *pg)
432 {
433   GnomeCanvasPathDef *pg_clip;
434   
435   pg_clip = gnome_canvas_path_def_new_sized(4);
436   gnome_canvas_path_def_moveto(pg_clip, 0., 0.);
437   gnome_canvas_path_def_lineto(pg_clip, 0., pg->height);
438   gnome_canvas_path_def_lineto(pg_clip, pg->width, pg->height);
439   gnome_canvas_path_def_lineto(pg_clip, pg->width, 0.);
440   gnome_canvas_path_def_closepath(pg_clip);
441   gnome_canvas_item_set(GNOME_CANVAS_ITEM(pg->group), "path", pg_clip, NULL);
442   gnome_canvas_path_def_unref(pg_clip);
443 }
444
445 void make_canvas_item_one(GnomeCanvasGroup *group, struct Item *item)
446 {
447   PangoFontDescription *font_desc;
448   GnomeCanvasPoints points;
449   int j;
450
451   if (item->type == ITEM_STROKE) {
452     if (!item->brush.variable_width)
453       item->canvas_item = gnome_canvas_item_new(group,
454             gnome_canvas_line_get_type(), "points", item->path,   
455             "cap-style", GDK_CAP_ROUND, "join-style", GDK_JOIN_ROUND,
456             "fill-color-rgba", item->brush.color_rgba,  
457             "width-units", item->brush.thickness, NULL);
458     else {
459       item->canvas_item = gnome_canvas_item_new(group,
460             gnome_canvas_group_get_type(), NULL);
461       points.num_points = 2;
462       points.ref_count = 1;
463       for (j = 0; j < item->path->num_points-1; j++) {
464         points.coords = item->path->coords+2*j;
465         gnome_canvas_item_new((GnomeCanvasGroup *) item->canvas_item,
466               gnome_canvas_line_get_type(), "points", &points, 
467               "cap-style", GDK_CAP_ROUND, "join-style", GDK_JOIN_ROUND, 
468               "fill-color-rgba", item->brush.color_rgba,
469               "width-units", item->widths[j], NULL);
470       }
471     }
472   }
473   if (item->type == ITEM_TEXT) {
474     font_desc = pango_font_description_from_string(item->font_name);
475     pango_font_description_set_absolute_size(font_desc, 
476             item->font_size*ui.zoom*PANGO_SCALE);
477     item->canvas_item = gnome_canvas_item_new(group,
478           gnome_canvas_text_get_type(),
479           "x", item->bbox.left, "y", item->bbox.top, "anchor", GTK_ANCHOR_NW,
480           "font-desc", font_desc, "fill-color-rgba", item->brush.color_rgba,
481           "text", item->text, NULL);
482     update_item_bbox(item);
483   }
484 }
485
486 void make_canvas_items(void)
487 {
488   struct Page *pg;
489   struct Layer *l;
490   struct Item *item;
491   GList *pagelist, *layerlist, *itemlist;
492   
493   for (pagelist = journal.pages; pagelist!=NULL; pagelist = pagelist->next) {
494     pg = (struct Page *)pagelist->data;
495     if (pg->group == NULL) {
496       pg->group = (GnomeCanvasGroup *) gnome_canvas_item_new(
497          gnome_canvas_root(canvas), gnome_canvas_clipgroup_get_type(), NULL);
498       make_page_clipbox(pg);
499     }
500     if (pg->bg->canvas_item == NULL) update_canvas_bg(pg);
501     for (layerlist = pg->layers; layerlist!=NULL; layerlist = layerlist->next) {
502       l = (struct Layer *)layerlist->data;
503       if (l->group == NULL)
504         l->group = (GnomeCanvasGroup *) gnome_canvas_item_new(
505            pg->group, gnome_canvas_group_get_type(), NULL);
506       for (itemlist = l->items; itemlist!=NULL; itemlist = itemlist->next) {
507         item = (struct Item *)itemlist->data;
508         if (item->canvas_item == NULL)
509           make_canvas_item_one(l->group, item);
510       }
511     }
512   }
513 }
514
515 void update_canvas_bg(struct Page *pg)
516 {
517   GnomeCanvasGroup *group;
518   GnomeCanvasPoints *seg;
519   GdkPixbuf *scaled_pix;
520   double *pt;
521   double x, y;
522   int w, h;
523   gboolean is_well_scaled;
524   
525   if (pg->bg->canvas_item != NULL)
526     gtk_object_destroy(GTK_OBJECT(pg->bg->canvas_item));
527   pg->bg->canvas_item = NULL;
528   
529   if (pg->bg->type == BG_SOLID)
530   {
531     pg->bg->canvas_item = gnome_canvas_item_new(pg->group,
532                                gnome_canvas_group_get_type(), NULL);
533     group = GNOME_CANVAS_GROUP(pg->bg->canvas_item);
534     lower_canvas_item_to(pg->group, pg->bg->canvas_item, NULL);
535     gnome_canvas_item_new(group, gnome_canvas_rect_get_type(),
536       "x1", 0., "x2", pg->width, "y1", 0., "y2", pg->height,
537       "fill-color-rgba", pg->bg->color_rgba, NULL);
538     if (pg->bg->ruling == RULING_NONE) return;
539     seg = gnome_canvas_points_new(2);
540     pt = seg->coords;
541     if (pg->bg->ruling == RULING_GRAPH) {
542       pt[1] = 0; pt[3] = pg->height;
543       for (x=RULING_GRAPHSPACING; x<pg->width-1; x+=RULING_GRAPHSPACING) {
544         pt[0] = pt[2] = x;
545         gnome_canvas_item_new(group, gnome_canvas_line_get_type(),
546            "points", seg, "fill-color-rgba", RULING_COLOR,
547            "width-units", RULING_THICKNESS, NULL);
548       }      
549       pt[0] = 0; pt[2] = pg->width;
550       for (y=RULING_GRAPHSPACING; y<pg->height-1; y+=RULING_GRAPHSPACING) {
551         pt[1] = pt[3] = y;
552         gnome_canvas_item_new(group, gnome_canvas_line_get_type(),
553            "points", seg, "fill-color-rgba", RULING_COLOR,
554            "width-units", RULING_THICKNESS, NULL);
555       }      
556       gnome_canvas_points_free(seg);
557       return;
558     }
559     pt[0] = 0; pt[2] = pg->width;
560     for (y=RULING_TOPMARGIN; y<pg->height-1; y+=RULING_SPACING) {
561       pt[1] = pt[3] = y;
562       gnome_canvas_item_new(group, gnome_canvas_line_get_type(),
563          "points", seg, "fill-color-rgba", RULING_COLOR,
564          "width-units", RULING_THICKNESS, NULL);
565     }      
566     if (pg->bg->ruling == RULING_LINED) {
567       pt[0] = pt[2] = RULING_LEFTMARGIN;
568       pt[1] = 0; pt[3] = pg->height;
569       gnome_canvas_item_new(group, gnome_canvas_line_get_type(),
570          "points", seg, "fill-color-rgba", RULING_MARGIN_COLOR,
571          "width-units", RULING_THICKNESS, NULL);
572     }
573     gnome_canvas_points_free(seg);
574     return;
575   }
576   
577   if (pg->bg->type == BG_PIXMAP)
578   {
579     if (ui.antialias_bg) {
580       set_cursor_busy(TRUE);
581       w = (int)floor(pg->width*ui.zoom+0.5);
582       h = (int)floor(pg->height*ui.zoom+0.5);
583       if (w == gdk_pixbuf_get_width(pg->bg->pixbuf) &&
584           h == gdk_pixbuf_get_height(pg->bg->pixbuf))
585         scaled_pix = gdk_pixbuf_ref(pg->bg->pixbuf);
586       else
587         scaled_pix = gdk_pixbuf_scale_simple(pg->bg->pixbuf, w, h, GDK_INTERP_BILINEAR);
588       pg->bg->pixbuf_scale = ui.zoom;
589       set_cursor_busy(FALSE);
590     }
591     else {
592       scaled_pix = gdk_pixbuf_ref(pg->bg->pixbuf);
593       pg->bg->pixbuf_scale = 0;
594     }
595     pg->bg->canvas_item = gnome_canvas_item_new(pg->group, 
596         gnome_canvas_pixbuf_get_type(), 
597         "pixbuf", scaled_pix,
598         "width", pg->width, "height", pg->height, 
599         "width-set", TRUE, "height-set", TRUE, 
600         NULL);
601     gdk_pixbuf_unref(scaled_pix);
602     lower_canvas_item_to(pg->group, pg->bg->canvas_item, NULL);
603   }
604
605   if (pg->bg->type == BG_PDF)
606   {
607     if (pg->bg->pixbuf == NULL) return;
608     is_well_scaled = (fabs(pg->bg->pixel_width - pg->width*ui.zoom) < 2.
609                    && fabs(pg->bg->pixel_height - pg->height*ui.zoom) < 2.);
610     if (is_well_scaled)
611       pg->bg->canvas_item = gnome_canvas_item_new(pg->group, 
612           gnome_canvas_pixbuf_get_type(), 
613           "pixbuf", pg->bg->pixbuf,
614           "width-in-pixels", TRUE, "height-in-pixels", TRUE, 
615           NULL);
616     else
617       pg->bg->canvas_item = gnome_canvas_item_new(pg->group, 
618           gnome_canvas_pixbuf_get_type(), 
619           "pixbuf", pg->bg->pixbuf,
620           "width", pg->width, "height", pg->height, 
621           "width-set", TRUE, "height-set", TRUE, 
622           NULL);
623     lower_canvas_item_to(pg->group, pg->bg->canvas_item, NULL);
624   }
625 }
626
627 gboolean is_visible(struct Page *pg)
628 {
629   GtkAdjustment *v_adj;
630   double ytop, ybot;
631   
632   if (!ui.view_continuous) return (pg == ui.cur_page);
633   v_adj = gtk_layout_get_vadjustment(GTK_LAYOUT(canvas));
634   ytop = v_adj->value/ui.zoom;
635   ybot = (v_adj->value + v_adj->page_size) / ui.zoom;
636   return (MAX(ytop, pg->voffset) < MIN(ybot, pg->voffset+pg->height));
637 }
638
639 void rescale_bg_pixmaps(void)
640 {
641   GList *pglist;
642   struct Page *pg;
643   GdkPixbuf *pix;
644   gboolean is_well_scaled;
645   gdouble zoom_to_request;
646   
647   for (pglist = journal.pages; pglist!=NULL; pglist = pglist->next) {
648     pg = (struct Page *)pglist->data;
649     // in progressive mode we scale only visible pages
650     if (ui.progressive_bg && !is_visible(pg)) continue;
651
652     if (pg->bg->type == BG_PIXMAP && pg->bg->canvas_item!=NULL) { // do the rescaling ourselves
653       if (ui.antialias_bg) {
654         if (pg->bg->pixbuf_scale == ui.zoom) continue;
655         set_cursor_busy(TRUE);
656         pix = gdk_pixbuf_scale_simple(pg->bg->pixbuf,
657           (int)floor(pg->width*ui.zoom+0.5), (int)floor(pg->height*ui.zoom+0.5),
658           GDK_INTERP_BILINEAR);
659         gnome_canvas_item_set(pg->bg->canvas_item, "pixbuf", pix, NULL);
660         gdk_pixbuf_unref(pix);
661         pg->bg->pixbuf_scale = ui.zoom;
662         set_cursor_busy(FALSE);
663       } else
664       {
665         g_object_get(G_OBJECT(pg->bg->canvas_item), "pixbuf", &pix, NULL);
666         if (pix!=pg->bg->pixbuf)
667           gnome_canvas_item_set(pg->bg->canvas_item, "pixbuf", pg->bg->pixbuf, NULL);
668         pg->bg->pixbuf_scale = 0;
669       }
670     }
671     if (pg->bg->type == BG_PDF) { 
672       // make pixmap scale to correct size if current one is wrong
673       is_well_scaled = (fabs(pg->bg->pixel_width - pg->width*ui.zoom) < 2.
674                      && fabs(pg->bg->pixel_height - pg->height*ui.zoom) < 2.);
675       if (pg->bg->canvas_item != NULL && !is_well_scaled) {
676         g_object_get(pg->bg->canvas_item, "width-in-pixels", &is_well_scaled, NULL);
677         if (is_well_scaled)
678           gnome_canvas_item_set(pg->bg->canvas_item,
679             "width", pg->width, "height", pg->height, 
680             "width-in-pixels", FALSE, "height-in-pixels", FALSE, 
681             "width-set", TRUE, "height-set", TRUE, 
682             NULL);
683       }
684       // request an asynchronous update to a better pixmap if needed
685       zoom_to_request = MIN(ui.zoom, MAX_SAFE_RENDER_DPI/72.0);
686       if (pg->bg->pixbuf_scale == zoom_to_request) continue;
687       add_bgpdf_request(pg->bg->file_page_seq, zoom_to_request);
688       pg->bg->pixbuf_scale = zoom_to_request;
689     }
690   }
691 }
692
693 gboolean have_intersect(struct BBox *a, struct BBox *b)
694 {
695   return (MAX(a->top, b->top) <= MIN(a->bottom, b->bottom)) &&
696          (MAX(a->left, b->left) <= MIN(a->right, b->right));
697 }
698
699 /* In libgnomecanvas 2.10.0, the lower/raise functions fail to update
700    correctly the end of the group's item list. We try to work around this.
701    DON'T USE gnome_canvas_item_raise/lower directly !! */
702
703 void lower_canvas_item_to(GnomeCanvasGroup *g, GnomeCanvasItem *item, GnomeCanvasItem *after)
704 {
705   int i1, i2;
706   
707   i1 = g_list_index(g->item_list, item);
708   if (i1 == -1) return;
709   
710   if (after == NULL) i2 = -1;
711   else i2 = g_list_index(g->item_list, after);
712
713   if (i1 < i2) gnome_canvas_item_raise(item, i2-i1);
714   if (i1 > i2+1) gnome_canvas_item_lower(item, i1-i2-1);
715   
716   // BUGFIX for libgnomecanvas
717   g->item_list_end = g_list_last(g->item_list);
718 }
719
720 void rgb_to_gdkcolor(guint rgba, GdkColor *color)
721 {
722   color->pixel = 0;
723   color->red = ((rgba>>24)&0xff)*0x101;
724   color->green = ((rgba>>16)&0xff)*0x101;
725   color->blue = ((rgba>>8)&0xff)*0x101;
726 }
727
728 // some interface functions
729
730 void update_thickness_buttons(void)
731 {
732   if (ui.selection!=NULL || ui.toolno[ui.cur_mapping] >= NUM_STROKE_TOOLS) {
733     gtk_toggle_tool_button_set_active(
734       GTK_TOGGLE_TOOL_BUTTON(GET_COMPONENT("buttonThicknessOther")), TRUE);
735   } else 
736   switch (ui.cur_brush->thickness_no) {
737     case THICKNESS_FINE:
738       gtk_toggle_tool_button_set_active(
739         GTK_TOGGLE_TOOL_BUTTON(GET_COMPONENT("buttonFine")), TRUE);
740       break;
741     case THICKNESS_MEDIUM:
742       gtk_toggle_tool_button_set_active(
743         GTK_TOGGLE_TOOL_BUTTON(GET_COMPONENT("buttonMedium")), TRUE);
744       break;
745     case THICKNESS_THICK:
746       gtk_toggle_tool_button_set_active(
747         GTK_TOGGLE_TOOL_BUTTON(GET_COMPONENT("buttonThick")), TRUE);
748       break;
749     default:
750       gtk_toggle_tool_button_set_active(
751         GTK_TOGGLE_TOOL_BUTTON(GET_COMPONENT("buttonThicknessOther")), TRUE);
752   }
753 }
754
755 void update_color_buttons(void)
756 {
757   if (ui.selection!=NULL || (ui.toolno[ui.cur_mapping] != TOOL_PEN 
758       && ui.toolno[ui.cur_mapping] != TOOL_HIGHLIGHTER && ui.toolno[ui.cur_mapping] != TOOL_TEXT)) {
759     gtk_toggle_tool_button_set_active(
760       GTK_TOGGLE_TOOL_BUTTON(GET_COMPONENT("buttonColorOther")), TRUE);
761   } else
762   switch (ui.cur_brush->color_no) {
763     case COLOR_BLACK:
764       gtk_toggle_tool_button_set_active(
765         GTK_TOGGLE_TOOL_BUTTON(GET_COMPONENT("buttonBlack")), TRUE);
766       break;
767     case COLOR_BLUE:
768       gtk_toggle_tool_button_set_active(
769         GTK_TOGGLE_TOOL_BUTTON(GET_COMPONENT("buttonBlue")), TRUE);
770       break;
771     case COLOR_RED:
772       gtk_toggle_tool_button_set_active(
773         GTK_TOGGLE_TOOL_BUTTON(GET_COMPONENT("buttonRed")), TRUE);
774       break;
775     case COLOR_GREEN:
776       gtk_toggle_tool_button_set_active(
777         GTK_TOGGLE_TOOL_BUTTON(GET_COMPONENT("buttonGreen")), TRUE);
778       break;
779     case COLOR_GRAY:
780       gtk_toggle_tool_button_set_active(
781         GTK_TOGGLE_TOOL_BUTTON(GET_COMPONENT("buttonGray")), TRUE);
782       break;
783     case COLOR_LIGHTBLUE:
784       gtk_toggle_tool_button_set_active(
785         GTK_TOGGLE_TOOL_BUTTON(GET_COMPONENT("buttonLightBlue")), TRUE);
786       break;
787     case COLOR_LIGHTGREEN:
788       gtk_toggle_tool_button_set_active(
789         GTK_TOGGLE_TOOL_BUTTON(GET_COMPONENT("buttonLightGreen")), TRUE);
790       break;
791     case COLOR_MAGENTA:
792       gtk_toggle_tool_button_set_active(
793         GTK_TOGGLE_TOOL_BUTTON(GET_COMPONENT("buttonMagenta")), TRUE);
794       break;
795     case COLOR_ORANGE:
796       gtk_toggle_tool_button_set_active(
797         GTK_TOGGLE_TOOL_BUTTON(GET_COMPONENT("buttonOrange")), TRUE);
798       break;
799     case COLOR_YELLOW:
800       gtk_toggle_tool_button_set_active(
801         GTK_TOGGLE_TOOL_BUTTON(GET_COMPONENT("buttonYellow")), TRUE);
802       break;
803     case COLOR_WHITE:
804       gtk_toggle_tool_button_set_active(
805         GTK_TOGGLE_TOOL_BUTTON(GET_COMPONENT("buttonWhite")), TRUE);
806       break;
807     default:
808       gtk_toggle_tool_button_set_active(
809         GTK_TOGGLE_TOOL_BUTTON(GET_COMPONENT("buttonColorOther")), TRUE);
810   }
811 }
812
813 void update_tool_buttons(void)
814 {
815   switch(ui.toolno[ui.cur_mapping]) {
816     case TOOL_PEN:
817       gtk_toggle_tool_button_set_active(
818         GTK_TOGGLE_TOOL_BUTTON(GET_COMPONENT("buttonPen")), TRUE);
819       break;
820     case TOOL_ERASER:
821       gtk_toggle_tool_button_set_active(
822         GTK_TOGGLE_TOOL_BUTTON(GET_COMPONENT("buttonEraser")), TRUE);
823       break;
824     case TOOL_HIGHLIGHTER:
825       gtk_toggle_tool_button_set_active(
826         GTK_TOGGLE_TOOL_BUTTON(GET_COMPONENT("buttonHighlighter")), TRUE);
827       break;
828     case TOOL_TEXT:
829       gtk_toggle_tool_button_set_active(
830         GTK_TOGGLE_TOOL_BUTTON(GET_COMPONENT("buttonText")), TRUE);
831       break;
832     case TOOL_SELECTREGION:
833       gtk_toggle_tool_button_set_active(
834         GTK_TOGGLE_TOOL_BUTTON(GET_COMPONENT("buttonSelectRegion")), TRUE);
835       break;
836     case TOOL_SELECTRECT:
837       gtk_toggle_tool_button_set_active(
838         GTK_TOGGLE_TOOL_BUTTON(GET_COMPONENT("buttonSelectRectangle")), TRUE);
839       break;
840     case TOOL_VERTSPACE:
841       gtk_toggle_tool_button_set_active(
842         GTK_TOGGLE_TOOL_BUTTON(GET_COMPONENT("buttonVerticalSpace")), TRUE);
843       break;
844     case TOOL_HAND:
845       gtk_toggle_tool_button_set_active(
846         GTK_TOGGLE_TOOL_BUTTON(GET_COMPONENT("buttonHand")), TRUE);
847       break;
848   }
849     
850   gtk_toggle_tool_button_set_active(
851       GTK_TOGGLE_TOOL_BUTTON(GET_COMPONENT("buttonRuler")), 
852       ui.toolno[ui.cur_mapping]<NUM_STROKE_TOOLS && ui.cur_brush->ruler);
853   gtk_toggle_tool_button_set_active(
854       GTK_TOGGLE_TOOL_BUTTON(GET_COMPONENT("buttonReco")), 
855       ui.toolno[ui.cur_mapping]<NUM_STROKE_TOOLS && ui.cur_brush->recognizer);
856
857   update_thickness_buttons();
858   update_color_buttons();
859 }
860
861 void update_tool_menu(void)
862 {
863   switch(ui.toolno[0]) {
864     case TOOL_PEN:
865       gtk_check_menu_item_set_active(
866         GTK_CHECK_MENU_ITEM(GET_COMPONENT("toolsPen")), TRUE);
867       break;
868     case TOOL_ERASER:
869       gtk_check_menu_item_set_active(
870         GTK_CHECK_MENU_ITEM(GET_COMPONENT("toolsEraser")), TRUE);
871       break;
872     case TOOL_HIGHLIGHTER:
873       gtk_check_menu_item_set_active(
874         GTK_CHECK_MENU_ITEM(GET_COMPONENT("toolsHighlighter")), TRUE);
875       break;
876     case TOOL_TEXT:
877       gtk_check_menu_item_set_active(
878         GTK_CHECK_MENU_ITEM(GET_COMPONENT("toolsText")), TRUE);
879       break;
880     case TOOL_SELECTREGION:
881       gtk_check_menu_item_set_active(
882         GTK_CHECK_MENU_ITEM(GET_COMPONENT("toolsSelectRegion")), TRUE);
883       break;
884     case TOOL_SELECTRECT:
885       gtk_check_menu_item_set_active(
886         GTK_CHECK_MENU_ITEM(GET_COMPONENT("toolsSelectRectangle")), TRUE);
887       break;
888     case TOOL_VERTSPACE:
889       gtk_check_menu_item_set_active(
890         GTK_CHECK_MENU_ITEM(GET_COMPONENT("toolsVerticalSpace")), TRUE);
891       break;
892     case TOOL_HAND:
893       gtk_check_menu_item_set_active(
894         GTK_CHECK_MENU_ITEM(GET_COMPONENT("toolsHand")), TRUE);
895       break;
896   }
897
898   gtk_check_menu_item_set_active(
899       GTK_CHECK_MENU_ITEM(GET_COMPONENT("toolsRuler")), 
900       ui.toolno[0]<NUM_STROKE_TOOLS && ui.brushes[0][ui.toolno[0]].ruler);
901   gtk_check_menu_item_set_active(
902       GTK_CHECK_MENU_ITEM(GET_COMPONENT("toolsReco")), 
903       ui.toolno[0]<NUM_STROKE_TOOLS && ui.brushes[0][ui.toolno[0]].recognizer);
904 }
905
906 void update_ruler_indicator(void)
907 {
908   gtk_toggle_tool_button_set_active(
909       GTK_TOGGLE_TOOL_BUTTON(GET_COMPONENT("buttonRuler")), 
910       ui.toolno[ui.cur_mapping]<NUM_STROKE_TOOLS && ui.cur_brush->ruler);
911   gtk_toggle_tool_button_set_active(
912       GTK_TOGGLE_TOOL_BUTTON(GET_COMPONENT("buttonReco")), 
913       ui.toolno[ui.cur_mapping]<NUM_STROKE_TOOLS && ui.cur_brush->recognizer);
914   gtk_check_menu_item_set_active(
915       GTK_CHECK_MENU_ITEM(GET_COMPONENT("toolsRuler")), 
916       ui.toolno[0]<NUM_STROKE_TOOLS && ui.brushes[0][ui.toolno[0]].ruler);
917   gtk_check_menu_item_set_active(
918       GTK_CHECK_MENU_ITEM(GET_COMPONENT("toolsReco")), 
919       ui.toolno[0]<NUM_STROKE_TOOLS && ui.brushes[0][ui.toolno[0]].recognizer);
920 }
921
922 void update_color_menu(void)
923 {
924   if (ui.selection!=NULL || (ui.toolno[ui.cur_mapping] != TOOL_PEN 
925     && ui.toolno[ui.cur_mapping] != TOOL_HIGHLIGHTER && ui.toolno[ui.cur_mapping] != TOOL_TEXT)) {
926     gtk_check_menu_item_set_active(
927       GTK_CHECK_MENU_ITEM(GET_COMPONENT("colorNA")), TRUE);
928   } else
929   switch (ui.cur_brush->color_no) {
930     case COLOR_BLACK:
931       gtk_check_menu_item_set_active(
932         GTK_CHECK_MENU_ITEM(GET_COMPONENT("colorBlack")), TRUE);
933       break;
934     case COLOR_BLUE:
935       gtk_check_menu_item_set_active(
936         GTK_CHECK_MENU_ITEM(GET_COMPONENT("colorBlue")), TRUE);
937       break;
938     case COLOR_RED:
939       gtk_check_menu_item_set_active(
940         GTK_CHECK_MENU_ITEM(GET_COMPONENT("colorRed")), TRUE);
941       break;
942     case COLOR_GREEN:
943       gtk_check_menu_item_set_active(
944         GTK_CHECK_MENU_ITEM(GET_COMPONENT("colorGreen")), TRUE);
945       break;
946     case COLOR_GRAY:
947       gtk_check_menu_item_set_active(
948         GTK_CHECK_MENU_ITEM(GET_COMPONENT("colorGray")), TRUE);
949       break;
950     case COLOR_LIGHTBLUE:
951       gtk_check_menu_item_set_active(
952         GTK_CHECK_MENU_ITEM(GET_COMPONENT("colorLightBlue")), TRUE);
953       break;
954     case COLOR_LIGHTGREEN:
955       gtk_check_menu_item_set_active(
956         GTK_CHECK_MENU_ITEM(GET_COMPONENT("colorLightGreen")), TRUE);
957       break;
958     case COLOR_MAGENTA:
959       gtk_check_menu_item_set_active(
960         GTK_CHECK_MENU_ITEM(GET_COMPONENT("colorMagenta")), TRUE);
961       break;
962     case COLOR_ORANGE:
963       gtk_check_menu_item_set_active(
964         GTK_CHECK_MENU_ITEM(GET_COMPONENT("colorOrange")), TRUE);
965       break;
966     case COLOR_YELLOW:
967       gtk_check_menu_item_set_active(
968         GTK_CHECK_MENU_ITEM(GET_COMPONENT("colorYellow")), TRUE);
969       break;
970     case COLOR_WHITE:
971       gtk_check_menu_item_set_active(
972         GTK_CHECK_MENU_ITEM(GET_COMPONENT("colorWhite")), TRUE);
973       break;
974     default:
975       gtk_check_menu_item_set_active(
976         GTK_CHECK_MENU_ITEM(GET_COMPONENT("colorOther")), TRUE);
977   }
978 }
979
980 void update_pen_props_menu(void)
981 {
982   switch(ui.brushes[0][TOOL_PEN].thickness_no) {
983     case THICKNESS_VERYFINE:
984       gtk_check_menu_item_set_active(
985         GTK_CHECK_MENU_ITEM(GET_COMPONENT("penthicknessVeryFine")), TRUE);
986       break;
987     case THICKNESS_FINE:
988       gtk_check_menu_item_set_active(
989         GTK_CHECK_MENU_ITEM(GET_COMPONENT("penthicknessFine")), TRUE);
990       break;
991     case THICKNESS_MEDIUM:
992       gtk_check_menu_item_set_active(
993         GTK_CHECK_MENU_ITEM(GET_COMPONENT("penthicknessMedium")), TRUE);
994       break;
995     case THICKNESS_THICK:
996       gtk_check_menu_item_set_active(
997         GTK_CHECK_MENU_ITEM(GET_COMPONENT("penthicknessThick")), TRUE);
998       break;
999     case THICKNESS_VERYTHICK:
1000       gtk_check_menu_item_set_active(
1001         GTK_CHECK_MENU_ITEM(GET_COMPONENT("penthicknessVeryThick")), TRUE);
1002       break;
1003   }
1004 }
1005
1006 void update_eraser_props_menu(void)
1007 {
1008   switch (ui.brushes[0][TOOL_ERASER].thickness_no) {
1009     case THICKNESS_FINE:
1010       gtk_check_menu_item_set_active(
1011         GTK_CHECK_MENU_ITEM(GET_COMPONENT("eraserFine")), TRUE);
1012       break;
1013     case THICKNESS_MEDIUM:
1014       gtk_check_menu_item_set_active(
1015         GTK_CHECK_MENU_ITEM(GET_COMPONENT("eraserMedium")), TRUE);
1016       break;
1017     case THICKNESS_THICK:
1018       gtk_check_menu_item_set_active(
1019         GTK_CHECK_MENU_ITEM(GET_COMPONENT("eraserThick")), TRUE);
1020       break;
1021   }
1022   
1023   gtk_check_menu_item_set_active(
1024     GTK_CHECK_MENU_ITEM(GET_COMPONENT("eraserStandard")),
1025     ui.brushes[0][TOOL_ERASER].tool_options == TOOLOPT_ERASER_STANDARD);
1026   gtk_check_menu_item_set_active(
1027     GTK_CHECK_MENU_ITEM(GET_COMPONENT("eraserWhiteout")),
1028     ui.brushes[0][TOOL_ERASER].tool_options == TOOLOPT_ERASER_WHITEOUT);
1029   gtk_check_menu_item_set_active(
1030     GTK_CHECK_MENU_ITEM(GET_COMPONENT("eraserDeleteStrokes")),
1031     ui.brushes[0][TOOL_ERASER].tool_options == TOOLOPT_ERASER_STROKES);
1032 }
1033
1034 void update_highlighter_props_menu(void)
1035 {
1036   switch (ui.brushes[0][TOOL_HIGHLIGHTER].thickness_no) {
1037     case THICKNESS_FINE:
1038       gtk_check_menu_item_set_active(
1039         GTK_CHECK_MENU_ITEM(GET_COMPONENT("highlighterFine")), TRUE);
1040       break;
1041     case THICKNESS_MEDIUM:
1042       gtk_check_menu_item_set_active(
1043         GTK_CHECK_MENU_ITEM(GET_COMPONENT("highlighterMedium")), TRUE);
1044       break;
1045     case THICKNESS_THICK:
1046       gtk_check_menu_item_set_active(
1047         GTK_CHECK_MENU_ITEM(GET_COMPONENT("highlighterThick")), TRUE);
1048       break;
1049   }
1050 }
1051
1052 void update_mappings_menu_linkings(void)
1053 {
1054   switch (ui.linked_brush[1]) {
1055     case BRUSH_LINKED:
1056       gtk_check_menu_item_set_active(
1057         GTK_CHECK_MENU_ITEM(GET_COMPONENT("button2LinkBrush")), TRUE);
1058       break;
1059     case BRUSH_COPIED:
1060       gtk_check_menu_item_set_active(
1061         GTK_CHECK_MENU_ITEM(GET_COMPONENT("button2CopyBrush")), TRUE);
1062       break;
1063     case BRUSH_STATIC:
1064       gtk_check_menu_item_set_active(
1065         GTK_CHECK_MENU_ITEM(GET_COMPONENT("button2NABrush")), TRUE);
1066       break;
1067   }
1068   switch (ui.linked_brush[2]) {
1069     case BRUSH_LINKED:
1070       gtk_check_menu_item_set_active(
1071         GTK_CHECK_MENU_ITEM(GET_COMPONENT("button3LinkBrush")), TRUE);
1072       break;
1073     case BRUSH_COPIED:
1074       gtk_check_menu_item_set_active(
1075         GTK_CHECK_MENU_ITEM(GET_COMPONENT("button3CopyBrush")), TRUE);
1076       break;
1077     case BRUSH_STATIC:
1078       gtk_check_menu_item_set_active(
1079         GTK_CHECK_MENU_ITEM(GET_COMPONENT("button3NABrush")), TRUE);
1080       break;
1081   }
1082 }
1083
1084 void update_mappings_menu(void)
1085 {
1086   gtk_widget_set_sensitive(GET_COMPONENT("optionsButtonMappings"), ui.use_xinput);
1087   gtk_widget_set_sensitive(GET_COMPONENT("optionsDiscardCoreEvents"), ui.use_xinput);
1088   gtk_widget_set_sensitive(GET_COMPONENT("optionsPressureSensitive"), ui.use_xinput);
1089   gtk_check_menu_item_set_active(
1090     GTK_CHECK_MENU_ITEM(GET_COMPONENT("optionsButtonMappings")), ui.use_erasertip);
1091   gtk_check_menu_item_set_active(
1092     GTK_CHECK_MENU_ITEM(GET_COMPONENT("optionsDiscardCoreEvents")), ui.discard_corepointer);
1093   gtk_check_menu_item_set_active(
1094     GTK_CHECK_MENU_ITEM(GET_COMPONENT("optionsPressureSensitive")), ui.pressure_sensitivity);
1095
1096   switch(ui.toolno[1]) {
1097     case TOOL_PEN:
1098       gtk_check_menu_item_set_active(
1099         GTK_CHECK_MENU_ITEM(GET_COMPONENT("button2Pen")), TRUE);
1100       break;
1101     case TOOL_ERASER:
1102       gtk_check_menu_item_set_active(
1103         GTK_CHECK_MENU_ITEM(GET_COMPONENT("button2Eraser")), TRUE);
1104       break;
1105     case TOOL_HIGHLIGHTER:
1106       gtk_check_menu_item_set_active(
1107         GTK_CHECK_MENU_ITEM(GET_COMPONENT("button2Highlighter")), TRUE);
1108       break;
1109     case TOOL_TEXT:
1110       gtk_check_menu_item_set_active(
1111         GTK_CHECK_MENU_ITEM(GET_COMPONENT("button2Text")), TRUE);
1112       break;
1113     case TOOL_SELECTREGION:
1114       gtk_check_menu_item_set_active(
1115         GTK_CHECK_MENU_ITEM(GET_COMPONENT("button2SelectRegion")), TRUE);
1116       break;
1117     case TOOL_SELECTRECT:
1118       gtk_check_menu_item_set_active(
1119         GTK_CHECK_MENU_ITEM(GET_COMPONENT("button2SelectRectangle")), TRUE);
1120       break;
1121     case TOOL_VERTSPACE:
1122       gtk_check_menu_item_set_active(
1123         GTK_CHECK_MENU_ITEM(GET_COMPONENT("button2VerticalSpace")), TRUE);
1124       break;
1125   }
1126   switch(ui.toolno[2]) {
1127     case TOOL_PEN:
1128       gtk_check_menu_item_set_active(
1129         GTK_CHECK_MENU_ITEM(GET_COMPONENT("button3Pen")), TRUE);
1130       break;
1131     case TOOL_ERASER:
1132       gtk_check_menu_item_set_active(
1133         GTK_CHECK_MENU_ITEM(GET_COMPONENT("button3Eraser")), TRUE);
1134       break;
1135     case TOOL_HIGHLIGHTER:
1136       gtk_check_menu_item_set_active(
1137         GTK_CHECK_MENU_ITEM(GET_COMPONENT("button3Highlighter")), TRUE);
1138       break;
1139     case TOOL_TEXT:
1140       gtk_check_menu_item_set_active(
1141         GTK_CHECK_MENU_ITEM(GET_COMPONENT("button3Text")), TRUE);
1142       break;
1143     case TOOL_SELECTREGION:
1144       gtk_check_menu_item_set_active(
1145         GTK_CHECK_MENU_ITEM(GET_COMPONENT("button3SelectRegion")), TRUE);
1146       break;
1147     case TOOL_SELECTRECT:
1148       gtk_check_menu_item_set_active(
1149         GTK_CHECK_MENU_ITEM(GET_COMPONENT("button3SelectRectangle")), TRUE);
1150       break;
1151     case TOOL_VERTSPACE:
1152       gtk_check_menu_item_set_active(
1153         GTK_CHECK_MENU_ITEM(GET_COMPONENT("button3VerticalSpace")), TRUE);
1154       break;
1155   }
1156   update_mappings_menu_linkings();
1157 }
1158
1159 void do_switch_page(int pg, gboolean rescroll, gboolean refresh_all)
1160 {
1161   int i, cx, cy;
1162   struct Layer *layer;
1163   GList *list;
1164   
1165   ui.pageno = pg;
1166
1167   /* re-show all the layers of the old page */
1168   if (ui.cur_page != NULL)
1169     for (i=0, list = ui.cur_page->layers; list!=NULL; i++, list = list->next) {
1170       layer = (struct Layer *)list->data;
1171       if (layer->group!=NULL)
1172         gnome_canvas_item_show(GNOME_CANVAS_ITEM(layer->group));
1173     }
1174   
1175   ui.cur_page = g_list_nth_data(journal.pages, ui.pageno);
1176   ui.layerno = ui.cur_page->nlayers-1;
1177   ui.cur_layer = (struct Layer *)(g_list_last(ui.cur_page->layers)->data);
1178   update_page_stuff();
1179   if (ui.progressive_bg) rescale_bg_pixmaps();
1180  
1181   if (rescroll) { // scroll and force a refresh
1182 /* -- this seems to cause some display bugs ??
1183     gtk_adjustment_set_value(gtk_layout_get_vadjustment(GTK_LAYOUT(canvas)),
1184       ui.cur_page->voffset*ui.zoom);  */
1185     gnome_canvas_get_scroll_offsets(canvas, &cx, &cy);
1186     cy = ui.cur_page->voffset*ui.zoom;
1187     gnome_canvas_scroll_to(canvas, cx, cy);
1188     
1189     if (refresh_all) 
1190       gnome_canvas_set_pixels_per_unit(canvas, ui.zoom);
1191     else if (!ui.view_continuous)
1192       gnome_canvas_item_move(GNOME_CANVAS_ITEM(ui.cur_page->group), 0., 0.);
1193   }
1194 }
1195
1196 void update_page_stuff(void)
1197 {
1198   gchar tmp[10];
1199   GtkComboBox *layerbox;
1200   int i;
1201   GList *pglist;
1202   GtkSpinButton *spin;
1203   struct Page *pg;
1204   double vertpos, maxwidth;
1205
1206   // move the page groups to their rightful locations or hide them
1207   if (ui.view_continuous) {
1208     vertpos = 0.; 
1209     maxwidth = 0.;
1210     for (i=0, pglist = journal.pages; pglist!=NULL; i++, pglist = pglist->next) {
1211       pg = (struct Page *)pglist->data;
1212       if (pg->group!=NULL) {
1213         pg->hoffset = 0.; pg->voffset = vertpos;
1214         gnome_canvas_item_set(GNOME_CANVAS_ITEM(pg->group), 
1215             "x", pg->hoffset, "y", pg->voffset, NULL);
1216         gnome_canvas_item_show(GNOME_CANVAS_ITEM(pg->group));
1217       }
1218       vertpos += pg->height + VIEW_CONTINUOUS_SKIP;
1219       if (pg->width > maxwidth) maxwidth = pg->width;
1220     }
1221     vertpos -= VIEW_CONTINUOUS_SKIP;
1222     gnome_canvas_set_scroll_region(canvas, 0, 0, maxwidth, vertpos);
1223   } else {
1224     for (pglist = journal.pages; pglist!=NULL; pglist = pglist->next) {
1225       pg = (struct Page *)pglist->data;
1226       if (pg == ui.cur_page && pg->group!=NULL) {
1227         pg->hoffset = 0.; pg->voffset = 0.;
1228         gnome_canvas_item_set(GNOME_CANVAS_ITEM(pg->group), 
1229             "x", pg->hoffset, "y", pg->voffset, NULL);
1230         gnome_canvas_item_show(GNOME_CANVAS_ITEM(pg->group));
1231       } else {
1232         if (pg->group!=NULL) gnome_canvas_item_hide(GNOME_CANVAS_ITEM(pg->group));
1233       }
1234     }
1235     gnome_canvas_set_scroll_region(canvas, 0, 0, ui.cur_page->width, ui.cur_page->height);
1236   }
1237
1238   // update the page / layer info at bottom of screen
1239
1240   spin = GTK_SPIN_BUTTON(GET_COMPONENT("spinPageNo"));
1241   ui.in_update_page_stuff = TRUE; // avoid a bad retroaction
1242   gtk_spin_button_set_range(spin, 1, journal.npages+1);
1243     /* npages+1 will be used to create a new page at end */
1244   gtk_spin_button_set_value(spin, ui.pageno+1);
1245   g_snprintf(tmp, 10, _(" of %d"), journal.npages);
1246   gtk_label_set_text(GTK_LABEL(GET_COMPONENT("labelNumpages")), tmp);
1247
1248   layerbox = GTK_COMBO_BOX(GET_COMPONENT("comboLayer"));
1249   if (ui.layerbox_length == 0) {
1250     gtk_combo_box_prepend_text(layerbox, _("Background"));
1251     ui.layerbox_length++;
1252   }
1253   while (ui.layerbox_length > ui.cur_page->nlayers+1) {
1254     gtk_combo_box_remove_text(layerbox, 0);
1255     ui.layerbox_length--;
1256   }
1257   while (ui.layerbox_length < ui.cur_page->nlayers+1) {
1258     g_snprintf(tmp, 10, _("Layer %d"), ui.layerbox_length++);
1259     gtk_combo_box_prepend_text(layerbox, tmp);
1260   }
1261   gtk_combo_box_set_active(layerbox, ui.cur_page->nlayers-1-ui.layerno);
1262   ui.in_update_page_stuff = FALSE;
1263   
1264   // update the paper-style menu radio buttons
1265   
1266   if (ui.view_continuous)
1267     gtk_check_menu_item_set_active(
1268        GTK_CHECK_MENU_ITEM(GET_COMPONENT("viewContinuous")), TRUE);
1269   else
1270     gtk_check_menu_item_set_active(
1271        GTK_CHECK_MENU_ITEM(GET_COMPONENT("viewOnePage")), TRUE);
1272
1273   if (ui.cur_page->bg->type == BG_SOLID && !ui.bg_apply_all_pages) {
1274     switch (ui.cur_page->bg->color_no) {
1275       case COLOR_WHITE:
1276         gtk_check_menu_item_set_active(
1277           GTK_CHECK_MENU_ITEM(GET_COMPONENT("papercolorWhite")), TRUE);
1278         break;
1279       case COLOR_YELLOW:
1280         gtk_check_menu_item_set_active(
1281           GTK_CHECK_MENU_ITEM(GET_COMPONENT("papercolorYellow")), TRUE);
1282         break;
1283       case COLOR_RED:
1284         gtk_check_menu_item_set_active(
1285           GTK_CHECK_MENU_ITEM(GET_COMPONENT("papercolorPink")), TRUE);
1286         break;
1287       case COLOR_ORANGE:
1288         gtk_check_menu_item_set_active(
1289           GTK_CHECK_MENU_ITEM(GET_COMPONENT("papercolorOrange")), TRUE);
1290         break;
1291       case COLOR_BLUE:
1292         gtk_check_menu_item_set_active(
1293           GTK_CHECK_MENU_ITEM(GET_COMPONENT("papercolorBlue")), TRUE);
1294         break;
1295       case COLOR_GREEN:
1296         gtk_check_menu_item_set_active(
1297           GTK_CHECK_MENU_ITEM(GET_COMPONENT("papercolorGreen")), TRUE);
1298         break;
1299       default:
1300         gtk_check_menu_item_set_active(
1301           GTK_CHECK_MENU_ITEM(GET_COMPONENT("papercolorOther")), TRUE);
1302         break;
1303     }
1304     switch (ui.cur_page->bg->ruling) {
1305       case RULING_NONE:
1306         gtk_check_menu_item_set_active(
1307           GTK_CHECK_MENU_ITEM(GET_COMPONENT("paperstylePlain")), TRUE);
1308         break;
1309       case RULING_LINED:
1310         gtk_check_menu_item_set_active(
1311           GTK_CHECK_MENU_ITEM(GET_COMPONENT("paperstyleLined")), TRUE);
1312         break;
1313       case RULING_RULED:
1314         gtk_check_menu_item_set_active(
1315           GTK_CHECK_MENU_ITEM(GET_COMPONENT("paperstyleRuled")), TRUE);
1316         break;
1317       case RULING_GRAPH:
1318         gtk_check_menu_item_set_active(
1319           GTK_CHECK_MENU_ITEM(GET_COMPONENT("paperstyleGraph")), TRUE);
1320         break;
1321     }
1322   } else {
1323     gtk_check_menu_item_set_active(
1324       GTK_CHECK_MENU_ITEM(GET_COMPONENT("papercolorNA")), TRUE);
1325     gtk_check_menu_item_set_active(
1326       GTK_CHECK_MENU_ITEM(GET_COMPONENT("paperstyleNA")), TRUE);
1327   }
1328   
1329   // enable/disable the page/layer menu items and toolbar buttons
1330
1331   gtk_widget_set_sensitive(GET_COMPONENT("journalPaperColor"), 
1332      ui.cur_page->bg->type == BG_SOLID || ui.bg_apply_all_pages);
1333   gtk_widget_set_sensitive(GET_COMPONENT("journalSetAsDefault"),
1334      ui.cur_page->bg->type == BG_SOLID);
1335   
1336   gtk_widget_set_sensitive(GET_COMPONENT("viewFirstPage"), ui.pageno!=0);
1337   gtk_widget_set_sensitive(GET_COMPONENT("viewPreviousPage"), ui.pageno!=0);
1338   gtk_widget_set_sensitive(GET_COMPONENT("viewNextPage"), TRUE);
1339   gtk_widget_set_sensitive(GET_COMPONENT("viewLastPage"), ui.pageno!=journal.npages-1);
1340   gtk_widget_set_sensitive(GET_COMPONENT("buttonFirstPage"), ui.pageno!=0);
1341   gtk_widget_set_sensitive(GET_COMPONENT("buttonPreviousPage"), ui.pageno!=0);
1342   gtk_widget_set_sensitive(GET_COMPONENT("buttonNextPage"), TRUE);
1343   gtk_widget_set_sensitive(GET_COMPONENT("buttonLastPage"), ui.pageno!=journal.npages-1);
1344   
1345   gtk_widget_set_sensitive(GET_COMPONENT("viewShowLayer"), ui.layerno!=ui.cur_page->nlayers-1);
1346   gtk_widget_set_sensitive(GET_COMPONENT("viewHideLayer"), ui.layerno>=0);
1347
1348   gtk_widget_set_sensitive(GET_COMPONENT("editPaste"), ui.cur_layer!=NULL);
1349   gtk_widget_set_sensitive(GET_COMPONENT("buttonPaste"), ui.cur_layer!=NULL);
1350 }
1351
1352 void update_toolbar_and_menu(void)
1353 {
1354   update_tool_buttons(); // takes care of other toolbar buttons as well  
1355   update_tool_menu();
1356   update_color_menu();
1357   update_pen_props_menu();
1358   update_eraser_props_menu();
1359   update_highlighter_props_menu();
1360   update_mappings_menu();
1361
1362   gtk_toggle_tool_button_set_active(
1363     GTK_TOGGLE_TOOL_BUTTON(GET_COMPONENT("buttonFullscreen")), ui.fullscreen);
1364   gtk_check_menu_item_set_active(
1365     GTK_CHECK_MENU_ITEM(GET_COMPONENT("viewFullscreen")), ui.fullscreen);
1366 }
1367
1368 void update_file_name(char *filename)
1369 {
1370   gchar tmp[100], *p;
1371   if (ui.filename != NULL) g_free(ui.filename);
1372   ui.filename = filename;
1373   if (filename == NULL) {
1374     gtk_window_set_title(GTK_WINDOW (winMain), _("Xournal"));
1375     return;
1376   }
1377   p = g_utf8_strrchr(filename, -1, '/');
1378   if (p == NULL) p = filename; 
1379   else p = g_utf8_next_char(p);
1380   g_snprintf(tmp, 100, _("Xournal - %s"), p);
1381   gtk_window_set_title(GTK_WINDOW (winMain), tmp);
1382   new_mru_entry(filename);
1383 }
1384
1385 void update_undo_redo_enabled(void)
1386 {
1387   gtk_widget_set_sensitive(GET_COMPONENT("editUndo"), undo!=NULL);
1388   gtk_widget_set_sensitive(GET_COMPONENT("editRedo"), redo!=NULL);
1389   gtk_widget_set_sensitive(GET_COMPONENT("buttonUndo"), undo!=NULL);
1390   gtk_widget_set_sensitive(GET_COMPONENT("buttonRedo"), redo!=NULL);
1391 }
1392
1393 void update_copy_paste_enabled(void)
1394 {
1395   gtk_widget_set_sensitive(GET_COMPONENT("editCut"), ui.selection!=NULL);
1396   gtk_widget_set_sensitive(GET_COMPONENT("editCopy"), ui.selection!=NULL);
1397   gtk_widget_set_sensitive(GET_COMPONENT("editPaste"), ui.cur_item_type!=ITEM_TEXT);
1398   gtk_widget_set_sensitive(GET_COMPONENT("editDelete"), ui.selection!=NULL);
1399   gtk_widget_set_sensitive(GET_COMPONENT("buttonCut"), ui.selection!=NULL);
1400   gtk_widget_set_sensitive(GET_COMPONENT("buttonCopy"), ui.selection!=NULL);
1401   gtk_widget_set_sensitive(GET_COMPONENT("buttonPaste"), ui.cur_item_type!=ITEM_TEXT);
1402 }
1403
1404 void update_mapping_linkings(int toolno)
1405 {
1406   int i;
1407   
1408   for (i = 1; i<=NUM_BUTTONS; i++) {
1409     if (ui.linked_brush[i] == BRUSH_LINKED) {
1410       if (toolno >= 0 && toolno < NUM_STROKE_TOOLS)
1411         g_memmove(&(ui.brushes[i][toolno]), &(ui.brushes[0][toolno]), sizeof(struct Brush));
1412     }
1413     if (ui.linked_brush[i] == BRUSH_COPIED && toolno == ui.toolno[i]) {
1414       ui.linked_brush[i] = BRUSH_STATIC;
1415       if (i==1 || i==2) update_mappings_menu_linkings();
1416     }
1417   }
1418 }
1419
1420 void set_cur_color(int color)
1421 {
1422   ui.cur_brush->color_no = color;
1423   if (ui.toolno[0] == TOOL_HIGHLIGHTER)
1424     ui.cur_brush->color_rgba = predef_colors_rgba[color] & ui.hiliter_alpha_mask;
1425   else
1426     ui.cur_brush->color_rgba = predef_colors_rgba[color];
1427   update_mapping_linkings(ui.toolno[0]);
1428 }
1429
1430 void recolor_temp_text(int color_no, guint color_rgba)
1431 {
1432   GdkColor gdkcolor;
1433   
1434   if (ui.cur_item_type!=ITEM_TEXT) return;
1435   if (ui.cur_item->text!=NULL && ui.cur_item->brush.color_rgba != color_rgba) {
1436     prepare_new_undo();
1437     undo->type = ITEM_TEXT_ATTRIB;
1438     undo->item = ui.cur_item;
1439     undo->str = g_strdup(ui.cur_item->font_name);
1440     undo->val_x = ui.cur_item->font_size;
1441     undo->brush = (struct Brush *)g_memdup(&(ui.cur_item->brush), sizeof(struct Brush));
1442   }
1443   ui.cur_item->brush.color_no = color_no;
1444   ui.cur_item->brush.color_rgba = color_rgba;
1445   rgb_to_gdkcolor(color_rgba, &gdkcolor);
1446   gtk_widget_modify_text(ui.cur_item->widget, GTK_STATE_NORMAL, &gdkcolor);
1447   gtk_widget_grab_focus(ui.cur_item->widget);
1448 }
1449
1450 void process_color_activate(GtkMenuItem *menuitem, int color)
1451 {
1452   if (GTK_OBJECT_TYPE(menuitem) == GTK_TYPE_RADIO_MENU_ITEM) {
1453     if (!gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM (menuitem)))
1454       return;
1455   } else {
1456     if (!gtk_toggle_tool_button_get_active(GTK_TOGGLE_TOOL_BUTTON (menuitem)))
1457       return;
1458   }
1459
1460   if (ui.cur_mapping != 0) return; // not user-generated
1461   reset_focus();
1462
1463   if (ui.cur_item_type == ITEM_TEXT)
1464     recolor_temp_text(color, predef_colors_rgba[color]);
1465
1466   if (ui.selection != NULL) {
1467     recolor_selection(color);
1468     update_color_buttons();
1469     update_color_menu();
1470   }
1471   
1472   if (ui.toolno[0] != TOOL_PEN && ui.toolno[0] != TOOL_HIGHLIGHTER
1473       && ui.toolno[0] != TOOL_TEXT) {
1474     if (ui.selection != NULL) return;
1475     end_text();
1476     ui.toolno[0] = TOOL_PEN;
1477     ui.cur_brush = &(ui.brushes[0][TOOL_PEN]);
1478     update_tool_buttons();
1479     update_tool_menu();
1480   }
1481   
1482   set_cur_color(color);
1483   update_color_buttons();
1484   update_color_menu();
1485   update_cursor();
1486 }
1487
1488 void process_thickness_activate(GtkMenuItem *menuitem, int tool, int val)
1489 {
1490   if (GTK_OBJECT_TYPE(menuitem) == GTK_TYPE_RADIO_MENU_ITEM) {
1491     if (!gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM (menuitem)))
1492       return;
1493   } else {
1494     if (!gtk_toggle_tool_button_get_active(GTK_TOGGLE_TOOL_BUTTON (menuitem)))
1495       return;
1496   }
1497
1498   if (ui.cur_mapping != 0) return; // not user-generated
1499
1500   if (ui.selection != NULL && GTK_OBJECT_TYPE(menuitem) != GTK_TYPE_RADIO_MENU_ITEM) {
1501     reset_focus();
1502     rethicken_selection(val);
1503     update_thickness_buttons();
1504   }
1505
1506   if (tool >= NUM_STROKE_TOOLS) {
1507     update_thickness_buttons(); // undo illegal button selection
1508     return;
1509   }
1510
1511   if (ui.brushes[0][tool].thickness_no == val) return;
1512   reset_focus();
1513   end_text();
1514   ui.brushes[0][tool].thickness_no = val;
1515   ui.brushes[0][tool].thickness = predef_thickness[tool][val];
1516   update_mapping_linkings(tool);
1517   
1518   update_thickness_buttons();
1519   if (tool == TOOL_PEN) update_pen_props_menu();
1520   if (tool == TOOL_ERASER) update_eraser_props_menu();
1521   if (tool == TOOL_HIGHLIGHTER) update_highlighter_props_menu();
1522   update_cursor();
1523 }
1524
1525 void process_papercolor_activate(GtkMenuItem *menuitem, int color)
1526 {
1527   struct Page *pg;
1528   GList *pglist;
1529   gboolean hasdone;
1530
1531   if (!gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM (menuitem)))
1532     return;
1533
1534   if ((ui.cur_page->bg->type != BG_SOLID) || ui.bg_apply_all_pages)
1535     gtk_check_menu_item_set_active(
1536       GTK_CHECK_MENU_ITEM(GET_COMPONENT("papercolorNA")), TRUE);
1537
1538   pg = ui.cur_page;
1539   hasdone = FALSE;
1540   for (pglist = journal.pages; pglist!=NULL; pglist = pglist->next) {
1541     if (ui.bg_apply_all_pages) pg = (struct Page *)pglist->data;
1542     if (pg->bg->type == BG_SOLID && pg->bg->color_no != color) {
1543       prepare_new_undo();
1544       if (hasdone) undo->multiop |= MULTIOP_CONT_UNDO;
1545       undo->multiop |= MULTIOP_CONT_REDO;
1546       hasdone = TRUE;
1547       undo->type = ITEM_NEW_BG_ONE;
1548       undo->page = pg;
1549       undo->bg = (struct Background *)g_memdup(pg->bg, sizeof(struct Background));
1550       undo->bg->canvas_item = NULL;
1551
1552       pg->bg->color_no = color;
1553       pg->bg->color_rgba = predef_bgcolors_rgba[color];
1554       update_canvas_bg(pg);
1555     }
1556     if (!ui.bg_apply_all_pages) break;
1557   }
1558   if (hasdone) undo->multiop -= MULTIOP_CONT_REDO;
1559 }
1560
1561 void process_paperstyle_activate(GtkMenuItem *menuitem, int style)
1562 {
1563   struct Page *pg;
1564   GList *pglist;
1565   gboolean hasdone, must_upd;
1566
1567   if (!gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM (menuitem)))
1568     return;
1569
1570   if (ui.bg_apply_all_pages)
1571     gtk_check_menu_item_set_active(
1572       GTK_CHECK_MENU_ITEM(GET_COMPONENT("paperstyleNA")), TRUE);
1573
1574   pg = ui.cur_page;
1575   hasdone = FALSE;
1576   must_upd = FALSE;
1577   for (pglist = journal.pages; pglist!=NULL; pglist = pglist->next) {
1578     if (ui.bg_apply_all_pages) pg = (struct Page *)pglist->data;
1579     if (pg->bg->type != BG_SOLID || pg->bg->ruling != style) {
1580       prepare_new_undo();
1581       undo->type = ITEM_NEW_BG_ONE;
1582       if (hasdone) undo->multiop |= MULTIOP_CONT_UNDO;
1583       undo->multiop |= MULTIOP_CONT_REDO;
1584       hasdone = TRUE;
1585       undo->page = pg;
1586       undo->bg = (struct Background *)g_memdup(pg->bg, sizeof(struct Background));
1587       undo->bg->canvas_item = NULL;
1588
1589       if (pg->bg->type != BG_SOLID) {
1590         pg->bg->type = BG_SOLID;
1591         pg->bg->color_no = COLOR_WHITE;
1592         pg->bg->color_rgba = predef_bgcolors_rgba[COLOR_WHITE];
1593         pg->bg->filename = NULL;
1594         pg->bg->pixbuf = NULL;
1595         must_upd = TRUE;
1596       }
1597       pg->bg->ruling = style;
1598       update_canvas_bg(pg);
1599     }
1600     if (!ui.bg_apply_all_pages) break;
1601   }
1602   if (hasdone) undo->multiop -= MULTIOP_CONT_REDO;
1603   if (must_upd) update_page_stuff();
1604 }
1605
1606 gboolean ok_to_close(void)
1607 {
1608   GtkWidget *dialog;
1609   GtkResponseType response;
1610
1611   if (ui.saved) return TRUE;
1612   dialog = gtk_message_dialog_new(GTK_WINDOW (winMain), GTK_DIALOG_DESTROY_WITH_PARENT,
1613     GTK_MESSAGE_WARNING, GTK_BUTTONS_YES_NO, _("Save changes to '%s'?"),
1614     (ui.filename!=NULL) ? ui.filename:_("Untitled"));
1615   gtk_dialog_add_button(GTK_DIALOG (dialog), GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL);
1616   response = gtk_dialog_run(GTK_DIALOG (dialog));
1617   gtk_widget_destroy(dialog);
1618   if (response == GTK_RESPONSE_CANCEL || response == GTK_RESPONSE_DELETE_EVENT) 
1619     return FALSE; // aborted
1620   if (response == GTK_RESPONSE_YES) {
1621     on_fileSave_activate(NULL, NULL);
1622     if (!ui.saved) return FALSE; // if save failed, then we abort
1623   }
1624   return TRUE;
1625 }
1626
1627 // send the focus back to the appropriate widget
1628 void reset_focus(void)
1629 {
1630   if (ui.cur_item_type == ITEM_TEXT)
1631     gtk_widget_grab_focus(ui.cur_item->widget);
1632   else
1633     gtk_widget_grab_focus(GTK_WIDGET(canvas));
1634   reset_recognizer();
1635 }
1636
1637 // selection / clipboard stuff
1638
1639 void reset_selection(void)
1640 {
1641   if (ui.selection == NULL) return;
1642   if (ui.selection->canvas_item != NULL) 
1643     gtk_object_destroy(GTK_OBJECT(ui.selection->canvas_item));
1644   g_list_free(ui.selection->items);
1645   g_free(ui.selection);
1646   ui.selection = NULL;
1647   update_copy_paste_enabled();
1648   update_color_menu();
1649   update_thickness_buttons();
1650   update_color_buttons();
1651   update_font_button();
1652   update_cursor();
1653 }
1654
1655 void move_journal_items_by(GList *itemlist, double dx, double dy,
1656                               struct Layer *l1, struct Layer *l2, GList *depths)
1657 {
1658   struct Item *item;
1659   GnomeCanvasItem *refitem;
1660   GList *link;
1661   int i;
1662   double *pt;
1663   
1664   while (itemlist!=NULL) {
1665     item = (struct Item *)itemlist->data;
1666     if (item->type == ITEM_STROKE)
1667       for (pt=item->path->coords, i=0; i<item->path->num_points; i++, pt+=2)
1668         { pt[0] += dx; pt[1] += dy; }
1669     if (item->type == ITEM_STROKE || item->type == ITEM_TEXT || item->type == ITEM_TEMP_TEXT) {
1670       item->bbox.left += dx;
1671       item->bbox.right += dx;
1672       item->bbox.top += dy;
1673       item->bbox.bottom += dy;
1674     }
1675     if (l1 != l2) {
1676       // find out where to insert
1677       if (depths != NULL) {
1678         if (depths->data == NULL) link = l2->items;
1679         else {
1680           link = g_list_find(l2->items, depths->data);
1681           if (link != NULL) link = link->next;
1682         }
1683       } else link = NULL;
1684       l2->items = g_list_insert_before(l2->items, link, item);
1685       l2->nitems++;
1686       l1->items = g_list_remove(l1->items, item);
1687       l1->nitems--;
1688     }
1689     if (depths != NULL) { // also raise/lower the canvas items
1690       if (item->canvas_item!=NULL) {
1691         if (depths->data == NULL) link = NULL;
1692         else link = g_list_find(l2->items, depths->data);
1693         if (link != NULL) refitem = ((struct Item *)(link->data))->canvas_item;
1694         else refitem = NULL;
1695         lower_canvas_item_to(l2->group, item->canvas_item, refitem);
1696       }
1697       depths = depths->next;
1698     }
1699     itemlist = itemlist->next;
1700   }
1701 }
1702
1703 void resize_journal_items_by(GList *itemlist, double scaling_x, double scaling_y,
1704                              double offset_x, double offset_y)
1705 {
1706   struct Item *item;
1707   GList *list;
1708   double mean_scaling, temp;
1709   double *pt, *wid;
1710   GnomeCanvasGroup *group;
1711   int i; 
1712   
1713   /* geometric mean of x and y scalings = rescaling for stroke widths
1714      and for text font sizes */
1715   mean_scaling = sqrt(fabs(scaling_x * scaling_y));
1716
1717   for (list = itemlist; list != NULL; list = list->next) {
1718     item = (struct Item *)list->data;
1719     if (item->type == ITEM_STROKE) {
1720       item->brush.thickness = item->brush.thickness * mean_scaling;
1721       for (i=0, pt=item->path->coords; i<item->path->num_points; i++, pt+=2) {
1722         pt[0] = pt[0]*scaling_x + offset_x;
1723         pt[1] = pt[1]*scaling_y + offset_y;
1724       }
1725       if (item->brush.variable_width)
1726         for (i=0, wid=item->widths; i<item->path->num_points-1; i++, wid++)
1727           *wid = *wid * mean_scaling;
1728
1729       item->bbox.left = item->bbox.left*scaling_x + offset_x;
1730       item->bbox.right = item->bbox.right*scaling_x + offset_x;
1731       item->bbox.top = item->bbox.top*scaling_y + offset_y;
1732       item->bbox.bottom = item->bbox.bottom*scaling_y + offset_y;
1733       if (item->bbox.left > item->bbox.right) {
1734         temp = item->bbox.left;
1735         item->bbox.left = item->bbox.right;
1736         item->bbox.right = temp;
1737       }
1738       if (item->bbox.top > item->bbox.bottom) {
1739         temp = item->bbox.top;
1740         item->bbox.top = item->bbox.bottom;
1741         item->bbox.bottom = temp;
1742       }
1743     }
1744     if (item->type == ITEM_TEXT) {
1745       /* must scale about NW corner -- all other points of the text box
1746          are font- and zoom-dependent, so scaling about center of text box
1747          couldn't be undone properly. FIXME? */
1748       item->font_size *= mean_scaling;
1749       item->bbox.left = item->bbox.left*scaling_x + offset_x;
1750       item->bbox.top = item->bbox.top*scaling_y + offset_y;
1751     }
1752     // redraw the item
1753     if (item->canvas_item!=NULL) {
1754       group = (GnomeCanvasGroup *) item->canvas_item->parent;
1755       gtk_object_destroy(GTK_OBJECT(item->canvas_item));
1756       make_canvas_item_one(group, item);
1757     }
1758   }
1759 }
1760
1761 // Switch between button mappings
1762
1763 /* NOTE ABOUT BUTTON MAPPINGS: ui.cur_mapping is 0 except while a canvas
1764    click event is being processed ... */
1765
1766 void switch_mapping(int m)
1767 {
1768   if (ui.cur_mapping == m) return;
1769
1770   ui.cur_mapping = m;
1771   if (ui.toolno[m] < NUM_STROKE_TOOLS) 
1772     ui.cur_brush = &(ui.brushes[m][ui.toolno[m]]);
1773   if (ui.toolno[m] == TOOL_TEXT)
1774     ui.cur_brush = &(ui.brushes[m][TOOL_PEN]);
1775   update_tool_buttons();
1776   update_color_menu();
1777   update_cursor();
1778 }
1779
1780 void process_mapping_activate(GtkMenuItem *menuitem, int m, int tool)
1781 {
1782   if (!gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(menuitem))) return;
1783   if (ui.cur_mapping!=0) return;
1784   if (ui.toolno[m] == tool) return;
1785   end_text();
1786   reset_focus();
1787     
1788   ui.toolno[m] = tool;
1789   if (ui.linked_brush[m] == BRUSH_COPIED) {
1790     ui.linked_brush[m] = BRUSH_STATIC;
1791     update_mappings_menu_linkings();
1792   }
1793 }
1794
1795 // update the ordering of components in the main vbox
1796
1797 const char *vbox_component_names[VBOX_MAIN_NITEMS]=
1798  {"scrolledwindowMain", "menubar", "toolbarMain", "toolbarPen", "hbox1"};
1799
1800 void update_vbox_order(int *order)
1801 {
1802   int i, j;
1803   GtkWidget *child;
1804   GtkBox *vboxMain = GTK_BOX(GET_COMPONENT("vboxMain"));
1805   gboolean present[VBOX_MAIN_NITEMS];
1806   
1807   for (i=0; i<VBOX_MAIN_NITEMS; i++) present[i] = FALSE;
1808   j=0;
1809   for (i=0; i<VBOX_MAIN_NITEMS; i++) {
1810     if (order[i]<0 || order[i]>=VBOX_MAIN_NITEMS) continue;
1811     present[order[i]] = TRUE;
1812     child = GET_COMPONENT(vbox_component_names[order[i]]);
1813     gtk_box_reorder_child(vboxMain, child, j++);
1814     gtk_widget_show(child);
1815   }
1816   for (i=1; i<VBOX_MAIN_NITEMS; i++) // hide others, but not the drawing area!
1817     if (!present[i]) gtk_widget_hide(GET_COMPONENT(vbox_component_names[i]));
1818 }
1819
1820 gchar *make_cur_font_name(void)
1821 {
1822   gchar *str;
1823   struct Item *it;
1824
1825   if (ui.cur_item_type == ITEM_TEXT)
1826     str = g_strdup_printf("%s %.1f", ui.cur_item->font_name, ui.cur_item->font_size);
1827   else if (ui.selection!=NULL && ui.selection->items!=NULL &&
1828            ui.selection->items->next==NULL &&
1829            (it=(struct Item*)ui.selection->items->data)->type == ITEM_TEXT)
1830     str = g_strdup_printf("%s %.1f", it->font_name, it->font_size);
1831   else
1832     str = g_strdup_printf("%s %.1f", ui.font_name, ui.font_size);
1833   return str;
1834 }
1835
1836 void update_font_button(void)
1837 {
1838   gchar *str;
1839
1840   str = make_cur_font_name();
1841   gtk_font_button_set_font_name(GTK_FONT_BUTTON(GET_COMPONENT("fontButton")), str);
1842   g_free(str);
1843 }
1844
1845 gboolean can_accel(GtkWidget *widget, guint id, gpointer data)
1846 {
1847   return GTK_WIDGET_SENSITIVE(widget);
1848 }
1849
1850 void allow_all_accels(void)
1851 {
1852   g_signal_connect((gpointer) GET_COMPONENT("fileNew"),
1853       "can-activate-accel", G_CALLBACK(can_accel), NULL);
1854   g_signal_connect((gpointer) GET_COMPONENT("fileOpen"),
1855       "can-activate-accel", G_CALLBACK(can_accel), NULL);
1856   g_signal_connect((gpointer) GET_COMPONENT("fileSave"),
1857       "can-activate-accel", G_CALLBACK(can_accel), NULL);
1858   g_signal_connect((gpointer) GET_COMPONENT("filePrint"),
1859       "can-activate-accel", G_CALLBACK(can_accel), NULL);
1860   g_signal_connect((gpointer) GET_COMPONENT("filePrintPDF"),
1861       "can-activate-accel", G_CALLBACK(can_accel), NULL);
1862   g_signal_connect((gpointer) GET_COMPONENT("fileQuit"),
1863       "can-activate-accel", G_CALLBACK(can_accel), NULL);
1864   g_signal_connect((gpointer) GET_COMPONENT("editUndo"),
1865       "can-activate-accel", G_CALLBACK(can_accel), NULL);
1866   g_signal_connect((gpointer) GET_COMPONENT("editRedo"),
1867       "can-activate-accel", G_CALLBACK(can_accel), NULL);
1868   g_signal_connect((gpointer) GET_COMPONENT("editCut"),
1869       "can-activate-accel", G_CALLBACK(can_accel), NULL);
1870   g_signal_connect((gpointer) GET_COMPONENT("editCopy"),
1871       "can-activate-accel", G_CALLBACK(can_accel), NULL);
1872   g_signal_connect((gpointer) GET_COMPONENT("editPaste"),
1873       "can-activate-accel", G_CALLBACK(can_accel), NULL);
1874   g_signal_connect((gpointer) GET_COMPONENT("editDelete"),
1875       "can-activate-accel", G_CALLBACK(can_accel), NULL);
1876   g_signal_connect((gpointer) GET_COMPONENT("viewFullscreen"),
1877       "can-activate-accel", G_CALLBACK(can_accel), NULL);
1878   g_signal_connect((gpointer) GET_COMPONENT("viewZoomIn"),
1879       "can-activate-accel", G_CALLBACK(can_accel), NULL);
1880   g_signal_connect((gpointer) GET_COMPONENT("viewZoomOut"),
1881       "can-activate-accel", G_CALLBACK(can_accel), NULL);
1882   g_signal_connect((gpointer) GET_COMPONENT("viewNormalSize"),
1883       "can-activate-accel", G_CALLBACK(can_accel), NULL);
1884   g_signal_connect((gpointer) GET_COMPONENT("viewPageWidth"),
1885       "can-activate-accel", G_CALLBACK(can_accel), NULL);
1886   g_signal_connect((gpointer) GET_COMPONENT("viewFirstPage"),
1887       "can-activate-accel", G_CALLBACK(can_accel), NULL);
1888   g_signal_connect((gpointer) GET_COMPONENT("viewPreviousPage"),
1889       "can-activate-accel", G_CALLBACK(can_accel), NULL);
1890   g_signal_connect((gpointer) GET_COMPONENT("viewNextPage"),
1891       "can-activate-accel", G_CALLBACK(can_accel), NULL);
1892   g_signal_connect((gpointer) GET_COMPONENT("viewLastPage"),
1893       "can-activate-accel", G_CALLBACK(can_accel), NULL);
1894   g_signal_connect((gpointer) GET_COMPONENT("toolsPen"),
1895       "can-activate-accel", G_CALLBACK(can_accel), NULL);
1896   g_signal_connect((gpointer) GET_COMPONENT("toolsEraser"),
1897       "can-activate-accel", G_CALLBACK(can_accel), NULL);
1898   g_signal_connect((gpointer) GET_COMPONENT("toolsHighlighter"),
1899       "can-activate-accel", G_CALLBACK(can_accel), NULL);
1900   g_signal_connect((gpointer) GET_COMPONENT("toolsText"),
1901       "can-activate-accel", G_CALLBACK(can_accel), NULL);
1902 /*  g_signal_connect((gpointer) GET_COMPONENT("toolsSelectRegion"),
1903       "can-activate-accel", G_CALLBACK(can_accel), NULL);  */
1904   g_signal_connect((gpointer) GET_COMPONENT("toolsSelectRectangle"),
1905       "can-activate-accel", G_CALLBACK(can_accel), NULL);
1906   g_signal_connect((gpointer) GET_COMPONENT("toolsVerticalSpace"),
1907       "can-activate-accel", G_CALLBACK(can_accel), NULL);
1908   g_signal_connect((gpointer) GET_COMPONENT("toolsHand"),
1909       "can-activate-accel", G_CALLBACK(can_accel), NULL);
1910   g_signal_connect((gpointer) GET_COMPONENT("toolsTextFont"),
1911       "can-activate-accel", G_CALLBACK(can_accel), NULL);
1912   g_signal_connect((gpointer) GET_COMPONENT("toolsRuler"),
1913       "can-activate-accel", G_CALLBACK(can_accel), NULL);
1914   g_signal_connect((gpointer) GET_COMPONENT("toolsReco"),
1915       "can-activate-accel", G_CALLBACK(can_accel), NULL);
1916 }
1917
1918 void add_scroll_bindings(void)
1919 {
1920   GtkBindingSet *binding_set;
1921   
1922   binding_set = gtk_binding_set_by_class(
1923      G_OBJECT_GET_CLASS(GET_COMPONENT("scrolledwindowMain")));
1924   gtk_binding_entry_add_signal(binding_set, GDK_Up, 0,
1925     "scroll_child", 2, GTK_TYPE_SCROLL_TYPE, GTK_SCROLL_STEP_BACKWARD, 
1926     G_TYPE_BOOLEAN, FALSE);  
1927   gtk_binding_entry_add_signal(binding_set, GDK_KP_Up, 0,
1928     "scroll_child", 2, GTK_TYPE_SCROLL_TYPE, GTK_SCROLL_STEP_BACKWARD, 
1929     G_TYPE_BOOLEAN, FALSE);  
1930   gtk_binding_entry_add_signal(binding_set, GDK_Down, 0,
1931     "scroll_child", 2, GTK_TYPE_SCROLL_TYPE, GTK_SCROLL_STEP_FORWARD, 
1932     G_TYPE_BOOLEAN, FALSE);  
1933   gtk_binding_entry_add_signal(binding_set, GDK_KP_Down, 0,
1934     "scroll_child", 2, GTK_TYPE_SCROLL_TYPE, GTK_SCROLL_STEP_FORWARD, 
1935     G_TYPE_BOOLEAN, FALSE);  
1936   gtk_binding_entry_add_signal(binding_set, GDK_Left, 0,
1937     "scroll_child", 2, GTK_TYPE_SCROLL_TYPE, GTK_SCROLL_STEP_BACKWARD, 
1938     G_TYPE_BOOLEAN, TRUE);  
1939   gtk_binding_entry_add_signal(binding_set, GDK_KP_Left, 0,
1940     "scroll_child", 2, GTK_TYPE_SCROLL_TYPE, GTK_SCROLL_STEP_BACKWARD, 
1941     G_TYPE_BOOLEAN, TRUE);  
1942   gtk_binding_entry_add_signal(binding_set, GDK_Right, 0,
1943     "scroll_child", 2, GTK_TYPE_SCROLL_TYPE, GTK_SCROLL_STEP_FORWARD, 
1944     G_TYPE_BOOLEAN, TRUE);  
1945   gtk_binding_entry_add_signal(binding_set, GDK_KP_Right, 0,
1946     "scroll_child", 2, GTK_TYPE_SCROLL_TYPE, GTK_SCROLL_STEP_FORWARD, 
1947     G_TYPE_BOOLEAN, TRUE);  
1948 }
1949
1950 gboolean is_event_within_textview(GdkEventButton *event)
1951 {
1952   double pt[2];
1953   
1954   if (ui.cur_item_type!=ITEM_TEXT) return FALSE;
1955   get_pointer_coords((GdkEvent *)event, pt);
1956   if (pt[0]<ui.cur_item->bbox.left || pt[0]>ui.cur_item->bbox.right) return FALSE;
1957   if (pt[1]<ui.cur_item->bbox.top || pt[1]>ui.cur_item->bbox.bottom) return FALSE;
1958   return TRUE;
1959 }
1960
1961 void hide_unimplemented(void)
1962 {
1963   gtk_widget_hide(GET_COMPONENT("filePrintOptions"));
1964   gtk_widget_hide(GET_COMPONENT("journalFlatten"));  
1965   gtk_widget_hide(GET_COMPONENT("papercolorOther")); 
1966   gtk_widget_hide(GET_COMPONENT("toolsSelectRegion"));
1967   gtk_widget_hide(GET_COMPONENT("buttonSelectRegion"));
1968   gtk_widget_hide(GET_COMPONENT("button2SelectRegion"));
1969   gtk_widget_hide(GET_COMPONENT("button3SelectRegion"));
1970   gtk_widget_hide(GET_COMPONENT("colorOther"));
1971   gtk_widget_hide(GET_COMPONENT("helpIndex")); 
1972
1973   /* config file only works with glib 2.6 and beyond */
1974   if (glib_minor_version<6) {
1975     gtk_widget_hide(GET_COMPONENT("optionsAutoSavePrefs"));
1976     gtk_widget_hide(GET_COMPONENT("optionsSavePreferences"));
1977   }
1978   /* gtkprint only works with gtk+ 2.10 and beyond */
1979   if (gtk_check_version(2, 10, 0)) {
1980     gtk_widget_hide(GET_COMPONENT("filePrint"));
1981   }  
1982 }  
1983
1984 // toggle fullscreen mode
1985 void do_fullscreen(gboolean active)
1986 {
1987   end_text();
1988   reset_focus();
1989   ui.fullscreen = active;
1990   gtk_check_menu_item_set_active(
1991     GTK_CHECK_MENU_ITEM(GET_COMPONENT("viewFullscreen")), ui.fullscreen);
1992   gtk_toggle_tool_button_set_active(
1993     GTK_TOGGLE_TOOL_BUTTON(GET_COMPONENT("buttonFullscreen")), ui.fullscreen);
1994
1995   if (ui.fullscreen) gtk_window_fullscreen(GTK_WINDOW(winMain));
1996   else gtk_window_unfullscreen(GTK_WINDOW(winMain));
1997   
1998   update_vbox_order(ui.vertical_order[ui.fullscreen?1:0]);
1999 }
2000
2001 /* attempt to work around GTK+ 2.16/2.17 bugs where random interface
2002    elements receive XInput events that they can't handle properly    */
2003
2004 // prevent interface items from getting bogus XInput events
2005
2006 gboolean filter_extended_events (GtkWidget *widget, GdkEvent *event,
2007                                    gpointer user_data)
2008 {
2009   if (event->type == GDK_MOTION_NOTIFY &&
2010       event->motion.device != gdk_device_get_core_pointer())
2011     return TRUE;
2012   if ((event->type == GDK_BUTTON_PRESS || event->type == GDK_2BUTTON_PRESS ||
2013       event->type == GDK_3BUTTON_PRESS || event->type == GDK_BUTTON_RELEASE) &&
2014       event->button.device != gdk_device_get_core_pointer())
2015     return TRUE;
2016   return FALSE;
2017 }
2018
2019 /* Code to turn an extended input event into a core event and send it to
2020    a different GdkWindow -- e.g. could be used when a click in a text edit box
2021    gets sent to the canvas instead due to incorrect event translation.
2022    We now turn off xinput altogether while editing text under GTK+ 2.17, so
2023    this isn't needed any more... but could become useful again someday!
2024 */
2025
2026 /*  
2027 gboolean fix_extended_events (GtkWidget *widget, GdkEvent *event,
2028                                    gpointer user_data)
2029 {
2030   int ix, iy;
2031   GdkWindow *window;
2032
2033   if (user_data) window = (GdkWindow *)user_data;
2034   else window = widget->window;
2035
2036   if (event->type == GDK_MOTION_NOTIFY &&
2037       event->motion.device != gdk_device_get_core_pointer()) {
2038 //    printf("fixing motion\n");
2039     gdk_window_get_pointer(window, &ix, &iy, NULL);
2040     event->motion.x = ix; event->motion.y = iy;
2041     event->motion.device = gdk_device_get_core_pointer();
2042     g_object_unref(event->motion.window);
2043     event->motion.window = g_object_ref(window);
2044     gtk_widget_event(widget, event);
2045     return TRUE;
2046   }
2047   if ((event->type == GDK_BUTTON_PRESS || event->type == GDK_BUTTON_RELEASE) &&
2048       event->button.device != gdk_device_get_core_pointer()) {
2049 //    printf("fixing button from pos = %f, %f\n", event->button.x, event->button.y);
2050     gdk_window_get_pointer(window, &ix, &iy, NULL);
2051     event->button.x = ix; event->button.y = iy;
2052     event->button.device = gdk_device_get_core_pointer();
2053     g_object_unref(event->button.window);
2054     event->button.window = g_object_ref(window);
2055 //    printf("fixing button to pos = %f, %f\n", event->button.x, event->button.y);
2056     gtk_widget_event(widget, event);
2057     return TRUE;
2058   }
2059   return FALSE;
2060 }
2061 */
2062
2063 // disable xinput when layer combo box is popped up, to avoid crash
2064
2065 gboolean combobox_popup_disable_xinput (GtkWidget *widget, GdkEvent *event,
2066                                    gpointer user_data)
2067 {
2068   gboolean is_shown;
2069   
2070   g_object_get(G_OBJECT(widget), "popup-shown", &is_shown, NULL);
2071   gdk_input_set_extension_events(GTK_WIDGET(canvas)->window, 
2072      GDK_POINTER_MOTION_MASK | GDK_BUTTON_MOTION_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK,
2073      (ui.use_xinput && !is_shown)?GDK_EXTENSION_EVENTS_ALL:GDK_EXTENSION_EVENTS_NONE);
2074 }