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