]> git.donarmstrong.com Git - xournal.git/blob - src/xo-misc.c
Initial revision
[xournal.git] / src / xo-misc.c
1 #ifdef HAVE_CONFIG_H
2 #  include <config.h>
3 #endif
4
5 #include <math.h>
6 #include <gtk/gtk.h>
7 #include <libgnomecanvas/libgnomecanvas.h>
8
9 #include "xournal.h"
10 #include "xo-interface.h"
11 #include "xo-support.h"
12 #include "xo-callbacks.h"
13 #include "xo-misc.h"
14
15 // some global constants
16
17 guint predef_colors_rgba[COLOR_MAX] =
18   { 0x000000ff, 0x3333ccff, 0xff0000ff, 0x008000ff,
19     0x808080ff, 0x00c0ffff, 0x00ff00ff, 0xff00ffff,
20     0xff8000ff, 0xffff00ff, 0xffffffff };
21
22 guint predef_bgcolors_rgba[COLOR_MAX] = // meaningless ones set to white
23   { 0xffffffff, 0xa0e8ffff, 0xffc0d4ff, 0x80ffc0ff,
24     0xffffffff, 0xa0e8ffff, 0x80ffc0ff, 0xffc0d4ff,
25     0xffc080ff, 0xffff80ff, 0xffffffff };
26
27 double predef_thickness[NUM_STROKE_TOOLS][THICKNESS_MAX] =
28   { { 0.42, 0.85, 1.41,  2.26, 5.67 }, // pen thicknesses = 0.15, 0.3, 0.5, 0.8, 2 mm
29     { 2.83, 2.83, 7.08, 14.17, 14.17 }, // eraser thicknesses = 1, 2.5, 5 mm
30     { 2.83, 2.83, 7.08, 14.17, 14.17 }, // highlighter thicknesses = 1, 2.5, 5 mm
31   };
32
33 // some manipulation functions
34
35 struct Page *new_page(struct Page *template)
36 {
37   struct Page *pg = (struct Page *) g_memdup(template, sizeof(struct Page));
38   struct Layer *l = g_new(struct Layer, 1);
39   
40   l->items = NULL;
41   l->nitems = 0;
42   pg->layers = g_list_append(NULL, l);
43   pg->nlayers = 1;
44   pg->bg = (struct Background *)g_memdup(template->bg, sizeof(struct Background));
45   pg->bg->canvas_item = NULL;
46   if (pg->bg->type == BG_PIXMAP || pg->bg->type == BG_PDF) {
47     gdk_pixbuf_ref(pg->bg->pixbuf);
48     refstring_ref(pg->bg->filename);
49   }
50   pg->group = (GnomeCanvasGroup *) gnome_canvas_item_new(
51       gnome_canvas_root(canvas), gnome_canvas_clipgroup_get_type(), NULL);
52   make_page_clipbox(pg);
53   update_canvas_bg(pg);
54   l->group = (GnomeCanvasGroup *) gnome_canvas_item_new(
55       pg->group, gnome_canvas_group_get_type(), NULL);
56   
57   return pg;
58 }
59
60 /* Create a page from a background. 
61    Note: bg should be an UNREFERENCED background.
62    If needed, first duplicate it and increase the refcount of the pixbuf.
63 */
64 struct Page *new_page_with_bg(struct Background *bg, double width, double height)
65 {
66   struct Page *pg = g_new(struct Page, 1);
67   struct Layer *l = g_new(struct Layer, 1);
68   
69   l->items = NULL;
70   l->nitems = 0;
71   pg->layers = g_list_append(NULL, l);
72   pg->nlayers = 1;
73   pg->bg = bg;
74   pg->bg->canvas_item = NULL;
75   pg->height = height;
76   pg->width = width;
77   pg->group = (GnomeCanvasGroup *) gnome_canvas_item_new(
78       gnome_canvas_root(canvas), gnome_canvas_clipgroup_get_type(), NULL);
79   make_page_clipbox(pg);
80   update_canvas_bg(pg);
81   l->group = (GnomeCanvasGroup *) gnome_canvas_item_new(
82       pg->group, gnome_canvas_group_get_type(), NULL);
83   
84   return pg;
85 }
86
87 void realloc_cur_path(int n)
88 {
89   if (n <= ui.cur_path_storage_alloc) return;
90   ui.cur_path_storage_alloc = n+10;
91   ui.cur_path.coords = g_realloc(ui.cur_path.coords, 2*(n+10)*sizeof(double));
92 }
93
94 // undo utility functions
95
96 void prepare_new_undo(void)
97 {
98   struct UndoItem *u;
99   // add a new UndoItem on the stack  
100   u = (struct UndoItem *)g_malloc(sizeof(struct UndoItem));
101   u->next = undo;
102   u->multiop = 0;
103   undo = u;
104   ui.saved = FALSE;
105   clear_redo_stack();
106 }
107
108 void clear_redo_stack(void)
109 {
110   struct UndoItem *u;  
111   GList *list, *repl;
112   struct UndoErasureData *erasure;
113   struct Item *it;
114
115   /* Warning: the redo items might reference items from past redo entries,
116      which have been destroyed before them. Be careful! As a rule, it's
117      safe to destroy data which has been created at the current history step,
118      it's unsafe to refer to any data from previous history steps */
119   
120   while (redo!=NULL) {
121     if (redo->type == ITEM_STROKE) {
122       gnome_canvas_points_free(redo->item->path);
123       g_free(redo->item);
124       /* the strokes are unmapped, so there are no associated canvas items */
125     }
126     else if (redo->type == ITEM_ERASURE) {
127       for (list = redo->erasurelist; list!=NULL; list=list->next) {
128         erasure = (struct UndoErasureData *)list->data;
129         for (repl = erasure->replacement_items; repl!=NULL; repl=repl->next) {
130           it = (struct Item *)repl->data;
131           gnome_canvas_points_free(it->path);
132           g_free(it);
133         }
134         g_list_free(erasure->replacement_items);
135         g_free(erasure);
136       }
137       g_list_free(redo->erasurelist);
138     }
139     else if (redo->type == ITEM_NEW_BG_ONE || redo->type == ITEM_NEW_BG_RESIZE
140           || redo->type == ITEM_NEW_DEFAULT_BG) {
141       if (redo->bg->type == BG_PIXMAP || redo->bg->type == BG_PDF) {
142         if (redo->bg->pixbuf!=NULL) gdk_pixbuf_unref(redo->bg->pixbuf);
143         refstring_unref(redo->bg->filename);
144       }
145       g_free(redo->bg);
146     }
147     else if (redo->type == ITEM_NEW_PAGE) {
148       redo->page->group = NULL;
149       delete_page(redo->page);
150     }
151     else if (redo->type == ITEM_MOVESEL) {
152       g_list_free(redo->itemlist);
153     }
154     else if (redo->type == ITEM_PASTE) {
155       for (list = redo->itemlist; list!=NULL; list=list->next) {
156         it = (struct Item *)list->data;
157         if (it->type == ITEM_STROKE) gnome_canvas_points_free(it->path);
158         g_free(it);
159       }
160       g_list_free(redo->itemlist);
161     }
162     else if (redo->type == ITEM_NEW_LAYER) {
163       g_free(redo->layer);
164     }
165
166     u = redo;
167     redo = redo->next;
168     g_free(u);
169   }
170   update_undo_redo_enabled();
171 }
172
173 void clear_undo_stack(void)
174 {
175   struct UndoItem *u;
176   GList *list;
177   struct UndoErasureData *erasure;
178   
179   while (undo!=NULL) {
180     // for strokes, items are already in the journal, so we don't free them
181     // for erasures, we need to free the dead items
182     if (undo->type == ITEM_ERASURE) {
183       for (list = undo->erasurelist; list!=NULL; list=list->next) {
184         erasure = (struct UndoErasureData *)list->data;
185         gnome_canvas_points_free(erasure->item->path);
186         g_free(erasure->item);
187         g_list_free(erasure->replacement_items);
188         g_free(erasure);
189       }
190       g_list_free(undo->erasurelist);
191     }
192     else if (undo->type == ITEM_NEW_BG_ONE || undo->type == ITEM_NEW_BG_RESIZE
193           || undo->type == ITEM_NEW_DEFAULT_BG) {
194       if (undo->bg->type == BG_PIXMAP || undo->bg->type == BG_PDF) {
195         if (undo->bg->pixbuf!=NULL) gdk_pixbuf_unref(undo->bg->pixbuf);
196         refstring_unref(undo->bg->filename);
197       }
198       g_free(undo->bg);
199     }
200     else if (undo->type == ITEM_MOVESEL || undo->type == ITEM_PASTE) {
201       g_list_free(undo->itemlist);
202     }
203     else if (undo->type == ITEM_DELETE_LAYER) {
204       undo->layer->group = NULL;
205       delete_layer(undo->layer);
206     }
207     else if (undo->type == ITEM_DELETE_PAGE) {
208       undo->page->group = NULL;
209       delete_page(undo->page);
210     }
211
212     u = undo;
213     undo = undo->next;
214     g_free(u);
215   }
216   update_undo_redo_enabled();
217 }
218
219 // free data structures 
220
221 void delete_journal(struct Journal *j)
222 {
223   while (j->pages!=NULL) {
224     delete_page((struct Page *)j->pages->data);
225     j->pages = g_list_delete_link(j->pages, j->pages);
226   }
227 }
228
229 void delete_page(struct Page *pg)
230 {
231   struct Layer *l;
232   
233   while (pg->layers!=NULL) {
234     l = (struct Layer *)pg->layers->data;
235     l->group = NULL;
236     delete_layer(l);
237     pg->layers = g_list_delete_link(pg->layers, pg->layers);
238   }
239   if (pg->group!=NULL) gtk_object_destroy(GTK_OBJECT(pg->group));
240               // this also destroys the background's canvas items
241   if (pg->bg->type == BG_PIXMAP || pg->bg->type == BG_PDF) {
242     if (pg->bg->pixbuf != NULL) gdk_pixbuf_unref(pg->bg->pixbuf);
243     if (pg->bg->filename != NULL) refstring_unref(pg->bg->filename);
244   }
245   g_free(pg->bg);
246   g_free(pg);
247 }
248
249 void delete_layer(struct Layer *l)
250 {
251   struct Item *item;
252   
253   while (l->items!=NULL) {
254     item = (struct Item *)l->items->data;
255     if (item->type == ITEM_STROKE && item->path != NULL) 
256       gnome_canvas_points_free(item->path);
257     // don't need to delete the canvas_item, as it's part of the group destroyed below
258     g_free(item);
259     l->items = g_list_delete_link(l->items, l->items);
260   }
261   if (l->group!= NULL) gtk_object_destroy(GTK_OBJECT(l->group));
262   g_free(l);
263 }
264
265 // referenced strings
266
267 struct Refstring *new_refstring(const char *s)
268 {
269   struct Refstring *rs = g_new(struct Refstring, 1);
270   rs->nref = 1;
271   if (s!=NULL) rs->s = g_strdup(s);
272   else rs->s = NULL;
273   rs->aux = NULL;
274   return rs;
275 }
276
277 struct Refstring *refstring_ref(struct Refstring *rs)
278 {
279   rs->nref++;
280   return rs;
281 }
282
283 void refstring_unref(struct Refstring *rs)
284 {
285   rs->nref--;
286   if (rs->nref == 0) {
287     if (rs->s!=NULL) g_free(rs->s);
288     if (rs->aux!=NULL) g_free(rs->aux);
289     g_free(rs);
290   }
291 }
292
293
294 // some helper functions
295
296 void get_pointer_coords(GdkEvent *event, gdouble *ret)
297 {
298   double x, y;
299   gdk_event_get_coords(event, &x, &y);
300   gnome_canvas_window_to_world(canvas, x, y, ret, ret+1);
301   ret[0] -= ui.cur_page->hoffset;
302   ret[1] -= ui.cur_page->voffset;
303 }
304
305 void fix_xinput_coords(GdkEvent *event)
306 {
307   double *axes, *px, *py, axis_width;
308   GdkDevice *device;
309   int wx, wy, sx, sy;
310   
311   if (event->type == GDK_BUTTON_PRESS || event->type == GDK_BUTTON_RELEASE) {
312     axes = event->button.axes;
313     px = &(event->button.x);
314     py = &(event->button.y);
315     device = event->button.device;
316   }
317   else if (event->type == GDK_MOTION_NOTIFY) {
318     axes = event->motion.axes;
319     px = &(event->motion.x);
320     py = &(event->motion.y);
321     device = event->motion.device;
322   }
323   else return; // nothing we know how to do
324   
325   gdk_window_get_origin(event->any.window, &wx, &wy);
326   gnome_canvas_get_scroll_offsets(canvas, &sx, &sy);
327   
328   axis_width = device->axes[0].max - device->axes[0].min;
329   if (axis_width>EPSILON)
330     *px = (axes[0]/axis_width)*ui.screen_width + sx - wx;
331
332   axis_width = device->axes[1].max - device->axes[1].min;
333   if (axis_width>EPSILON)
334     *py = (axes[1]/axis_width)*ui.screen_height + sy - wy;
335 }
336
337 void update_item_bbox(struct Item *item)
338 {
339   int i;
340   double *p;
341   
342   if (item->type == ITEM_STROKE) {
343     item->bbox.left = item->bbox.right = item->path->coords[0];
344     item->bbox.top = item->bbox.bottom = item->path->coords[1];
345     for (i=1, p=item->path->coords+2; i<item->path->num_points; i++, p+=2)
346     {
347       if (p[0] < item->bbox.left) item->bbox.left = p[0];
348       if (p[0] > item->bbox.right) item->bbox.right = p[0];
349       if (p[1] < item->bbox.top) item->bbox.top = p[1];
350       if (p[1] > item->bbox.bottom) item->bbox.bottom = p[1];
351     }
352   }
353 }
354
355 void make_page_clipbox(struct Page *pg)
356 {
357   GnomeCanvasPathDef *pg_clip;
358   
359   pg_clip = gnome_canvas_path_def_new_sized(4);
360   gnome_canvas_path_def_moveto(pg_clip, 0., 0.);
361   gnome_canvas_path_def_lineto(pg_clip, 0., pg->height);
362   gnome_canvas_path_def_lineto(pg_clip, pg->width, pg->height);
363   gnome_canvas_path_def_lineto(pg_clip, pg->width, 0.);
364   gnome_canvas_path_def_closepath(pg_clip);
365   gnome_canvas_item_set(GNOME_CANVAS_ITEM(pg->group), "path", pg_clip, NULL);
366   gnome_canvas_path_def_unref(pg_clip);
367 }
368
369 void make_canvas_items(void)
370 {
371   struct Page *pg;
372   struct Layer *l;
373   struct Item *item;
374   GList *pagelist, *layerlist, *itemlist;
375   
376   for (pagelist = journal.pages; pagelist!=NULL; pagelist = pagelist->next) {
377     pg = (struct Page *)pagelist->data;
378     if (pg->group == NULL) {
379       pg->group = (GnomeCanvasGroup *) gnome_canvas_item_new(
380          gnome_canvas_root(canvas), gnome_canvas_clipgroup_get_type(), NULL);
381       make_page_clipbox(pg);
382     }
383     if (pg->bg->canvas_item == NULL) update_canvas_bg(pg);
384     for (layerlist = pg->layers; layerlist!=NULL; layerlist = layerlist->next) {
385       l = (struct Layer *)layerlist->data;
386       if (l->group == NULL)
387         l->group = (GnomeCanvasGroup *) gnome_canvas_item_new(
388            pg->group, gnome_canvas_group_get_type(), NULL);
389       for (itemlist = l->items; itemlist!=NULL; itemlist = itemlist->next) {
390         item = (struct Item *)itemlist->data;
391         if (item->type == ITEM_STROKE && item->canvas_item == NULL) {
392           item->canvas_item = gnome_canvas_item_new(l->group,
393               gnome_canvas_line_get_type(), "points", item->path,
394               "cap-style", GDK_CAP_ROUND, "join-style", GDK_JOIN_ROUND,
395               "fill-color-rgba", item->brush.color_rgba,
396               "width-units", item->brush.thickness, NULL);
397         }
398       }
399     }
400   }
401 }
402
403 void update_canvas_bg(struct Page *pg)
404 {
405   GnomeCanvasGroup *group;
406   GnomeCanvasPoints *seg;
407   GdkPixbuf *scaled_pix;
408   double *pt;
409   double x, y;
410   int w, h;
411   
412   if (pg->bg->canvas_item != NULL)
413     gtk_object_destroy(GTK_OBJECT(pg->bg->canvas_item));
414   pg->bg->canvas_item = NULL;
415   
416   if (pg->bg->type == BG_SOLID)
417   {
418     pg->bg->canvas_item = gnome_canvas_item_new(pg->group,
419                                gnome_canvas_group_get_type(), NULL);
420     group = GNOME_CANVAS_GROUP(pg->bg->canvas_item);
421     lower_canvas_item_to(pg->group, pg->bg->canvas_item, NULL);
422     gnome_canvas_item_new(group, gnome_canvas_rect_get_type(),
423       "x1", 0., "x2", pg->width, "y1", 0., "y2", pg->height,
424       "fill-color-rgba", pg->bg->color_rgba, NULL);
425     if (pg->bg->ruling == RULING_NONE) return;
426     seg = gnome_canvas_points_new(2);
427     pt = seg->coords;
428     if (pg->bg->ruling == RULING_GRAPH) {
429       pt[1] = 0; pt[3] = pg->height;
430       for (x=RULING_GRAPHSPACING; x<pg->width-1; x+=RULING_GRAPHSPACING) {
431         pt[0] = pt[2] = x;
432         gnome_canvas_item_new(group, gnome_canvas_line_get_type(),
433            "points", seg, "fill-color-rgba", RULING_COLOR,
434            "width-units", RULING_THICKNESS, NULL);
435       }      
436       pt[0] = 0; pt[2] = pg->width;
437       for (y=RULING_GRAPHSPACING; y<pg->height-1; y+=RULING_GRAPHSPACING) {
438         pt[1] = pt[3] = y;
439         gnome_canvas_item_new(group, gnome_canvas_line_get_type(),
440            "points", seg, "fill-color-rgba", RULING_COLOR,
441            "width-units", RULING_THICKNESS, NULL);
442       }      
443       gnome_canvas_points_free(seg);
444       return;
445     }
446     pt[0] = 0; pt[2] = pg->width;
447     for (y=RULING_TOPMARGIN; y<pg->height-1; y+=RULING_SPACING) {
448       pt[1] = pt[3] = y;
449       gnome_canvas_item_new(group, gnome_canvas_line_get_type(),
450          "points", seg, "fill-color-rgba", RULING_COLOR,
451          "width-units", RULING_THICKNESS, NULL);
452     }      
453     if (pg->bg->ruling == RULING_LINED) {
454       pt[0] = pt[2] = RULING_LEFTMARGIN;
455       pt[1] = 0; pt[3] = pg->height;
456       gnome_canvas_item_new(group, gnome_canvas_line_get_type(),
457          "points", seg, "fill-color-rgba", RULING_MARGIN_COLOR,
458          "width-units", RULING_THICKNESS, NULL);
459     }
460     gnome_canvas_points_free(seg);
461     return;
462   }
463   
464   if (pg->bg->type == BG_PIXMAP)
465   {
466     if (ui.antialias_bg) {
467       set_cursor_busy(TRUE);
468       w = (int)floor(pg->width*ui.zoom+0.5);
469       h = (int)floor(pg->height*ui.zoom+0.5);
470       if (w == gdk_pixbuf_get_width(pg->bg->pixbuf) &&
471           h == gdk_pixbuf_get_height(pg->bg->pixbuf))
472         scaled_pix = gdk_pixbuf_ref(pg->bg->pixbuf);
473       else
474         scaled_pix = gdk_pixbuf_scale_simple(pg->bg->pixbuf, w, h, GDK_INTERP_BILINEAR);
475       pg->bg->pixbuf_scale = ui.zoom;
476       set_cursor_busy(FALSE);
477     }
478     else {
479       scaled_pix = gdk_pixbuf_ref(pg->bg->pixbuf);
480       pg->bg->pixbuf_scale = 0;
481     }
482     pg->bg->canvas_item = gnome_canvas_item_new(pg->group, 
483         gnome_canvas_pixbuf_get_type(), 
484         "pixbuf", scaled_pix,
485         "width", pg->width, "height", pg->height, 
486         "width-set", TRUE, "height-set", TRUE, 
487         NULL);
488     gdk_pixbuf_unref(scaled_pix);
489     lower_canvas_item_to(pg->group, pg->bg->canvas_item, NULL);
490   }
491
492   if (pg->bg->type == BG_PDF)
493   {
494     if (pg->bg->pixbuf == NULL) return;
495     pg->bg->canvas_item = gnome_canvas_item_new(pg->group, 
496         gnome_canvas_pixbuf_get_type(), 
497         "pixbuf", pg->bg->pixbuf,
498         "width", pg->width, "height", pg->height, 
499         "width-set", TRUE, "height-set", TRUE, 
500         NULL);
501     lower_canvas_item_to(pg->group, pg->bg->canvas_item, NULL);
502   }
503
504 }
505
506 gboolean is_visible(struct Page *pg)
507 {
508   GtkAdjustment *v_adj;
509   double ytop, ybot;
510   
511   if (!ui.view_continuous) return (pg == ui.cur_page);
512   v_adj = gtk_layout_get_vadjustment(GTK_LAYOUT(canvas));
513   ytop = v_adj->value/ui.zoom;
514   ybot = (v_adj->value + v_adj->page_size) / ui.zoom;
515   return (MAX(ytop, pg->voffset) < MIN(ybot, pg->voffset+pg->height));
516 }
517
518 void rescale_bg_pixmaps(void)
519 {
520   GList *pglist;
521   struct Page *pg;
522   GdkPixbuf *pix;
523   
524   for (pglist = journal.pages; pglist!=NULL; pglist = pglist->next) {
525     pg = (struct Page *)pglist->data;
526     // in progressive mode we scale only visible pages
527     if (ui.progressive_bg && !is_visible(pg)) continue;
528
529     if (pg->bg->type == BG_PIXMAP) { // do the rescaling ourselves
530       if (ui.antialias_bg) {
531         if (pg->bg->pixbuf_scale == ui.zoom) continue;
532         set_cursor_busy(TRUE);
533         pix = gdk_pixbuf_scale_simple(pg->bg->pixbuf,
534           (int)floor(pg->width*ui.zoom+0.5), (int)floor(pg->height*ui.zoom+0.5),
535           GDK_INTERP_BILINEAR);
536         gnome_canvas_item_set(pg->bg->canvas_item, "pixbuf", pix, NULL);
537         gdk_pixbuf_unref(pix);
538         pg->bg->pixbuf_scale = ui.zoom;
539         set_cursor_busy(FALSE);
540       } else
541       {
542         pix = GDK_PIXBUF(g_object_get_data(G_OBJECT(pg->bg->canvas_item), "pixbuf"));
543         if (pix!=pg->bg->pixbuf)
544           gnome_canvas_item_set(pg->bg->canvas_item, "pixbuf", pg->bg->pixbuf, NULL);
545         pg->bg->pixbuf_scale = 0;
546       }
547     }
548     if (pg->bg->type == BG_PDF) { // request an asynchronous update
549       if (pg->bg->pixbuf_scale == ui.zoom) continue;
550       add_bgpdf_request(pg->bg->file_page_seq, ui.zoom, FALSE);
551       pg->bg->pixbuf_scale = ui.zoom;
552     }
553   }
554 }
555
556 gboolean have_intersect(struct BBox *a, struct BBox *b)
557 {
558   return (MAX(a->top, b->top) <= MIN(a->bottom, b->bottom)) &&
559          (MAX(a->left, b->left) <= MIN(a->right, b->right));
560 }
561
562 /* In libgnomecanvas 2.10.0, the lower/raise functions fail to update
563    correctly the end of the group's item list. We try to work around this.
564    DON'T USE gnome_canvas_item_raise/lower directly !! */
565
566 void lower_canvas_item_to(GnomeCanvasGroup *g, GnomeCanvasItem *item, GnomeCanvasItem *after)
567 {
568   int i1, i2;
569   
570   i1 = g_list_index(g->item_list, item);
571   if (i1 == -1) return;
572   
573   if (after == NULL) i2 = -1;
574   else i2 = g_list_index(g->item_list, after);
575
576   if (i1 < i2) gnome_canvas_item_raise(item, i2-i1);
577   if (i1 > i2+1) gnome_canvas_item_lower(item, i1-i2-1);
578   
579   // BUGFIX for libgnomecanvas
580   g->item_list_end = g_list_last(g->item_list);
581 }
582
583 // some interface functions
584
585 void update_thickness_buttons(void)
586 {
587   if (ui.toolno >= NUM_STROKE_TOOLS) {
588     gtk_toggle_tool_button_set_active(
589       GTK_TOGGLE_TOOL_BUTTON(GET_COMPONENT("buttonThicknessOther")), TRUE);
590   } else 
591   switch (ui.cur_brush->thickness_no) {
592     case THICKNESS_FINE:
593       gtk_toggle_tool_button_set_active(
594         GTK_TOGGLE_TOOL_BUTTON(GET_COMPONENT("buttonFine")), TRUE);
595       break;
596     case THICKNESS_MEDIUM:
597       gtk_toggle_tool_button_set_active(
598         GTK_TOGGLE_TOOL_BUTTON(GET_COMPONENT("buttonMedium")), TRUE);
599       break;
600     case THICKNESS_THICK:
601       gtk_toggle_tool_button_set_active(
602         GTK_TOGGLE_TOOL_BUTTON(GET_COMPONENT("buttonThick")), TRUE);
603       break;
604     default:
605       gtk_toggle_tool_button_set_active(
606         GTK_TOGGLE_TOOL_BUTTON(GET_COMPONENT("buttonThicknessOther")), TRUE);
607   }
608 }
609
610 void update_color_buttons(void)
611 {
612   if (ui.toolno != TOOL_PEN && ui.toolno != TOOL_HIGHLIGHTER) {
613     gtk_toggle_tool_button_set_active(
614       GTK_TOGGLE_TOOL_BUTTON(GET_COMPONENT("buttonColorOther")), TRUE);
615   } else
616   switch (ui.cur_brush->color_no) {
617     case COLOR_BLACK:
618       gtk_toggle_tool_button_set_active(
619         GTK_TOGGLE_TOOL_BUTTON(GET_COMPONENT("buttonBlack")), TRUE);
620       break;
621     case COLOR_BLUE:
622       gtk_toggle_tool_button_set_active(
623         GTK_TOGGLE_TOOL_BUTTON(GET_COMPONENT("buttonBlue")), TRUE);
624       break;
625     case COLOR_RED:
626       gtk_toggle_tool_button_set_active(
627         GTK_TOGGLE_TOOL_BUTTON(GET_COMPONENT("buttonRed")), TRUE);
628       break;
629     case COLOR_GREEN:
630       gtk_toggle_tool_button_set_active(
631         GTK_TOGGLE_TOOL_BUTTON(GET_COMPONENT("buttonGreen")), TRUE);
632       break;
633     case COLOR_GRAY:
634       gtk_toggle_tool_button_set_active(
635         GTK_TOGGLE_TOOL_BUTTON(GET_COMPONENT("buttonGray")), TRUE);
636       break;
637     case COLOR_LIGHTBLUE:
638       gtk_toggle_tool_button_set_active(
639         GTK_TOGGLE_TOOL_BUTTON(GET_COMPONENT("buttonLightBlue")), TRUE);
640       break;
641     case COLOR_LIGHTGREEN:
642       gtk_toggle_tool_button_set_active(
643         GTK_TOGGLE_TOOL_BUTTON(GET_COMPONENT("buttonLightGreen")), TRUE);
644       break;
645     case COLOR_MAGENTA:
646       gtk_toggle_tool_button_set_active(
647         GTK_TOGGLE_TOOL_BUTTON(GET_COMPONENT("buttonMagenta")), TRUE);
648       break;
649     case COLOR_ORANGE:
650       gtk_toggle_tool_button_set_active(
651         GTK_TOGGLE_TOOL_BUTTON(GET_COMPONENT("buttonOrange")), TRUE);
652       break;
653     case COLOR_YELLOW:
654       gtk_toggle_tool_button_set_active(
655         GTK_TOGGLE_TOOL_BUTTON(GET_COMPONENT("buttonYellow")), TRUE);
656       break;
657     case COLOR_WHITE:
658       gtk_toggle_tool_button_set_active(
659         GTK_TOGGLE_TOOL_BUTTON(GET_COMPONENT("buttonWhite")), TRUE);
660       break;
661     default:
662       gtk_toggle_tool_button_set_active(
663         GTK_TOGGLE_TOOL_BUTTON(GET_COMPONENT("buttonColorOther")), TRUE);
664   }
665 }
666
667 void update_tool_buttons(void)
668 {
669   switch(ui.toolno) {
670     case TOOL_PEN:
671       gtk_toggle_tool_button_set_active(
672         GTK_TOGGLE_TOOL_BUTTON(GET_COMPONENT("buttonPen")), TRUE);
673       break;
674     case TOOL_ERASER:
675       gtk_toggle_tool_button_set_active(
676         GTK_TOGGLE_TOOL_BUTTON(GET_COMPONENT("buttonEraser")), TRUE);
677       break;
678     case TOOL_HIGHLIGHTER:
679       gtk_toggle_tool_button_set_active(
680         GTK_TOGGLE_TOOL_BUTTON(GET_COMPONENT("buttonHighlighter")), TRUE);
681       break;
682     case TOOL_TEXT:
683       gtk_toggle_tool_button_set_active(
684         GTK_TOGGLE_TOOL_BUTTON(GET_COMPONENT("buttonText")), TRUE);
685       break;
686     case TOOL_SELECTREGION:
687       gtk_toggle_tool_button_set_active(
688         GTK_TOGGLE_TOOL_BUTTON(GET_COMPONENT("buttonSelectRegion")), TRUE);
689       break;
690     case TOOL_SELECTRECT:
691       gtk_toggle_tool_button_set_active(
692         GTK_TOGGLE_TOOL_BUTTON(GET_COMPONENT("buttonSelectRectangle")), TRUE);
693       break;
694     case TOOL_VERTSPACE:
695       gtk_toggle_tool_button_set_active(
696         GTK_TOGGLE_TOOL_BUTTON(GET_COMPONENT("buttonVerticalSpace")), TRUE);
697       break;
698   }
699     
700   gtk_toggle_tool_button_set_active(
701     GTK_TOGGLE_TOOL_BUTTON(GET_COMPONENT("buttonRuler")), ui.ruler);
702   update_thickness_buttons();
703   update_color_buttons();
704 }
705
706 void update_tool_menu(void)
707 {
708   switch(ui.toolno) {
709     case TOOL_PEN:
710       gtk_check_menu_item_set_active(
711         GTK_CHECK_MENU_ITEM(GET_COMPONENT("toolsPen")), TRUE);
712       break;
713     case TOOL_ERASER:
714       gtk_check_menu_item_set_active(
715         GTK_CHECK_MENU_ITEM(GET_COMPONENT("toolsEraser")), TRUE);
716       break;
717     case TOOL_HIGHLIGHTER:
718       gtk_check_menu_item_set_active(
719         GTK_CHECK_MENU_ITEM(GET_COMPONENT("toolsHighlighter")), TRUE);
720       break;
721     case TOOL_TEXT:
722       gtk_check_menu_item_set_active(
723         GTK_CHECK_MENU_ITEM(GET_COMPONENT("toolsText")), TRUE);
724       break;
725     case TOOL_SELECTREGION:
726       gtk_check_menu_item_set_active(
727         GTK_CHECK_MENU_ITEM(GET_COMPONENT("toolsSelectRegion")), TRUE);
728       break;
729     case TOOL_SELECTRECT:
730       gtk_check_menu_item_set_active(
731         GTK_CHECK_MENU_ITEM(GET_COMPONENT("toolsSelectRectangle")), TRUE);
732       break;
733     case TOOL_VERTSPACE:
734       gtk_check_menu_item_set_active(
735         GTK_CHECK_MENU_ITEM(GET_COMPONENT("toolsVerticalSpace")), TRUE);
736       break;
737   }
738
739   gtk_check_menu_item_set_active(
740     GTK_CHECK_MENU_ITEM(GET_COMPONENT("toolsRuler")), ui.ruler);
741 }
742
743 void update_ruler_indicator(void)
744 {
745   gtk_toggle_tool_button_set_active(
746     GTK_TOGGLE_TOOL_BUTTON(GET_COMPONENT("buttonRuler")), ui.ruler);
747   gtk_check_menu_item_set_active(
748     GTK_CHECK_MENU_ITEM(GET_COMPONENT("toolsRuler")), ui.ruler);
749 }
750
751 void update_color_menu(void)
752 {
753   if (ui.toolno != TOOL_PEN && ui.toolno != TOOL_HIGHLIGHTER) {
754     gtk_check_menu_item_set_active(
755       GTK_CHECK_MENU_ITEM(GET_COMPONENT("colorNA")), TRUE);
756   } else
757   switch (ui.cur_brush->color_no) {
758     case COLOR_BLACK:
759       gtk_check_menu_item_set_active(
760         GTK_CHECK_MENU_ITEM(GET_COMPONENT("colorBlack")), TRUE);
761       break;
762     case COLOR_BLUE:
763       gtk_check_menu_item_set_active(
764         GTK_CHECK_MENU_ITEM(GET_COMPONENT("colorBlue")), TRUE);
765       break;
766     case COLOR_RED:
767       gtk_check_menu_item_set_active(
768         GTK_CHECK_MENU_ITEM(GET_COMPONENT("colorRed")), TRUE);
769       break;
770     case COLOR_GREEN:
771       gtk_check_menu_item_set_active(
772         GTK_CHECK_MENU_ITEM(GET_COMPONENT("colorGreen")), TRUE);
773       break;
774     case COLOR_GRAY:
775       gtk_check_menu_item_set_active(
776         GTK_CHECK_MENU_ITEM(GET_COMPONENT("colorGray")), TRUE);
777       break;
778     case COLOR_LIGHTBLUE:
779       gtk_check_menu_item_set_active(
780         GTK_CHECK_MENU_ITEM(GET_COMPONENT("colorLightBlue")), TRUE);
781       break;
782     case COLOR_LIGHTGREEN:
783       gtk_check_menu_item_set_active(
784         GTK_CHECK_MENU_ITEM(GET_COMPONENT("colorLightGreen")), TRUE);
785       break;
786     case COLOR_MAGENTA:
787       gtk_check_menu_item_set_active(
788         GTK_CHECK_MENU_ITEM(GET_COMPONENT("colorMagenta")), TRUE);
789       break;
790     case COLOR_ORANGE:
791       gtk_check_menu_item_set_active(
792         GTK_CHECK_MENU_ITEM(GET_COMPONENT("colorOrange")), TRUE);
793       break;
794     case COLOR_YELLOW:
795       gtk_check_menu_item_set_active(
796         GTK_CHECK_MENU_ITEM(GET_COMPONENT("colorYellow")), TRUE);
797       break;
798     case COLOR_WHITE:
799       gtk_check_menu_item_set_active(
800         GTK_CHECK_MENU_ITEM(GET_COMPONENT("colorWhite")), TRUE);
801       break;
802     default:
803       gtk_check_menu_item_set_active(
804         GTK_CHECK_MENU_ITEM(GET_COMPONENT("colorOther")), TRUE);
805   }
806 }
807
808 void update_pen_props_menu(void)
809 {
810   switch(ui.brushes[TOOL_PEN].thickness_no) {
811     case THICKNESS_VERYFINE:
812       gtk_check_menu_item_set_active(
813         GTK_CHECK_MENU_ITEM(GET_COMPONENT("penthicknessVeryFine")), TRUE);
814       break;
815     case THICKNESS_FINE:
816       gtk_check_menu_item_set_active(
817         GTK_CHECK_MENU_ITEM(GET_COMPONENT("penthicknessFine")), TRUE);
818       break;
819     case THICKNESS_MEDIUM:
820       gtk_check_menu_item_set_active(
821         GTK_CHECK_MENU_ITEM(GET_COMPONENT("penthicknessMedium")), TRUE);
822       break;
823     case THICKNESS_THICK:
824       gtk_check_menu_item_set_active(
825         GTK_CHECK_MENU_ITEM(GET_COMPONENT("penthicknessThick")), TRUE);
826       break;
827     case THICKNESS_VERYTHICK:
828       gtk_check_menu_item_set_active(
829         GTK_CHECK_MENU_ITEM(GET_COMPONENT("penthicknessVeryThick")), TRUE);
830       break;
831   }
832 }
833
834 void update_eraser_props_menu(void)
835 {
836   switch (ui.brushes[TOOL_ERASER].thickness_no) {
837     case THICKNESS_FINE:
838       gtk_check_menu_item_set_active(
839         GTK_CHECK_MENU_ITEM(GET_COMPONENT("eraserFine")), TRUE);
840       break;
841     case THICKNESS_MEDIUM:
842       gtk_check_menu_item_set_active(
843         GTK_CHECK_MENU_ITEM(GET_COMPONENT("eraserMedium")), TRUE);
844       break;
845     case THICKNESS_THICK:
846       gtk_check_menu_item_set_active(
847         GTK_CHECK_MENU_ITEM(GET_COMPONENT("eraserThick")), TRUE);
848       break;
849   }
850   
851   gtk_check_menu_item_set_active(
852     GTK_CHECK_MENU_ITEM(GET_COMPONENT("eraserStandard")),
853     ui.brushes[TOOL_ERASER].tool_options == TOOLOPT_ERASER_STANDARD);
854   gtk_check_menu_item_set_active(
855     GTK_CHECK_MENU_ITEM(GET_COMPONENT("eraserWhiteout")),
856     ui.brushes[TOOL_ERASER].tool_options == TOOLOPT_ERASER_WHITEOUT);
857   gtk_check_menu_item_set_active(
858     GTK_CHECK_MENU_ITEM(GET_COMPONENT("eraserDeleteStrokes")),
859     ui.brushes[TOOL_ERASER].tool_options == TOOLOPT_ERASER_STROKES);
860 }
861
862 void update_highlighter_props_menu(void)
863 {
864   switch (ui.brushes[TOOL_HIGHLIGHTER].thickness_no) {
865     case THICKNESS_FINE:
866       gtk_check_menu_item_set_active(
867         GTK_CHECK_MENU_ITEM(GET_COMPONENT("highlighterFine")), TRUE);
868       break;
869     case THICKNESS_MEDIUM:
870       gtk_check_menu_item_set_active(
871         GTK_CHECK_MENU_ITEM(GET_COMPONENT("highlighterMedium")), TRUE);
872       break;
873     case THICKNESS_THICK:
874       gtk_check_menu_item_set_active(
875         GTK_CHECK_MENU_ITEM(GET_COMPONENT("highlighterThick")), TRUE);
876       break;
877   }
878 }
879
880 void do_switch_page(int pg, gboolean rescroll)
881 {
882   int i;
883   struct Layer *layer;
884   GList *list;
885   
886   ui.pageno = pg;
887
888   /* re-show all the layers of the old page */
889   if (ui.cur_page != NULL)
890     for (i=0, list = ui.cur_page->layers; list!=NULL; i++, list = list->next) {
891       layer = (struct Layer *)list->data;
892       if (layer->group!=NULL)
893         gnome_canvas_item_show(GNOME_CANVAS_ITEM(layer->group));
894     }
895   
896   ui.cur_page = g_list_nth_data(journal.pages, ui.pageno);
897   ui.layerno = ui.cur_page->nlayers-1;
898   ui.cur_layer = (struct Layer *)(g_list_last(ui.cur_page->layers)->data);
899   update_page_stuff();
900   if (ui.progressive_bg) rescale_bg_pixmaps();
901  
902   if (rescroll) { // scroll and force a refresh
903     gtk_adjustment_set_value(gtk_layout_get_vadjustment(GTK_LAYOUT(canvas)),
904       ui.cur_page->voffset*ui.zoom);
905     gnome_canvas_set_pixels_per_unit(canvas, ui.zoom);
906   }
907 }
908
909 void update_page_stuff(void)
910 {
911   gchar tmp[10];
912   GtkComboBox *layerbox;
913   int i;
914   GList *pglist;
915   GtkSpinButton *spin;
916   struct Page *pg;
917   double vertpos, maxwidth;
918   struct Layer *layer;
919   int relscroll;
920
921   // move the page groups to their rightful locations or hide them
922   if (ui.view_continuous) {
923     vertpos = 0.; 
924     maxwidth = 0.;
925     for (i=0, pglist = journal.pages; pglist!=NULL; i++, pglist = pglist->next) {
926       pg = (struct Page *)pglist->data;
927       if (pg->group!=NULL) {
928         pg->hoffset = 0.; pg->voffset = vertpos;
929         gnome_canvas_item_set(GNOME_CANVAS_ITEM(pg->group), 
930             "x", pg->hoffset, "y", pg->voffset, NULL);
931         gnome_canvas_item_show(GNOME_CANVAS_ITEM(pg->group));
932       }
933       vertpos += pg->height + VIEW_CONTINUOUS_SKIP;
934       if (pg->width > maxwidth) maxwidth = pg->width;
935     }
936     vertpos -= VIEW_CONTINUOUS_SKIP;
937     gnome_canvas_set_scroll_region(canvas, 0, 0, maxwidth, vertpos);
938   } else {
939     for (pglist = journal.pages; pglist!=NULL; pglist = pglist->next) {
940       pg = (struct Page *)pglist->data;
941       if (pg == ui.cur_page && pg->group!=NULL) {
942         pg->hoffset = 0.; pg->voffset = 0.;
943         gnome_canvas_item_set(GNOME_CANVAS_ITEM(pg->group), 
944             "x", pg->hoffset, "y", pg->voffset, NULL);
945         gnome_canvas_item_show(GNOME_CANVAS_ITEM(pg->group));
946       } else {
947         if (pg->group!=NULL) gnome_canvas_item_hide(GNOME_CANVAS_ITEM(pg->group));
948       }
949     }
950     gnome_canvas_set_scroll_region(canvas, 0, 0, ui.cur_page->width, ui.cur_page->height);
951   }
952
953   // update the page / layer info at bottom of screen
954
955   spin = GTK_SPIN_BUTTON(GET_COMPONENT("spinPageNo"));
956   ui.in_update_page_stuff = TRUE; // avoid a bad retroaction
957   gtk_spin_button_set_range(spin, 1, journal.npages+1);
958     /* npages+1 will be used to create a new page at end */
959   gtk_spin_button_set_value(spin, ui.pageno+1);
960   g_snprintf(tmp, 10, " of %d", journal.npages);
961   gtk_label_set_text(GTK_LABEL(GET_COMPONENT("labelNumpages")), tmp);
962
963   layerbox = GTK_COMBO_BOX(GET_COMPONENT("comboLayer"));
964   if (ui.layerbox_length == 0) {
965     gtk_combo_box_prepend_text(layerbox, "Background");
966     ui.layerbox_length++;
967   }
968   while (ui.layerbox_length > ui.cur_page->nlayers+1) {
969     gtk_combo_box_remove_text(layerbox, 0);
970     ui.layerbox_length--;
971   }
972   while (ui.layerbox_length < ui.cur_page->nlayers+1) {
973     g_snprintf(tmp, 10, "Layer %d", ui.layerbox_length++);
974     gtk_combo_box_prepend_text(layerbox, tmp);
975   }
976   gtk_combo_box_set_active(layerbox, ui.cur_page->nlayers-1-ui.layerno);
977   ui.in_update_page_stuff = FALSE;
978   
979   // update the paper-style menu radio buttons
980   
981   if (ui.view_continuous)
982     gtk_check_menu_item_set_active(
983        GTK_CHECK_MENU_ITEM(GET_COMPONENT("viewContinuous")), TRUE);
984   else
985     gtk_check_menu_item_set_active(
986        GTK_CHECK_MENU_ITEM(GET_COMPONENT("viewOnePage")), TRUE);
987
988   if (ui.cur_page->bg->type == BG_SOLID) {
989     switch (ui.cur_page->bg->color_no) {
990       case COLOR_WHITE:
991         gtk_check_menu_item_set_active(
992           GTK_CHECK_MENU_ITEM(GET_COMPONENT("papercolorWhite")), TRUE);
993         break;
994       case COLOR_YELLOW:
995         gtk_check_menu_item_set_active(
996           GTK_CHECK_MENU_ITEM(GET_COMPONENT("papercolorYellow")), TRUE);
997         break;
998       case COLOR_RED:
999         gtk_check_menu_item_set_active(
1000           GTK_CHECK_MENU_ITEM(GET_COMPONENT("papercolorPink")), TRUE);
1001         break;
1002       case COLOR_ORANGE:
1003         gtk_check_menu_item_set_active(
1004           GTK_CHECK_MENU_ITEM(GET_COMPONENT("papercolorOrange")), TRUE);
1005         break;
1006       case COLOR_BLUE:
1007         gtk_check_menu_item_set_active(
1008           GTK_CHECK_MENU_ITEM(GET_COMPONENT("papercolorBlue")), TRUE);
1009         break;
1010       case COLOR_GREEN:
1011         gtk_check_menu_item_set_active(
1012           GTK_CHECK_MENU_ITEM(GET_COMPONENT("papercolorGreen")), TRUE);
1013         break;
1014       default:
1015         gtk_check_menu_item_set_active(
1016           GTK_CHECK_MENU_ITEM(GET_COMPONENT("papercolorOther")), TRUE);
1017         break;
1018     }
1019     switch (ui.cur_page->bg->ruling) {
1020       case RULING_NONE:
1021         gtk_check_menu_item_set_active(
1022           GTK_CHECK_MENU_ITEM(GET_COMPONENT("paperstylePlain")), TRUE);
1023         break;
1024       case RULING_LINED:
1025         gtk_check_menu_item_set_active(
1026           GTK_CHECK_MENU_ITEM(GET_COMPONENT("paperstyleLined")), TRUE);
1027         break;
1028       case RULING_RULED:
1029         gtk_check_menu_item_set_active(
1030           GTK_CHECK_MENU_ITEM(GET_COMPONENT("paperstyleRuled")), TRUE);
1031         break;
1032       case RULING_GRAPH:
1033         gtk_check_menu_item_set_active(
1034           GTK_CHECK_MENU_ITEM(GET_COMPONENT("paperstyleGraph")), TRUE);
1035         break;
1036     }
1037   } else {
1038     gtk_check_menu_item_set_active(
1039       GTK_CHECK_MENU_ITEM(GET_COMPONENT("papercolorNA")), TRUE);
1040     gtk_check_menu_item_set_active(
1041       GTK_CHECK_MENU_ITEM(GET_COMPONENT("paperstyleNA")), TRUE);
1042   }
1043   
1044   // enable/disable the page/layer menu items and toolbar buttons
1045
1046   gtk_widget_set_sensitive(GET_COMPONENT("journalPaperColor"), 
1047      ui.cur_page->bg->type == BG_SOLID);
1048   gtk_widget_set_sensitive(GET_COMPONENT("journalSetAsDefault"),
1049      ui.cur_page->bg->type == BG_SOLID);
1050   
1051   gtk_widget_set_sensitive(GET_COMPONENT("viewFirstPage"), ui.pageno!=0);
1052   gtk_widget_set_sensitive(GET_COMPONENT("viewPreviousPage"), ui.pageno!=0);
1053   gtk_widget_set_sensitive(GET_COMPONENT("viewNextPage"), TRUE);
1054   gtk_widget_set_sensitive(GET_COMPONENT("viewLastPage"), ui.pageno!=journal.npages-1);
1055   gtk_widget_set_sensitive(GET_COMPONENT("buttonFirstPage"), ui.pageno!=0);
1056   gtk_widget_set_sensitive(GET_COMPONENT("buttonPreviousPage"), ui.pageno!=0);
1057   gtk_widget_set_sensitive(GET_COMPONENT("buttonNextPage"), TRUE);
1058   gtk_widget_set_sensitive(GET_COMPONENT("buttonLastPage"), ui.pageno!=journal.npages-1);
1059   
1060   gtk_widget_set_sensitive(GET_COMPONENT("viewShowLayer"), ui.layerno!=ui.cur_page->nlayers-1);
1061   gtk_widget_set_sensitive(GET_COMPONENT("viewHideLayer"), ui.layerno>=0);
1062
1063   gtk_widget_set_sensitive(GET_COMPONENT("editPaste"), ui.cur_layer!=NULL);
1064   gtk_widget_set_sensitive(GET_COMPONENT("buttonPaste"), ui.cur_layer!=NULL);
1065 }
1066
1067 void update_toolbar_and_menu(void)
1068 {
1069   update_tool_buttons(); // takes care of other toolbar buttons as well  
1070   update_tool_menu();
1071   update_color_menu();
1072   update_pen_props_menu();
1073   update_eraser_props_menu();
1074   update_highlighter_props_menu();
1075
1076   gtk_toggle_tool_button_set_active(
1077     GTK_TOGGLE_TOOL_BUTTON(GET_COMPONENT("buttonFullscreen")), ui.fullscreen);
1078   gtk_check_menu_item_set_active(
1079     GTK_CHECK_MENU_ITEM(GET_COMPONENT("viewFullscreen")), ui.fullscreen);
1080 }
1081
1082 void update_file_name(char *filename)
1083 {
1084   gchar tmp[100], *p;
1085   if (ui.filename != NULL) g_free(ui.filename);
1086   ui.filename = filename;
1087   if (filename == NULL) {
1088     gtk_window_set_title(GTK_WINDOW (winMain), "Xournal");
1089     return;
1090   }
1091   p = g_utf8_strrchr(filename, -1, '/');
1092   if (p == NULL) p = filename; 
1093   else p = g_utf8_next_char(p);
1094   g_snprintf(tmp, 100, "Xournal - %s", p);
1095   gtk_window_set_title(GTK_WINDOW (winMain), tmp);
1096 }
1097
1098 void update_undo_redo_enabled(void)
1099 {
1100   gtk_widget_set_sensitive(GET_COMPONENT("editUndo"), undo!=NULL);
1101   gtk_widget_set_sensitive(GET_COMPONENT("editRedo"), redo!=NULL);
1102   gtk_widget_set_sensitive(GET_COMPONENT("buttonUndo"), undo!=NULL);
1103   gtk_widget_set_sensitive(GET_COMPONENT("buttonRedo"), redo!=NULL);
1104 }
1105
1106 void update_copy_paste_enabled(void)
1107 {
1108   gtk_widget_set_sensitive(GET_COMPONENT("editCut"), ui.selection!=NULL);
1109   gtk_widget_set_sensitive(GET_COMPONENT("editCopy"), ui.selection!=NULL);
1110   gtk_widget_set_sensitive(GET_COMPONENT("editDelete"), ui.selection!=NULL);
1111   gtk_widget_set_sensitive(GET_COMPONENT("buttonCut"), ui.selection!=NULL);
1112   gtk_widget_set_sensitive(GET_COMPONENT("buttonCopy"), ui.selection!=NULL);
1113 }
1114
1115 void set_cur_color(int color)
1116 {
1117   ui.cur_brush->color_no = color;
1118   if (ui.toolno == TOOL_HIGHLIGHTER)
1119     ui.cur_brush->color_rgba = predef_colors_rgba[color] & HILITER_ALPHA_MASK;
1120   else
1121     ui.cur_brush->color_rgba = predef_colors_rgba[color];
1122 }
1123
1124 void process_color_activate(GtkMenuItem *menuitem, int color)
1125 {
1126   if (GTK_OBJECT_TYPE(menuitem) == GTK_TYPE_RADIO_MENU_ITEM) {
1127     if (!gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM (menuitem)))
1128       return;
1129   } else {
1130     if (!gtk_toggle_tool_button_get_active(GTK_TOGGLE_TOOL_BUTTON (menuitem)))
1131       return;
1132   }
1133
1134   if (ui.toolno != TOOL_PEN && ui.toolno != TOOL_HIGHLIGHTER
1135         && ui.toolno != TOOL_TEXT && ui.selection == NULL) {
1136     ui.toolno = TOOL_PEN;
1137     ui.cur_brush = ui.brushes+TOOL_PEN;
1138     update_tool_buttons();
1139     update_tool_menu();
1140   }
1141   
1142   if (ui.toolno == TOOL_PEN || ui.toolno == TOOL_HIGHLIGHTER)
1143     set_cur_color(color);
1144
1145   // later add selection tools
1146
1147   update_color_buttons();
1148   update_color_menu();
1149   update_cursor();
1150 }
1151
1152 void process_thickness_activate(GtkMenuItem *menuitem, int tool, int val)
1153 {
1154   if (GTK_OBJECT_TYPE(menuitem) == GTK_TYPE_RADIO_MENU_ITEM) {
1155     if (!gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM (menuitem)))
1156       return;
1157   } else {
1158     if (!gtk_toggle_tool_button_get_active(GTK_TOGGLE_TOOL_BUTTON (menuitem)))
1159       return;
1160   }
1161
1162   if (tool >= NUM_STROKE_TOOLS) {
1163     update_thickness_buttons(); // undo illegal button selection
1164     return;
1165   }
1166   
1167   if (ui.brushes[tool].thickness_no == val) return; // avoid loops
1168   ui.brushes[tool].thickness_no = val;
1169   ui.brushes[tool].thickness = predef_thickness[tool][val];
1170   
1171   update_thickness_buttons();
1172   if (tool == TOOL_PEN) update_pen_props_menu();
1173   if (tool == TOOL_ERASER) update_eraser_props_menu();
1174   if (tool == TOOL_HIGHLIGHTER) update_highlighter_props_menu();
1175   update_cursor();
1176 }
1177
1178 void process_papercolor_activate(GtkMenuItem *menuitem, int color)
1179 {
1180   if (!gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM (menuitem)))
1181     return;
1182
1183   if (ui.cur_page->bg->type != BG_SOLID) {
1184     gtk_check_menu_item_set_active(
1185       GTK_CHECK_MENU_ITEM(GET_COMPONENT("papercolorNA")), TRUE);
1186     return;
1187   }
1188
1189   if (ui.cur_page->bg->color_no == color) return;
1190   
1191   reset_selection();
1192   prepare_new_undo();
1193   undo->type = ITEM_NEW_BG_ONE;
1194   undo->page = ui.cur_page;
1195   undo->bg = (struct Background *)g_memdup(ui.cur_page->bg, sizeof(struct Background));
1196   undo->bg->canvas_item = NULL;
1197
1198   ui.cur_page->bg->color_no = color;
1199   ui.cur_page->bg->color_rgba = predef_bgcolors_rgba[color];
1200   update_canvas_bg(ui.cur_page);
1201 }
1202
1203 void process_paperstyle_activate(GtkMenuItem *menuitem, int style)
1204 {
1205   if (!gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM (menuitem)))
1206     return;
1207
1208   if (ui.cur_page->bg->type == BG_SOLID && ui.cur_page->bg->ruling == style)
1209     return;
1210
1211   reset_selection();
1212   prepare_new_undo();
1213   undo->type = ITEM_NEW_BG_ONE;
1214   undo->page = ui.cur_page;
1215   undo->bg = (struct Background *)g_memdup(ui.cur_page->bg, sizeof(struct Background));
1216   undo->bg->canvas_item = NULL;
1217
1218   if (ui.cur_page->bg->type != BG_SOLID) {
1219     ui.cur_page->bg->type = BG_SOLID;
1220     ui.cur_page->bg->color_no = COLOR_WHITE;
1221     ui.cur_page->bg->color_rgba = predef_bgcolors_rgba[COLOR_WHITE];
1222     ui.cur_page->bg->filename = NULL;
1223     ui.cur_page->bg->pixbuf = NULL;
1224     update_page_stuff();
1225   }
1226
1227   ui.cur_page->bg->ruling = style;
1228   update_canvas_bg(ui.cur_page);
1229 }
1230
1231 gboolean ok_to_close(void)
1232 {
1233   GtkWidget *dialog;
1234   GtkResponseType response;
1235   GList *pagelist;
1236
1237   if (ui.saved) return TRUE;
1238   dialog = gtk_message_dialog_new(GTK_WINDOW (winMain), GTK_DIALOG_DESTROY_WITH_PARENT,
1239     GTK_MESSAGE_WARNING, GTK_BUTTONS_YES_NO, "Save changes to '%s'?",
1240     (ui.filename!=NULL) ? ui.filename:"Untitled");
1241   gtk_dialog_add_button(GTK_DIALOG (dialog), GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL);
1242   response = gtk_dialog_run(GTK_DIALOG (dialog));
1243   gtk_widget_destroy(dialog);
1244   if (response == GTK_RESPONSE_CANCEL || response == GTK_RESPONSE_DELETE_EVENT) 
1245     return FALSE; // aborted
1246   if (response == GTK_RESPONSE_YES) {
1247     on_fileSave_activate(NULL, NULL);
1248     if (!ui.saved) return FALSE; // if save failed, then we abort
1249   }
1250   return TRUE;
1251 }
1252
1253 // test if we're still busy loading a PDF background file
1254 gboolean page_ops_forbidden(void)
1255 {
1256   return (bgpdf.status != STATUS_NOT_INIT && bgpdf.create_pages);
1257 }
1258
1259 // selection / clipboard stuff
1260
1261 void reset_selection(void)
1262 {
1263   if (ui.selection == NULL) return;
1264   if (ui.selection->canvas_item != NULL) 
1265     gtk_object_destroy(GTK_OBJECT(ui.selection->canvas_item));
1266   g_list_free(ui.selection->items);
1267   g_free(ui.selection);
1268   ui.selection = NULL;
1269   update_copy_paste_enabled();
1270 }
1271
1272 void move_journal_items_by(GList *itemlist, double dx, double dy)
1273 {
1274   struct Item *item;
1275   int i;
1276   double *pt;
1277   
1278   while (itemlist!=NULL) {
1279     item = (struct Item *)itemlist->data;
1280     if (item->type == ITEM_STROKE) {
1281       for (pt=item->path->coords, i=0; i<item->path->num_points; i++, pt+=2)
1282         { pt[0] += dx; pt[1] += dy; }
1283       item->bbox.left += dx;
1284       item->bbox.right += dx;
1285       item->bbox.top += dy;
1286       item->bbox.bottom += dy;
1287     }
1288     itemlist = itemlist->next;
1289   }
1290 }