]> git.donarmstrong.com Git - xournal.git/blob - src/xo-misc.c
custom color chooser; misc patches
[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   gnome_canvas_get_scroll_offsets(canvas, &sx, &sy);
374
375 #ifdef ENABLE_XINPUT_BUGFIX
376   // fix broken events with the core pointer's location
377   if (!finite(axes[0]) || !finite(axes[1]) || (axes[0]==0. && axes[1]==0.)) {
378     gdk_window_get_pointer(GTK_WIDGET(canvas)->window, &ix, &iy, NULL);
379     *px = ix + sx; 
380     *py = iy + sy;
381   }
382   else {
383     gdk_window_get_origin(GTK_WIDGET(canvas)->window, &wx, &wy);  
384     axis_width = device->axes[0].max - device->axes[0].min;
385     if (axis_width>EPSILON)
386       *px = (axes[0]/axis_width)*ui.screen_width + sx - wx;
387     axis_width = device->axes[1].max - device->axes[1].min;
388     if (axis_width>EPSILON)
389       *py = (axes[1]/axis_width)*ui.screen_height + sy - wy;
390   }
391 #else
392   if (!finite(*px) || !finite(*py) || (*px==0. && *py==0.)) {
393     gdk_window_get_pointer(GTK_WIDGET(canvas)->window, &ix, &iy, NULL);
394     *px = ix + sx; 
395     *py = iy + sy;
396   }
397   else {
398     *px += sx;
399     *py += sy;
400     /* with GTK+ 2.17, events come improperly translated, and the event's
401        GdkWindow isn't even the same for ButtonDown as for MotionNotify... */
402     if (!gtk_check_version(2,17,0)) { // GTK+ 2.17 issues !!
403       gdk_window_get_position(GTK_WIDGET(canvas)->window, &wx, &wy);
404       *px -= wx;
405       *py -= wy;
406     }
407   }
408 #endif
409 }
410
411 double get_pressure_multiplier(GdkEvent *event)
412 {
413   double rawpressure;
414   
415   if (event->button.device == gdk_device_get_core_pointer()
416       || event->button.device->num_axes <= 2) return 1.0;
417
418   rawpressure = event->button.axes[2]/(event->button.device->axes[2].max - event->button.device->axes[2].min);
419
420   return ((1-rawpressure)*ui.width_minimum_multiplier + rawpressure*ui.width_maximum_multiplier);
421 }
422
423 void update_item_bbox(struct Item *item)
424 {
425   int i;
426   gdouble *p, h, w;
427   
428   if (item->type == ITEM_STROKE) {
429     item->bbox.left = item->bbox.right = item->path->coords[0];
430     item->bbox.top = item->bbox.bottom = item->path->coords[1];
431     for (i=1, p=item->path->coords+2; i<item->path->num_points; i++, p+=2)
432     {
433       if (p[0] < item->bbox.left) item->bbox.left = p[0];
434       if (p[0] > item->bbox.right) item->bbox.right = p[0];
435       if (p[1] < item->bbox.top) item->bbox.top = p[1];
436       if (p[1] > item->bbox.bottom) item->bbox.bottom = p[1];
437     }
438   }
439   if (item->type == ITEM_TEXT && item->canvas_item!=NULL) {
440     h=0.; w=0.;
441     g_object_get(item->canvas_item, "text_width", &w, "text_height", &h, NULL);
442     item->bbox.right = item->bbox.left + w;
443     item->bbox.bottom = item->bbox.top + h;
444   }
445 }
446
447 void make_page_clipbox(struct Page *pg)
448 {
449   GnomeCanvasPathDef *pg_clip;
450   
451   pg_clip = gnome_canvas_path_def_new_sized(4);
452   gnome_canvas_path_def_moveto(pg_clip, 0., 0.);
453   gnome_canvas_path_def_lineto(pg_clip, 0., pg->height);
454   gnome_canvas_path_def_lineto(pg_clip, pg->width, pg->height);
455   gnome_canvas_path_def_lineto(pg_clip, pg->width, 0.);
456   gnome_canvas_path_def_closepath(pg_clip);
457   gnome_canvas_item_set(GNOME_CANVAS_ITEM(pg->group), "path", pg_clip, NULL);
458   gnome_canvas_path_def_unref(pg_clip);
459 }
460
461 void make_canvas_item_one(GnomeCanvasGroup *group, struct Item *item)
462 {
463   PangoFontDescription *font_desc;
464   GnomeCanvasPoints points;
465   int j;
466
467   if (item->type == ITEM_STROKE) {
468     if (!item->brush.variable_width)
469       item->canvas_item = gnome_canvas_item_new(group,
470             gnome_canvas_line_get_type(), "points", item->path,   
471             "cap-style", GDK_CAP_ROUND, "join-style", GDK_JOIN_ROUND,
472             "fill-color-rgba", item->brush.color_rgba,  
473             "width-units", item->brush.thickness, NULL);
474     else {
475       item->canvas_item = gnome_canvas_item_new(group,
476             gnome_canvas_group_get_type(), NULL);
477       points.num_points = 2;
478       points.ref_count = 1;
479       for (j = 0; j < item->path->num_points-1; j++) {
480         points.coords = item->path->coords+2*j;
481         gnome_canvas_item_new((GnomeCanvasGroup *) item->canvas_item,
482               gnome_canvas_line_get_type(), "points", &points, 
483               "cap-style", GDK_CAP_ROUND, "join-style", GDK_JOIN_ROUND, 
484               "fill-color-rgba", item->brush.color_rgba,
485               "width-units", item->widths[j], NULL);
486       }
487     }
488   }
489   if (item->type == ITEM_TEXT) {
490     font_desc = pango_font_description_from_string(item->font_name);
491     pango_font_description_set_absolute_size(font_desc, 
492             item->font_size*ui.zoom*PANGO_SCALE);
493     item->canvas_item = gnome_canvas_item_new(group,
494           gnome_canvas_text_get_type(),
495           "x", item->bbox.left, "y", item->bbox.top, "anchor", GTK_ANCHOR_NW,
496           "font-desc", font_desc, "fill-color-rgba", item->brush.color_rgba,
497           "text", item->text, NULL);
498     update_item_bbox(item);
499   }
500 }
501
502 void make_canvas_items(void)
503 {
504   struct Page *pg;
505   struct Layer *l;
506   struct Item *item;
507   GList *pagelist, *layerlist, *itemlist;
508   
509   for (pagelist = journal.pages; pagelist!=NULL; pagelist = pagelist->next) {
510     pg = (struct Page *)pagelist->data;
511     if (pg->group == NULL) {
512       pg->group = (GnomeCanvasGroup *) gnome_canvas_item_new(
513          gnome_canvas_root(canvas), gnome_canvas_clipgroup_get_type(), NULL);
514       make_page_clipbox(pg);
515     }
516     if (pg->bg->canvas_item == NULL) update_canvas_bg(pg);
517     for (layerlist = pg->layers; layerlist!=NULL; layerlist = layerlist->next) {
518       l = (struct Layer *)layerlist->data;
519       if (l->group == NULL)
520         l->group = (GnomeCanvasGroup *) gnome_canvas_item_new(
521            pg->group, gnome_canvas_group_get_type(), NULL);
522       for (itemlist = l->items; itemlist!=NULL; itemlist = itemlist->next) {
523         item = (struct Item *)itemlist->data;
524         if (item->canvas_item == NULL)
525           make_canvas_item_one(l->group, item);
526       }
527     }
528   }
529 }
530
531 void update_canvas_bg(struct Page *pg)
532 {
533   GnomeCanvasGroup *group;
534   GnomeCanvasPoints *seg;
535   GdkPixbuf *scaled_pix;
536   double *pt;
537   double x, y;
538   int w, h;
539   gboolean is_well_scaled;
540   
541   if (pg->bg->canvas_item != NULL)
542     gtk_object_destroy(GTK_OBJECT(pg->bg->canvas_item));
543   pg->bg->canvas_item = NULL;
544   
545   if (pg->bg->type == BG_SOLID)
546   {
547     pg->bg->canvas_item = gnome_canvas_item_new(pg->group,
548                                gnome_canvas_group_get_type(), NULL);
549     group = GNOME_CANVAS_GROUP(pg->bg->canvas_item);
550     lower_canvas_item_to(pg->group, pg->bg->canvas_item, NULL);
551     gnome_canvas_item_new(group, gnome_canvas_rect_get_type(),
552       "x1", 0., "x2", pg->width, "y1", 0., "y2", pg->height,
553       "fill-color-rgba", pg->bg->color_rgba, NULL);
554     if (pg->bg->ruling == RULING_NONE) return;
555     seg = gnome_canvas_points_new(2);
556     pt = seg->coords;
557     if (pg->bg->ruling == RULING_GRAPH) {
558       pt[1] = 0; pt[3] = pg->height;
559       for (x=RULING_GRAPHSPACING; x<pg->width-1; x+=RULING_GRAPHSPACING) {
560         pt[0] = pt[2] = x;
561         gnome_canvas_item_new(group, gnome_canvas_line_get_type(),
562            "points", seg, "fill-color-rgba", RULING_COLOR,
563            "width-units", RULING_THICKNESS, NULL);
564       }      
565       pt[0] = 0; pt[2] = pg->width;
566       for (y=RULING_GRAPHSPACING; y<pg->height-1; y+=RULING_GRAPHSPACING) {
567         pt[1] = pt[3] = y;
568         gnome_canvas_item_new(group, gnome_canvas_line_get_type(),
569            "points", seg, "fill-color-rgba", RULING_COLOR,
570            "width-units", RULING_THICKNESS, NULL);
571       }      
572       gnome_canvas_points_free(seg);
573       return;
574     }
575     pt[0] = 0; pt[2] = pg->width;
576     for (y=RULING_TOPMARGIN; y<pg->height-1; y+=RULING_SPACING) {
577       pt[1] = pt[3] = y;
578       gnome_canvas_item_new(group, gnome_canvas_line_get_type(),
579          "points", seg, "fill-color-rgba", RULING_COLOR,
580          "width-units", RULING_THICKNESS, NULL);
581     }      
582     if (pg->bg->ruling == RULING_LINED) {
583       pt[0] = pt[2] = RULING_LEFTMARGIN;
584       pt[1] = 0; pt[3] = pg->height;
585       gnome_canvas_item_new(group, gnome_canvas_line_get_type(),
586          "points", seg, "fill-color-rgba", RULING_MARGIN_COLOR,
587          "width-units", RULING_THICKNESS, NULL);
588     }
589     gnome_canvas_points_free(seg);
590     return;
591   }
592   
593   if (pg->bg->type == BG_PIXMAP)
594   {
595     pg->bg->pixbuf_scale = 0;
596     pg->bg->canvas_item = gnome_canvas_item_new(pg->group, 
597         gnome_canvas_pixbuf_get_type(), 
598         "pixbuf", pg->bg->pixbuf,
599         "width", pg->width, "height", pg->height, 
600         "width-set", TRUE, "height-set", TRUE, 
601         NULL);
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       g_object_get(G_OBJECT(pg->bg->canvas_item), "pixbuf", &pix, NULL);
654       if (pix!=pg->bg->pixbuf)
655         gnome_canvas_item_set(pg->bg->canvas_item, "pixbuf", pg->bg->pixbuf, NULL);
656       pg->bg->pixbuf_scale = 0;
657     }
658     if (pg->bg->type == BG_PDF) { 
659       // make pixmap scale to correct size if current one is wrong
660       is_well_scaled = (fabs(pg->bg->pixel_width - pg->width*ui.zoom) < 2.
661                      && fabs(pg->bg->pixel_height - pg->height*ui.zoom) < 2.);
662       if (pg->bg->canvas_item != NULL && !is_well_scaled) {
663         g_object_get(pg->bg->canvas_item, "width-in-pixels", &is_well_scaled, NULL);
664         if (is_well_scaled)
665           gnome_canvas_item_set(pg->bg->canvas_item,
666             "width", pg->width, "height", pg->height, 
667             "width-in-pixels", FALSE, "height-in-pixels", FALSE, 
668             "width-set", TRUE, "height-set", TRUE, 
669             NULL);
670       }
671       // request an asynchronous update to a better pixmap if needed
672       zoom_to_request = MIN(ui.zoom, MAX_SAFE_RENDER_DPI/72.0);
673       if (pg->bg->pixbuf_scale == zoom_to_request) continue;
674       add_bgpdf_request(pg->bg->file_page_seq, zoom_to_request);
675       pg->bg->pixbuf_scale = zoom_to_request;
676     }
677   }
678 }
679
680 gboolean have_intersect(struct BBox *a, struct BBox *b)
681 {
682   return (MAX(a->top, b->top) <= MIN(a->bottom, b->bottom)) &&
683          (MAX(a->left, b->left) <= MIN(a->right, b->right));
684 }
685
686 /* In libgnomecanvas 2.10.0, the lower/raise functions fail to update
687    correctly the end of the group's item list. We try to work around this.
688    DON'T USE gnome_canvas_item_raise/lower directly !! */
689
690 void lower_canvas_item_to(GnomeCanvasGroup *g, GnomeCanvasItem *item, GnomeCanvasItem *after)
691 {
692   int i1, i2;
693   
694   i1 = g_list_index(g->item_list, item);
695   if (i1 == -1) return;
696   
697   if (after == NULL) i2 = -1;
698   else i2 = g_list_index(g->item_list, after);
699
700   if (i1 < i2) gnome_canvas_item_raise(item, i2-i1);
701   if (i1 > i2+1) gnome_canvas_item_lower(item, i1-i2-1);
702   
703   // BUGFIX for libgnomecanvas
704   g->item_list_end = g_list_last(g->item_list);
705 }
706
707 void rgb_to_gdkcolor(guint rgba, GdkColor *color)
708 {
709   color->pixel = 0;
710   color->red = ((rgba>>24)&0xff)*0x101;
711   color->green = ((rgba>>16)&0xff)*0x101;
712   color->blue = ((rgba>>8)&0xff)*0x101;
713 }
714
715 guint32 gdkcolor_to_rgba(GdkColor gdkcolor, guint16 alpha) 
716 {
717   guint32 rgba =  ((gdkcolor.red   & 0xff00) << 16) |
718                   ((gdkcolor.green & 0xff00) << 8)  |
719                   ((gdkcolor.blue  & 0xff00) )      |
720                   ((alpha & 0xff00) >> 8);
721
722   return rgba;
723 }
724
725 // some interface functions
726
727 void update_thickness_buttons(void)
728 {
729   if (ui.selection!=NULL || ui.toolno[ui.cur_mapping] >= NUM_STROKE_TOOLS) {
730     gtk_toggle_tool_button_set_active(
731       GTK_TOGGLE_TOOL_BUTTON(GET_COMPONENT("buttonThicknessOther")), TRUE);
732   } else 
733   switch (ui.cur_brush->thickness_no) {
734     case THICKNESS_FINE:
735       gtk_toggle_tool_button_set_active(
736         GTK_TOGGLE_TOOL_BUTTON(GET_COMPONENT("buttonFine")), TRUE);
737       break;
738     case THICKNESS_MEDIUM:
739       gtk_toggle_tool_button_set_active(
740         GTK_TOGGLE_TOOL_BUTTON(GET_COMPONENT("buttonMedium")), TRUE);
741       break;
742     case THICKNESS_THICK:
743       gtk_toggle_tool_button_set_active(
744         GTK_TOGGLE_TOOL_BUTTON(GET_COMPONENT("buttonThick")), TRUE);
745       break;
746     default:
747       gtk_toggle_tool_button_set_active(
748         GTK_TOGGLE_TOOL_BUTTON(GET_COMPONENT("buttonThicknessOther")), TRUE);
749   }
750 }
751
752 void update_color_buttons(void)
753 {
754   GdkColor gdkcolor;
755   GtkColorButton *colorbutton;
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   colorbutton = GTK_COLOR_BUTTON(GET_COMPONENT("buttonColorChooser"));
813   if ((ui.toolno[ui.cur_mapping] != TOOL_PEN && 
814        ui.toolno[ui.cur_mapping] != TOOL_HIGHLIGHTER && 
815        ui.toolno[ui.cur_mapping] != TOOL_TEXT))
816     gdkcolor.red = gdkcolor.blue = gdkcolor.green = 0;
817   else rgb_to_gdkcolor(ui.cur_brush->color_rgba, &gdkcolor);
818   gtk_color_button_set_color(colorbutton, &gdkcolor);
819   if (ui.toolno[ui.cur_mapping] == TOOL_HIGHLIGHTER) {
820     gtk_color_button_set_alpha(colorbutton,
821       (ui.cur_brush->color_rgba&0xff)*0x101);
822     gtk_color_button_set_use_alpha(colorbutton, TRUE);
823   } else {
824     gtk_color_button_set_alpha(colorbutton, 0xffff);
825     gtk_color_button_set_use_alpha(colorbutton, FALSE);
826   }
827 }
828
829 void update_tool_buttons(void)
830 {
831   switch(ui.toolno[ui.cur_mapping]) {
832     case TOOL_PEN:
833       gtk_toggle_tool_button_set_active(
834         GTK_TOGGLE_TOOL_BUTTON(GET_COMPONENT("buttonPen")), TRUE);
835       break;
836     case TOOL_ERASER:
837       gtk_toggle_tool_button_set_active(
838         GTK_TOGGLE_TOOL_BUTTON(GET_COMPONENT("buttonEraser")), TRUE);
839       break;
840     case TOOL_HIGHLIGHTER:
841       gtk_toggle_tool_button_set_active(
842         GTK_TOGGLE_TOOL_BUTTON(GET_COMPONENT("buttonHighlighter")), TRUE);
843       break;
844     case TOOL_TEXT:
845       gtk_toggle_tool_button_set_active(
846         GTK_TOGGLE_TOOL_BUTTON(GET_COMPONENT("buttonText")), TRUE);
847       break;
848     case TOOL_SELECTREGION:
849       gtk_toggle_tool_button_set_active(
850         GTK_TOGGLE_TOOL_BUTTON(GET_COMPONENT("buttonSelectRegion")), TRUE);
851       break;
852     case TOOL_SELECTRECT:
853       gtk_toggle_tool_button_set_active(
854         GTK_TOGGLE_TOOL_BUTTON(GET_COMPONENT("buttonSelectRectangle")), TRUE);
855       break;
856     case TOOL_VERTSPACE:
857       gtk_toggle_tool_button_set_active(
858         GTK_TOGGLE_TOOL_BUTTON(GET_COMPONENT("buttonVerticalSpace")), TRUE);
859       break;
860     case TOOL_HAND:
861       gtk_toggle_tool_button_set_active(
862         GTK_TOGGLE_TOOL_BUTTON(GET_COMPONENT("buttonHand")), TRUE);
863       break;
864   }
865     
866   gtk_toggle_tool_button_set_active(
867       GTK_TOGGLE_TOOL_BUTTON(GET_COMPONENT("buttonRuler")), 
868       ui.toolno[ui.cur_mapping]<NUM_STROKE_TOOLS && ui.cur_brush->ruler);
869   gtk_toggle_tool_button_set_active(
870       GTK_TOGGLE_TOOL_BUTTON(GET_COMPONENT("buttonReco")), 
871       ui.toolno[ui.cur_mapping]<NUM_STROKE_TOOLS && ui.cur_brush->recognizer);
872
873   update_thickness_buttons();
874   update_color_buttons();
875 }
876
877 void update_tool_menu(void)
878 {
879   switch(ui.toolno[0]) {
880     case TOOL_PEN:
881       gtk_check_menu_item_set_active(
882         GTK_CHECK_MENU_ITEM(GET_COMPONENT("toolsPen")), TRUE);
883       break;
884     case TOOL_ERASER:
885       gtk_check_menu_item_set_active(
886         GTK_CHECK_MENU_ITEM(GET_COMPONENT("toolsEraser")), TRUE);
887       break;
888     case TOOL_HIGHLIGHTER:
889       gtk_check_menu_item_set_active(
890         GTK_CHECK_MENU_ITEM(GET_COMPONENT("toolsHighlighter")), TRUE);
891       break;
892     case TOOL_TEXT:
893       gtk_check_menu_item_set_active(
894         GTK_CHECK_MENU_ITEM(GET_COMPONENT("toolsText")), TRUE);
895       break;
896     case TOOL_SELECTREGION:
897       gtk_check_menu_item_set_active(
898         GTK_CHECK_MENU_ITEM(GET_COMPONENT("toolsSelectRegion")), TRUE);
899       break;
900     case TOOL_SELECTRECT:
901       gtk_check_menu_item_set_active(
902         GTK_CHECK_MENU_ITEM(GET_COMPONENT("toolsSelectRectangle")), TRUE);
903       break;
904     case TOOL_VERTSPACE:
905       gtk_check_menu_item_set_active(
906         GTK_CHECK_MENU_ITEM(GET_COMPONENT("toolsVerticalSpace")), TRUE);
907       break;
908     case TOOL_HAND:
909       gtk_check_menu_item_set_active(
910         GTK_CHECK_MENU_ITEM(GET_COMPONENT("toolsHand")), TRUE);
911       break;
912   }
913
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_ruler_indicator(void)
923 {
924   gtk_toggle_tool_button_set_active(
925       GTK_TOGGLE_TOOL_BUTTON(GET_COMPONENT("buttonRuler")), 
926       ui.toolno[ui.cur_mapping]<NUM_STROKE_TOOLS && ui.cur_brush->ruler);
927   gtk_toggle_tool_button_set_active(
928       GTK_TOGGLE_TOOL_BUTTON(GET_COMPONENT("buttonReco")), 
929       ui.toolno[ui.cur_mapping]<NUM_STROKE_TOOLS && ui.cur_brush->recognizer);
930   gtk_check_menu_item_set_active(
931       GTK_CHECK_MENU_ITEM(GET_COMPONENT("toolsRuler")), 
932       ui.toolno[0]<NUM_STROKE_TOOLS && ui.brushes[0][ui.toolno[0]].ruler);
933   gtk_check_menu_item_set_active(
934       GTK_CHECK_MENU_ITEM(GET_COMPONENT("toolsReco")), 
935       ui.toolno[0]<NUM_STROKE_TOOLS && ui.brushes[0][ui.toolno[0]].recognizer);
936 }
937
938 void update_color_menu(void)
939 {
940   if (ui.selection!=NULL || (ui.toolno[ui.cur_mapping] != TOOL_PEN 
941     && ui.toolno[ui.cur_mapping] != TOOL_HIGHLIGHTER && ui.toolno[ui.cur_mapping] != TOOL_TEXT)) {
942     gtk_check_menu_item_set_active(
943       GTK_CHECK_MENU_ITEM(GET_COMPONENT("colorNA")), TRUE);
944   } else
945   switch (ui.cur_brush->color_no) {
946     case COLOR_BLACK:
947       gtk_check_menu_item_set_active(
948         GTK_CHECK_MENU_ITEM(GET_COMPONENT("colorBlack")), TRUE);
949       break;
950     case COLOR_BLUE:
951       gtk_check_menu_item_set_active(
952         GTK_CHECK_MENU_ITEM(GET_COMPONENT("colorBlue")), TRUE);
953       break;
954     case COLOR_RED:
955       gtk_check_menu_item_set_active(
956         GTK_CHECK_MENU_ITEM(GET_COMPONENT("colorRed")), TRUE);
957       break;
958     case COLOR_GREEN:
959       gtk_check_menu_item_set_active(
960         GTK_CHECK_MENU_ITEM(GET_COMPONENT("colorGreen")), TRUE);
961       break;
962     case COLOR_GRAY:
963       gtk_check_menu_item_set_active(
964         GTK_CHECK_MENU_ITEM(GET_COMPONENT("colorGray")), TRUE);
965       break;
966     case COLOR_LIGHTBLUE:
967       gtk_check_menu_item_set_active(
968         GTK_CHECK_MENU_ITEM(GET_COMPONENT("colorLightBlue")), TRUE);
969       break;
970     case COLOR_LIGHTGREEN:
971       gtk_check_menu_item_set_active(
972         GTK_CHECK_MENU_ITEM(GET_COMPONENT("colorLightGreen")), TRUE);
973       break;
974     case COLOR_MAGENTA:
975       gtk_check_menu_item_set_active(
976         GTK_CHECK_MENU_ITEM(GET_COMPONENT("colorMagenta")), TRUE);
977       break;
978     case COLOR_ORANGE:
979       gtk_check_menu_item_set_active(
980         GTK_CHECK_MENU_ITEM(GET_COMPONENT("colorOrange")), TRUE);
981       break;
982     case COLOR_YELLOW:
983       gtk_check_menu_item_set_active(
984         GTK_CHECK_MENU_ITEM(GET_COMPONENT("colorYellow")), TRUE);
985       break;
986     case COLOR_WHITE:
987       gtk_check_menu_item_set_active(
988         GTK_CHECK_MENU_ITEM(GET_COMPONENT("colorWhite")), TRUE);
989       break;
990     default:
991       gtk_check_menu_item_set_active(
992         GTK_CHECK_MENU_ITEM(GET_COMPONENT("colorNA")), TRUE);
993   }
994 }
995
996 void update_pen_props_menu(void)
997 {
998   switch(ui.brushes[0][TOOL_PEN].thickness_no) {
999     case THICKNESS_VERYFINE:
1000       gtk_check_menu_item_set_active(
1001         GTK_CHECK_MENU_ITEM(GET_COMPONENT("penthicknessVeryFine")), TRUE);
1002       break;
1003     case THICKNESS_FINE:
1004       gtk_check_menu_item_set_active(
1005         GTK_CHECK_MENU_ITEM(GET_COMPONENT("penthicknessFine")), TRUE);
1006       break;
1007     case THICKNESS_MEDIUM:
1008       gtk_check_menu_item_set_active(
1009         GTK_CHECK_MENU_ITEM(GET_COMPONENT("penthicknessMedium")), TRUE);
1010       break;
1011     case THICKNESS_THICK:
1012       gtk_check_menu_item_set_active(
1013         GTK_CHECK_MENU_ITEM(GET_COMPONENT("penthicknessThick")), TRUE);
1014       break;
1015     case THICKNESS_VERYTHICK:
1016       gtk_check_menu_item_set_active(
1017         GTK_CHECK_MENU_ITEM(GET_COMPONENT("penthicknessVeryThick")), TRUE);
1018       break;
1019   }
1020 }
1021
1022 void update_eraser_props_menu(void)
1023 {
1024   switch (ui.brushes[0][TOOL_ERASER].thickness_no) {
1025     case THICKNESS_FINE:
1026       gtk_check_menu_item_set_active(
1027         GTK_CHECK_MENU_ITEM(GET_COMPONENT("eraserFine")), TRUE);
1028       break;
1029     case THICKNESS_MEDIUM:
1030       gtk_check_menu_item_set_active(
1031         GTK_CHECK_MENU_ITEM(GET_COMPONENT("eraserMedium")), TRUE);
1032       break;
1033     case THICKNESS_THICK:
1034       gtk_check_menu_item_set_active(
1035         GTK_CHECK_MENU_ITEM(GET_COMPONENT("eraserThick")), TRUE);
1036       break;
1037   }
1038   
1039   gtk_check_menu_item_set_active(
1040     GTK_CHECK_MENU_ITEM(GET_COMPONENT("eraserStandard")),
1041     ui.brushes[0][TOOL_ERASER].tool_options == TOOLOPT_ERASER_STANDARD);
1042   gtk_check_menu_item_set_active(
1043     GTK_CHECK_MENU_ITEM(GET_COMPONENT("eraserWhiteout")),
1044     ui.brushes[0][TOOL_ERASER].tool_options == TOOLOPT_ERASER_WHITEOUT);
1045   gtk_check_menu_item_set_active(
1046     GTK_CHECK_MENU_ITEM(GET_COMPONENT("eraserDeleteStrokes")),
1047     ui.brushes[0][TOOL_ERASER].tool_options == TOOLOPT_ERASER_STROKES);
1048 }
1049
1050 void update_highlighter_props_menu(void)
1051 {
1052   switch (ui.brushes[0][TOOL_HIGHLIGHTER].thickness_no) {
1053     case THICKNESS_FINE:
1054       gtk_check_menu_item_set_active(
1055         GTK_CHECK_MENU_ITEM(GET_COMPONENT("highlighterFine")), TRUE);
1056       break;
1057     case THICKNESS_MEDIUM:
1058       gtk_check_menu_item_set_active(
1059         GTK_CHECK_MENU_ITEM(GET_COMPONENT("highlighterMedium")), TRUE);
1060       break;
1061     case THICKNESS_THICK:
1062       gtk_check_menu_item_set_active(
1063         GTK_CHECK_MENU_ITEM(GET_COMPONENT("highlighterThick")), TRUE);
1064       break;
1065   }
1066 }
1067
1068 void update_mappings_menu_linkings(void)
1069 {
1070   switch (ui.linked_brush[1]) {
1071     case BRUSH_LINKED:
1072       gtk_check_menu_item_set_active(
1073         GTK_CHECK_MENU_ITEM(GET_COMPONENT("button2LinkBrush")), TRUE);
1074       break;
1075     case BRUSH_COPIED:
1076       gtk_check_menu_item_set_active(
1077         GTK_CHECK_MENU_ITEM(GET_COMPONENT("button2CopyBrush")), TRUE);
1078       break;
1079     case BRUSH_STATIC:
1080       gtk_check_menu_item_set_active(
1081         GTK_CHECK_MENU_ITEM(GET_COMPONENT("button2NABrush")), TRUE);
1082       break;
1083   }
1084   switch (ui.linked_brush[2]) {
1085     case BRUSH_LINKED:
1086       gtk_check_menu_item_set_active(
1087         GTK_CHECK_MENU_ITEM(GET_COMPONENT("button3LinkBrush")), TRUE);
1088       break;
1089     case BRUSH_COPIED:
1090       gtk_check_menu_item_set_active(
1091         GTK_CHECK_MENU_ITEM(GET_COMPONENT("button3CopyBrush")), TRUE);
1092       break;
1093     case BRUSH_STATIC:
1094       gtk_check_menu_item_set_active(
1095         GTK_CHECK_MENU_ITEM(GET_COMPONENT("button3NABrush")), TRUE);
1096       break;
1097   }
1098 }
1099
1100 void update_mappings_menu(void)
1101 {
1102   gtk_widget_set_sensitive(GET_COMPONENT("optionsButtonMappings"), ui.use_xinput);
1103   gtk_widget_set_sensitive(GET_COMPONENT("optionsDiscardCoreEvents"), ui.use_xinput);
1104   gtk_widget_set_sensitive(GET_COMPONENT("optionsPressureSensitive"), ui.use_xinput);
1105   gtk_check_menu_item_set_active(
1106     GTK_CHECK_MENU_ITEM(GET_COMPONENT("optionsButtonMappings")), ui.use_erasertip);
1107   gtk_check_menu_item_set_active(
1108     GTK_CHECK_MENU_ITEM(GET_COMPONENT("optionsDiscardCoreEvents")), ui.discard_corepointer);
1109   gtk_check_menu_item_set_active(
1110     GTK_CHECK_MENU_ITEM(GET_COMPONENT("optionsPressureSensitive")), ui.pressure_sensitivity);
1111
1112   switch(ui.toolno[1]) {
1113     case TOOL_PEN:
1114       gtk_check_menu_item_set_active(
1115         GTK_CHECK_MENU_ITEM(GET_COMPONENT("button2Pen")), TRUE);
1116       break;
1117     case TOOL_ERASER:
1118       gtk_check_menu_item_set_active(
1119         GTK_CHECK_MENU_ITEM(GET_COMPONENT("button2Eraser")), TRUE);
1120       break;
1121     case TOOL_HIGHLIGHTER:
1122       gtk_check_menu_item_set_active(
1123         GTK_CHECK_MENU_ITEM(GET_COMPONENT("button2Highlighter")), TRUE);
1124       break;
1125     case TOOL_TEXT:
1126       gtk_check_menu_item_set_active(
1127         GTK_CHECK_MENU_ITEM(GET_COMPONENT("button2Text")), TRUE);
1128       break;
1129     case TOOL_SELECTREGION:
1130       gtk_check_menu_item_set_active(
1131         GTK_CHECK_MENU_ITEM(GET_COMPONENT("button2SelectRegion")), TRUE);
1132       break;
1133     case TOOL_SELECTRECT:
1134       gtk_check_menu_item_set_active(
1135         GTK_CHECK_MENU_ITEM(GET_COMPONENT("button2SelectRectangle")), TRUE);
1136       break;
1137     case TOOL_VERTSPACE:
1138       gtk_check_menu_item_set_active(
1139         GTK_CHECK_MENU_ITEM(GET_COMPONENT("button2VerticalSpace")), TRUE);
1140       break;
1141   }
1142   switch(ui.toolno[2]) {
1143     case TOOL_PEN:
1144       gtk_check_menu_item_set_active(
1145         GTK_CHECK_MENU_ITEM(GET_COMPONENT("button3Pen")), TRUE);
1146       break;
1147     case TOOL_ERASER:
1148       gtk_check_menu_item_set_active(
1149         GTK_CHECK_MENU_ITEM(GET_COMPONENT("button3Eraser")), TRUE);
1150       break;
1151     case TOOL_HIGHLIGHTER:
1152       gtk_check_menu_item_set_active(
1153         GTK_CHECK_MENU_ITEM(GET_COMPONENT("button3Highlighter")), TRUE);
1154       break;
1155     case TOOL_TEXT:
1156       gtk_check_menu_item_set_active(
1157         GTK_CHECK_MENU_ITEM(GET_COMPONENT("button3Text")), TRUE);
1158       break;
1159     case TOOL_SELECTREGION:
1160       gtk_check_menu_item_set_active(
1161         GTK_CHECK_MENU_ITEM(GET_COMPONENT("button3SelectRegion")), TRUE);
1162       break;
1163     case TOOL_SELECTRECT:
1164       gtk_check_menu_item_set_active(
1165         GTK_CHECK_MENU_ITEM(GET_COMPONENT("button3SelectRectangle")), TRUE);
1166       break;
1167     case TOOL_VERTSPACE:
1168       gtk_check_menu_item_set_active(
1169         GTK_CHECK_MENU_ITEM(GET_COMPONENT("button3VerticalSpace")), TRUE);
1170       break;
1171   }
1172   update_mappings_menu_linkings();
1173 }
1174
1175 void do_switch_page(int pg, gboolean rescroll, gboolean refresh_all)
1176 {
1177   int i, cx, cy;
1178   struct Layer *layer;
1179   GList *list;
1180   
1181   ui.pageno = pg;
1182
1183   /* re-show all the layers of the old page */
1184   if (ui.cur_page != NULL)
1185     for (i=0, list = ui.cur_page->layers; list!=NULL; i++, list = list->next) {
1186       layer = (struct Layer *)list->data;
1187       if (layer->group!=NULL)
1188         gnome_canvas_item_show(GNOME_CANVAS_ITEM(layer->group));
1189     }
1190   
1191   ui.cur_page = g_list_nth_data(journal.pages, ui.pageno);
1192   ui.layerno = ui.cur_page->nlayers-1;
1193   ui.cur_layer = (struct Layer *)(g_list_last(ui.cur_page->layers)->data);
1194   update_page_stuff();
1195   if (ui.progressive_bg) rescale_bg_pixmaps();
1196  
1197   if (rescroll) { // scroll and force a refresh
1198 /* -- this seems to cause some display bugs ??
1199     gtk_adjustment_set_value(gtk_layout_get_vadjustment(GTK_LAYOUT(canvas)),
1200       ui.cur_page->voffset*ui.zoom);  */
1201     gnome_canvas_get_scroll_offsets(canvas, &cx, &cy);
1202     cy = ui.cur_page->voffset*ui.zoom;
1203     gnome_canvas_scroll_to(canvas, cx, cy);
1204     
1205     if (refresh_all) 
1206       gnome_canvas_set_pixels_per_unit(canvas, ui.zoom);
1207     else if (!ui.view_continuous)
1208       gnome_canvas_item_move(GNOME_CANVAS_ITEM(ui.cur_page->group), 0., 0.);
1209   }
1210 }
1211
1212 void update_page_stuff(void)
1213 {
1214   gchar tmp[10];
1215   GtkComboBox *layerbox;
1216   int i;
1217   GList *pglist;
1218   GtkSpinButton *spin;
1219   struct Page *pg;
1220   double vertpos, maxwidth;
1221
1222   // move the page groups to their rightful locations or hide them
1223   if (ui.view_continuous) {
1224     vertpos = 0.; 
1225     maxwidth = 0.;
1226     for (i=0, pglist = journal.pages; pglist!=NULL; i++, pglist = pglist->next) {
1227       pg = (struct Page *)pglist->data;
1228       if (pg->group!=NULL) {
1229         pg->hoffset = 0.; pg->voffset = vertpos;
1230         gnome_canvas_item_set(GNOME_CANVAS_ITEM(pg->group), 
1231             "x", pg->hoffset, "y", pg->voffset, NULL);
1232         gnome_canvas_item_show(GNOME_CANVAS_ITEM(pg->group));
1233       }
1234       vertpos += pg->height + VIEW_CONTINUOUS_SKIP;
1235       if (pg->width > maxwidth) maxwidth = pg->width;
1236     }
1237     vertpos -= VIEW_CONTINUOUS_SKIP;
1238     gnome_canvas_set_scroll_region(canvas, 0, 0, maxwidth, vertpos);
1239   } else {
1240     for (pglist = journal.pages; pglist!=NULL; pglist = pglist->next) {
1241       pg = (struct Page *)pglist->data;
1242       if (pg == ui.cur_page && pg->group!=NULL) {
1243         pg->hoffset = 0.; pg->voffset = 0.;
1244         gnome_canvas_item_set(GNOME_CANVAS_ITEM(pg->group), 
1245             "x", pg->hoffset, "y", pg->voffset, NULL);
1246         gnome_canvas_item_show(GNOME_CANVAS_ITEM(pg->group));
1247       } else {
1248         if (pg->group!=NULL) gnome_canvas_item_hide(GNOME_CANVAS_ITEM(pg->group));
1249       }
1250     }
1251     gnome_canvas_set_scroll_region(canvas, 0, 0, ui.cur_page->width, ui.cur_page->height);
1252   }
1253
1254   // update the page / layer info at bottom of screen
1255
1256   spin = GTK_SPIN_BUTTON(GET_COMPONENT("spinPageNo"));
1257   ui.in_update_page_stuff = TRUE; // avoid a bad retroaction
1258   gtk_spin_button_set_range(spin, 1, journal.npages+1);
1259     /* npages+1 will be used to create a new page at end */
1260   gtk_spin_button_set_value(spin, ui.pageno+1);
1261   g_snprintf(tmp, 10, _(" of %d"), journal.npages);
1262   gtk_label_set_text(GTK_LABEL(GET_COMPONENT("labelNumpages")), tmp);
1263
1264   layerbox = GTK_COMBO_BOX(GET_COMPONENT("comboLayer"));
1265   if (ui.layerbox_length == 0) {
1266     gtk_combo_box_prepend_text(layerbox, _("Background"));
1267     ui.layerbox_length++;
1268   }
1269   while (ui.layerbox_length > ui.cur_page->nlayers+1) {
1270     gtk_combo_box_remove_text(layerbox, 0);
1271     ui.layerbox_length--;
1272   }
1273   while (ui.layerbox_length < ui.cur_page->nlayers+1) {
1274     g_snprintf(tmp, 10, _("Layer %d"), ui.layerbox_length++);
1275     gtk_combo_box_prepend_text(layerbox, tmp);
1276   }
1277   gtk_combo_box_set_active(layerbox, ui.cur_page->nlayers-1-ui.layerno);
1278   ui.in_update_page_stuff = FALSE;
1279   
1280   // update the paper-style menu radio buttons
1281   
1282   if (ui.view_continuous)
1283     gtk_check_menu_item_set_active(
1284        GTK_CHECK_MENU_ITEM(GET_COMPONENT("viewContinuous")), TRUE);
1285   else
1286     gtk_check_menu_item_set_active(
1287        GTK_CHECK_MENU_ITEM(GET_COMPONENT("viewOnePage")), TRUE);
1288
1289   if (ui.cur_page->bg->type == BG_SOLID && !ui.bg_apply_all_pages) {
1290     switch (ui.cur_page->bg->color_no) {
1291       case COLOR_WHITE:
1292         gtk_check_menu_item_set_active(
1293           GTK_CHECK_MENU_ITEM(GET_COMPONENT("papercolorWhite")), TRUE);
1294         break;
1295       case COLOR_YELLOW:
1296         gtk_check_menu_item_set_active(
1297           GTK_CHECK_MENU_ITEM(GET_COMPONENT("papercolorYellow")), TRUE);
1298         break;
1299       case COLOR_RED:
1300         gtk_check_menu_item_set_active(
1301           GTK_CHECK_MENU_ITEM(GET_COMPONENT("papercolorPink")), TRUE);
1302         break;
1303       case COLOR_ORANGE:
1304         gtk_check_menu_item_set_active(
1305           GTK_CHECK_MENU_ITEM(GET_COMPONENT("papercolorOrange")), TRUE);
1306         break;
1307       case COLOR_BLUE:
1308         gtk_check_menu_item_set_active(
1309           GTK_CHECK_MENU_ITEM(GET_COMPONENT("papercolorBlue")), TRUE);
1310         break;
1311       case COLOR_GREEN:
1312         gtk_check_menu_item_set_active(
1313           GTK_CHECK_MENU_ITEM(GET_COMPONENT("papercolorGreen")), TRUE);
1314         break;
1315       default:
1316         gtk_check_menu_item_set_active(
1317           GTK_CHECK_MENU_ITEM(GET_COMPONENT("papercolorOther")), TRUE);
1318         break;
1319     }
1320     switch (ui.cur_page->bg->ruling) {
1321       case RULING_NONE:
1322         gtk_check_menu_item_set_active(
1323           GTK_CHECK_MENU_ITEM(GET_COMPONENT("paperstylePlain")), TRUE);
1324         break;
1325       case RULING_LINED:
1326         gtk_check_menu_item_set_active(
1327           GTK_CHECK_MENU_ITEM(GET_COMPONENT("paperstyleLined")), TRUE);
1328         break;
1329       case RULING_RULED:
1330         gtk_check_menu_item_set_active(
1331           GTK_CHECK_MENU_ITEM(GET_COMPONENT("paperstyleRuled")), TRUE);
1332         break;
1333       case RULING_GRAPH:
1334         gtk_check_menu_item_set_active(
1335           GTK_CHECK_MENU_ITEM(GET_COMPONENT("paperstyleGraph")), TRUE);
1336         break;
1337     }
1338   } else {
1339     gtk_check_menu_item_set_active(
1340       GTK_CHECK_MENU_ITEM(GET_COMPONENT("papercolorNA")), TRUE);
1341     gtk_check_menu_item_set_active(
1342       GTK_CHECK_MENU_ITEM(GET_COMPONENT("paperstyleNA")), TRUE);
1343   }
1344   
1345   // enable/disable the page/layer menu items and toolbar buttons
1346
1347   gtk_widget_set_sensitive(GET_COMPONENT("journalPaperColor"), 
1348      ui.cur_page->bg->type == BG_SOLID || ui.bg_apply_all_pages);
1349   gtk_widget_set_sensitive(GET_COMPONENT("journalSetAsDefault"),
1350      ui.cur_page->bg->type == BG_SOLID);
1351   
1352   gtk_widget_set_sensitive(GET_COMPONENT("viewFirstPage"), ui.pageno!=0);
1353   gtk_widget_set_sensitive(GET_COMPONENT("viewPreviousPage"), ui.pageno!=0);
1354   gtk_widget_set_sensitive(GET_COMPONENT("viewNextPage"), TRUE);
1355   gtk_widget_set_sensitive(GET_COMPONENT("viewLastPage"), ui.pageno!=journal.npages-1);
1356   gtk_widget_set_sensitive(GET_COMPONENT("buttonFirstPage"), ui.pageno!=0);
1357   gtk_widget_set_sensitive(GET_COMPONENT("buttonPreviousPage"), ui.pageno!=0);
1358   gtk_widget_set_sensitive(GET_COMPONENT("buttonNextPage"), TRUE);
1359   gtk_widget_set_sensitive(GET_COMPONENT("buttonLastPage"), ui.pageno!=journal.npages-1);
1360   
1361   gtk_widget_set_sensitive(GET_COMPONENT("viewShowLayer"), ui.layerno!=ui.cur_page->nlayers-1);
1362   gtk_widget_set_sensitive(GET_COMPONENT("viewHideLayer"), ui.layerno>=0);
1363
1364   gtk_widget_set_sensitive(GET_COMPONENT("editPaste"), ui.cur_layer!=NULL);
1365   gtk_widget_set_sensitive(GET_COMPONENT("buttonPaste"), ui.cur_layer!=NULL);
1366 }
1367
1368 void update_toolbar_and_menu(void)
1369 {
1370   update_tool_buttons(); // takes care of other toolbar buttons as well  
1371   update_tool_menu();
1372   update_color_menu();
1373   update_pen_props_menu();
1374   update_eraser_props_menu();
1375   update_highlighter_props_menu();
1376   update_mappings_menu();
1377
1378   gtk_toggle_tool_button_set_active(
1379     GTK_TOGGLE_TOOL_BUTTON(GET_COMPONENT("buttonFullscreen")), ui.fullscreen);
1380   gtk_check_menu_item_set_active(
1381     GTK_CHECK_MENU_ITEM(GET_COMPONENT("viewFullscreen")), ui.fullscreen);
1382 }
1383
1384 void update_file_name(char *filename)
1385 {
1386   gchar tmp[100], *p;
1387   if (ui.filename != NULL) g_free(ui.filename);
1388   ui.filename = filename;
1389   if (filename == NULL) {
1390     gtk_window_set_title(GTK_WINDOW (winMain), _("Xournal"));
1391     return;
1392   }
1393   p = g_utf8_strrchr(filename, -1, '/');
1394   if (p == NULL) p = filename; 
1395   else p = g_utf8_next_char(p);
1396   g_snprintf(tmp, 100, _("Xournal - %s"), p);
1397   gtk_window_set_title(GTK_WINDOW (winMain), tmp);
1398   new_mru_entry(filename);
1399
1400   if (filename[0]=='/') {
1401     if (ui.default_path!=NULL) g_free(ui.default_path);
1402     ui.default_path = g_path_get_dirname(filename);
1403   }
1404 }
1405
1406 void update_undo_redo_enabled(void)
1407 {
1408   gtk_widget_set_sensitive(GET_COMPONENT("editUndo"), undo!=NULL);
1409   gtk_widget_set_sensitive(GET_COMPONENT("editRedo"), redo!=NULL);
1410   gtk_widget_set_sensitive(GET_COMPONENT("buttonUndo"), undo!=NULL);
1411   gtk_widget_set_sensitive(GET_COMPONENT("buttonRedo"), redo!=NULL);
1412 }
1413
1414 void update_copy_paste_enabled(void)
1415 {
1416   gtk_widget_set_sensitive(GET_COMPONENT("editCut"), ui.selection!=NULL);
1417   gtk_widget_set_sensitive(GET_COMPONENT("editCopy"), ui.selection!=NULL);
1418   gtk_widget_set_sensitive(GET_COMPONENT("editPaste"), ui.cur_item_type!=ITEM_TEXT);
1419   gtk_widget_set_sensitive(GET_COMPONENT("editDelete"), ui.selection!=NULL);
1420   gtk_widget_set_sensitive(GET_COMPONENT("buttonCut"), ui.selection!=NULL);
1421   gtk_widget_set_sensitive(GET_COMPONENT("buttonCopy"), ui.selection!=NULL);
1422   gtk_widget_set_sensitive(GET_COMPONENT("buttonPaste"), ui.cur_item_type!=ITEM_TEXT);
1423 }
1424
1425 void update_mapping_linkings(int toolno)
1426 {
1427   int i;
1428   
1429   for (i = 1; i<=NUM_BUTTONS; i++) {
1430     if (ui.linked_brush[i] == BRUSH_LINKED) {
1431       if (toolno >= 0 && toolno < NUM_STROKE_TOOLS)
1432         g_memmove(&(ui.brushes[i][toolno]), &(ui.brushes[0][toolno]), sizeof(struct Brush));
1433     }
1434     if (ui.linked_brush[i] == BRUSH_COPIED && toolno == ui.toolno[i]) {
1435       ui.linked_brush[i] = BRUSH_STATIC;
1436       if (i==1 || i==2) update_mappings_menu_linkings();
1437     }
1438   }
1439 }
1440
1441 void set_cur_color(int color_no, guint color_rgba)
1442 {
1443   int which_mapping, tool;
1444   
1445   if (ui.toolno[ui.cur_mapping] == TOOL_HIGHLIGHTER) tool = TOOL_HIGHLIGHTER;
1446   else tool = TOOL_PEN;
1447   if (ui.cur_mapping>0 && ui.linked_brush[ui.cur_mapping]!=BRUSH_LINKED)
1448     which_mapping = ui.cur_mapping;
1449   else which_mapping = 0;
1450
1451   ui.brushes[which_mapping][tool].color_no = color_no;
1452   if (tool == TOOL_HIGHLIGHTER && (color_rgba & 0xff) == 0xff)
1453     ui.brushes[which_mapping][tool].color_rgba = color_rgba & ui.hiliter_alpha_mask;
1454   else
1455     ui.brushes[which_mapping][tool].color_rgba = color_rgba;
1456   update_mapping_linkings(tool);
1457 }
1458
1459 void recolor_temp_text(int color_no, guint color_rgba)
1460 {
1461   GdkColor gdkcolor;
1462   
1463   if (ui.cur_item_type!=ITEM_TEXT) return;
1464   if (ui.cur_item->text!=NULL && ui.cur_item->brush.color_rgba != color_rgba) {
1465     prepare_new_undo();
1466     undo->type = ITEM_TEXT_ATTRIB;
1467     undo->item = ui.cur_item;
1468     undo->str = g_strdup(ui.cur_item->font_name);
1469     undo->val_x = ui.cur_item->font_size;
1470     undo->brush = (struct Brush *)g_memdup(&(ui.cur_item->brush), sizeof(struct Brush));
1471   }
1472   ui.cur_item->brush.color_no = color_no;
1473   ui.cur_item->brush.color_rgba = color_rgba;
1474   rgb_to_gdkcolor(color_rgba, &gdkcolor);
1475   gtk_widget_modify_text(ui.cur_item->widget, GTK_STATE_NORMAL, &gdkcolor);
1476   gtk_widget_grab_focus(ui.cur_item->widget);
1477 }
1478
1479 void process_color_activate(GtkMenuItem *menuitem, int color_no, guint color_rgba)
1480 {
1481   if (GTK_OBJECT_TYPE(menuitem) == GTK_TYPE_RADIO_MENU_ITEM) {
1482     if (!gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM (menuitem)))
1483       return;
1484   } 
1485   else if (GTK_OBJECT_TYPE(menuitem) == GTK_TYPE_RADIO_TOOL_BUTTON) {
1486     if (!gtk_toggle_tool_button_get_active(GTK_TOGGLE_TOOL_BUTTON (menuitem)))
1487       return;
1488   }
1489
1490   if (ui.cur_mapping != 0 && !ui.button_switch_mapping) return; // not user-generated
1491   reset_focus();
1492
1493   if (ui.cur_item_type == ITEM_TEXT)
1494     recolor_temp_text(color_no, color_rgba);
1495
1496   if (ui.selection != NULL) {
1497     recolor_selection(color_no, color_rgba);
1498     update_color_buttons();
1499     update_color_menu();
1500   }
1501   
1502   if (ui.toolno[ui.cur_mapping] != TOOL_PEN && ui.toolno[ui.cur_mapping] != TOOL_HIGHLIGHTER
1503       && ui.toolno[ui.cur_mapping] != TOOL_TEXT) {
1504     if (ui.selection != NULL) return;
1505     ui.cur_mapping = 0;
1506     end_text();
1507     ui.toolno[ui.cur_mapping] = TOOL_PEN;
1508     ui.cur_brush = &(ui.brushes[ui.cur_mapping][TOOL_PEN]);
1509     update_tool_buttons();
1510     update_tool_menu();
1511   }
1512   
1513   set_cur_color(color_no, color_rgba);
1514   update_color_buttons();
1515   update_color_menu();
1516   update_cursor();
1517 }
1518
1519 void process_thickness_activate(GtkMenuItem *menuitem, int tool, int val)
1520 {
1521   int which_mapping;
1522   
1523   if (GTK_OBJECT_TYPE(menuitem) == GTK_TYPE_RADIO_MENU_ITEM) {
1524     if (!gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM (menuitem)))
1525       return;
1526   } else {
1527     if (!gtk_toggle_tool_button_get_active(GTK_TOGGLE_TOOL_BUTTON (menuitem)))
1528       return;
1529   }
1530
1531   if (ui.cur_mapping != 0 && !ui.button_switch_mapping) return; // not user-generated
1532
1533   if (ui.selection != NULL && GTK_OBJECT_TYPE(menuitem) != GTK_TYPE_RADIO_MENU_ITEM) {
1534     reset_focus();
1535     rethicken_selection(val);
1536     update_thickness_buttons();
1537   }
1538
1539   if (tool >= NUM_STROKE_TOOLS) {
1540     update_thickness_buttons(); // undo illegal button selection
1541     return;
1542   }
1543
1544   if (ui.cur_mapping>0 && ui.linked_brush[ui.cur_mapping]!=BRUSH_LINKED)
1545     which_mapping = ui.cur_mapping;
1546   else which_mapping = 0;
1547   if (ui.brushes[which_mapping][tool].thickness_no == val) return;
1548   reset_focus();
1549   end_text();
1550   ui.brushes[which_mapping][tool].thickness_no = val;
1551   ui.brushes[which_mapping][tool].thickness = predef_thickness[tool][val];
1552   update_mapping_linkings(tool);
1553   
1554   update_thickness_buttons();
1555   if (tool == TOOL_PEN) update_pen_props_menu();
1556   if (tool == TOOL_ERASER) update_eraser_props_menu();
1557   if (tool == TOOL_HIGHLIGHTER) update_highlighter_props_menu();
1558   update_cursor();
1559 }
1560
1561 void process_papercolor_activate(GtkMenuItem *menuitem, int color)
1562 {
1563   struct Page *pg;
1564   GList *pglist;
1565   gboolean hasdone;
1566
1567   if (!gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM (menuitem)))
1568     return;
1569
1570   if ((ui.cur_page->bg->type != BG_SOLID) || ui.bg_apply_all_pages)
1571     gtk_check_menu_item_set_active(
1572       GTK_CHECK_MENU_ITEM(GET_COMPONENT("papercolorNA")), TRUE);
1573
1574   pg = ui.cur_page;
1575   hasdone = FALSE;
1576   for (pglist = journal.pages; pglist!=NULL; pglist = pglist->next) {
1577     if (ui.bg_apply_all_pages) pg = (struct Page *)pglist->data;
1578     if (pg->bg->type == BG_SOLID && pg->bg->color_no != color) {
1579       prepare_new_undo();
1580       if (hasdone) undo->multiop |= MULTIOP_CONT_UNDO;
1581       undo->multiop |= MULTIOP_CONT_REDO;
1582       hasdone = TRUE;
1583       undo->type = ITEM_NEW_BG_ONE;
1584       undo->page = pg;
1585       undo->bg = (struct Background *)g_memdup(pg->bg, sizeof(struct Background));
1586       undo->bg->canvas_item = NULL;
1587
1588       pg->bg->color_no = color;
1589       pg->bg->color_rgba = predef_bgcolors_rgba[color];
1590       update_canvas_bg(pg);
1591     }
1592     if (!ui.bg_apply_all_pages) break;
1593   }
1594   if (hasdone) undo->multiop -= MULTIOP_CONT_REDO;
1595 }
1596
1597 void process_paperstyle_activate(GtkMenuItem *menuitem, int style)
1598 {
1599   struct Page *pg;
1600   GList *pglist;
1601   gboolean hasdone, must_upd;
1602
1603   if (!gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM (menuitem)))
1604     return;
1605
1606   if (ui.bg_apply_all_pages)
1607     gtk_check_menu_item_set_active(
1608       GTK_CHECK_MENU_ITEM(GET_COMPONENT("paperstyleNA")), TRUE);
1609
1610   pg = ui.cur_page;
1611   hasdone = FALSE;
1612   must_upd = FALSE;
1613   for (pglist = journal.pages; pglist!=NULL; pglist = pglist->next) {
1614     if (ui.bg_apply_all_pages) pg = (struct Page *)pglist->data;
1615     if (pg->bg->type != BG_SOLID || pg->bg->ruling != style) {
1616       prepare_new_undo();
1617       undo->type = ITEM_NEW_BG_ONE;
1618       if (hasdone) undo->multiop |= MULTIOP_CONT_UNDO;
1619       undo->multiop |= MULTIOP_CONT_REDO;
1620       hasdone = TRUE;
1621       undo->page = pg;
1622       undo->bg = (struct Background *)g_memdup(pg->bg, sizeof(struct Background));
1623       undo->bg->canvas_item = NULL;
1624
1625       if (pg->bg->type != BG_SOLID) {
1626         pg->bg->type = BG_SOLID;
1627         pg->bg->color_no = COLOR_WHITE;
1628         pg->bg->color_rgba = predef_bgcolors_rgba[COLOR_WHITE];
1629         pg->bg->filename = NULL;
1630         pg->bg->pixbuf = NULL;
1631         must_upd = TRUE;
1632       }
1633       pg->bg->ruling = style;
1634       update_canvas_bg(pg);
1635     }
1636     if (!ui.bg_apply_all_pages) break;
1637   }
1638   if (hasdone) undo->multiop -= MULTIOP_CONT_REDO;
1639   if (must_upd) update_page_stuff();
1640 }
1641
1642 gboolean ok_to_close(void)
1643 {
1644   GtkWidget *dialog;
1645   GtkResponseType response;
1646
1647   if (ui.saved) return TRUE;
1648   dialog = gtk_message_dialog_new(GTK_WINDOW (winMain), GTK_DIALOG_DESTROY_WITH_PARENT,
1649     GTK_MESSAGE_WARNING, GTK_BUTTONS_YES_NO, _("Save changes to '%s'?"),
1650     (ui.filename!=NULL) ? ui.filename:_("Untitled"));
1651   gtk_dialog_add_button(GTK_DIALOG (dialog), GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL);
1652   response = gtk_dialog_run(GTK_DIALOG (dialog));
1653   gtk_widget_destroy(dialog);
1654   if (response == GTK_RESPONSE_CANCEL || response == GTK_RESPONSE_DELETE_EVENT) 
1655     return FALSE; // aborted
1656   if (response == GTK_RESPONSE_YES) {
1657     on_fileSave_activate(NULL, NULL);
1658     if (!ui.saved) return FALSE; // if save failed, then we abort
1659   }
1660   return TRUE;
1661 }
1662
1663 // send the focus back to the appropriate widget
1664 void reset_focus(void)
1665 {
1666   if (ui.cur_item_type == ITEM_TEXT)
1667     gtk_widget_grab_focus(ui.cur_item->widget);
1668   else
1669     gtk_widget_grab_focus(GTK_WIDGET(canvas));
1670   reset_recognizer();
1671 }
1672
1673 // selection / clipboard stuff
1674
1675 void reset_selection(void)
1676 {
1677   if (ui.selection == NULL) return;
1678   if (ui.selection->canvas_item != NULL) 
1679     gtk_object_destroy(GTK_OBJECT(ui.selection->canvas_item));
1680   g_list_free(ui.selection->items);
1681   g_free(ui.selection);
1682   ui.selection = NULL;
1683   update_copy_paste_enabled();
1684   update_color_menu();
1685   update_thickness_buttons();
1686   update_color_buttons();
1687   update_font_button();
1688   update_cursor();
1689 }
1690
1691 void move_journal_items_by(GList *itemlist, double dx, double dy,
1692                               struct Layer *l1, struct Layer *l2, GList *depths)
1693 {
1694   struct Item *item;
1695   GnomeCanvasItem *refitem;
1696   GList *link;
1697   int i;
1698   double *pt;
1699   
1700   while (itemlist!=NULL) {
1701     item = (struct Item *)itemlist->data;
1702     if (item->type == ITEM_STROKE)
1703       for (pt=item->path->coords, i=0; i<item->path->num_points; i++, pt+=2)
1704         { pt[0] += dx; pt[1] += dy; }
1705     if (item->type == ITEM_STROKE || item->type == ITEM_TEXT || item->type == ITEM_TEMP_TEXT) {
1706       item->bbox.left += dx;
1707       item->bbox.right += dx;
1708       item->bbox.top += dy;
1709       item->bbox.bottom += dy;
1710     }
1711     if (l1 != l2) {
1712       // find out where to insert
1713       if (depths != NULL) {
1714         if (depths->data == NULL) link = l2->items;
1715         else {
1716           link = g_list_find(l2->items, depths->data);
1717           if (link != NULL) link = link->next;
1718         }
1719       } else link = NULL;
1720       l2->items = g_list_insert_before(l2->items, link, item);
1721       l2->nitems++;
1722       l1->items = g_list_remove(l1->items, item);
1723       l1->nitems--;
1724     }
1725     if (depths != NULL) { // also raise/lower the canvas items
1726       if (item->canvas_item!=NULL) {
1727         if (depths->data == NULL) link = NULL;
1728         else link = g_list_find(l2->items, depths->data);
1729         if (link != NULL) refitem = ((struct Item *)(link->data))->canvas_item;
1730         else refitem = NULL;
1731         lower_canvas_item_to(l2->group, item->canvas_item, refitem);
1732       }
1733       depths = depths->next;
1734     }
1735     itemlist = itemlist->next;
1736   }
1737 }
1738
1739 void resize_journal_items_by(GList *itemlist, double scaling_x, double scaling_y,
1740                              double offset_x, double offset_y)
1741 {
1742   struct Item *item;
1743   GList *list;
1744   double mean_scaling, temp;
1745   double *pt, *wid;
1746   GnomeCanvasGroup *group;
1747   int i; 
1748   
1749   /* geometric mean of x and y scalings = rescaling for stroke widths
1750      and for text font sizes */
1751   mean_scaling = sqrt(fabs(scaling_x * scaling_y));
1752
1753   for (list = itemlist; list != NULL; list = list->next) {
1754     item = (struct Item *)list->data;
1755     if (item->type == ITEM_STROKE) {
1756       item->brush.thickness = item->brush.thickness * mean_scaling;
1757       for (i=0, pt=item->path->coords; i<item->path->num_points; i++, pt+=2) {
1758         pt[0] = pt[0]*scaling_x + offset_x;
1759         pt[1] = pt[1]*scaling_y + offset_y;
1760       }
1761       if (item->brush.variable_width)
1762         for (i=0, wid=item->widths; i<item->path->num_points-1; i++, wid++)
1763           *wid = *wid * mean_scaling;
1764
1765       item->bbox.left = item->bbox.left*scaling_x + offset_x;
1766       item->bbox.right = item->bbox.right*scaling_x + offset_x;
1767       item->bbox.top = item->bbox.top*scaling_y + offset_y;
1768       item->bbox.bottom = item->bbox.bottom*scaling_y + offset_y;
1769       if (item->bbox.left > item->bbox.right) {
1770         temp = item->bbox.left;
1771         item->bbox.left = item->bbox.right;
1772         item->bbox.right = temp;
1773       }
1774       if (item->bbox.top > item->bbox.bottom) {
1775         temp = item->bbox.top;
1776         item->bbox.top = item->bbox.bottom;
1777         item->bbox.bottom = temp;
1778       }
1779     }
1780     if (item->type == ITEM_TEXT) {
1781       /* must scale about NW corner -- all other points of the text box
1782          are font- and zoom-dependent, so scaling about center of text box
1783          couldn't be undone properly. FIXME? */
1784       item->font_size *= mean_scaling;
1785       item->bbox.left = item->bbox.left*scaling_x + offset_x;
1786       item->bbox.top = item->bbox.top*scaling_y + offset_y;
1787     }
1788     // redraw the item
1789     if (item->canvas_item!=NULL) {
1790       group = (GnomeCanvasGroup *) item->canvas_item->parent;
1791       gtk_object_destroy(GTK_OBJECT(item->canvas_item));
1792       make_canvas_item_one(group, item);
1793     }
1794   }
1795 }
1796
1797 // Switch between button mappings
1798
1799 /* NOTE ABOUT BUTTON MAPPINGS: ui.cur_mapping is 0 except while a canvas
1800    click event is being processed ... or if ui.button_switch_mapping is
1801    enabled and mappings are switched! */
1802
1803 void switch_mapping(int m)
1804 {
1805   if (ui.cur_mapping == m) return;
1806
1807   ui.cur_mapping = m;
1808   if (ui.toolno[m] < NUM_STROKE_TOOLS) 
1809     ui.cur_brush = &(ui.brushes[m][ui.toolno[m]]);
1810   if (ui.toolno[m] == TOOL_TEXT)
1811     ui.cur_brush = &(ui.brushes[m][TOOL_PEN]);
1812   update_tool_buttons();
1813   update_color_menu();
1814   update_cursor();
1815 }
1816
1817 void process_mapping_activate(GtkMenuItem *menuitem, int m, int tool)
1818 {
1819   if (!gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(menuitem))) return;
1820   if (ui.cur_mapping!=0 && !ui.button_switch_mapping) return;
1821   if (ui.toolno[m] == tool) return;
1822   switch_mapping(0);
1823   end_text();
1824   reset_focus();
1825     
1826   ui.toolno[m] = tool;
1827   if (ui.linked_brush[m] == BRUSH_COPIED) {
1828     ui.linked_brush[m] = BRUSH_STATIC;
1829     update_mappings_menu_linkings();
1830   }
1831 }
1832
1833 // update the ordering of components in the main vbox
1834
1835 const char *vbox_component_names[VBOX_MAIN_NITEMS]=
1836  {"scrolledwindowMain", "menubar", "toolbarMain", "toolbarPen", "hbox1"};
1837
1838 void update_vbox_order(int *order)
1839 {
1840   int i, j;
1841   GtkWidget *child;
1842   GtkBox *vboxMain = GTK_BOX(GET_COMPONENT("vboxMain"));
1843   gboolean present[VBOX_MAIN_NITEMS];
1844   
1845   for (i=0; i<VBOX_MAIN_NITEMS; i++) present[i] = FALSE;
1846   j=0;
1847   for (i=0; i<VBOX_MAIN_NITEMS; i++) {
1848     if (order[i]<0 || order[i]>=VBOX_MAIN_NITEMS) continue;
1849     present[order[i]] = TRUE;
1850     child = GET_COMPONENT(vbox_component_names[order[i]]);
1851     gtk_box_reorder_child(vboxMain, child, j++);
1852     gtk_widget_show(child);
1853   }
1854   for (i=1; i<VBOX_MAIN_NITEMS; i++) // hide others, but not the drawing area!
1855     if (!present[i]) gtk_widget_hide(GET_COMPONENT(vbox_component_names[i]));
1856 }
1857
1858 gchar *make_cur_font_name(void)
1859 {
1860   gchar *str;
1861   struct Item *it;
1862
1863   if (ui.cur_item_type == ITEM_TEXT)
1864     str = g_strdup_printf("%s %.1f", ui.cur_item->font_name, ui.cur_item->font_size);
1865   else if (ui.selection!=NULL && ui.selection->items!=NULL &&
1866            ui.selection->items->next==NULL &&
1867            (it=(struct Item*)ui.selection->items->data)->type == ITEM_TEXT)
1868     str = g_strdup_printf("%s %.1f", it->font_name, it->font_size);
1869   else
1870     str = g_strdup_printf("%s %.1f", ui.font_name, ui.font_size);
1871   return str;
1872 }
1873
1874 void update_font_button(void)
1875 {
1876   gchar *str;
1877
1878   str = make_cur_font_name();
1879   gtk_font_button_set_font_name(GTK_FONT_BUTTON(GET_COMPONENT("fontButton")), str);
1880   g_free(str);
1881 }
1882
1883 gboolean can_accel(GtkWidget *widget, guint id, gpointer data)
1884 {
1885   return GTK_WIDGET_SENSITIVE(widget);
1886 }
1887
1888 gboolean can_accel_except_text(GtkWidget *widget, guint id, gpointer data)
1889 {
1890   if (ui.cur_item_type == ITEM_TEXT) {
1891     g_signal_stop_emission_by_name(widget, "can-activate-accel");
1892     return FALSE;
1893   }
1894   return GTK_WIDGET_SENSITIVE(widget);
1895 }
1896
1897 void allow_all_accels(void)
1898 {
1899   g_signal_connect((gpointer) GET_COMPONENT("fileNew"),
1900       "can-activate-accel", G_CALLBACK(can_accel), NULL);
1901   g_signal_connect((gpointer) GET_COMPONENT("fileOpen"),
1902       "can-activate-accel", G_CALLBACK(can_accel), NULL);
1903   g_signal_connect((gpointer) GET_COMPONENT("fileSave"),
1904       "can-activate-accel", G_CALLBACK(can_accel), NULL);
1905   g_signal_connect((gpointer) GET_COMPONENT("filePrint"),
1906       "can-activate-accel", G_CALLBACK(can_accel), NULL);
1907   g_signal_connect((gpointer) GET_COMPONENT("filePrintPDF"),
1908       "can-activate-accel", G_CALLBACK(can_accel), NULL);
1909   g_signal_connect((gpointer) GET_COMPONENT("fileQuit"),
1910       "can-activate-accel", G_CALLBACK(can_accel), NULL);
1911   g_signal_connect((gpointer) GET_COMPONENT("editUndo"),
1912       "can-activate-accel", G_CALLBACK(can_accel), NULL);
1913   g_signal_connect((gpointer) GET_COMPONENT("editRedo"),
1914       "can-activate-accel", G_CALLBACK(can_accel), NULL);
1915   g_signal_connect((gpointer) GET_COMPONENT("editCut"),
1916       "can-activate-accel", G_CALLBACK(can_accel), NULL);
1917   g_signal_connect((gpointer) GET_COMPONENT("editCopy"),
1918       "can-activate-accel", G_CALLBACK(can_accel), NULL);
1919   g_signal_connect((gpointer) GET_COMPONENT("editPaste"),
1920       "can-activate-accel", G_CALLBACK(can_accel), NULL);
1921   g_signal_connect((gpointer) GET_COMPONENT("editDelete"),
1922       "can-activate-accel", G_CALLBACK(can_accel), NULL);
1923   g_signal_connect((gpointer) GET_COMPONENT("viewFullscreen"),
1924       "can-activate-accel", G_CALLBACK(can_accel), NULL);
1925   g_signal_connect((gpointer) GET_COMPONENT("viewZoomIn"),
1926       "can-activate-accel", G_CALLBACK(can_accel), NULL);
1927   g_signal_connect((gpointer) GET_COMPONENT("viewZoomOut"),
1928       "can-activate-accel", G_CALLBACK(can_accel), NULL);
1929   g_signal_connect((gpointer) GET_COMPONENT("viewNormalSize"),
1930       "can-activate-accel", G_CALLBACK(can_accel), NULL);
1931   g_signal_connect((gpointer) GET_COMPONENT("viewPageWidth"),
1932       "can-activate-accel", G_CALLBACK(can_accel), NULL);
1933   g_signal_connect((gpointer) GET_COMPONENT("viewFirstPage"),
1934       "can-activate-accel", G_CALLBACK(can_accel), NULL);
1935   g_signal_connect((gpointer) GET_COMPONENT("viewPreviousPage"),
1936       "can-activate-accel", G_CALLBACK(can_accel_except_text), NULL);
1937   g_signal_connect((gpointer) GET_COMPONENT("viewNextPage"),
1938       "can-activate-accel", G_CALLBACK(can_accel_except_text), NULL);
1939   g_signal_connect((gpointer) GET_COMPONENT("viewLastPage"),
1940       "can-activate-accel", G_CALLBACK(can_accel), NULL);
1941   g_signal_connect((gpointer) GET_COMPONENT("toolsPen"),
1942       "can-activate-accel", G_CALLBACK(can_accel), NULL);
1943   g_signal_connect((gpointer) GET_COMPONENT("toolsEraser"),
1944       "can-activate-accel", G_CALLBACK(can_accel), NULL);
1945   g_signal_connect((gpointer) GET_COMPONENT("toolsHighlighter"),
1946       "can-activate-accel", G_CALLBACK(can_accel), NULL);
1947   g_signal_connect((gpointer) GET_COMPONENT("toolsText"),
1948       "can-activate-accel", G_CALLBACK(can_accel), NULL);
1949 /*  g_signal_connect((gpointer) GET_COMPONENT("toolsSelectRegion"),
1950       "can-activate-accel", G_CALLBACK(can_accel), NULL);  */
1951   g_signal_connect((gpointer) GET_COMPONENT("toolsSelectRectangle"),
1952       "can-activate-accel", G_CALLBACK(can_accel), NULL);
1953   g_signal_connect((gpointer) GET_COMPONENT("toolsVerticalSpace"),
1954       "can-activate-accel", G_CALLBACK(can_accel), NULL);
1955   g_signal_connect((gpointer) GET_COMPONENT("toolsHand"),
1956       "can-activate-accel", G_CALLBACK(can_accel), NULL);
1957   g_signal_connect((gpointer) GET_COMPONENT("toolsTextFont"),
1958       "can-activate-accel", G_CALLBACK(can_accel), NULL);
1959   g_signal_connect((gpointer) GET_COMPONENT("toolsRuler"),
1960       "can-activate-accel", G_CALLBACK(can_accel), NULL);
1961   g_signal_connect((gpointer) GET_COMPONENT("toolsReco"),
1962       "can-activate-accel", G_CALLBACK(can_accel), NULL);
1963 }
1964
1965 void add_scroll_bindings(void)
1966 {
1967   GtkBindingSet *binding_set;
1968   
1969   binding_set = gtk_binding_set_by_class(
1970      G_OBJECT_GET_CLASS(GET_COMPONENT("scrolledwindowMain")));
1971   gtk_binding_entry_add_signal(binding_set, GDK_Up, 0,
1972     "scroll_child", 2, GTK_TYPE_SCROLL_TYPE, GTK_SCROLL_STEP_BACKWARD, 
1973     G_TYPE_BOOLEAN, FALSE);  
1974   gtk_binding_entry_add_signal(binding_set, GDK_KP_Up, 0,
1975     "scroll_child", 2, GTK_TYPE_SCROLL_TYPE, GTK_SCROLL_STEP_BACKWARD, 
1976     G_TYPE_BOOLEAN, FALSE);  
1977   gtk_binding_entry_add_signal(binding_set, GDK_Down, 0,
1978     "scroll_child", 2, GTK_TYPE_SCROLL_TYPE, GTK_SCROLL_STEP_FORWARD, 
1979     G_TYPE_BOOLEAN, FALSE);  
1980   gtk_binding_entry_add_signal(binding_set, GDK_KP_Down, 0,
1981     "scroll_child", 2, GTK_TYPE_SCROLL_TYPE, GTK_SCROLL_STEP_FORWARD, 
1982     G_TYPE_BOOLEAN, FALSE);  
1983   gtk_binding_entry_add_signal(binding_set, GDK_Left, 0,
1984     "scroll_child", 2, GTK_TYPE_SCROLL_TYPE, GTK_SCROLL_STEP_BACKWARD, 
1985     G_TYPE_BOOLEAN, TRUE);  
1986   gtk_binding_entry_add_signal(binding_set, GDK_KP_Left, 0,
1987     "scroll_child", 2, GTK_TYPE_SCROLL_TYPE, GTK_SCROLL_STEP_BACKWARD, 
1988     G_TYPE_BOOLEAN, TRUE);  
1989   gtk_binding_entry_add_signal(binding_set, GDK_Right, 0,
1990     "scroll_child", 2, GTK_TYPE_SCROLL_TYPE, GTK_SCROLL_STEP_FORWARD, 
1991     G_TYPE_BOOLEAN, TRUE);  
1992   gtk_binding_entry_add_signal(binding_set, GDK_KP_Right, 0,
1993     "scroll_child", 2, GTK_TYPE_SCROLL_TYPE, GTK_SCROLL_STEP_FORWARD, 
1994     G_TYPE_BOOLEAN, TRUE);  
1995 }
1996
1997 gboolean is_event_within_textview(GdkEventButton *event)
1998 {
1999   double pt[2];
2000   
2001   if (ui.cur_item_type!=ITEM_TEXT) return FALSE;
2002   get_pointer_coords((GdkEvent *)event, pt);
2003   if (pt[0]<ui.cur_item->bbox.left || pt[0]>ui.cur_item->bbox.right) return FALSE;
2004   if (pt[1]<ui.cur_item->bbox.top || pt[1]>ui.cur_item->bbox.bottom) return FALSE;
2005   return TRUE;
2006 }
2007
2008 void hide_unimplemented(void)
2009 {
2010   gtk_widget_hide(GET_COMPONENT("filePrintOptions"));
2011   gtk_widget_hide(GET_COMPONENT("journalFlatten"));  
2012   gtk_widget_hide(GET_COMPONENT("papercolorOther")); 
2013   gtk_widget_hide(GET_COMPONENT("toolsSelectRegion"));
2014   gtk_widget_hide(GET_COMPONENT("buttonSelectRegion"));
2015   gtk_widget_hide(GET_COMPONENT("button2SelectRegion"));
2016   gtk_widget_hide(GET_COMPONENT("button3SelectRegion"));
2017   gtk_widget_hide(GET_COMPONENT("helpIndex")); 
2018
2019   /* config file only works with glib 2.6 and beyond */
2020   if (glib_minor_version<6) {
2021     gtk_widget_hide(GET_COMPONENT("optionsAutoSavePrefs"));
2022     gtk_widget_hide(GET_COMPONENT("optionsSavePreferences"));
2023   }
2024   /* gtkprint only works with gtk+ 2.10 and beyond */
2025   if (gtk_check_version(2, 10, 0)) {
2026     gtk_widget_hide(GET_COMPONENT("filePrint"));
2027   }  
2028 }  
2029
2030 // toggle fullscreen mode
2031 void do_fullscreen(gboolean active)
2032 {
2033   end_text();
2034   reset_focus();
2035   ui.fullscreen = active;
2036   gtk_check_menu_item_set_active(
2037     GTK_CHECK_MENU_ITEM(GET_COMPONENT("viewFullscreen")), ui.fullscreen);
2038   gtk_toggle_tool_button_set_active(
2039     GTK_TOGGLE_TOOL_BUTTON(GET_COMPONENT("buttonFullscreen")), ui.fullscreen);
2040
2041   if (ui.fullscreen) gtk_window_fullscreen(GTK_WINDOW(winMain));
2042   else gtk_window_unfullscreen(GTK_WINDOW(winMain));
2043   
2044   update_vbox_order(ui.vertical_order[ui.fullscreen?1:0]);
2045 }
2046
2047 /* attempt to work around GTK+ 2.16/2.17 bugs where random interface
2048    elements receive XInput events that they can't handle properly    */
2049
2050 // prevent interface items from getting bogus XInput events
2051
2052 gboolean filter_extended_events (GtkWidget *widget, GdkEvent *event,
2053                                    gpointer user_data)
2054 {
2055   if (event->type == GDK_MOTION_NOTIFY &&
2056       event->motion.device != gdk_device_get_core_pointer())
2057     return TRUE;
2058   if ((event->type == GDK_BUTTON_PRESS || event->type == GDK_2BUTTON_PRESS ||
2059       event->type == GDK_3BUTTON_PRESS || event->type == GDK_BUTTON_RELEASE) &&
2060       event->button.device != gdk_device_get_core_pointer())
2061     return TRUE;
2062   return FALSE;
2063 }
2064
2065 /* Code to turn an extended input event into a core event and send it to
2066    a different GdkWindow -- e.g. could be used when a click in a text edit box
2067    gets sent to the canvas instead due to incorrect event translation.
2068    We now turn off xinput altogether while editing text under GTK+ 2.17, so
2069    this isn't needed any more... but could become useful again someday!
2070 */
2071
2072 /*  
2073 gboolean fix_extended_events (GtkWidget *widget, GdkEvent *event,
2074                                    gpointer user_data)
2075 {
2076   int ix, iy;
2077   GdkWindow *window;
2078
2079   if (user_data) window = (GdkWindow *)user_data;
2080   else window = widget->window;
2081
2082   if (event->type == GDK_MOTION_NOTIFY &&
2083       event->motion.device != gdk_device_get_core_pointer()) {
2084 //    printf("fixing motion\n");
2085     gdk_window_get_pointer(window, &ix, &iy, NULL);
2086     event->motion.x = ix; event->motion.y = iy;
2087     event->motion.device = gdk_device_get_core_pointer();
2088     g_object_unref(event->motion.window);
2089     event->motion.window = g_object_ref(window);
2090     gtk_widget_event(widget, event);
2091     return TRUE;
2092   }
2093   if ((event->type == GDK_BUTTON_PRESS || event->type == GDK_BUTTON_RELEASE) &&
2094       event->button.device != gdk_device_get_core_pointer()) {
2095 //    printf("fixing button from pos = %f, %f\n", event->button.x, event->button.y);
2096     gdk_window_get_pointer(window, &ix, &iy, NULL);
2097     event->button.x = ix; event->button.y = iy;
2098     event->button.device = gdk_device_get_core_pointer();
2099     g_object_unref(event->button.window);
2100     event->button.window = g_object_ref(window);
2101 //    printf("fixing button to pos = %f, %f\n", event->button.x, event->button.y);
2102     gtk_widget_event(widget, event);
2103     return TRUE;
2104   }
2105   return FALSE;
2106 }
2107 */
2108
2109 // disable xinput when layer combo box is popped up, to avoid GTK+ 2.17 crash
2110
2111 gboolean combobox_popup_disable_xinput (GtkWidget *widget, GdkEvent *event,
2112                                    gpointer user_data)
2113 {
2114   gboolean is_shown;
2115   
2116   g_object_get(G_OBJECT(widget), "popup-shown", &is_shown, NULL);
2117   gdk_input_set_extension_events(GTK_WIDGET(canvas)->window, 
2118      GDK_POINTER_MOTION_MASK | GDK_BUTTON_MOTION_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK,
2119      (ui.use_xinput && !is_shown)?GDK_EXTENSION_EVENTS_ALL:GDK_EXTENSION_EVENTS_NONE);
2120 }
2121
2122