]> git.sur5r.net Git - glabels/blobdiff - glabels2/src/view.c
2007-09-27 Jim Evins <evins@snaught.com>
[glabels] / glabels2 / src / view.c
index c1006858415d1bd44737c3698cd9bafb35a67602..2636eb9d088b145bee344f3be2d2145a694af83c 100644 (file)
@@ -1,9 +1,11 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- */
+
 /*
  *  (GLABELS) Label and Business Card Creation program for GNOME
  *
  *  view.c:  GLabels View module
  *
- *  Copyright (C) 2001-2002  Jim Evins <evins@snaught.com>.
+ *  Copyright (C) 2001-2007  Jim Evins <evins@snaught.com>.
  *
  *  This program is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License as published by
 
 #include <config.h>
 
-#include <gtk/gtk.h>
-#include <gtk/gtkinvisible.h>
+#include "view.h"
 
+#include <glib/gi18n.h>
+#include <gtk/gtkscrolledwindow.h>
+#include <gtk/gtklayout.h>
+#include <gtk/gtkselection.h>
+#include <gtk/gtkinvisible.h>
+#include <gdk/gdkkeysyms.h>
 #include <string.h>
 #include <math.h>
 
-#include "view.h"
+#include "label.h"
+#include "cairo-label-path.h"
+#include "cairo-markup-path.h"
 #include "view-object.h"
 #include "view-box.h"
 #include "view-ellipse.h"
@@ -38,8 +47,7 @@
 #include "view-barcode.h"
 #include "xml-label.h"
 #include "color.h"
-#include "stock.h"
-#include "merge-properties-dialog.h"
+#include "prefs.h"
 #include "marshal.h"
 
 #include "debug.h"
 /*==========================================================================*/
 
 #define BG_COLOR        GL_COLOR (192, 192, 192)
-#define OUTLINE_COLOR   GL_COLOR (173, 216, 230)
-#define PAPER_COLOR     GL_COLOR (255, 255, 255)
-#define GRID_COLOR      BG_COLOR
-#define MARKUP_COLOR    GL_COLOR (240, 100, 100)
 
-#define SEL_LINE_COLOR  GL_COLOR_A (0, 0, 255, 128)
-#define SEL_FILL_COLOR  GL_COLOR_A (192, 192, 255, 128)
+#define PAPER_RGB_ARGS          1.0,   1.0,   1.0
+#define GRID_RGB_ARGS           0.753, 0.753, 0.753
+#define MARKUP_RGB_ARGS         0.94,  0.39,  0.39
+#define OUTLINE_RGB_ARGS        0.68,  0.85,  0.90
+#define SELECT_LINE_RGBA_ARGS   0.0,   0.0,   1.0,   0.5
+#define SELECT_FILL_RGBA_ARGS   0.75,  0.75,  1.0,   0.5
+
+#define GRID_LINE_WIDTH_PIXELS    1.0
+#define MARKUP_LINE_WIDTH_PIXELS  1.0
+#define OUTLINE_WIDTH_PIXELS      3.0
+#define SELECT_LINE_WIDTH_PIXELS  3.0
+
+#define ZOOMTOFIT_PAD   16
+
+#define POINTS_PER_MM    2.83464566929
 
 /*==========================================================================*/
 /* Private types.                                                           */
@@ -63,6 +80,7 @@
 
 enum {
        SELECTION_CHANGED,
+       CONTEXT_MENU_ACTIVATE,
        ZOOM_CHANGED,
        POINTER_MOVED,
        POINTER_EXIT,
@@ -75,154 +93,144 @@ enum {
 /* Private globals                                                          */
 /*==========================================================================*/
 
-static GtkContainerClass *parent_class;
-
 static guint signals[LAST_SIGNAL] = {0};
 
 /* "CLIPBOARD" selection */
 static GdkAtom clipboard_atom = GDK_NONE;
 
-static gdouble scales[] = {
-       8.0, 6.0, 4.0, 3.0,
-       2.0,
-       1.5, 1.0, 0.5, 0.25,
+static gdouble zooms[] = {
+       8.00,
+       6.00,
+       4.00,
+       3.00,
+       2.00,
+       1.50,
+       1.00,
+       0.75,
+       0.67,
+       0.50,
+       0.33,
+       0.25,
+       0.20,
+       0.15,
+       0.10,
 };
-#define N_SCALES G_N_ELEMENTS(scales)
-#define HOME_SCALE 2.0
+#define N_ZOOMS G_N_ELEMENTS(zooms)
+
 
 /*==========================================================================*/
 /* Local function prototypes                                                */
 /*==========================================================================*/
 
-static void       gl_view_class_init              (glViewClass *class);
-static void       gl_view_init                    (glView *view);
-static void       gl_view_finalize                (GObject *object);
+static void       gl_view_finalize                (GObject        *object);
+
+static void       gl_view_construct               (glView         *view,
+                                                   glLabel        *label);
+
+static gdouble    get_home_scale                  (glView         *view);
 
-static void       gl_view_construct               (glView *view);
-static GtkWidget *gl_view_construct_canvas        (glView *view);
-static void       gl_view_construct_selection     (glView *view);
+static gboolean   expose_cb                       (glView         *view,
+                                                   GdkEventExpose *event);
 
-static gdouble    get_apropriate_scale            (gdouble w, gdouble h);
+static void       realize_cb                      (glView         *view);
 
-static void       draw_layers                     (glView *view);
+static void       size_allocate_cb                (glView         *view,
+                                                   GtkAllocation  *allocation);
 
-static void       draw_label_layer                (glView *view);
+static void       screen_changed_cb               (glView         *view);
 
-static void       draw_highlight_layer            (glView *view);
+static void       label_changed_cb                (glView         *view);
 
-static void       draw_bg_fg_layers               (glView *view);
-static void       draw_bg_fg_rect                 (glView *view);
-static void       draw_bg_fg_rounded_rect         (glView *view);
-static void       draw_bg_fg_round                (glView *view);
-static void       draw_bg_fg_cd                   (glView *view);
+static void       label_resized_cb                (glView         *view);
 
-static void       draw_grid_layer                 (glView *view);
+static void       label_object_added_cb           (glView         *view,
+                                                   glLabelObject  *object);
 
-static void       draw_markup_layer               (glView *view);
+static void       draw_layers                     (glView         *view,
+                                                   cairo_t        *cr);
 
-static void       draw_markup_margin              (glView *view,
-                                                  glTemplateMarkupMargin *margin);
-static void       draw_markup_margin_rect         (glView *view,
-                                                  glTemplateMarkupMargin *margin);
-static void       draw_markup_margin_rounded_rect (glView *view,
-                                                  glTemplateMarkupMargin *margin);
-static void       draw_markup_margin_round        (glView *view,
-                                                  glTemplateMarkupMargin *margin);
-static void       draw_markup_margin_cd           (glView *view,
-                                                  glTemplateMarkupMargin *margin);
+static void       draw_bg_layer                   (glView         *view,
+                                                   cairo_t        *cr);
+static void       draw_grid_layer                 (glView         *view,
+                                                   cairo_t        *cr);
+static void       draw_markup_layer               (glView         *view,
+                                                   cairo_t        *cr);
+static void       draw_objects_layer              (glView         *view,
+                                                   cairo_t        *cr);
+static void       draw_fg_layer                   (glView         *view,
+                                                   cairo_t        *cr);
+static void       draw_highlight_layer            (glView         *view,
+                                                   cairo_t        *cr);
+static void       draw_select_region_layer        (glView         *view,
+                                                   cairo_t        *cr);
 
-static void       draw_markup_line                (glView *view,
-                                                  glTemplateMarkupLine   *line);
+static void       select_object_real              (glView         *view,
+                                                  glViewObject   *view_object);
+static void       unselect_object_real            (glView         *view,
+                                                  glViewObject   *view_object);
 
+static glViewObject *view_view_object_at          (glView         *view,
+                                                   cairo_t        *cr,
+                                                  gdouble         x,
+                                                   gdouble         y);
 
-static void       select_object_real              (glView *view,
-                                                  glViewObject *view_object);
-static void       unselect_object_real            (glView *view,
-                                                  glViewObject *view_object);
+static void       set_zoom_real                   (glView         *view,
+                                                  gdouble         zoom,
+                                                  gboolean        scale_to_fit_flag);
 
-static gboolean   object_at                       (glView *view,
-                                                  gdouble x, gdouble y);
+static void       selection_clear_cb              (GtkWidget         *widget,
+                                                   GdkEventSelection *event,
+                                                   glView            *view);
 
-static gboolean   is_item_member_of_group         (glView          *view,
-                                                  GnomeCanvasItem *item,
-                                                  GnomeCanvasItem *group);
+static void       selection_get_cb                (GtkWidget         *widget,
+                                                   GtkSelectionData  *selection_data,
+                                                   guint              info,
+                                                   guint              time,
+                                                   glView            *view);
 
-static gboolean   is_object_selected              (glView *view,
-                                                  glViewObject *view_object);
+static void       selection_received_cb           (GtkWidget         *widget,
+                                                   GtkSelectionData  *selection_data,
+                                                   guint              time,
+                                                   glView            *view);
 
-static void       move_selection                  (glView *view,
-                                                  gdouble dx, gdouble dy);
+static gboolean   focus_in_event_cb               (glView            *view,
+                                                   GdkEventFocus     *event);
 
-static int        canvas_event                    (GnomeCanvas *canvas,
-                                                  GdkEvent    *event,
-                                                  glView      *view);
-static int        canvas_event_arrow_mode         (GnomeCanvas *canvas,
-                                                  GdkEvent    *event,
-                                                  glView      *view);
+static gboolean   focus_out_event_cb              (glView            *view,
+                                                   GdkEventFocus     *event);
 
-static int        item_event_arrow_mode          (GnomeCanvasItem *item,
-                                                 GdkEvent        *event,
-                                                 glViewObject    *view_object);
+static gboolean   enter_notify_event_cb           (glView            *view,
+                                                   GdkEventCrossing  *event);
 
-static void       construct_selection_menu       (glView *view);
+static gboolean   leave_notify_event_cb           (glView            *view,
+                                                   GdkEventCrossing  *event);
 
-static void       construct_empty_selection_menu (glView *view);
+static gboolean   motion_notify_event_cb          (glView            *view,
+                                                   GdkEventMotion    *event);
 
-static void       popup_menu                     (glView       *view,
-                                                 GdkEvent     *event);
+static gboolean   button_press_event_cb           (glView            *view,
+                                                   GdkEventButton    *event);
 
-static void       selection_clear_cb             (GtkWidget         *widget,
-                                                 GdkEventSelection *event,
-                                                 gpointer          data);
+static gboolean   button_release_event_cb         (glView            *view,
+                                                   GdkEventButton    *event);
 
-static void       selection_get_cb               (GtkWidget         *widget,
-                                                 GtkSelectionData  *selection_data,
-                                                 guint             info,
-                                                 guint             time,
-                                                 gpointer          data);
+static gboolean   key_press_event_cb              (glView            *view,
+                                                   GdkEventKey       *event);
 
-static void       selection_received_cb          (GtkWidget         *widget,
-                                                 GtkSelectionData  *selection_data,
-                                                 guint             time,
-                                                 gpointer          data);
 \f
 /****************************************************************************/
 /* Boilerplate Object stuff.                                                */
 /****************************************************************************/
-guint
-gl_view_get_type (void)
-{
-       static guint view_type = 0;
-
-       if (!view_type) {
-               GTypeInfo view_info = {
-                       sizeof (glViewClass),
-                       NULL,
-                       NULL,
-                       (GClassInitFunc) gl_view_class_init,
-                       NULL,
-                       NULL,
-                       sizeof (glView),
-                       0,
-                       (GInstanceInitFunc) gl_view_init,
-               };
-
-               view_type =
-                   g_type_register_static (gtk_vbox_get_type (),
-                                           "glView", &view_info, 0);
-       }
-
-       return view_type;
-}
+G_DEFINE_TYPE (glView, gl_view, GTK_TYPE_VBOX);
 
 static void
 gl_view_class_init (glViewClass *class)
 {
-       GObjectClass *object_class = (GObjectClass *) class;
+       GObjectClass *object_class = G_OBJECT_CLASS (class);
 
        gl_debug (DEBUG_VIEW, "START");
 
-       parent_class = g_type_class_peek_parent (class);
+       gl_view_parent_class = g_type_class_peek_parent (class);
 
        object_class->finalize = gl_view_finalize;
 
@@ -236,6 +244,16 @@ gl_view_class_init (glViewClass *class)
                              G_TYPE_NONE,
                              0);
 
+       signals[CONTEXT_MENU_ACTIVATE] =
+               g_signal_new ("context_menu_activate",
+                             G_OBJECT_CLASS_TYPE (object_class),
+                             G_SIGNAL_RUN_LAST,
+                             G_STRUCT_OFFSET (glViewClass, context_menu_activate),
+                             NULL, NULL,
+                             gl_marshal_VOID__INT_UINT,
+                             G_TYPE_NONE,
+                             2, G_TYPE_INT, G_TYPE_UINT);
+
        signals[ZOOM_CHANGED] =
                g_signal_new ("zoom_changed",
                              G_OBJECT_CLASS_TYPE (object_class),
@@ -282,11 +300,106 @@ gl_view_class_init (glViewClass *class)
 static void
 gl_view_init (glView *view)
 {
+       GtkWidget *wscroll;
+       GdkColor  *bg_color;
+
        gl_debug (DEBUG_VIEW, "START");
 
-       view->label = NULL;
+       view->label                = NULL;
+       view->grid_visible         = TRUE;
+       view->grid_spacing         = 9;
+       view->markup_visible       = TRUE;
+       view->default_font_family  = NULL;
+       view->mode                 = GL_VIEW_MODE_ARROW;
+       view->object_list          = NULL;
+       view->selected_object_list = NULL;
+       view->zoom                 = 1.0;
+       view->home_scale           = get_home_scale (view);
+
+        /*
+         * Canvas
+         */
+        view->canvas = gtk_layout_new (NULL, NULL);
+        wscroll = gtk_scrolled_window_new (NULL, NULL);
+       gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (wscroll),
+                                       GTK_POLICY_AUTOMATIC,
+                                       GTK_POLICY_AUTOMATIC);
+       gtk_box_pack_start (GTK_BOX (view), wscroll, TRUE, TRUE, 0);
+       gtk_container_add (GTK_CONTAINER (wscroll), view->canvas);
+
+       bg_color = gl_color_to_gdk_color (BG_COLOR);
+       gtk_widget_modify_bg (GTK_WIDGET (view->canvas), GTK_STATE_NORMAL, bg_color);
+       g_free (bg_color);
+
+        GTK_WIDGET_SET_FLAGS (GTK_WIDGET (view->canvas), GTK_CAN_FOCUS);
+
+        gtk_widget_add_events (GTK_WIDGET (view->canvas),
+                               (GDK_FOCUS_CHANGE_MASK   |
+                                GDK_ENTER_NOTIFY_MASK   |
+                                GDK_LEAVE_NOTIFY_MASK   |
+                                GDK_POINTER_MOTION_MASK |
+                                GDK_BUTTON_PRESS_MASK   |
+                                GDK_BUTTON_RELEASE_MASK |
+                                GDK_KEY_PRESS_MASK));
+
+       g_signal_connect_swapped (G_OBJECT (view->canvas), "expose-event",
+                                 G_CALLBACK (expose_cb), view);
+       g_signal_connect_swapped (G_OBJECT (view->canvas), "realize",
+                                 G_CALLBACK (realize_cb), view);
+       g_signal_connect_swapped (G_OBJECT (view->canvas), "size-allocate",
+                                 G_CALLBACK (size_allocate_cb), view);
+       g_signal_connect_swapped (G_OBJECT (view->canvas), "screen-changed",
+                                 G_CALLBACK (screen_changed_cb), view);
+       g_signal_connect_swapped (G_OBJECT (view->canvas), "focus-in-event",
+                                 G_CALLBACK (focus_in_event_cb), view);
+       g_signal_connect_swapped (G_OBJECT (view->canvas), "focus-out-event",
+                                 G_CALLBACK (focus_out_event_cb), view);
+       g_signal_connect_swapped (G_OBJECT (view->canvas), "enter-notify-event",
+                                 G_CALLBACK (enter_notify_event_cb), view);
+       g_signal_connect_swapped (G_OBJECT (view->canvas), "leave-notify-event",
+                                 G_CALLBACK (leave_notify_event_cb), view);
+       g_signal_connect_swapped (G_OBJECT (view->canvas), "motion-notify-event",
+                                 G_CALLBACK (motion_notify_event_cb), view);
+       g_signal_connect_swapped (G_OBJECT (view->canvas), "button-press-event",
+                                 G_CALLBACK (button_press_event_cb), view);
+       g_signal_connect_swapped (G_OBJECT (view->canvas), "button-release-event",
+                                 G_CALLBACK (button_release_event_cb), view);
+       g_signal_connect_swapped (G_OBJECT (view->canvas), "key-press-event",
+                                 G_CALLBACK (key_press_event_cb), view);
+
+        /*
+         * Clipboard
+         */
+       view->have_selection       = FALSE;
+       view->selection_data       = NULL;
+       view->invisible            = gtk_invisible_new ();
+       if (!clipboard_atom) {
+               clipboard_atom = gdk_atom_intern ("GLABELS_CLIPBOARD", FALSE);
+       }
+       gtk_selection_add_target (view->invisible,
+                                 clipboard_atom, GDK_SELECTION_TYPE_STRING, 1);
+       g_signal_connect (G_OBJECT (view->invisible),
+                         "selection_clear_event",
+                         G_CALLBACK (selection_clear_cb), view);
+       g_signal_connect (G_OBJECT (view->invisible), "selection_get",
+                         G_CALLBACK (selection_get_cb), view);
+       g_signal_connect (G_OBJECT (view->invisible),
+                         "selection_received",
+                         G_CALLBACK (selection_received_cb), view);
 
-       view->grid_spacing = 9;
+        /*
+         * Defaults from preferences
+         */
+       gl_view_set_default_font_family       (view, gl_prefs->default_font_family);
+       gl_view_set_default_font_size         (view, gl_prefs->default_font_size);
+       gl_view_set_default_font_weight       (view, gl_prefs->default_font_weight);
+       gl_view_set_default_font_italic_flag  (view, gl_prefs->default_font_italic_flag);
+       gl_view_set_default_text_color        (view, gl_prefs->default_text_color);
+       gl_view_set_default_text_alignment    (view, gl_prefs->default_text_alignment);
+       gl_view_set_default_text_line_spacing (view, gl_prefs->default_text_line_spacing);
+       gl_view_set_default_line_width        (view, gl_prefs->default_line_width);
+       gl_view_set_default_line_color        (view, gl_prefs->default_line_color);
+       gl_view_set_default_fill_color        (view, gl_prefs->default_fill_color);
 
        gl_debug (DEBUG_VIEW, "END");
 }
@@ -294,16 +407,18 @@ gl_view_init (glView *view)
 static void
 gl_view_finalize (GObject *object)
 {
-       glView *view;
+       glView *view = GL_VIEW (object);
 
        gl_debug (DEBUG_VIEW, "START");
 
        g_return_if_fail (object != NULL);
        g_return_if_fail (GL_IS_VIEW (object));
 
-       view = GL_VIEW (object);
+       if (view->default_font_family) {
+               g_free (view->default_font_family);
+       }
 
-       G_OBJECT_CLASS (parent_class)->finalize (object);
+       G_OBJECT_CLASS (gl_view_parent_class)->finalize (object);
 
        gl_debug (DEBUG_VIEW, "END");
 }
@@ -314,13 +429,15 @@ gl_view_finalize (GObject *object)
 GtkWidget *
 gl_view_new (glLabel *label)
 {
-       glView *view = g_object_new (gl_view_get_type (), NULL);
+       glView *view;
 
        gl_debug (DEBUG_VIEW, "START");
 
-       view->label = label;
+       g_return_val_if_fail (label && GL_IS_LABEL (label), NULL);
+
+       view = g_object_new (GL_TYPE_VIEW, NULL);
 
-       gl_view_construct (view);
+       gl_view_construct (view, label);
 
        gl_debug (DEBUG_VIEW, "END");
 
@@ -331,925 +448,640 @@ gl_view_new (glLabel *label)
 /* PRIVATE.  Construct composite widget.                                     */
 /*---------------------------------------------------------------------------*/
 static void
-gl_view_construct (glView *view)
+gl_view_construct (glView  *view,
+                   glLabel *label)
 {
-       GtkWidget *wvbox, *wscroll;
+        GList            *p_obj;
+        glLabelObject    *object;
 
        gl_debug (DEBUG_VIEW, "START");
 
        g_return_if_fail (GL_IS_VIEW (view));
 
-       wvbox = GTK_WIDGET (view);
-
-       view->state = GL_VIEW_STATE_ARROW;
-       view->object_list = NULL;
-
-       gl_view_construct_canvas (view);
-       wscroll = gtk_scrolled_window_new (NULL, NULL);
-       gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (wscroll),
-                                       GTK_POLICY_AUTOMATIC,
-                                       GTK_POLICY_AUTOMATIC);
-       gtk_box_pack_start (GTK_BOX (wvbox), wscroll, TRUE, TRUE, 0);
-       gtk_container_add (GTK_CONTAINER (wscroll), view->canvas);
-
-       gl_view_construct_selection (view);
+       view->label = label;
 
-       construct_selection_menu (view);
-       construct_empty_selection_menu (view);
+        for (p_obj = label->objects; p_obj != NULL; p_obj = p_obj->next)
+        {
+                object = GL_LABEL_OBJECT (p_obj->data);
+
+                if (GL_IS_LABEL_BOX (object)) {
+                        gl_view_box_new (GL_LABEL_BOX(object), view);
+                } else if (GL_IS_LABEL_ELLIPSE (object)) {
+                        gl_view_ellipse_new (GL_LABEL_ELLIPSE(object), view);
+                } else if (GL_IS_LABEL_LINE (object)) {
+                        gl_view_line_new (GL_LABEL_LINE(object), view);
+                } else if (GL_IS_LABEL_IMAGE (object)) {
+                        gl_view_image_new (GL_LABEL_IMAGE(object), view);
+                } else if (GL_IS_LABEL_TEXT (object)) {
+                        gl_view_text_new (GL_LABEL_TEXT(object), view);
+                } else if (GL_IS_LABEL_BARCODE (object)) {
+                        gl_view_barcode_new (GL_LABEL_BARCODE(object), view);
+                } else {
+                        /* Should not happen! */
+                        g_message ("Invalid label object type.");
+                }
+        }
+
+       g_signal_connect_swapped (G_OBJECT (view->label), "changed",
+                                  G_CALLBACK (label_changed_cb), view);
+       g_signal_connect_swapped (G_OBJECT (view->label), "size_changed",
+                                  G_CALLBACK (label_resized_cb), view);
+       g_signal_connect_swapped (G_OBJECT (view->label), "object_added",
+                                  G_CALLBACK (label_object_added_cb), view);
 
        gl_debug (DEBUG_VIEW, "END");
 }
 
 /*---------------------------------------------------------------------------*/
-/* PRIVATE.  Create canvas w/ a background in the shape of the label/card.   */
+/* PRIAVTE.  Calculate 1:1 scale for screen.                                 */
 /*---------------------------------------------------------------------------*/
-static GtkWidget *
-gl_view_construct_canvas (glView *view)
+static gdouble
+get_home_scale (glView *view)
 {
-       gdouble   scale;
-       glLabel  *label = view->label;
-       gdouble   label_width, label_height;
-       GdkColor *bg_color;
+       GdkScreen *screen;
+       gdouble    screen_width_pixels;
+       gdouble    screen_width_mm;
+       gdouble    screen_height_pixels;
+       gdouble    screen_height_mm;
+       gdouble    x_pixels_per_mm;
+       gdouble    y_pixels_per_mm;
+       gdouble    scale;
 
-       gl_debug (DEBUG_VIEW, "START");
+       if (view->canvas == NULL) return 1.0;
 
-       g_return_val_if_fail (GL_IS_VIEW (view), NULL);
-       g_return_val_if_fail (label != NULL, NULL);
+       if (!gtk_widget_has_screen (GTK_WIDGET (view->canvas))) return 1.0;
 
-       gtk_widget_push_colormap (gdk_rgb_get_colormap ());
-       view->canvas = gnome_canvas_new_aa ();
-       gtk_widget_pop_colormap ();
+       screen = gtk_widget_get_screen (GTK_WIDGET (view->canvas));
 
-       bg_color = gl_color_to_gdk_color (BG_COLOR);
-       gtk_widget_modify_bg (GTK_WIDGET(view->canvas), GTK_STATE_NORMAL, bg_color);
-       g_free (bg_color);
+       gl_debug (DEBUG_VIEW, "Screen = %p", screen);
 
-       gl_label_get_size (label, &label_width, &label_height);
-       gl_debug (DEBUG_VIEW, "Label size: w=%lf, h=%lf",
-                 label_width, label_height);
+       screen_width_pixels  = gdk_screen_get_width (screen);
+       screen_width_mm      = gdk_screen_get_width_mm (screen);
+       screen_height_pixels = gdk_screen_get_height (screen);
+       screen_height_mm     = gdk_screen_get_height_mm (screen);
 
-       scale = get_apropriate_scale (label_width, label_height);
-       gl_debug (DEBUG_VIEW, "scale =%lf", scale);
+       x_pixels_per_mm      = screen_width_pixels / screen_width_mm;
+       y_pixels_per_mm      = screen_height_pixels / screen_height_mm;
 
-       gl_debug (DEBUG_VIEW, "Canvas size: w=%lf, h=%lf",
-                             scale * label_width + 40,
-                             scale * label_height + 40);
-       gtk_widget_set_size_request (GTK_WIDGET(view->canvas),
-                                    scale * label_width + 40,
-                                    scale * label_height + 40);
-       gnome_canvas_set_pixels_per_unit (GNOME_CANVAS (view->canvas),
-                                         scale);
-       view->scale = scale;
+       gl_debug (DEBUG_VIEW, "Horizontal dot pitch: %g pixels/mm (%g dpi)",
+                 x_pixels_per_mm, x_pixels_per_mm * 25.4);
+       gl_debug (DEBUG_VIEW, "Vertical dot pitch: %g pixels/mm (%g dpi)",
+                 y_pixels_per_mm, y_pixels_per_mm * 25.4);
 
-       gnome_canvas_set_scroll_region (GNOME_CANVAS (view->canvas),
-                                       0.0, 0.0, label_width, label_height);
+       scale = (x_pixels_per_mm + y_pixels_per_mm) / 2.0;
 
-       draw_layers (view);
+       gl_debug (DEBUG_VIEW, "Average dot pitch: %g pixels/mm (%g dpi)",
+                 scale, scale * 25.4);
 
-       g_signal_connect (G_OBJECT (view->canvas), "event",
-                         G_CALLBACK (canvas_event), view);
+       scale /= POINTS_PER_MM;
 
-       gl_debug (DEBUG_VIEW, "END");
+       gl_debug (DEBUG_VIEW, "Scale = %g pixels/point", scale);
+
+       /* Make sure scale is somewhat sane. */
+       if ( (scale < 0.25) || (scale > 4.0) ) return 1.0;
 
-       return view->canvas;
+       return scale;
 }
 
 /*---------------------------------------------------------------------------*/
-/* PRIVATE.  Create clipboard selection targets.                             */
+/* Schedule canvas update.                                                   */
 /*---------------------------------------------------------------------------*/
-static void
-gl_view_construct_selection (glView *view)
+void
+gl_view_update (glView  *view)
 {
+       GtkWidget *widget;
+       GdkRegion *region;
+       
        gl_debug (DEBUG_VIEW, "START");
 
-       g_return_if_fail (GL_IS_VIEW (view));
+       widget = GTK_WIDGET (view->canvas);
 
-       view->have_selection = FALSE;
-       view->selection_data = NULL;
-       view->invisible = gtk_invisible_new ();
+       if (!widget->window) return;
 
-       view->selected_object_list = NULL;
+        if ( !view->update_scheduled_flag )
+        {
+                view->update_scheduled_flag = TRUE;
 
-       if (!clipboard_atom) {
-               clipboard_atom = gdk_atom_intern ("GLABELS_CLIPBOARD", FALSE);
-       }
+                region = gdk_drawable_get_clip_region (widget->window);
+                /* redraw the cairo canvas completely by exposing it */
+                gdk_window_invalidate_region (widget->window, region, TRUE);
+                gdk_region_destroy (region);
+        }
 
-       gtk_selection_add_target (view->invisible,
-                                 clipboard_atom, GDK_SELECTION_TYPE_STRING, 1);
+       gl_debug (DEBUG_VIEW, "END");
+}
 
-       g_signal_connect (G_OBJECT (view->invisible),
-                         "selection_clear_event",
-                         G_CALLBACK (selection_clear_cb), view);
+/*---------------------------------------------------------------------------*/
+/* Schedule canvas region update.                                            */
+/*---------------------------------------------------------------------------*/
+void
+gl_view_update_region (glView        *view,
+                       cairo_t       *cr,
+                       glLabelRegion *region)
+{
+       GtkWidget    *widget;
+       GdkRectangle  rect;
+        gdouble       x, y, w, h;
 
-       g_signal_connect (G_OBJECT (view->invisible), "selection_get",
-                         G_CALLBACK (selection_get_cb), view);
+       gl_debug (DEBUG_VIEW, "START");
 
-       g_signal_connect (G_OBJECT (view->invisible),
-                         "selection_received",
-                         G_CALLBACK (selection_received_cb), view);
+       widget = GTK_WIDGET (view->canvas);
+
+       if (!widget->window) return;
+
+        x = MIN (region->x1, region->x2);
+        y = MIN (region->y1, region->y2);
+        w = fabs (region->x2 - region->x1);
+        h = fabs (region->y2 - region->y1);
+
+        cairo_user_to_device (cr, &x, &y);
+        cairo_user_to_device_distance (cr, &w, &h);
+
+        rect.x      = x - 3;
+        rect.y      = y - 3;
+        rect.width  = w + 6;
+        rect.height = h + 6;
+
+        gdk_window_invalidate_rect (widget->window, &rect, TRUE);
 
        gl_debug (DEBUG_VIEW, "END");
 }
 
 /*---------------------------------------------------------------------------*/
-/* PRIVATE.  Determine an apropriate scale for given label & screen size     */
+/* PRIVATE.  Expose handler.                                                 */
 /*---------------------------------------------------------------------------*/
-static gdouble
-get_apropriate_scale (gdouble w, gdouble h)
+static gboolean
+expose_cb (glView         *view,
+           GdkEventExpose *event)
 {
-       gdouble w_screen, h_screen;
-       gint i;
-       gdouble k;
+       cairo_t *cr;
 
-       gl_debug (DEBUG_VIEW, "");
+       gl_debug (DEBUG_VIEW, "START");
 
-       w_screen = (gdouble) gdk_screen_width ();
-       h_screen = (gdouble) gdk_screen_height ();
+        view->update_scheduled_flag = FALSE;
 
-       for (i = 0; i < N_SCALES; i++) {
-               k = scales[i];
-               if (k <= HOME_SCALE) {
-                       if ((k * w < (w_screen - 256))
-                           && (k * h < (h_screen - 256)))
-                               return k;
-               }
-       }
+       /* get a cairo_t */
+       cr = gdk_cairo_create (GTK_LAYOUT (view->canvas)->bin_window);
+
+       cairo_rectangle (cr,
+                       event->area.x, event->area.y,
+                       event->area.width, event->area.height);
+       cairo_clip (cr);
+       
+       draw_layers (view, cr);
 
-       return 0.25;
+       cairo_destroy (cr);
+
+       gl_debug (DEBUG_VIEW, "END");
+
+       return FALSE;
 }
 
 /*---------------------------------------------------------------------------*/
-/* PRIVATE.  Create, draw and order layers.                                  */
+/* PRIVATE.  Realize handler.                                                */
 /*---------------------------------------------------------------------------*/
 static void
-draw_layers (glView *view)
+realize_cb (glView  *view)
 {
-       draw_bg_fg_layers (view);
-       draw_grid_layer (view);
-       draw_markup_layer (view);
-       draw_highlight_layer (view); /* Must be done before label layer */
-       draw_label_layer (view);
+       g_return_if_fail (view && GL_IS_VIEW (view));
+
+       gl_debug (DEBUG_VIEW, "START");
 
-       gnome_canvas_item_raise_to_top (GNOME_CANVAS_ITEM(view->fg_group));
-       gnome_canvas_item_raise_to_top (GNOME_CANVAS_ITEM(view->highlight_group));
+       gl_debug (DEBUG_VIEW, "END");
 }
 
 /*---------------------------------------------------------------------------*/
-/* PRIVATE.  Draw label layer.                                               */
+/* PRIVATE. Size allocation changed callback.                                */
 /*---------------------------------------------------------------------------*/
 static void
-draw_label_layer (glView *view)
+size_allocate_cb (glView         *view,
+                  GtkAllocation  *allocation)
 {
-       GnomeCanvasGroup *group;
-       glLabel          *label;
-       GList            *p_obj;
-       glLabelObject    *object;
-       glViewObject     *view_object;
-
-       group = gnome_canvas_root (GNOME_CANVAS (view->canvas));
-       view->label_group = GNOME_CANVAS_GROUP(
-               gnome_canvas_item_new (group,
-                                      gnome_canvas_group_get_type (),
-                                      "x", 0.0,
-                                      "y", 0.0,
-                                      NULL));
+       gl_debug (DEBUG_VIEW, "START");
 
-       label = view->label;
+        GTK_LAYOUT (view->canvas)->hadjustment->page_size = allocation->width;
+        GTK_LAYOUT (view->canvas)->hadjustment->page_increment = allocation->width / 2;
+        GTK_LAYOUT (view->canvas)->vadjustment->page_size = allocation->height;
+        GTK_LAYOUT (view->canvas)->vadjustment->page_increment = allocation->height / 2;
 
-       for (p_obj = label->objects; p_obj != NULL; p_obj = p_obj->next) {
-               object = (glLabelObject *) p_obj->data;
+        g_signal_emit_by_name (GTK_LAYOUT (view->canvas)->hadjustment, "changed");
+        g_signal_emit_by_name (GTK_LAYOUT (view->canvas)->vadjustment, "changed");
 
-               if (GL_IS_LABEL_BOX (object)) {
-                       view_object = gl_view_box_new (GL_LABEL_BOX(object),
-                                                      view);
-               } else if (GL_IS_LABEL_ELLIPSE (object)) {
-                       view_object = gl_view_ellipse_new (GL_LABEL_ELLIPSE(object),
-                                                          view);
-               } else if (GL_IS_LABEL_LINE (object)) {
-                       view_object = gl_view_line_new (GL_LABEL_LINE(object),
-                                                       view);
-               } else if (GL_IS_LABEL_IMAGE (object)) {
-                       view_object = gl_view_image_new (GL_LABEL_IMAGE(object),
-                                                        view);
-               } else if (GL_IS_LABEL_TEXT (object)) {
-                       view_object = gl_view_text_new (GL_LABEL_TEXT(object),
-                                                       view);
-               } else if (GL_IS_LABEL_BARCODE (object)) {
-                       view_object = gl_view_barcode_new (GL_LABEL_BARCODE(object),
-                                                          view);
-               } else {
-                       /* Should not happen! */
-                       view_object = NULL;
-                       g_warning ("Invalid label object type.");
-               }
+       if (view->zoom_to_fit_flag) {
+               /* Maintain best fit zoom */
+               gl_view_zoom_to_fit (view);
        }
+
+       gl_debug (DEBUG_VIEW, "END");
 }
 
-/*---------------------------------------------------------------------------*/
-/* PRIVATE.  Create highlight layer.                                         */
-/*---------------------------------------------------------------------------*/
-static void
-draw_highlight_layer (glView *view)
-{
-       GnomeCanvasGroup *group;
 
-       group = gnome_canvas_root (GNOME_CANVAS (view->canvas));
-       view->highlight_group = GNOME_CANVAS_GROUP(
-               gnome_canvas_item_new (group,
-                                      gnome_canvas_group_get_type (),
-                                      "x", 0.0,
-                                      "y", 0.0,
-                                      NULL));
-}
 
 /*---------------------------------------------------------------------------*/
-/* PRIVATE.  Draw background and foreground outlines.                        */
+/* PRIVATE. Screen changed callback.                                         */
 /*---------------------------------------------------------------------------*/
 static void
-draw_bg_fg_layers (glView *view)
-{
-       glLabel          *label;
-       glTemplate       *template;
-       GnomeCanvasGroup *group;
-
-       group = gnome_canvas_root (GNOME_CANVAS (view->canvas));
-       view->bg_group = GNOME_CANVAS_GROUP(
-               gnome_canvas_item_new (group,
-                                      gnome_canvas_group_get_type (),
-                                      "x", 0.0,
-                                      "y", 0.0,
-                                      NULL));
-       view->fg_group = GNOME_CANVAS_GROUP(
-               gnome_canvas_item_new (group,
-                                      gnome_canvas_group_get_type (),
-                                      "x", 0.0,
-                                      "y", 0.0,
-                                      NULL));
-
-       label = view->label;
-       template = gl_label_get_template (label);
-
-       switch (template->label.style) {
-
-       case GL_TEMPLATE_STYLE_RECT:
-               if (template->label.rect.r == 0.0) {
-                       /* Square corners. */
-                       draw_bg_fg_rect (view);
-               } else {
-                       /* Rounded corners. */
-                       draw_bg_fg_rounded_rect (view);
-               }
-               break;
+screen_changed_cb (glView *view)
+{
+       gl_debug (DEBUG_VIEW, "START");
 
-       case GL_TEMPLATE_STYLE_ROUND:
-               draw_bg_fg_round (view);
-               break;
+       if (gtk_widget_has_screen (GTK_WIDGET (view->canvas))) {
 
-       case GL_TEMPLATE_STYLE_CD:
-               draw_bg_fg_cd (view);
-               break;
+               view->home_scale = get_home_scale (view);
 
-       default:
-               g_warning ("Unknown template label style");
-               break;
+               if (view->zoom_to_fit_flag) {
+                       /* Maintain best fit zoom */
+                       gl_view_zoom_to_fit (view);
+               }
        }
+
+       gl_debug (DEBUG_VIEW, "END");
 }
 
 /*---------------------------------------------------------------------------*/
-/* PRIVATE.  Draw simple recangular background.                              */
+/* PRIVATE.  Handle label changed event.                                     */
 /*---------------------------------------------------------------------------*/
 static void
-draw_bg_fg_rect (glView *view)
+label_changed_cb (glView  *view)
 {
-       glLabel          *label = view->label;
-       glTemplate       *template;
-       gdouble           w, h;
-       GnomeCanvasItem  *item;
+       g_return_if_fail (view && GL_IS_VIEW (view));
 
        gl_debug (DEBUG_VIEW, "START");
 
-       g_return_if_fail (GL_IS_VIEW (view));
-       g_return_if_fail (label != NULL);
-
-       gl_label_get_size (label, &w, &h);
-       template = gl_label_get_template (label);
-
-       /* Background */
-       item = gnome_canvas_item_new (view->bg_group,
-                                     gnome_canvas_rect_get_type (),
-                                     "x1", 0.0,
-                                     "y1", 0.0,
-                                     "x2", w,
-                                     "y2", h,
-                                     "fill_color_rgba", PAPER_COLOR,
-                                     NULL);
-
-       /* Foreground */
-       item = gnome_canvas_item_new (view->fg_group,
-                                     gnome_canvas_rect_get_type (),
-                                     "x1", 0.0,
-                                     "y1", 0.0,
-                                     "x2", w,
-                                     "y2", h,
-                                     "width_pixels", 2,
-                                     "outline_color_rgba", OUTLINE_COLOR,
-                                     NULL);
+        gl_view_update (view);
 
        gl_debug (DEBUG_VIEW, "END");
 }
 
+
 /*---------------------------------------------------------------------------*/
-/* PRIVATE.  Draw rounded recangular background.                             */
+/* PRIVATE.  Handle label resize event.                                      */
 /*---------------------------------------------------------------------------*/
 static void
-draw_bg_fg_rounded_rect (glView *view)
+label_resized_cb (glView  *view)
 {
-       glLabel           *label = view->label;
-       GnomeCanvasPoints *points;
-       gint               i_coords, i_theta;
-       glTemplate        *template;
-       gdouble            r, w, h;
-       GnomeCanvasItem   *item;
+       g_return_if_fail (view && GL_IS_VIEW (view));
 
        gl_debug (DEBUG_VIEW, "START");
 
-       g_return_if_fail (GL_IS_VIEW (view));
-       g_return_if_fail (label != NULL);
-
-       gl_label_get_size (label, &w, &h);
-       template = gl_label_get_template (label);
-       r = template->label.rect.r;
+        g_signal_emit_by_name (GTK_LAYOUT (view->canvas)->hadjustment, "changed");
+        g_signal_emit_by_name (GTK_LAYOUT (view->canvas)->vadjustment, "changed");
 
-       points = gnome_canvas_points_new (4 * (1 + 90 / 5));
-       i_coords = 0;
-       for (i_theta = 0; i_theta <= 90; i_theta += 5) {
-               points->coords[i_coords++] =
-                   r - r * sin (i_theta * G_PI / 180.0);
-               points->coords[i_coords++] =
-                   r - r * cos (i_theta * G_PI / 180.0);
-       }
-       for (i_theta = 0; i_theta <= 90; i_theta += 5) {
-               points->coords[i_coords++] =
-                   r - r * cos (i_theta * G_PI / 180.0);
-               points->coords[i_coords++] =
-                   (h - r) + r * sin (i_theta * G_PI / 180.0);
-       }
-       for (i_theta = 0; i_theta <= 90; i_theta += 5) {
-               points->coords[i_coords++] =
-                   (w - r) + r * sin (i_theta * G_PI / 180.0);
-               points->coords[i_coords++] =
-                   (h - r) + r * cos (i_theta * G_PI / 180.0);
-       }
-       for (i_theta = 0; i_theta <= 90; i_theta += 5) {
-               points->coords[i_coords++] =
-                   (w - r) + r * cos (i_theta * G_PI / 180.0);
-               points->coords[i_coords++] =
-                   r - r * sin (i_theta * G_PI / 180.0);
-       }
+        gl_view_update (view);
 
-       /* Background */
-       item = gnome_canvas_item_new (view->bg_group,
-                                     gnome_canvas_polygon_get_type (),
-                                     "points", points,
-                                     "fill_color_rgba", PAPER_COLOR,
-                                     NULL);
+       gl_debug (DEBUG_VIEW, "END");
+}
 
-       /* Foreground */
-       item = gnome_canvas_item_new (view->fg_group,
-                                     gnome_canvas_polygon_get_type (),
-                                     "points", points,
-                                     "width_pixels", 2,
-                                     "outline_color_rgba", OUTLINE_COLOR,
-                                     NULL);
 
-       gnome_canvas_points_free (points);
+/*---------------------------------------------------------------------------*/
+/* PRIVATE.  Handle new label object.                                        */
+/*---------------------------------------------------------------------------*/
+static void
+label_object_added_cb (glView         *view,
+                       glLabelObject  *object)
+{
+        glViewObject *view_object;
 
-       gl_debug (DEBUG_VIEW, "END");
+       g_return_if_fail (view && GL_IS_VIEW (view));
+       g_return_if_fail (object && GL_IS_LABEL_OBJECT (object));
+
+        if (GL_IS_LABEL_BOX (object)) {
+                view_object = gl_view_box_new (GL_LABEL_BOX(object), view);
+        } else if (GL_IS_LABEL_ELLIPSE (object)) {
+                view_object = gl_view_ellipse_new (GL_LABEL_ELLIPSE(object), view);
+        } else if (GL_IS_LABEL_LINE (object)) {
+                view_object = gl_view_line_new (GL_LABEL_LINE(object), view);
+        } else if (GL_IS_LABEL_IMAGE (object)) {
+                view_object = gl_view_image_new (GL_LABEL_IMAGE(object), view);
+        } else if (GL_IS_LABEL_TEXT (object)) {
+                view_object = gl_view_text_new (GL_LABEL_TEXT(object), view);
+        } else if (GL_IS_LABEL_BARCODE (object)) {
+                view_object = gl_view_barcode_new (GL_LABEL_BARCODE(object), view);
+        } else {
+                /* Should not happen! */
+                view_object = NULL;
+                g_message ("Invalid label object type.");
+        }
+
+        gl_view_select_object (view, view_object);
 }
 
 /*---------------------------------------------------------------------------*/
-/* PRIVATE.  Draw round background.                                          */
+/* PRIVATE.  Create, draw and order layers.                                  */
 /*---------------------------------------------------------------------------*/
 static void
-draw_bg_fg_round (glView *view)
+draw_layers (glView  *view,
+             cairo_t *cr)
 {
-       glLabel          *label = view->label;
-       glTemplate       *template;
-       gdouble           r;
-       GnomeCanvasItem  *item;
+       gdouble                    scale;
+       gdouble                    w, h;
+        gint                       canvas_w, canvas_h;
+
+       g_return_if_fail (view && GL_IS_VIEW (view));
+       g_return_if_fail (view->label && GL_IS_LABEL (view->label));
 
        gl_debug (DEBUG_VIEW, "START");
 
-       g_return_if_fail (GL_IS_VIEW (view));
-       g_return_if_fail (label != NULL);
+        scale = view->zoom * view->home_scale;
+
+        gl_label_get_size (view->label, &w, &h);
+
+        scale = view->home_scale * view->zoom;
+        gtk_layout_set_size (GTK_LAYOUT (view->canvas), w*scale+8, h*scale+8);
+
+        gdk_drawable_get_size (GTK_LAYOUT (view->canvas)->bin_window, &canvas_w, &canvas_h);
+
+        view->x0 = (canvas_w/scale - w) / 2.0;
+        view->y0 = (canvas_h/scale - h) / 2.0;
+        view->w  = w;
+        view->h  = h;
 
-       template = gl_label_get_template (label);
+        cairo_save (cr);
 
-       r = template->label.round.r;
+        cairo_scale (cr, scale, scale);
+        cairo_translate (cr, view->x0, view->y0);
 
-       /* Background */
-       item = gnome_canvas_item_new (view->bg_group,
-                                     gnome_canvas_ellipse_get_type (),
-                                     "x1", 0.0,
-                                     "y1", 0.0,
-                                     "x2", 2.0*r,
-                                     "y2", 2.0*r,
-                                     "fill_color_rgba", PAPER_COLOR,
-                                     NULL);
+       draw_bg_layer (view, cr);
+       draw_grid_layer (view, cr);
+       draw_markup_layer (view, cr);
+       draw_objects_layer (view, cr);
+       draw_fg_layer (view, cr);
+       draw_highlight_layer (view, cr);
+        draw_select_region_layer (view, cr);
 
-       /* Foreground */
-       item = gnome_canvas_item_new (view->fg_group,
-                                     gnome_canvas_ellipse_get_type (),
-                                     "x1", 0.0,
-                                     "y1", 0.0,
-                                     "x2", 2.0*r,
-                                     "y2", 2.0*r,
-                                     "width_pixels", 2,
-                                     "outline_color_rgba", OUTLINE_COLOR,
-                                     NULL);
+        cairo_restore (cr);
 
        gl_debug (DEBUG_VIEW, "END");
+
 }
 
 /*---------------------------------------------------------------------------*/
-/* PRIVATE.  Draw CD style background, circular w/ concentric hole.          */
+/* PRIVATE.  Draw background                                                 */
 /*---------------------------------------------------------------------------*/
 static void
-draw_bg_fg_cd (glView *view)
+draw_bg_layer (glView  *view,
+               cairo_t *cr)
 {
-       glLabel          *label = view->label;
-       glTemplate       *template;
-       gdouble           r1, r2;
-       GnomeCanvasItem  *item;
-
-       gl_debug (DEBUG_VIEW, "START");
+       g_return_if_fail (view && GL_IS_VIEW (view));
+       g_return_if_fail (view->label && GL_IS_LABEL (view->label));
 
-       g_return_if_fail (GL_IS_VIEW (view));
-       g_return_if_fail (label != NULL);
-
-       template = gl_label_get_template (label);
-
-       r1 = template->label.cd.r1;
-       r2 = template->label.cd.r2;
-
-       /* Background */
-       /* outer circle */
-       item = gnome_canvas_item_new (view->bg_group,
-                                     gnome_canvas_ellipse_get_type (),
-                                     "x1", 0.0,
-                                     "y1", 0.0,
-                                     "x2", 2.0*r1,
-                                     "y2", 2.0*r1,
-                                     "fill_color_rgba", PAPER_COLOR,
-                                     NULL);
-       /* hole */
-       item = gnome_canvas_item_new (view->bg_group,
-                                     gnome_canvas_ellipse_get_type (),
-                                     "x1", r1 - r2,
-                                     "y1", r1 - r2,
-                                     "x2", r1 + r2,
-                                     "y2", r1 + r2,
-                                     "fill_color_rgba", GRID_COLOR,
-                                     NULL);
-
-       /* Foreground */
-       /* outer circle */
-       item = gnome_canvas_item_new (view->fg_group,
-                                     gnome_canvas_ellipse_get_type (),
-                                     "x1", 0.0,
-                                     "y1", 0.0,
-                                     "x2", 2.0*r1,
-                                     "y2", 2.0*r1,
-                                     "width_pixels", 2,
-                                     "outline_color_rgba", OUTLINE_COLOR,
-                                     NULL);
-       /* hole */
-       item = gnome_canvas_item_new (view->fg_group,
-                                     gnome_canvas_ellipse_get_type (),
-                                     "x1", r1 - r2,
-                                     "y1", r1 - r2,
-                                     "x2", r1 + r2,
-                                     "y2", r1 + r2,
-                                     "width_pixels", 2,
-                                     "outline_color_rgba", OUTLINE_COLOR,
-                                     NULL);
+        gl_cairo_label_path (cr, view->label->template, view->label->rotate_flag, FALSE);
 
-       gl_debug (DEBUG_VIEW, "END");
+        cairo_set_source_rgb (cr, PAPER_RGB_ARGS);
+        cairo_set_fill_rule (cr, CAIRO_FILL_RULE_EVEN_ODD);
+        cairo_fill (cr);
 }
 
 /*---------------------------------------------------------------------------*/
 /* PRIVATE.  Draw grid lines.                                                */
 /*---------------------------------------------------------------------------*/
 static void
-draw_grid_layer (glView *view)
+draw_grid_layer (glView  *view,
+                 cairo_t *cr)
 {
-       gdouble            w, h, x, y;
-       GnomeCanvasPoints *points;
-       GnomeCanvasItem  *item;
-       GnomeCanvasGroup *group;
+       gdouble                    w, h;
+       gdouble                    x, y;
+       gdouble                    x0, y0;
+       const lglTemplateFrame    *frame;
 
        gl_debug (DEBUG_VIEW, "START");
 
        g_return_if_fail (view && GL_IS_VIEW (view));
        g_return_if_fail (view->label && GL_IS_LABEL(view->label));
 
-       gl_label_get_size (view->label, &w, &h);
+        if (view->grid_visible)
+        {
 
-       group = gnome_canvas_root (GNOME_CANVAS (view->canvas));
-       view->grid_group = GNOME_CANVAS_GROUP(
-               gnome_canvas_item_new (group,
-                                      gnome_canvas_group_get_type (),
-                                      "x", 0.0,
-                                      "y", 0.0,
-                                      NULL));
-       points = gnome_canvas_points_new (2);
-
-       points->coords[1] = 0.0;
-       points->coords[3] = h;
-       for ( x=0.0; x < w; x += view->grid_spacing ) {
-               points->coords[0] = points->coords[2] = x;
-               item = gnome_canvas_item_new (view->grid_group,
-                                             gnome_canvas_line_get_type (),
-                                             "points", points,
-                                             "width_pixels", 1,
-                                             "fill_color_rgba", GRID_COLOR,
-                                             NULL);
-       }
-       points->coords[0] = points->coords[2] = w;
-       item = gnome_canvas_item_new (view->grid_group,
-                                     gnome_canvas_line_get_type (),
-                                     "points", points,
-                                     "width_pixels", 1,
-                                     "fill_color_rgba", GRID_COLOR,
-                                     NULL);
-
-       points->coords[0] = 0.0;
-       points->coords[2] = w;
-       for ( y=0.0; y < h; y += view->grid_spacing ) {
-               points->coords[1] = points->coords[3] = y;
-               item = gnome_canvas_item_new (view->grid_group,
-                                             gnome_canvas_line_get_type (),
-                                             "points", points,
-                                             "width_pixels", 1,
-                                             "fill_color_rgba", GRID_COLOR,
-                                             NULL);
-       }
-       points->coords[1] = points->coords[3] = h;
-       item = gnome_canvas_item_new (view->grid_group,
-                                     gnome_canvas_line_get_type (),
-                                     "points", points,
-                                     "width_pixels", 1,
-                                     "fill_color_rgba", GRID_COLOR,
-                                     NULL);
-
-       gnome_canvas_points_free (points);
-
-       gl_debug (DEBUG_VIEW, "END");
-}
-
-/*---------------------------------------------------------------------------*/
-/* PRIVATE.  Draw markup lines.                                              */
-/*---------------------------------------------------------------------------*/
-static void
-draw_markup_layer (glView *view)
-{
-       GnomeCanvasGroup *group;
-       glLabel          *label;
-       glTemplate       *template;
-       GList            *p;
-       glTemplateMarkup *markup;
-
-       group = gnome_canvas_root (GNOME_CANVAS (view->canvas));
-       view->markup_group = GNOME_CANVAS_GROUP(
-               gnome_canvas_item_new (group,
-                                      gnome_canvas_group_get_type (),
-                                      "x", 0.0,
-                                      "y", 0.0,
-                                      NULL));
-       label = view->label;
-       template = gl_label_get_template (label);
-
-       for ( p=template->label.any.markups; p != NULL; p=p->next ) {
-               markup = (glTemplateMarkup *)p->data;
-
-               switch (markup->type) {
-               case GL_TEMPLATE_MARKUP_MARGIN:
-                       draw_markup_margin (view,
-                                           (glTemplateMarkupMargin *)markup);
-                       break;
-               case GL_TEMPLATE_MARKUP_LINE:
-                       draw_markup_line (view,
-                                         (glTemplateMarkupLine *)markup);
-                       break;
-               default:
-                       g_warning ("Unknown template markup type");
-                       break;
-               }
-       }
-}
+                frame = lgl_template_get_first_frame (view->label->template);
 
-/*---------------------------------------------------------------------------*/
-/* PRIVATE.  Draw margin markup.                                             */
-/*---------------------------------------------------------------------------*/
-static void
-draw_markup_margin (glView                 *view,
-                   glTemplateMarkupMargin *margin)
-{
-       glLabel    *label;
-       glTemplate *template;
+                gl_label_get_size (view->label, &w, &h);
+       
+                if (frame->shape == LGL_TEMPLATE_FRAME_SHAPE_RECT) {
+                        x0 = 0.0;
+                        y0 = 0.0;
+                } else {
+                        /* round labels, adjust grid to line up with center of label. */
+                        x0 = fmod (w/2.0, view->grid_spacing);
+                        y0 = fmod (h/2.0, view->grid_spacing);
+                }
 
-       label = view->label;
-       template = gl_label_get_template (label);
 
-       switch (template->label.style) {
+                cairo_save (cr);
 
-       case GL_TEMPLATE_STYLE_RECT:
-               if (template->label.rect.r == 0.0) {
-                       /* Square corners. */
-                       draw_markup_margin_rect (view, margin);
-               } else {
-                       if ( margin->size < template->label.rect.r) {
-                               /* Rounded corners. */
-                               draw_markup_margin_rounded_rect (view, margin);
-                       } else {
-                               /* Square corners. */
-                               draw_markup_margin_rect (view, margin);
-                       }
-               }
-               break;
+                cairo_set_antialias (cr, CAIRO_ANTIALIAS_NONE);
+                cairo_set_line_width (cr, GRID_LINE_WIDTH_PIXELS/(view->home_scale * view->zoom));
+                cairo_set_source_rgb (cr, GRID_RGB_ARGS);
 
-       case GL_TEMPLATE_STYLE_ROUND:
-               draw_markup_margin_round (view, margin);
-               break;
+                for ( x=x0+view->grid_spacing; x < w; x += view->grid_spacing )
+                {
+                        cairo_move_to (cr, x, 0);
+                        cairo_line_to (cr, x, h);
+                        cairo_stroke (cr);
+                }
 
-       case GL_TEMPLATE_STYLE_CD:
-               draw_markup_margin_cd (view, margin);
-               break;
+                for ( y=y0+view->grid_spacing; y < h; y += view->grid_spacing )
+                {
+                        cairo_move_to (cr, 0, y);
+                        cairo_line_to (cr, w, y);
+                        cairo_stroke (cr);
+                }
 
-       default:
-               g_warning ("Unknown template label style");
-               break;
-       }
+                cairo_restore (cr);
+
+        }
+
+       gl_debug (DEBUG_VIEW, "END");
 }
 
 /*---------------------------------------------------------------------------*/
-/* PRIVATE.  Draw simple recangular margin.                                  */
+/* PRIVATE.  Draw markup layer.                                              */
 /*---------------------------------------------------------------------------*/
 static void
-draw_markup_margin_rect (glView                 *view,
-                        glTemplateMarkupMargin *margin)
+draw_markup_layer (glView  *view,
+                   cairo_t *cr)
 {
-       glLabel          *label = view->label;
-       glTemplate       *template;
-       gdouble           w, h, m;
-       GnomeCanvasItem  *item;
-
-       gl_debug (DEBUG_VIEW, "START");
-
-       g_return_if_fail (GL_IS_VIEW (view));
-       g_return_if_fail (label != NULL);
+       glLabel                   *label;
+       const lglTemplateFrame    *frame;
+       GList                     *p;
+       lglTemplateMarkup         *markup;
 
-       gl_label_get_size (label, &w, &h);
-       template = gl_label_get_template (label);
-       m = margin->size;
+       g_return_if_fail (view && GL_IS_VIEW (view));
+       g_return_if_fail (view->label && GL_IS_LABEL (view->label));
 
-       /* Bounding box @ margin */
-       gnome_canvas_item_new (view->markup_group,
-                              gnome_canvas_rect_get_type (),
-                              "x1", m,
-                              "y1", m,
-                              "x2", w - m,
-                              "y2", h - m,
-                              "width_pixels", 1,
-                              "outline_color_rgba", MARKUP_COLOR,
-                              NULL);
+        if (view->markup_visible)
+        {
 
-       gl_debug (DEBUG_VIEW, "END");
-}
+                label      = view->label;
+                frame = lgl_template_get_first_frame (label->template);
 
-/*---------------------------------------------------------------------------*/
-/* PRIVATE.  Draw rounded recangular markup.                                 */
-/*---------------------------------------------------------------------------*/
-static void
-draw_markup_margin_rounded_rect (glView                 *view,
-                                glTemplateMarkupMargin *margin)
-{
-       glLabel           *label = view->label;
-       GnomeCanvasPoints *points;
-       gint               i_coords, i_theta;
-       glTemplate        *template;
-       gdouble            r, w, h, m;
-       GnomeCanvasItem   *item;
+                cairo_save (cr);
 
-       gl_debug (DEBUG_VIEW, "START");
+                cairo_set_line_width (cr, MARKUP_LINE_WIDTH_PIXELS/(view->home_scale * view->zoom));
+                cairo_set_source_rgb (cr, MARKUP_RGB_ARGS);
 
-       g_return_if_fail (GL_IS_VIEW (view));
-       g_return_if_fail (label != NULL);
+                for ( p=frame->all.markups; p != NULL; p=p->next )
+                {
+                        markup = (lglTemplateMarkup *)p->data;
 
-       gl_label_get_size (label, &w, &h);
-       template = gl_label_get_template (label);
-       r = template->label.rect.r;
-       m = margin->size;
+                        gl_cairo_markup_path (cr, markup, label);
 
-       r = r - m;
-       w = w - 2 * m;
-       h = h - 2 * m;
+                        cairo_stroke (cr);
+                }
 
-       /* rectangle with rounded corners */
-       points = gnome_canvas_points_new (4 * (1 + 90 / 5));
-       i_coords = 0;
-       for (i_theta = 0; i_theta <= 90; i_theta += 5) {
-               points->coords[i_coords++] =
-                       m + r - r * sin (i_theta * G_PI / 180.0);
-               points->coords[i_coords++] =
-                       m + r - r * cos (i_theta * G_PI / 180.0);
-       }
-       for (i_theta = 0; i_theta <= 90; i_theta += 5) {
-               points->coords[i_coords++] =
-                       m + r - r * cos (i_theta * G_PI / 180.0);
-               points->coords[i_coords++] =
-                       m + (h - r) + r * sin (i_theta * G_PI / 180.0);
-       }
-       for (i_theta = 0; i_theta <= 90; i_theta += 5) {
-               points->coords[i_coords++] =
-                       m + (w - r) + r * sin (i_theta * G_PI / 180.0);
-               points->coords[i_coords++] =
-                       m + (h - r) + r * cos (i_theta * G_PI / 180.0);
-       }
-       for (i_theta = 0; i_theta <= 90; i_theta += 5) {
-               points->coords[i_coords++] =
-                       m + (w - r) + r * cos (i_theta * G_PI / 180.0);
-               points->coords[i_coords++] =
-                       m + r - r * sin (i_theta * G_PI / 180.0);
-       }
-       item = gnome_canvas_item_new (view->markup_group,
-                                     gnome_canvas_polygon_get_type (),
-                                     "points", points,
-                                     "width_pixels", 1,
-                                     "outline_color_rgba", MARKUP_COLOR,
-                                     NULL);
-       gnome_canvas_points_free (points);
+                cairo_restore (cr);
+        }
 
-       gl_debug (DEBUG_VIEW, "END");
 }
 
 /*---------------------------------------------------------------------------*/
-/* PRIVATE.  Draw round margin.                                              */
+/* PRIVATE.  Draw objects layer.                                             */
 /*---------------------------------------------------------------------------*/
 static void
-draw_markup_margin_round (glView                 *view,
-                         glTemplateMarkupMargin *margin)
+draw_objects_layer (glView  *view,
+                    cairo_t *cr)
 {
-       glLabel          *label = view->label;
-       glTemplate       *template;
-       gdouble           r, m;
-       GnomeCanvasItem  *item;
-
-       gl_debug (DEBUG_VIEW, "START");
-
-       g_return_if_fail (GL_IS_VIEW (view));
-       g_return_if_fail (label != NULL);
-
-       template = gl_label_get_template (label);
+        gl_label_draw (view->label, cr, TRUE, NULL);
+}
 
-       r = template->label.round.r;
-       m = margin->size;
+/*---------------------------------------------------------------------------*/
+/* PRIVATE.  Draw foreground                                                 */
+/*---------------------------------------------------------------------------*/
+static void
+draw_fg_layer (glView  *view,
+               cairo_t *cr)
+{
+       g_return_if_fail (view && GL_IS_VIEW (view));
+       g_return_if_fail (view->label && GL_IS_LABEL (view->label));
 
-       /* Margin outline */
-       item = gnome_canvas_item_new (view->markup_group,
-                                     gnome_canvas_ellipse_get_type (),
-                                     "x1", m,
-                                     "y1", m,
-                                     "x2", 2.0*r - m,
-                                     "y2", 2.0*r - m,
-                                     "width_pixels", 1,
-                                     "outline_color_rgba", MARKUP_COLOR,
-                                     NULL);
+        gl_cairo_label_path (cr, view->label->template, view->label->rotate_flag, FALSE);
 
-       gl_debug (DEBUG_VIEW, "END");
+        cairo_set_line_width (cr, OUTLINE_WIDTH_PIXELS/(view->home_scale * view->zoom));
+        cairo_set_source_rgb (cr, OUTLINE_RGB_ARGS);
+        cairo_stroke (cr);
 }
 
 /*---------------------------------------------------------------------------*/
-/* PRIVATE.  Draw CD margins.                                                */
+/* PRIVATE.  Create highlight layer.                                         */
 /*---------------------------------------------------------------------------*/
 static void
-draw_markup_margin_cd (glView                 *view,
-                      glTemplateMarkupMargin *margin)
+draw_highlight_layer (glView  *view,
+                      cairo_t *cr)
 {
-       glLabel          *label = view->label;
-       glTemplate       *template;
-       gdouble           m, r1, r2;
-       GnomeCanvasItem  *item;
+       GList            *p_obj;
+       glViewObject     *view_object;
 
-       gl_debug (DEBUG_VIEW, "START");
+       g_return_if_fail (view && GL_IS_VIEW (view));
 
-       g_return_if_fail (GL_IS_VIEW (view));
-       g_return_if_fail (label != NULL);
+        cairo_save (cr);
 
-       template = gl_label_get_template (label);
+        cairo_set_antialias (cr, CAIRO_ANTIALIAS_NONE);
 
-       r1 = template->label.cd.r1;
-       r2 = template->label.cd.r2;
-       m  = margin->size;
+       for (p_obj = view->selected_object_list; p_obj != NULL; p_obj = p_obj->next)
+        {
+               view_object = GL_VIEW_OBJECT (p_obj->data);
 
-       /* outer margin */
-       item = gnome_canvas_item_new (view->markup_group,
-                                     gnome_canvas_ellipse_get_type (),
-                                     "x1", m,
-                                     "y1", m,
-                                     "x2", 2.0*r1 - m,
-                                     "y2", 2.0*r1 - m,
-                                     "width_pixels", 1,
-                                     "outline_color_rgba", MARKUP_COLOR,
-                                     NULL);
-       /* inner margin */
-       item = gnome_canvas_item_new (view->markup_group,
-                                     gnome_canvas_ellipse_get_type (),
-                                     "x1", r1 - r2 - m,
-                                     "y1", r1 - r2 - m,
-                                     "x2", r1 + r2 + m,
-                                     "y2", r1 + r2 + m,
-                                     "width_pixels", 1,
-                                     "outline_color_rgba", MARKUP_COLOR,
-                                     NULL);
+                gl_view_object_draw_handles (view_object, cr);
+       }
 
-       gl_debug (DEBUG_VIEW, "END");
+        cairo_restore (cr);
 }
 
 /*---------------------------------------------------------------------------*/
-/* PRIVATE.  Draw line markup.                                               */
+/* PRIVATE.  Draw select region layer.                                       */
 /*---------------------------------------------------------------------------*/
 static void
-draw_markup_line (glView               *view,
-                 glTemplateMarkupLine *line)
+draw_select_region_layer (glView  *view,
+                          cairo_t *cr)
 {
-       GnomeCanvasPoints *points;
+        gdouble x1, y1;
+        gdouble w, h;
 
-       gl_debug (DEBUG_VIEW, "START");
+       g_return_if_fail (view && GL_IS_VIEW (view));
 
-       g_return_if_fail (GL_IS_VIEW (view));
+        if (view->select_region_visible)
+        {
+                x1 = MIN (view->select_region.x1, view->select_region.x2);
+                y1 = MIN (view->select_region.y1, view->select_region.y2);
+                w  = fabs (view->select_region.x2 - view->select_region.x1);
+                h  = fabs (view->select_region.y2 - view->select_region.y1);
 
-       points = gnome_canvas_points_new (2);
-       points->coords[0] = line->x1;
-       points->coords[1] = line->y1;
-       points->coords[2] = line->x2;
-       points->coords[3] = line->y2;
+                cairo_save (cr);
 
-       /* Bounding box @ margin */
-       gnome_canvas_item_new (view->markup_group,
-                              gnome_canvas_line_get_type (),
-                              "points", points,
-                              "width_pixels", 1,
-                              "fill_color_rgba", MARKUP_COLOR,
-                              NULL);
+                cairo_set_antialias (cr, CAIRO_ANTIALIAS_NONE);
 
-       gnome_canvas_points_free (points);
+                cairo_rectangle (cr, x1, y1, w, h);
 
-       gl_debug (DEBUG_VIEW, "END");
+                cairo_set_source_rgba (cr, SELECT_FILL_RGBA_ARGS);
+                cairo_fill_preserve (cr);
+
+                cairo_set_line_width (cr, SELECT_LINE_WIDTH_PIXELS/(view->home_scale * view->zoom));
+                cairo_set_source_rgba (cr, SELECT_LINE_RGBA_ARGS);
+                cairo_stroke (cr);
+
+                cairo_restore (cr);
+        }
 }
 
 /*****************************************************************************/
 /* Show grid.                                                                */
 /*****************************************************************************/
-void       gl_view_show_grid               (glView            *view)
+void
+gl_view_show_grid (glView *view)
 {
-       gnome_canvas_item_show (GNOME_CANVAS_ITEM(view->grid_group));
+       g_return_if_fail (view && GL_IS_VIEW (view));
+
+        view->grid_visible = TRUE;
+        gl_view_update (view);
 }
 
 /*****************************************************************************/
 /* Hide grid.                                                                */
 /*****************************************************************************/
-void       gl_view_hide_grid               (glView            *view)
+void
+gl_view_hide_grid (glView *view)
 {
-       gnome_canvas_item_hide (GNOME_CANVAS_ITEM(view->grid_group));
+       g_return_if_fail (view && GL_IS_VIEW (view));
+
+        view->grid_visible = FALSE;
+        gl_view_update (view);
 }
 
 /*****************************************************************************/
 /* Set grid spacing.                                                         */
 /*****************************************************************************/
-void       gl_view_set_grid_spacing        (glView            *view,
-                                           gdouble            spacing)
+void
+gl_view_set_grid_spacing (glView  *view,
+                         gdouble  spacing)
 {
-       view->grid_spacing = spacing;
+       g_return_if_fail (view && GL_IS_VIEW (view));
 
-       gtk_object_destroy (GTK_OBJECT(view->grid_group));
-       draw_grid_layer (view);
+       view->grid_spacing = spacing;
+        gl_view_update (view);
 }
 
 /*****************************************************************************/
 /* Show markup.                                                              */
 /*****************************************************************************/
-void       gl_view_show_markup             (glView            *view)
+void
+gl_view_show_markup (glView *view)
 {
-       gnome_canvas_item_show (GNOME_CANVAS_ITEM(view->markup_group));
+       g_return_if_fail (view && GL_IS_VIEW (view));
+
+        view->markup_visible = TRUE;
+        gl_view_update (view);
 }
 
 /*****************************************************************************/
 /* Hide markup.                                                              */
 /*****************************************************************************/
-void       gl_view_hide_markup             (glView            *view)
+void
+gl_view_hide_markup (glView *view)
 {
-       gnome_canvas_item_hide (GNOME_CANVAS_ITEM(view->markup_group));
+       g_return_if_fail (view && GL_IS_VIEW (view));
+
+        view->markup_visible = FALSE;
+        gl_view_update (view);
 }
 
 /*****************************************************************************/
@@ -1258,19 +1090,18 @@ void       gl_view_hide_markup             (glView            *view)
 void
 gl_view_arrow_mode (glView *view)
 {
-       static GdkCursor *cursor = NULL;
+       GdkCursor *cursor;
 
        gl_debug (DEBUG_VIEW, "START");
 
-       g_return_if_fail (GL_IS_VIEW (view));
-
-       if (!cursor) {
-               cursor = gdk_cursor_new (GDK_LEFT_PTR);
-       }
+       g_return_if_fail (view && GL_IS_VIEW (view));
 
+        cursor = gdk_cursor_new (GDK_LEFT_PTR);
        gdk_window_set_cursor (view->canvas->window, cursor);
+        gdk_cursor_unref (cursor);
 
-       view->state = GL_VIEW_STATE_ARROW;
+       view->mode = GL_VIEW_MODE_ARROW;
+        view->state = GL_VIEW_IDLE;
 
        gl_debug (DEBUG_VIEW, "END");
 }
@@ -1280,15 +1111,16 @@ gl_view_arrow_mode (glView *view)
 /*****************************************************************************/
 void
 gl_view_object_create_mode (glView            *view,
-                           glLabelObjectType type)
+                           glLabelObjectType  type)
 {
-       GdkCursor *cursor;
+       GdkCursor *cursor = NULL;
 
        gl_debug (DEBUG_VIEW, "START");
 
-       g_return_if_fail (GL_IS_VIEW (view));
+       g_return_if_fail (view && GL_IS_VIEW (view));
 
-       switch (type) {
+       switch (type)
+        {
        case GL_LABEL_OBJECT_BOX:
                cursor = gl_view_box_get_create_cursor ();
                break;
@@ -1308,13 +1140,15 @@ gl_view_object_create_mode (glView            *view,
                cursor = gl_view_barcode_get_create_cursor ();
                break;
        default:
-               g_warning ("Invalid label object type.");/*Should not happen!*/
+               g_message ("Invalid label object type.");/*Should not happen!*/
                break;
        }
 
        gdk_window_set_cursor (view->canvas->window, cursor);
+        gdk_cursor_unref (cursor);
 
-       view->state = GL_VIEW_STATE_OBJECT_CREATE;
+       view->mode = GL_VIEW_MODE_OBJECT_CREATE;
+        view->state = GL_VIEW_IDLE;
        view->create_type = type;
 
        gl_debug (DEBUG_VIEW, "END");
@@ -1329,6 +1163,8 @@ gl_view_select_object (glView       *view,
 {
        gl_debug (DEBUG_VIEW, "START");
 
+       g_return_if_fail (view && GL_IS_VIEW (view));
+
        select_object_real (view, view_object);
 
        g_signal_emit (G_OBJECT(view), signals[SELECTION_CHANGED], 0);
@@ -1345,6 +1181,8 @@ gl_view_unselect_object (glView       *view,
 {
        gl_debug (DEBUG_VIEW, "START");
 
+       g_return_if_fail (view && GL_IS_VIEW (view));
+
        unselect_object_real (view, view_object);
 
        g_signal_emit (G_OBJECT(view), signals[SELECTION_CHANGED], 0);
@@ -1362,7 +1200,7 @@ gl_view_select_all (glView *view)
 
        gl_debug (DEBUG_VIEW, "START");
 
-       g_return_if_fail (GL_IS_VIEW (view));
+       g_return_if_fail (view && GL_IS_VIEW (view));
 
        /* 1st unselect anything already selected. */
        for (p = view->selected_object_list; p != NULL; p = p_next) {
@@ -1386,11 +1224,12 @@ gl_view_select_all (glView *view)
 void
 gl_view_unselect_all (glView *view)
 {
-       GList *p, *p_next;
+       GList *p;
+       GList *p_next;
 
        gl_debug (DEBUG_VIEW, "START");
 
-       g_return_if_fail (GL_IS_VIEW (view));
+       g_return_if_fail (view && GL_IS_VIEW (view));
 
        for (p = view->selected_object_list; p != NULL; p = p_next) {
                p_next = p->next;
@@ -1406,31 +1245,39 @@ gl_view_unselect_all (glView *view)
 /* Select all objects within given rectangular region (adding to selection). */
 /*****************************************************************************/
 void
-gl_view_select_region (glView  *view,
-                      gdouble  x1,
-                      gdouble  y1,
-                      gdouble  x2,
-                      gdouble  y2)
+gl_view_select_region (glView        *view,
+                       glLabelRegion *region)
 {
-       GList *p;
-       glViewObject *view_object;
+       GList         *p;
+       glViewObject  *view_object;
        glLabelObject *object;
-       gdouble i_x1, i_y1, i_x2, i_y2;
+        gdouble        r_x1, r_y1;
+        gdouble        r_x2, r_y2;
+        glLabelRegion  obj_extent;
 
        gl_debug (DEBUG_VIEW, "START");
 
-       g_return_if_fail (GL_IS_VIEW (view));
-       g_return_if_fail ((x1 <= x2) && (y1 <= y2));
+       g_return_if_fail (view && GL_IS_VIEW (view));
 
-       for (p = view->object_list; p != NULL; p = p->next) {
+        r_x1 = MIN (region->x1, region->x2);
+        r_y1 = MIN (region->y1, region->y2);
+        r_x2 = MAX (region->x1, region->x2);
+        r_y2 = MAX (region->y1, region->y2);
+
+       for (p = view->object_list; p != NULL; p = p->next)
+        {
                view_object = GL_VIEW_OBJECT(p->data);
-               if (!is_object_selected (view, view_object)) {
+               if (!gl_view_is_object_selected (view, view_object))
+                {
 
                        object = gl_view_object_get_object (view_object);
 
-                       gl_label_object_get_extent (object, &i_x1, &i_y1, &i_x2, &i_y2);
-                       if ((i_x1 >= x1) && (i_x2 <= x2) && (i_y1 >= y1)
-                           && (i_y2 <= y2)) {
+                       gl_label_object_get_extent (object, &obj_extent);
+                       if ((obj_extent.x1 >= r_x1) &&
+                            (obj_extent.x2 <= r_x2) &&
+                            (obj_extent.y1 >= r_y1) &&
+                            (obj_extent.y2 <= r_y2))
+                        {
                                select_object_real (view, view_object);
                        }
 
@@ -1451,16 +1298,17 @@ select_object_real (glView       *view,
 {
        gl_debug (DEBUG_VIEW, "START");
 
-       g_return_if_fail (GL_IS_VIEW (view));
+       g_return_if_fail (view && GL_IS_VIEW (view));
        g_return_if_fail (GL_IS_VIEW_OBJECT (view_object));
 
-       if (!is_object_selected (view, view_object)) {
+       if (!gl_view_is_object_selected (view, view_object)) {
                view->selected_object_list =
-                   g_list_prepend (view->selected_object_list, view_object);
+                   g_list_append (view->selected_object_list, view_object);
        }
-       gl_view_object_show_highlight (view_object);
        gtk_widget_grab_focus (GTK_WIDGET (view->canvas));
 
+        gl_view_update (view);
+
        gl_debug (DEBUG_VIEW, "END");
 }
 
@@ -1473,75 +1321,86 @@ unselect_object_real (glView       *view,
 {
        gl_debug (DEBUG_VIEW, "START");
 
-       g_return_if_fail (GL_IS_VIEW (view));
+       g_return_if_fail (view && GL_IS_VIEW (view));
        g_return_if_fail (GL_IS_VIEW_OBJECT (view_object));
 
-       gl_view_object_hide_highlight (view_object);
-
        view->selected_object_list =
            g_list_remove (view->selected_object_list, view_object);
 
+        gl_view_update (view);
+
        gl_debug (DEBUG_VIEW, "END");
 }
 
 /*---------------------------------------------------------------------------*/
 /* PRIVATE. Return object at (x,y).                                          */
 /*---------------------------------------------------------------------------*/
-static gboolean
-object_at (glView  *view,
-          gdouble  x,
-          gdouble  y)
+static glViewObject *
+view_view_object_at (glView  *view,
+                     cairo_t *cr,
+                     gdouble  x,
+                     gdouble  y)
 {
-       GnomeCanvasItem *item, *p_item;
-       GList *p;
+       GList            *p_obj;
+       glViewObject     *view_object;
 
-       gl_debug (DEBUG_VIEW, "");
+       g_return_val_if_fail (view && GL_IS_VIEW (view), NULL);
 
-       g_return_val_if_fail (GL_IS_VIEW (view), FALSE);
+       for (p_obj = g_list_last (view->object_list); p_obj != NULL; p_obj = p_obj->prev)
+        {
 
-       item = gnome_canvas_get_item_at (GNOME_CANVAS (view->canvas), x, y);
+               view_object = GL_VIEW_OBJECT (p_obj->data);
 
-       /* No item is at x, y */
-       if (item == NULL)
-               return FALSE;
+                if (gl_view_object_at (view_object, cr, x, y))
+                {
+                        return view_object;
+                }
 
-       /* ignore items not in label or highlight layers, e.g. background items */
-       if (!is_item_member_of_group(view, item, GNOME_CANVAS_ITEM(view->label_group)) &&
-           !is_item_member_of_group(view, item, GNOME_CANVAS_ITEM(view->highlight_group)))
-               return FALSE;
+       }
 
-       return TRUE;
+        return NULL;
 }
 
 /*---------------------------------------------------------------------------*/
-/* PRIVATE.  Is the item a child (or grandchild, etc.) of group.             */
+/* PRIVATE. Return object handle at (x,y).                                   */
 /*---------------------------------------------------------------------------*/
-static gboolean
-is_item_member_of_group (glView          *view,
-                        GnomeCanvasItem *item,
-                        GnomeCanvasItem *group)
+static glViewObject *
+view_handle_at (glView             *view,
+                cairo_t            *cr,
+                gdouble             x,
+                gdouble             y,
+                glViewObjectHandle *handle)
 {
-       GnomeCanvasItem *parent;
-       GnomeCanvasItem *root_group;
+       GList            *p_obj;
+       glViewObject     *view_object;
+
+       g_return_val_if_fail (view && GL_IS_VIEW (view), NULL);
+
+       for (p_obj = g_list_last (view->selected_object_list); p_obj != NULL; p_obj = p_obj->prev)
+        {
 
-       root_group = GNOME_CANVAS_ITEM(gnome_canvas_root (GNOME_CANVAS (view->canvas)));
+               view_object = GL_VIEW_OBJECT (p_obj->data);
+
+                if ((*handle = gl_view_object_handle_at (view_object, cr, x, y)))
+                {
+                        return view_object;
+                }
 
-       for ( parent=item->parent; parent && (parent!=root_group); parent=parent->parent) {
-               if (parent == group) return TRUE;
        }
-       return FALSE;
+
+        return NULL;
 }
 
-/*---------------------------------------------------------------------------*/
-/* PRIVATE.  Is the object in our current selection?                         */
-/*---------------------------------------------------------------------------*/
-static gboolean
-is_object_selected (glView       *view,
-                   glViewObject *view_object)
+/*****************************************************************************/
+/* Is the object in our current selection?                                   */
+/*****************************************************************************/
+gboolean
+gl_view_is_object_selected (glView       *view,
+                           glViewObject *view_object)
 {
        gl_debug (DEBUG_VIEW, "");
 
-       g_return_val_if_fail (GL_IS_VIEW (view), FALSE);
+       g_return_val_if_fail (view && GL_IS_VIEW (view), FALSE);
        g_return_val_if_fail (GL_IS_VIEW_OBJECT (view_object), FALSE);
 
        if (g_list_find (view->selected_object_list, view_object) == NULL) {
@@ -1558,7 +1417,7 @@ gl_view_is_selection_empty (glView *view)
 {
        gl_debug (DEBUG_VIEW, "");
 
-       g_return_val_if_fail (GL_IS_VIEW (view), FALSE);
+       g_return_val_if_fail (view && GL_IS_VIEW (view), FALSE);
 
        if (view->selected_object_list == NULL) {
                return TRUE;
@@ -1575,7 +1434,7 @@ gl_view_is_selection_atomic (glView *view)
 {
        gl_debug (DEBUG_VIEW, "");
 
-       g_return_val_if_fail (GL_IS_VIEW (view), FALSE);
+       g_return_val_if_fail (view && GL_IS_VIEW (view), FALSE);
 
        if (view->selected_object_list == NULL)
                return FALSE;
@@ -1590,42 +1449,55 @@ gl_view_is_selection_atomic (glView *view)
 void
 gl_view_delete_selection (glView *view)
 {
-       GList *p, *p_next;
+       GList         *object_list;
+       GList         *p;
+       GList         *p_next;
+       glViewObject  *view_object;
+       glLabelObject *object;
 
        gl_debug (DEBUG_VIEW, "START");
 
-       g_return_if_fail (GL_IS_VIEW (view));
+       g_return_if_fail (view && GL_IS_VIEW (view));
 
-       for (p = view->selected_object_list; p != NULL; p = p_next) {
+       object_list = view->selected_object_list;
+       view->selected_object_list = NULL;
+       g_signal_emit (G_OBJECT(view), signals[SELECTION_CHANGED], 0);
+
+       for (p = object_list; p != NULL; p = p_next) {
                p_next = p->next;
-               g_object_unref (G_OBJECT (p->data));
+               view_object = GL_VIEW_OBJECT (p->data);
+               object = gl_view_object_get_object (view_object);
+                gl_label_object_remove (object);
        }
 
-       g_signal_emit (G_OBJECT(view), signals[SELECTION_CHANGED], 0);
+        g_list_free (object_list);
 
        gl_debug (DEBUG_VIEW, "END");
 }
 
 /*****************************************************************************/
-/* Edit properties of selected object.                                       */
+/* Get object property editor of first selected object.                      */
 /*****************************************************************************/
-void
-gl_view_edit_object_props (glView *view)
+GtkWidget *
+gl_view_get_editor (glView *view)
 {
        glViewObject *view_object;
+       GtkWidget    *editor = NULL;
 
        gl_debug (DEBUG_VIEW, "START");
 
-       g_return_if_fail (GL_IS_VIEW (view));
+       g_return_val_if_fail (view && GL_IS_VIEW (view), NULL);
 
-       if (gl_view_is_selection_atomic (view)) {
+       if (!gl_view_is_selection_empty (view)) {
 
                view_object = GL_VIEW_OBJECT(view->selected_object_list->data);
-               gl_view_object_show_dialog (view_object);
+               editor = gl_view_object_get_editor (view_object);
 
        }
 
        gl_debug (DEBUG_VIEW, "END");
+
+       return editor;
 }
 
 /*****************************************************************************/
@@ -1640,7 +1512,7 @@ gl_view_raise_selection (glView *view)
 
        gl_debug (DEBUG_VIEW, "START");
 
-       g_return_if_fail (GL_IS_VIEW (view));
+       g_return_if_fail (view && GL_IS_VIEW (view));
 
        for (p = view->selected_object_list; p != NULL; p = p->next) {
                view_object = GL_VIEW_OBJECT (p->data);
@@ -1663,7 +1535,7 @@ gl_view_lower_selection (glView *view)
 
        gl_debug (DEBUG_VIEW, "START");
 
-       g_return_if_fail (GL_IS_VIEW (view));
+       g_return_if_fail (view && GL_IS_VIEW (view));
 
        for (p = view->selected_object_list; p != NULL; p = p->next) {
                view_object = GL_VIEW_OBJECT (p->data);
@@ -1687,7 +1559,7 @@ gl_view_rotate_selection (glView *view,
 
        gl_debug (DEBUG_VIEW, "START");
 
-       g_return_if_fail (GL_IS_VIEW (view));
+       g_return_if_fail (view && GL_IS_VIEW (view));
 
        for (p = view->selected_object_list; p != NULL; p = p->next) {
                view_object = GL_VIEW_OBJECT (p->data);
@@ -1710,7 +1582,7 @@ gl_view_rotate_selection_left (glView *view)
 
        gl_debug (DEBUG_VIEW, "START");
 
-       g_return_if_fail (GL_IS_VIEW (view));
+       g_return_if_fail (view && GL_IS_VIEW (view));
 
        for (p = view->selected_object_list; p != NULL; p = p->next) {
                view_object = GL_VIEW_OBJECT (p->data);
@@ -1733,7 +1605,7 @@ gl_view_rotate_selection_right (glView *view)
 
        gl_debug (DEBUG_VIEW, "START");
 
-       g_return_if_fail (GL_IS_VIEW (view));
+       g_return_if_fail (view && GL_IS_VIEW (view));
 
        for (p = view->selected_object_list; p != NULL; p = p->next) {
                view_object = GL_VIEW_OBJECT (p->data);
@@ -1756,7 +1628,7 @@ gl_view_flip_selection_horiz (glView *view)
 
        gl_debug (DEBUG_VIEW, "START");
 
-       g_return_if_fail (GL_IS_VIEW (view));
+       g_return_if_fail (view && GL_IS_VIEW (view));
 
        for (p = view->selected_object_list; p != NULL; p = p->next) {
                view_object = GL_VIEW_OBJECT (p->data);
@@ -1779,7 +1651,7 @@ gl_view_flip_selection_vert (glView *view)
 
        gl_debug (DEBUG_VIEW, "START");
 
-       g_return_if_fail (GL_IS_VIEW (view));
+       g_return_if_fail (view && GL_IS_VIEW (view));
 
        for (p = view->selected_object_list; p != NULL; p = p->next) {
                view_object = GL_VIEW_OBJECT (p->data);
@@ -1799,11 +1671,12 @@ gl_view_align_selection_left (glView *view)
        GList         *p;
        glViewObject  *view_object;
        glLabelObject *object;
-       gdouble        dx, x1min, x1, y1, x2, y2;
+       gdouble        dx, x1_min;
+        glLabelRegion  obj_extent;
 
        gl_debug (DEBUG_VIEW, "START");
 
-       g_return_if_fail (GL_IS_VIEW (view));
+       g_return_if_fail (view && GL_IS_VIEW (view));
 
        g_return_if_fail (!gl_view_is_selection_empty (view) &&
                          !gl_view_is_selection_atomic (view));
@@ -1812,20 +1685,23 @@ gl_view_align_selection_left (glView *view)
        p = view->selected_object_list;
        view_object = GL_VIEW_OBJECT (p->data);
        object = gl_view_object_get_object (view_object);
-       gl_label_object_get_extent (object, &x1min, &y1, &x2, &y2);
-       for (p = p->next; p != NULL; p = p->next) {
+       gl_label_object_get_extent (object, &obj_extent);
+        x1_min = obj_extent.x1;
+       for (p = p->next; p != NULL; p = p->next)
+        {
                view_object = GL_VIEW_OBJECT (p->data);
                object = gl_view_object_get_object (view_object);
-               gl_label_object_get_extent (object, &x1, &y1, &x2, &y2);
-               if ( x1 < x1min ) x1min = x1;
+               gl_label_object_get_extent (object, &obj_extent);
+               if ( obj_extent.x1 < x1_min ) x1_min = obj_extent.x1;
        }
 
        /* now adjust the object positions to line up the left edges */
-       for (p = view->selected_object_list; p != NULL; p = p->next) {
+       for (p = view->selected_object_list; p != NULL; p = p->next)
+        {
                view_object = GL_VIEW_OBJECT (p->data);
                object = gl_view_object_get_object (view_object);
-               gl_label_object_get_extent (object, &x1, &y1, &x2, &y2);
-               dx = x1min - x1;
+               gl_label_object_get_extent (object, &obj_extent);
+               dx = x1_min - obj_extent.x1;
                gl_label_object_set_position_relative (object, dx, 0.0);
        }
 
@@ -1842,11 +1718,12 @@ gl_view_align_selection_right (glView *view)
        GList         *p;
        glViewObject  *view_object;
        glLabelObject *object;
-       gdouble        dx, x2max, x1, y1, x2, y2;
+       gdouble        dx, x2_max;
+        glLabelRegion  obj_extent;
 
        gl_debug (DEBUG_VIEW, "START");
 
-       g_return_if_fail (GL_IS_VIEW (view));
+       g_return_if_fail (view && GL_IS_VIEW (view));
 
        g_return_if_fail (!gl_view_is_selection_empty (view) &&
                          !gl_view_is_selection_atomic (view));
@@ -1855,20 +1732,23 @@ gl_view_align_selection_right (glView *view)
        p = view->selected_object_list;
        view_object = GL_VIEW_OBJECT (p->data);
        object = gl_view_object_get_object (view_object);
-       gl_label_object_get_extent (object, &x1, &y1, &x2max, &y2);
-       for (p = p->next; p != NULL; p = p->next) {
+       gl_label_object_get_extent (object, &obj_extent);
+        x2_max = obj_extent.x2;
+       for (p = p->next; p != NULL; p = p->next)
+        {
                view_object = GL_VIEW_OBJECT (p->data);
                object = gl_view_object_get_object (view_object);
-               gl_label_object_get_extent (object, &x1, &y1, &x2, &y2);
-               if ( x2 > x2max ) x2max = x2;
+               gl_label_object_get_extent (object, &obj_extent);
+               if ( obj_extent.x2 > x2_max ) x2_max = obj_extent.x2;
        }
 
        /* now adjust the object positions to line up the right edges */
-       for (p = view->selected_object_list; p != NULL; p = p->next) {
+       for (p = view->selected_object_list; p != NULL; p = p->next)
+        {
                view_object = GL_VIEW_OBJECT (p->data);
                object = gl_view_object_get_object (view_object);
-               gl_label_object_get_extent (object, &x1, &y1, &x2, &y2);
-               dx = x2max - x2;
+               gl_label_object_get_extent (object, &obj_extent);
+               dx = x2_max - obj_extent.x2;
                gl_label_object_set_position_relative (object, dx, 0.0);
        }
 
@@ -1884,12 +1764,16 @@ gl_view_align_selection_hcenter (glView *view)
        GList         *p;
        glViewObject  *view_object;
        glLabelObject *object;
-       gdouble        dx, dxmin, xsum, xavg, xcenter, x1, y1, x2, y2;
+       gdouble        dx;
+       gdouble        dxmin;
+       gdouble        xsum, xavg;
+        glLabelRegion  obj_extent;
+       gdouble        xcenter;
        gint           n;
 
        gl_debug (DEBUG_VIEW, "START");
 
-       g_return_if_fail (GL_IS_VIEW (view));
+       g_return_if_fail (view && GL_IS_VIEW (view));
 
        g_return_if_fail (!gl_view_is_selection_empty (view) &&
                          !gl_view_is_selection_atomic (view));
@@ -1897,11 +1781,12 @@ gl_view_align_selection_hcenter (glView *view)
        /* find average center of objects */
        xsum = 0.0;
        n = 0;
-       for (p = view->selected_object_list; p != NULL; p = p->next) {
+       for (p = view->selected_object_list; p != NULL; p = p->next)
+        {
                view_object = GL_VIEW_OBJECT (p->data);
                object = gl_view_object_get_object (view_object);
-               gl_label_object_get_extent (object, &x1, &y1, &x2, &y2);
-               xsum += (x1 + x2) / 2.0;
+               gl_label_object_get_extent (object, &obj_extent);
+               xsum += (obj_extent.x1 + obj_extent.x2) / 2.0;
                n++;
        }
        xavg = xsum / n;
@@ -1910,17 +1795,19 @@ gl_view_align_selection_hcenter (glView *view)
        p = view->selected_object_list;
        view_object = GL_VIEW_OBJECT (p->data);
        object = gl_view_object_get_object (view_object);
-       gl_label_object_get_extent (object, &x1, &y1, &x2, &y2);
-       dxmin = fabs (xavg - (x1 + x2)/2.0);
-       xcenter = (x1 + x2)/2.0;
-       for (p = p->next; p != NULL; p = p->next) {
+       gl_label_object_get_extent (object, &obj_extent);
+       dxmin = fabs (xavg - (obj_extent.x1 + obj_extent.x2)/2.0);
+       xcenter = (obj_extent.x1 + obj_extent.x2)/2.0;
+       for (p = p->next; p != NULL; p = p->next)
+        {
                view_object = GL_VIEW_OBJECT (p->data);
                object = gl_view_object_get_object (view_object);
-               gl_label_object_get_extent (object, &x1, &y1, &x2, &y2);
-               dx = fabs (xavg - (x1 + x2)/2.0);
-               if ( dx < dxmin ) {
+               gl_label_object_get_extent (object, &obj_extent);
+               dx = fabs (xavg - (obj_extent.x1 + obj_extent.x2)/2.0);
+               if ( dx < dxmin )
+                {
                        dxmin = dx;
-                       xcenter = (x1 + x2)/2.0;
+                       xcenter = (obj_extent.x1 + obj_extent.x2)/2.0;
                }
        }
 
@@ -1928,8 +1815,8 @@ gl_view_align_selection_hcenter (glView *view)
        for (p = view->selected_object_list; p != NULL; p = p->next) {
                view_object = GL_VIEW_OBJECT (p->data);
                object = gl_view_object_get_object (view_object);
-               gl_label_object_get_extent (object, &x1, &y1, &x2, &y2);
-               dx = xcenter - (x1 + x2)/2.0;
+               gl_label_object_get_extent (object, &obj_extent);
+               dx = xcenter - (obj_extent.x1 + obj_extent.x2)/2.0;
                gl_label_object_set_position_relative (object, dx, 0.0);
        }
 
@@ -1945,11 +1832,12 @@ gl_view_align_selection_top (glView *view)
        GList         *p;
        glViewObject  *view_object;
        glLabelObject *object;
-       gdouble        dy, y1min, x1, y1, x2, y2;
+       gdouble        dy, y1_min;
+        glLabelRegion  obj_extent;
 
        gl_debug (DEBUG_VIEW, "START");
 
-       g_return_if_fail (GL_IS_VIEW (view));
+       g_return_if_fail (view && GL_IS_VIEW (view));
 
        g_return_if_fail (!gl_view_is_selection_empty (view) &&
                          !gl_view_is_selection_atomic (view));
@@ -1958,20 +1846,23 @@ gl_view_align_selection_top (glView *view)
        p = view->selected_object_list;
        view_object = GL_VIEW_OBJECT (p->data);
        object = gl_view_object_get_object (view_object);
-       gl_label_object_get_extent (object, &x1, &y1min, &x2, &y2);
-       for (p = p->next; p != NULL; p = p->next) {
+       gl_label_object_get_extent (object, &obj_extent);
+        y1_min = obj_extent.y1;
+       for (p = p->next; p != NULL; p = p->next)
+        {
                view_object = GL_VIEW_OBJECT (p->data);
                object = gl_view_object_get_object (view_object);
-               gl_label_object_get_extent (object, &x1, &y1, &x2, &y2);
-               if ( y1 < y1min ) y1min = y1;
+               gl_label_object_get_extent (object, &obj_extent);
+               if ( obj_extent.y1 < y1_min ) y1_min = obj_extent.y1;
        }
 
        /* now adjust the object positions to line up the top edges */
-       for (p = view->selected_object_list; p != NULL; p = p->next) {
+       for (p = view->selected_object_list; p != NULL; p = p->next)
+        {
                view_object = GL_VIEW_OBJECT (p->data);
                object = gl_view_object_get_object (view_object);
-               gl_label_object_get_extent (object, &x1, &y1, &x2, &y2);
-               dy = y1min - y1;
+               gl_label_object_get_extent (object, &obj_extent);
+               dy = y1_min - obj_extent.y1;
                gl_label_object_set_position_relative (object, 0.0, dy);
        }
 
@@ -1987,11 +1878,12 @@ gl_view_align_selection_bottom (glView *view)
        GList         *p;
        glViewObject  *view_object;
        glLabelObject *object;
-       gdouble        dy, y2max, x1, y1, x2, y2;
+       gdouble        dy, y2_max;
+        glLabelRegion  obj_extent;
 
        gl_debug (DEBUG_VIEW, "START");
 
-       g_return_if_fail (GL_IS_VIEW (view));
+       g_return_if_fail (view && GL_IS_VIEW (view));
 
        g_return_if_fail (!gl_view_is_selection_empty (view) &&
                          !gl_view_is_selection_atomic (view));
@@ -2000,20 +1892,23 @@ gl_view_align_selection_bottom (glView *view)
        p = view->selected_object_list;
        view_object = GL_VIEW_OBJECT (p->data);
        object = gl_view_object_get_object (view_object);
-       gl_label_object_get_extent (object, &x1, &y1, &x2, &y2max);
-       for (p = p->next; p != NULL; p = p->next) {
+       gl_label_object_get_extent (object, &obj_extent);
+        y2_max = obj_extent.y2;
+       for (p = p->next; p != NULL; p = p->next)
+        {
                view_object = GL_VIEW_OBJECT (p->data);
                object = gl_view_object_get_object (view_object);
-               gl_label_object_get_extent (object, &x1, &y1, &x2, &y2);
-               if ( y2 > y2max ) y2max = y2;
+               gl_label_object_get_extent (object, &obj_extent);
+               if ( obj_extent.y2 > y2_max ) y2_max = obj_extent.y2;
        }
 
        /* now adjust the object positions to line up the bottom edges */
-       for (p = view->selected_object_list; p != NULL; p = p->next) {
+       for (p = view->selected_object_list; p != NULL; p = p->next)
+        {
                view_object = GL_VIEW_OBJECT (p->data);
                object = gl_view_object_get_object (view_object);
-               gl_label_object_get_extent (object, &x1, &y1, &x2, &y2);
-               dy = y2max - y2;
+               gl_label_object_get_extent (object, &obj_extent);
+               dy = y2_max - obj_extent.y2;
                gl_label_object_set_position_relative (object, 0.0, dy);
        }
 
@@ -2029,12 +1924,16 @@ gl_view_align_selection_vcenter (glView *view)
        GList         *p;
        glViewObject  *view_object;
        glLabelObject *object;
-       gdouble        dy, dymin, ysum, yavg, ycenter, x1, y1, x2, y2;
+       gdouble        dy;
+       gdouble        dymin;
+       gdouble        ysum, yavg;
+        glLabelRegion  obj_extent;
+       gdouble        ycenter;
        gint           n;
 
        gl_debug (DEBUG_VIEW, "START");
 
-       g_return_if_fail (GL_IS_VIEW (view));
+       g_return_if_fail (view && GL_IS_VIEW (view));
 
        g_return_if_fail (!gl_view_is_selection_empty (view) &&
                          !gl_view_is_selection_atomic (view));
@@ -2042,11 +1941,12 @@ gl_view_align_selection_vcenter (glView *view)
        /* find average center of objects */
        ysum = 0.0;
        n = 0;
-       for (p = view->selected_object_list; p != NULL; p = p->next) {
+       for (p = view->selected_object_list; p != NULL; p = p->next)
+        {
                view_object = GL_VIEW_OBJECT (p->data);
                object = gl_view_object_get_object (view_object);
-               gl_label_object_get_extent (object, &x1, &y1, &x2, &y2);
-               ysum += (y1 + y2) / 2.0;
+               gl_label_object_get_extent (object, &obj_extent);
+               ysum += (obj_extent.y1 + obj_extent.y2) / 2.0;
                n++;
        }
        yavg = ysum / n;
@@ -2055,26 +1955,29 @@ gl_view_align_selection_vcenter (glView *view)
        p = view->selected_object_list;
        view_object = GL_VIEW_OBJECT (p->data);
        object = gl_view_object_get_object (view_object);
-       gl_label_object_get_extent (object, &x1, &y1, &x2, &y2);
-       dymin = fabs (yavg - (y1 + y2)/2.0);
-       ycenter = (y1 + y2)/2.0;
-       for (p = p->next; p != NULL; p = p->next) {
+       gl_label_object_get_extent (object, &obj_extent);
+       dymin = fabs (yavg - (obj_extent.y1 + obj_extent.y2)/2.0);
+       ycenter = (obj_extent.y1 + obj_extent.y2)/2.0;
+       for (p = p->next; p != NULL; p = p->next)
+        {
                view_object = GL_VIEW_OBJECT (p->data);
                object = gl_view_object_get_object (view_object);
-               gl_label_object_get_extent (object, &x1, &y1, &x2, &y2);
-               dy = fabs (yavg - (y1 + y2)/2.0);
-               if ( dy < dymin ) {
+               gl_label_object_get_extent (object, &obj_extent);
+               dy = fabs (yavg - (obj_extent.y1 + obj_extent.y2)/2.0);
+               if ( dy < dymin )
+                {
                        dymin = dy;
-                       ycenter = (y1 + y2)/2.0;
+                       ycenter = (obj_extent.y1 + obj_extent.y2)/2.0;
                }
        }
 
        /* now adjust the object positions to line up this center */
-       for (p = view->selected_object_list; p != NULL; p = p->next) {
+       for (p = view->selected_object_list; p != NULL; p = p->next)
+        {
                view_object = GL_VIEW_OBJECT (p->data);
                object = gl_view_object_get_object (view_object);
-               gl_label_object_get_extent (object, &x1, &y1, &x2, &y2);
-               dy = ycenter - (y1 + y2)/2.0;
+               gl_label_object_get_extent (object, &obj_extent);
+               dy = ycenter - (obj_extent.y1 + obj_extent.y2)/2.0;
                gl_label_object_set_position_relative (object, 0.0, dy);
        }
 
@@ -2090,11 +1993,15 @@ gl_view_center_selection_horiz (glView *view)
        GList         *p;
        glViewObject  *view_object;
        glLabelObject *object;
-       gdouble        dx, x_label_center, x_obj_center, x1, y1, x2, y2, w, h;
+       gdouble        dx;
+       gdouble        x_label_center;
+       gdouble        x_obj_center;
+       glLabelRegion  obj_extent;
+       gdouble        w, h;
 
        gl_debug (DEBUG_VIEW, "START");
 
-       g_return_if_fail (GL_IS_VIEW (view));
+       g_return_if_fail (view && GL_IS_VIEW (view));
 
        g_return_if_fail (!gl_view_is_selection_empty (view));
 
@@ -2102,11 +2009,12 @@ gl_view_center_selection_horiz (glView *view)
        x_label_center = w / 2.0;
 
        /* adjust the object positions */
-       for (p = view->selected_object_list; p != NULL; p = p->next) {
+       for (p = view->selected_object_list; p != NULL; p = p->next)
+        {
                view_object = GL_VIEW_OBJECT (p->data);
                object = gl_view_object_get_object (view_object);
-               gl_label_object_get_extent (object, &x1, &y1, &x2, &y2);
-               x_obj_center = (x1 + x2) / 2.0;
+               gl_label_object_get_extent (object, &obj_extent);
+               x_obj_center = (obj_extent.x1 + obj_extent.x2) / 2.0;
                dx = x_label_center - x_obj_center;
                gl_label_object_set_position_relative (object, dx, 0.0);
        }
@@ -2124,11 +2032,15 @@ gl_view_center_selection_vert (glView *view)
        GList         *p;
        glViewObject  *view_object;
        glLabelObject *object;
-       gdouble        dy, y_label_center, y_obj_center, x1, y1, x2, y2, w, h;
+       gdouble        dy;
+       gdouble        y_label_center;
+       gdouble        y_obj_center;
+       glLabelRegion  obj_extent;
+       gdouble        w, h;
 
        gl_debug (DEBUG_VIEW, "START");
 
-       g_return_if_fail (GL_IS_VIEW (view));
+       g_return_if_fail (view && GL_IS_VIEW (view));
 
        g_return_if_fail (!gl_view_is_selection_empty (view));
 
@@ -2136,11 +2048,12 @@ gl_view_center_selection_vert (glView *view)
        y_label_center = h / 2.0;
 
        /* adjust the object positions */
-       for (p = view->selected_object_list; p != NULL; p = p->next) {
+       for (p = view->selected_object_list; p != NULL; p = p->next)
+        {
                view_object = GL_VIEW_OBJECT (p->data);
                object = gl_view_object_get_object (view_object);
-               gl_label_object_get_extent (object, &x1, &y1, &x2, &y2);
-               y_obj_center = (y1 + y2) / 2.0;
+               gl_label_object_get_extent (object, &obj_extent);
+               y_obj_center = (obj_extent.y1 + obj_extent.y2) / 2.0;
                dy = y_label_center - y_obj_center;
                gl_label_object_set_position_relative (object, 0.0, dy);
        }
@@ -2150,103 +2063,100 @@ gl_view_center_selection_vert (glView *view)
 
 
 /*****************************************************************************/
-/* "Cut" selected items and place in clipboard selections.                   */
+/* Move selected objects                                                     */
 /*****************************************************************************/
 void
-gl_view_cut (glView *view)
+gl_view_move_selection (glView  *view,
+                       gdouble  dx,
+                       gdouble  dy)
 {
+       GList         *p;
+       glLabelObject *object;
+
        gl_debug (DEBUG_VIEW, "START");
 
-       g_return_if_fail (GL_IS_VIEW (view));
+       g_return_if_fail (view && GL_IS_VIEW (view));
 
-       gl_view_copy (view);
-       gl_view_delete_selection (view);
+       for (p = view->selected_object_list; p != NULL; p = p->next)
+        {
+
+               object = gl_view_object_get_object(GL_VIEW_OBJECT (p->data));
+               gl_label_object_set_position_relative (object, dx, dy);
+
+       }
 
        gl_debug (DEBUG_VIEW, "END");
 }
 
 /*****************************************************************************/
-/* "Copy" selected items to clipboard selections.                            */
+/* Can text properties be set for selection?                                 */
 /*****************************************************************************/
-void
-gl_view_copy (glView *view)
+gboolean
+gl_view_can_selection_text (glView *view)
 {
-       GList *p;
-       glViewObject *view_object;
+       GList         *p;
        glLabelObject *object;
-       glTemplate *template;
-       gboolean rotate_flag;
-
-       gl_debug (DEBUG_VIEW, "START");
-
-       g_return_if_fail (GL_IS_VIEW (view));
-
-       if (view->selected_object_list) {
 
-               if ( view->selection_data ) {
-                       g_object_unref (view->selection_data);
-               }
-               template = gl_label_get_template (view->label);
-               rotate_flag = gl_label_get_rotate_flag (view->label);
-               view->selection_data = GL_LABEL(gl_label_new ());
-               gl_label_set_template (view->selection_data, template);
-               gl_label_set_rotate_flag (view->selection_data, rotate_flag);
-               gl_template_free (&template);
-
-               for (p = view->selected_object_list; p != NULL; p = p->next) {
+       gl_debug (DEBUG_VIEW, "");
 
-                       view_object = GL_VIEW_OBJECT (p->data);
-                       object = gl_view_object_get_object (view_object);
+       g_return_val_if_fail (view && GL_IS_VIEW (view), FALSE);
 
-                       gl_label_object_dup (object, view->selection_data);
+       for (p = view->selected_object_list; p != NULL; p = p->next)
+        {
 
+               object = gl_view_object_get_object(GL_VIEW_OBJECT (p->data));
+               if (gl_label_object_can_text (object))
+                {
+                       return TRUE;
                }
 
-               gtk_selection_owner_set (view->invisible,
-                                        clipboard_atom, GDK_CURRENT_TIME);
-               view->have_selection = TRUE;
-
        }
 
-       gl_debug (DEBUG_VIEW, "END");
+       return FALSE;
 }
 
 /*****************************************************************************/
-/* "Paste" from private clipboard selection.                                 */
+/* Set font family for all text contained in selected objects.               */
 /*****************************************************************************/
 void
-gl_view_paste (glView *view)
+gl_view_set_selection_font_family (glView      *view,
+                                  const gchar *font_family)
 {
+       GList         *p;
+       glLabelObject *object;
+
        gl_debug (DEBUG_VIEW, "START");
 
-       g_return_if_fail (GL_IS_VIEW (view));
+       g_return_if_fail (view && GL_IS_VIEW (view));
 
-       gtk_selection_convert (GTK_WIDGET (view->invisible),
-                              clipboard_atom, GDK_SELECTION_TYPE_STRING,
-                              GDK_CURRENT_TIME);
+       for (p = view->selected_object_list; p != NULL; p = p->next) {
+
+               object = gl_view_object_get_object(GL_VIEW_OBJECT (p->data));
+               gl_label_object_set_font_family (object, font_family);
+
+       }
 
        gl_debug (DEBUG_VIEW, "END");
 }
 
-/*---------------------------------------------------------------------------*/
-/* PRIVATE.  move selected objects                                           */
-/*---------------------------------------------------------------------------*/
-static void
-move_selection (glView  *view,
-               gdouble  dx,
-               gdouble  dy)
+/*****************************************************************************/
+/* Set font size for all text contained in selected objects.                 */
+/*****************************************************************************/
+void
+gl_view_set_selection_font_size (glView  *view,
+                                gdouble  font_size)
 {
-       GList *p;
+       GList         *p;
        glLabelObject *object;
 
        gl_debug (DEBUG_VIEW, "START");
 
-       g_return_if_fail (GL_IS_VIEW (view));
+       g_return_if_fail (view && GL_IS_VIEW (view));
 
        for (p = view->selected_object_list; p != NULL; p = p->next) {
 
                object = gl_view_object_get_object(GL_VIEW_OBJECT (p->data));
-               gl_label_object_set_position_relative (object, dx, dy);
+               gl_label_object_set_font_size (object, font_size);
 
        }
 
@@ -2254,906 +2164,607 @@ move_selection (glView  *view,
 }
 
 /*****************************************************************************/
-/* Zoom in one "notch"                                                       */
+/* Set font weight for all text contained in selected objects.               */
 /*****************************************************************************/
 void
-gl_view_zoom_in (glView *view)
+gl_view_set_selection_font_weight (glView      *view,
+                                  PangoWeight  font_weight)
 {
-       gint i, i_min;
-       gdouble dist, dist_min;
+       GList         *p;
+       glLabelObject *object;
 
        gl_debug (DEBUG_VIEW, "START");
 
-       g_return_if_fail (GL_IS_VIEW (view));
+       g_return_if_fail (view && GL_IS_VIEW (view));
 
-       /* Find index of current scale (or best match) */
-       i_min = 1;              /* start with 2nd largest scale */
-       dist_min = fabs (scales[1] - view->scale);
-       for (i = 2; i < N_SCALES; i++) {
-               dist = fabs (scales[i] - view->scale);
-               if (dist < dist_min) {
-                       i_min = i;
-                       dist_min = dist;
-               }
-       }
+       for (p = view->selected_object_list; p != NULL; p = p->next) {
 
-       /* zoom in one "notch" */
-       i = MAX (0, i_min - 1);
-       gl_view_set_zoom (view, scales[i] / HOME_SCALE);
+               object = gl_view_object_get_object(GL_VIEW_OBJECT (p->data));
+               gl_label_object_set_font_weight (object, font_weight);
+
+       }
 
        gl_debug (DEBUG_VIEW, "END");
 }
 
 /*****************************************************************************/
-/* Zoom out one "notch"                                                      */
+/* Set font italic flag for all text contained in selected objects.          */
 /*****************************************************************************/
 void
-gl_view_zoom_out (glView *view)
+gl_view_set_selection_font_italic_flag (glView   *view,
+                                       gboolean  font_italic_flag)
 {
-       gint i, i_min;
-       gdouble dist, dist_min;
+       GList         *p;
+       glLabelObject *object;
 
        gl_debug (DEBUG_VIEW, "START");
 
-       g_return_if_fail (GL_IS_VIEW (view));
+       g_return_if_fail (view && GL_IS_VIEW (view));
 
-       /* Find index of current scale (or best match) */
-       i_min = 0;              /* start with largest scale */
-       dist_min = fabs (scales[0] - view->scale);
-       for (i = 1; i < N_SCALES; i++) {
-               dist = fabs (scales[i] - view->scale);
-               if (dist < dist_min) {
-                       i_min = i;
-                       dist_min = dist;
-               }
-       }
+       for (p = view->selected_object_list; p != NULL; p = p->next) {
 
-       /* zoom out one "notch" */
-       if (i_min >= N_SCALES)
-               return;
-       i = i_min + 1;
-       if (i >= N_SCALES)
-               return;
-       gl_view_set_zoom (view, scales[i] / HOME_SCALE);
+               object = gl_view_object_get_object(GL_VIEW_OBJECT (p->data));
+               gl_label_object_set_font_italic_flag (object, font_italic_flag);
+
+       }
 
        gl_debug (DEBUG_VIEW, "END");
 }
 
 /*****************************************************************************/
-/* Set current zoom factor to explicit value.                                */
+/* Set text alignment for all text contained in selected objects.            */
 /*****************************************************************************/
 void
-gl_view_set_zoom (glView  *view,
-                 gdouble scale)
+gl_view_set_selection_text_alignment (glView            *view,
+                                     PangoAlignment     text_alignment)
 {
+       GList         *p;
+       glLabelObject *object;
+
        gl_debug (DEBUG_VIEW, "START");
 
-       g_return_if_fail (GL_IS_VIEW (view));
-       g_return_if_fail (scale > 0.0);
+       g_return_if_fail (view && GL_IS_VIEW (view));
+
+       for (p = view->selected_object_list; p != NULL; p = p->next) {
 
-       view->scale = scale * HOME_SCALE;
-       gnome_canvas_set_pixels_per_unit (GNOME_CANVAS (view->canvas),
-                                         scale * HOME_SCALE);
+               object = gl_view_object_get_object(GL_VIEW_OBJECT (p->data));
+               gl_label_object_set_text_alignment (object, text_alignment);
 
-       g_signal_emit (G_OBJECT(view), signals[ZOOM_CHANGED], 0, scale);
+       }
 
        gl_debug (DEBUG_VIEW, "END");
 }
 
 /*****************************************************************************/
-/* Get current zoom factor.                                                  */
+/* Set text line spacing for all text contained in selected objects.         */
 /*****************************************************************************/
-gdouble
-gl_view_get_zoom (glView *view)
+void
+gl_view_set_selection_text_line_spacing (glView  *view,
+                                        gdouble  text_line_spacing)
 {
-       gl_debug (DEBUG_VIEW, "");
+       GList         *p;
+       glLabelObject *object;
 
-       g_return_val_if_fail (GL_IS_VIEW (view), 1.0);
+       gl_debug (DEBUG_VIEW, "START");
 
-       return view->scale / HOME_SCALE;
-}
+       g_return_if_fail (view && GL_IS_VIEW (view));
 
-/*****************************************************************************/
-/* Is this the maximum zoom level.                                           */
-/*****************************************************************************/
-gboolean
-gl_view_is_zoom_max (glView *view)
-{
-       gl_debug (DEBUG_VIEW, "");
+       for (p = view->selected_object_list; p != NULL; p = p->next) {
 
-       g_return_val_if_fail (GL_IS_VIEW (view), FALSE);
+               object = gl_view_object_get_object(GL_VIEW_OBJECT (p->data));
+               gl_label_object_set_text_line_spacing (object, text_line_spacing);
 
-       return view->scale >= scales[0];
-}
+       }
 
+       gl_debug (DEBUG_VIEW, "END");
+}
 /*****************************************************************************/
-/* Is this the minimum zoom level.                                           */
+/* Set text color for all text contained in selected objects.                */
 /*****************************************************************************/
-gboolean
-gl_view_is_zoom_min (glView *view)
+void
+gl_view_set_selection_text_color (glView      *view,
+                                 glColorNode *text_color_node)
 {
-       gl_debug (DEBUG_VIEW, "");
+       GList         *p;
+       glLabelObject *object;
 
-       g_return_val_if_fail (GL_IS_VIEW (view), FALSE);
+       gl_debug (DEBUG_VIEW, "START");
+
+       g_return_if_fail (view && GL_IS_VIEW (view));
+
+       for (p = view->selected_object_list; p != NULL; p = p->next) {
+
+               object = gl_view_object_get_object(GL_VIEW_OBJECT (p->data));
+               gl_label_object_set_text_color (object, text_color_node);
 
-       return view->scale <= scales[N_SCALES-1];
+       }
+
+       gl_debug (DEBUG_VIEW, "END");
 }
 
 /*****************************************************************************/
-/* Launch merge properties dialog.                                           */
+/* Can fill properties be set for selection?                                 */
 /*****************************************************************************/
-void
-gl_view_edit_merge_props (glView *view)
+gboolean
+gl_view_can_selection_fill (glView *view)
 {
+       GList         *p;
+       glLabelObject *object;
+
        gl_debug (DEBUG_VIEW, "");
 
-       g_return_if_fail (GL_IS_VIEW (view));
+       g_return_val_if_fail (view && GL_IS_VIEW (view), FALSE);
 
-       if (view->merge_props_dialog != NULL) {
-               gtk_widget_show_all (view->merge_props_dialog);
-               gtk_window_present (GTK_WINDOW(view->merge_props_dialog));
-               return;
-       }
+       for (p = view->selected_object_list; p != NULL; p = p->next) {
+
+               object = gl_view_object_get_object(GL_VIEW_OBJECT (p->data));
+               if (gl_label_object_can_fill (object)) {
+                       return TRUE;
+               }
 
-       view->merge_props_dialog = gl_merge_properties_dialog_new (view);
-       gtk_widget_show_all (view->merge_props_dialog);
+       }
 
-       g_signal_connect (G_OBJECT(view->merge_props_dialog), "destroy",
-                         G_CALLBACK (gtk_widget_destroyed),
-                         &view->merge_props_dialog);
+       return FALSE;
 }
 
-/*---------------------------------------------------------------------------*/
-/* PRIVATE.  Canvas event handler.                                           */
-/*---------------------------------------------------------------------------*/
-static int
-canvas_event (GnomeCanvas *canvas,
-             GdkEvent    *event,
-             glView      *view)
+/*****************************************************************************/
+/* Set fill color for all selected objects.                                  */
+/*****************************************************************************/
+void
+gl_view_set_selection_fill_color (glView      *view,
+                                 glColorNode *fill_color_node)
 {
-       gdouble x, y;
+       GList         *p;
+       glLabelObject *object;
 
-       gl_debug (DEBUG_VIEW, "");
+       gl_debug (DEBUG_VIEW, "START");
 
-       /* emit pointer signals regardless of state */
-       switch (event->type) {
-       case GDK_MOTION_NOTIFY:
-               gl_debug (DEBUG_VIEW, "MOTION_NOTIFY");
-               gnome_canvas_window_to_world (canvas,
-                                             event->motion.x,
-                                             event->motion.y, &x, &y);
-               g_signal_emit (G_OBJECT(view), signals[POINTER_MOVED], 0, x, y);
-               break; /* fall through */
-
-       case GDK_LEAVE_NOTIFY:
-               gl_debug (DEBUG_VIEW, "LEAVEW_NOTIFY");
-               g_signal_emit (G_OBJECT(view), signals[POINTER_EXIT], 0);
-               break; /* fall through */
+       g_return_if_fail (view && GL_IS_VIEW (view));
 
-       default:
-               break; /* fall through */
-       }
-
-
-       switch (view->state) {
-
-       case GL_VIEW_STATE_ARROW:
-               return canvas_event_arrow_mode (canvas, event, view);
-
-       case GL_VIEW_STATE_OBJECT_CREATE:
-               switch (view->create_type) {
-               case GL_LABEL_OBJECT_BOX:
-                       return gl_view_box_create_event_handler (canvas,
-                                                                event,
-                                                                view);
-                       break;
-               case GL_LABEL_OBJECT_ELLIPSE:
-                       return gl_view_ellipse_create_event_handler (canvas,
-                                                                    event,
-                                                                    view);
-                       break;
-               case GL_LABEL_OBJECT_LINE:
-                       return gl_view_line_create_event_handler (canvas,
-                                                                 event,
-                                                                 view);
-                       break;
-               case GL_LABEL_OBJECT_IMAGE:
-                       return gl_view_image_create_event_handler (canvas,
-                                                                  event,
-                                                                  view);
-                       break;
-               case GL_LABEL_OBJECT_TEXT:
-                       return gl_view_text_create_event_handler (canvas,
-                                                                 event,
-                                                                 view);
-                       break;
-               case GL_LABEL_OBJECT_BARCODE:
-                       return gl_view_barcode_create_event_handler (canvas,
-                                                                    event,
-                                                                    view);
-                       break;
-               default:
-                        /*Should not happen!*/
-                       g_warning ("Invalid label object type.");
-                       return FALSE;
-       }
+       for (p = view->selected_object_list; p != NULL; p = p->next) {
 
-       default:
-               g_warning ("Invalid view state.");      /*Should not happen!*/
-               return FALSE;
+               object = gl_view_object_get_object(GL_VIEW_OBJECT (p->data));
+               gl_label_object_set_fill_color (object, fill_color_node);
 
        }
+
+       gl_debug (DEBUG_VIEW, "END");
 }
 
-/*---------------------------------------------------------------------------*/
-/* PRIVATE.  Canvas event handler (arrow mode)                               */
-/*---------------------------------------------------------------------------*/
-static int
-canvas_event_arrow_mode (GnomeCanvas *canvas,
-                        GdkEvent    *event,
-                        glView      *view)
+/*****************************************************************************/
+/* Can line color properties be set for selection?                           */
+/*****************************************************************************/
+gboolean
+gl_view_can_selection_line_color (glView *view)
 {
-       static gdouble x0, y0;
-       static gboolean dragging = FALSE;
-       static GnomeCanvasItem *item;
-       gdouble x, y, x1, y1, x2, y2;
-       GnomeCanvasGroup *group;
-       GdkCursor *cursor;
+       GList         *p;
+       glLabelObject *object;
 
        gl_debug (DEBUG_VIEW, "");
 
-       switch (event->type) {
-
-       case GDK_BUTTON_PRESS:
-               gl_debug (DEBUG_VIEW, "BUTTON_PRESS");
-               switch (event->button.button) {
-               case 1:
-                       gnome_canvas_window_to_world (canvas,
-                                                     event->button.x,
-                                                     event->button.y, &x, &y);
-
-                       if (!object_at (view, x, y)) {
-                               if (!(event->button.state & GDK_CONTROL_MASK)) {
-                                       gl_view_unselect_all (view);
-                               }
-
-                               dragging = TRUE;
-                               gnome_canvas_item_grab (canvas->root,
-                                                       GDK_POINTER_MOTION_MASK |
-                                                       GDK_BUTTON_RELEASE_MASK |
-                                                       GDK_BUTTON_PRESS_MASK,
-                                                       NULL, event->button.time);
-                               group =
-                                   gnome_canvas_root (GNOME_CANVAS
-                                                      (view->canvas));
-                               item =
-                                   gnome_canvas_item_new (group,
-                                                          gnome_canvas_rect_get_type (),
-                                                          "x1", x, "y1", y,
-                                                          "x2", x, "y2", y,
-                                                          "width_pixels", 2,
-                                                          "outline_color_rgba",
-                                                          SEL_LINE_COLOR,
-                                                          "fill_color_rgba",
-                                                          SEL_FILL_COLOR,
-                                                          NULL);
-                               x0 = x;
-                               y0 = y;
-
-                       }
-                       return FALSE;
-               case 3:
-                       gnome_canvas_window_to_world (canvas,
-                                                     event->button.x,
-                                                     event->button.y, &x, &y);
-
-                       if (!object_at (view, x, y)) {
-                               /* bring up apropriate menu for selection. */
-                               popup_menu (view, event);
-                       }
-                       return FALSE;
-               default:
-                       return FALSE;
-               }
-
-       case GDK_BUTTON_RELEASE:
-               gl_debug (DEBUG_VIEW, "BUTTON_RELEASE");
-               switch (event->button.button) {
-               case 1:
-                       if (dragging) {
-                               dragging = FALSE;
-                               gnome_canvas_item_ungrab (canvas->root,
-                                                         event->button.time);
-                               gnome_canvas_window_to_world (canvas,
-                                                             event->button.x,
-                                                             event->button.y,
-                                                             &x, &y);
-                               x1 = MIN (x, x0);
-                               y1 = MIN (y, y0);
-                               x2 = MAX (x, x0);
-                               y2 = MAX (y, y0);
-                               gl_view_select_region (view, x1, y1, x2, y2);
-                               gtk_object_destroy (GTK_OBJECT (item));
-                               return TRUE;
-                       }
-                       return FALSE;
+       g_return_val_if_fail (view && GL_IS_VIEW (view), FALSE);
 
-               default:
-                       return FALSE;
-               }
+       for (p = view->selected_object_list; p != NULL; p = p->next) {
 
-       case GDK_MOTION_NOTIFY:
-               gl_debug (DEBUG_VIEW, "MOTION_NOTIFY");
-               gnome_canvas_window_to_world (canvas,
-                                             event->motion.x,
-                                             event->motion.y, &x, &y);
-               if (dragging && (event->motion.state & GDK_BUTTON1_MASK)) {
-                       gnome_canvas_item_set (item,
-                                              "x1", MIN (x, x0),
-                                              "y1", MIN (y, y0),
-                                              "x2", MAX (x, x0),
-                                              "y2", MAX (y, y0), NULL);
+               object = gl_view_object_get_object(GL_VIEW_OBJECT (p->data));
+               if (gl_label_object_can_line_color (object)) {
                        return TRUE;
-               } else {
-                       return FALSE;
-               }
-
-       case GDK_KEY_PRESS:
-               gl_debug (DEBUG_VIEW, "KEY_PRESS");
-               if (!dragging) {
-                       switch (event->key.keyval) {
-                       case GDK_Left:
-                       case GDK_KP_Left:
-                               move_selection (view,
-                                               -1.0 / (view->scale), 0.0);
-                               break;
-                       case GDK_Up:
-                       case GDK_KP_Up:
-                               move_selection (view,
-                                               0.0, -1.0 / (view->scale));
-                               break;
-                       case GDK_Right:
-                       case GDK_KP_Right:
-                               move_selection (view,
-                                               1.0 / (view->scale), 0.0);
-                               break;
-                       case GDK_Down:
-                       case GDK_KP_Down:
-                               move_selection (view,
-                                               0.0, 1.0 / (view->scale));
-                               break;
-                       case GDK_Delete:
-                       case GDK_KP_Delete:
-                               gl_view_delete_selection (view);
-                               cursor = gdk_cursor_new (GDK_LEFT_PTR);
-                               gdk_window_set_cursor (view->canvas->window,
-                                                      cursor);
-                               gdk_cursor_unref (cursor);
-                               break;
-                       default:
-                               return FALSE;
-                       }
                }
-               return TRUE;    /* We handled this or we were dragging. */
 
-       default:
-               gl_debug (DEBUG_VIEW, "default");
-               return FALSE;
        }
 
+       return FALSE;
 }
 
 /*****************************************************************************/
-/* Item event handler.                                                       */
+/* Set line color for all selected objects.                                  */
 /*****************************************************************************/
-gint
-gl_view_item_event_handler (GnomeCanvasItem *item,
-                           GdkEvent        *event,
-                           glViewObject    *view_object)
+void
+gl_view_set_selection_line_color (glView      *view,
+                                 glColorNode *line_color_node)
 {
-       glView *view;
+       GList         *p;
+       glLabelObject *object;
 
-       gl_debug (DEBUG_VIEW, "");
+       gl_debug (DEBUG_VIEW, "START");
 
-       view = gl_view_object_get_view(view_object);
-       switch (view->state) {
+       g_return_if_fail (view && GL_IS_VIEW (view));
 
-       case GL_VIEW_STATE_ARROW:
-               return item_event_arrow_mode (item, event, view_object);
+       for (p = view->selected_object_list; p != NULL; p = p->next) {
 
-       default:
-               return FALSE;
+               object = gl_view_object_get_object(GL_VIEW_OBJECT (p->data));
+               gl_label_object_set_line_color (object, line_color_node);
 
        }
 
+       gl_debug (DEBUG_VIEW, "END");
 }
 
-/*---------------------------------------------------------------------------*/
-/* PRIVATE.  Item event handler (arrow mode)                                 */
-/*---------------------------------------------------------------------------*/
-static int
-item_event_arrow_mode (GnomeCanvasItem *item,
-                      GdkEvent        *event,
-                      glViewObject    *view_object)
+/*****************************************************************************/
+/* Can line width properties be set for selection?                           */
+/*****************************************************************************/
+gboolean
+gl_view_can_selection_line_width (glView *view)
 {
-       static gdouble x, y;
-       static gboolean dragging = FALSE;
-       glView *view;
-       GdkCursor *cursor;
-       gdouble item_x, item_y;
-       gdouble new_x, new_y;
-       gboolean control_key_pressed;
+       GList         *p;
+       glLabelObject *object;
 
        gl_debug (DEBUG_VIEW, "");
 
-       item_x = event->button.x;
-       item_y = event->button.y;
-       gnome_canvas_item_w2i (item->parent, &item_x, &item_y);
-
-       view = gl_view_object_get_view(view_object);
-
-       switch (event->type) {
-
-       case GDK_BUTTON_PRESS:
-               gl_debug (DEBUG_VIEW, "BUTTON_PRESS");
-               control_key_pressed = event->button.state & GDK_CONTROL_MASK;
-               switch (event->button.button) {
-               case 1:
-                       if (control_key_pressed) {
-                               if (is_object_selected (view, view_object)) {
-                                       /* Un-selecting a selected item */
-                                       gl_view_unselect_object (view,
-                                                                view_object);
-                                       return TRUE;
-                               } else {
-                                       /* Add to current selection */
-                                       gl_view_select_object (view,
-                                                              view_object);
-                               }
-                       } else {
-                               if (!is_object_selected (view, view_object)) {
-                                       /* No control, key so remove any selections before adding */
-                                       gl_view_unselect_all (view);
-                                       /* Add to current selection */
-                                       gl_view_select_object (view,
-                                                              view_object);
-                               }
-                       }
-                       /* Go into dragging mode while button remains pressed. */
-                       x = item_x;
-                       y = item_y;
-                       cursor = gdk_cursor_new (GDK_FLEUR);
-                       gnome_canvas_item_grab (item,
-                                               GDK_POINTER_MOTION_MASK |
-                                               GDK_BUTTON_RELEASE_MASK |
-                                               GDK_BUTTON_PRESS_MASK,
-                                               cursor, event->button.time);
-                       gdk_cursor_unref (cursor);
-                       dragging = TRUE;
-                       return TRUE;
-
-               case 3:
-                       if (!is_object_selected (view, view_object)) {
-                               if (!control_key_pressed) {
-                                       /* No control, key so remove any selections before adding */
-                                       gl_view_unselect_all (view);
-                               }
-                       }
-                       /* Add to current selection */
-                       gl_view_select_object (view, view_object);
-                       /* bring up apropriate menu for selection. */
-                       popup_menu (view, event);
-                       return TRUE;
-
-               default:
-                       return FALSE;
-               }
-
-       case GDK_BUTTON_RELEASE:
-               gl_debug (DEBUG_VIEW, "BUTTON_RELEASE");
-               switch (event->button.button) {
-               case 1:
-                       /* Exit dragging mode */
-                       gnome_canvas_item_ungrab (item, event->button.time);
-                       dragging = FALSE;
-                       return TRUE;
-
-               default:
-                       return FALSE;
-               }
+       g_return_val_if_fail (view && GL_IS_VIEW (view), FALSE);
 
-       case GDK_MOTION_NOTIFY:
-               gl_debug (DEBUG_VIEW, "MOTION_NOTIFY");
-               if (dragging && (event->motion.state & GDK_BUTTON1_MASK)) {
-                       /* Dragging mode, move selection */
-                       new_x = item_x;
-                       new_y = item_y;
-                       move_selection (view, (new_x - x), (new_y - y));
-                       x = new_x;
-                       y = new_y;
-                       return TRUE;
-               } else {
-                       return FALSE;
-               }
+       for (p = view->selected_object_list; p != NULL; p = p->next) {
 
-       case GDK_2BUTTON_PRESS:
-               gl_debug (DEBUG_VIEW, "2BUTTON_PRESS");
-               switch (event->button.button) {
-               case 1:
-                       /* Also exit dragging mode w/ double-click, run dlg */
-                       gnome_canvas_item_ungrab (item, event->button.time);
-                       dragging = FALSE;
-                       gl_view_select_object (view, view_object);
-                       gl_view_object_show_dialog (view_object);
+               object = gl_view_object_get_object(GL_VIEW_OBJECT (p->data));
+               if (gl_label_object_can_line_width (object)) {
                        return TRUE;
-
-               default:
-                       return FALSE;
                }
 
-       case GDK_ENTER_NOTIFY:
-               gl_debug (DEBUG_VIEW, "ENTER_NOTIFY");
-               cursor = gdk_cursor_new (GDK_FLEUR);
-               gdk_window_set_cursor (view->canvas->window, cursor);
-               gdk_cursor_unref (cursor);
-               return TRUE;
-
-       case GDK_LEAVE_NOTIFY:
-               gl_debug (DEBUG_VIEW, "LEAVE_NOTIFY");
-               cursor = gdk_cursor_new (GDK_LEFT_PTR);
-               gdk_window_set_cursor (view->canvas->window, cursor);
-               gdk_cursor_unref (cursor);
-               return TRUE;
-
-       default:
-               gl_debug (DEBUG_VIEW, "default");
-               return FALSE;
        }
 
+       return FALSE;
 }
 
-/*---------------------------------------------------------------------------*/
-/* PRIVATE.  create menu for selections.                                     */
-/*---------------------------------------------------------------------------*/
+/*****************************************************************************/
+/* Set line width for all selected objects.                                  */
+/*****************************************************************************/
 void
-construct_selection_menu (glView *view)
+gl_view_set_selection_line_width (glView  *view,
+                                 gdouble  line_width)
 {
-       GtkWidget *menu, *menuitem, *submenu;
+       GList         *p;
+       glLabelObject *object;
 
        gl_debug (DEBUG_VIEW, "START");
 
-       g_return_if_fail (GL_IS_VIEW (view));
+       g_return_if_fail (view && GL_IS_VIEW (view));
 
-       menu = gtk_menu_new ();
-
-       menuitem = gtk_image_menu_item_new_from_stock (GL_STOCK_PROPERTIES, NULL);
-       gtk_menu_shell_append (GTK_MENU_SHELL (menu), menuitem);
-       gtk_widget_show (menuitem);
-       g_signal_connect_swapped (G_OBJECT (menuitem), "activate",
-                                 G_CALLBACK (gl_view_edit_object_props), view);
-       view->atomic_selection_items =
-               g_list_prepend (view->atomic_selection_items, menuitem);
-
-       /*
-        * Separator -------------------------
-        */
-       menuitem = gtk_menu_item_new ();
-       gtk_menu_shell_append (GTK_MENU_SHELL (menu), menuitem);
-       gtk_widget_show (menuitem);
-
-       /*
-        * Submenu: Order
-        */
-       menuitem = gtk_menu_item_new_with_mnemonic (_("_Order"));
-       gtk_menu_shell_append (GTK_MENU_SHELL (menu), menuitem);
-       gtk_widget_show (menuitem);
-       submenu = gtk_menu_new ();
-       gtk_menu_item_set_submenu (GTK_MENU_ITEM (menuitem), submenu);
-
-       menuitem = gtk_image_menu_item_new_from_stock (GL_STOCK_ORDER_TOP, NULL);
-       gtk_menu_shell_append (GTK_MENU_SHELL (submenu), menuitem);
-       gtk_widget_show (menuitem);
-       g_signal_connect_swapped (G_OBJECT (menuitem), "activate",
-                                 G_CALLBACK (gl_view_raise_selection), view);
-
-       menuitem = gtk_image_menu_item_new_from_stock (GL_STOCK_ORDER_BOTTOM, NULL);
-       gtk_menu_shell_append (GTK_MENU_SHELL (submenu), menuitem);
-       gtk_widget_show (menuitem);
-       g_signal_connect_swapped (G_OBJECT (menuitem), "activate",
-                                 G_CALLBACK (gl_view_lower_selection), view);
-
-       /*
-        * Submenu: Rotate/Flip
-        */
-       menuitem = gtk_menu_item_new_with_mnemonic (_("_Rotate/Flip"));
-       gtk_menu_shell_append (GTK_MENU_SHELL (menu), menuitem);
-       gtk_widget_show (menuitem);
-       submenu = gtk_menu_new ();
-       gtk_menu_item_set_submenu (GTK_MENU_ITEM (menuitem), submenu);
-
-       menuitem = gtk_image_menu_item_new_from_stock (GL_STOCK_ROTATE_LEFT, NULL);
-       gtk_menu_shell_append (GTK_MENU_SHELL (submenu), menuitem);
-       gtk_widget_show (menuitem);
-       g_signal_connect_swapped (G_OBJECT (menuitem), "activate",
-                                 G_CALLBACK (gl_view_rotate_selection_left), view);
-
-       menuitem = gtk_image_menu_item_new_from_stock (GL_STOCK_ROTATE_RIGHT, NULL);
-       gtk_menu_shell_append (GTK_MENU_SHELL (submenu), menuitem);
-       gtk_widget_show (menuitem);
-       g_signal_connect_swapped (G_OBJECT (menuitem), "activate",
-                                 G_CALLBACK (gl_view_rotate_selection_right), view);
-
-       menuitem = gtk_image_menu_item_new_from_stock (GL_STOCK_FLIP_HORIZ, NULL);
-       gtk_menu_shell_append (GTK_MENU_SHELL (submenu), menuitem);
-       gtk_widget_show (menuitem);
-       g_signal_connect_swapped (G_OBJECT (menuitem), "activate",
-                                 G_CALLBACK (gl_view_flip_selection_horiz), view);
-
-       menuitem = gtk_image_menu_item_new_from_stock (GL_STOCK_FLIP_VERT, NULL);
-       gtk_menu_shell_append (GTK_MENU_SHELL (submenu), menuitem);
-       gtk_widget_show (menuitem);
-       g_signal_connect_swapped (G_OBJECT (menuitem), "activate",
-                                 G_CALLBACK (gl_view_flip_selection_vert), view);
-
-       /*
-        * Submenu: Align Horizontally
-        */
-       menuitem = gtk_menu_item_new_with_mnemonic (_("Align _Horizontally"));
-       gtk_menu_shell_append (GTK_MENU_SHELL (menu), menuitem);
-       gtk_widget_show (menuitem);
-       submenu = gtk_menu_new ();
-       gtk_menu_item_set_submenu (GTK_MENU_ITEM (menuitem), submenu);
-
-       menuitem = gtk_image_menu_item_new_from_stock (GL_STOCK_ALIGN_LEFT, NULL);
-       gtk_menu_shell_append (GTK_MENU_SHELL (submenu), menuitem);
-       gtk_widget_show (menuitem);
-       g_signal_connect_swapped (G_OBJECT (menuitem), "activate",
-                                 G_CALLBACK (gl_view_align_selection_left), view);
-       view->multi_selection_items =
-               g_list_prepend (view->multi_selection_items, menuitem);
-
-       menuitem = gtk_image_menu_item_new_from_stock (GL_STOCK_ALIGN_HCENTER, NULL);
-       gtk_menu_shell_append (GTK_MENU_SHELL (submenu), menuitem);
-       gtk_widget_show (menuitem);
-       g_signal_connect_swapped (G_OBJECT (menuitem), "activate",
-                                 G_CALLBACK (gl_view_align_selection_hcenter), view);
-       view->multi_selection_items =
-               g_list_prepend (view->multi_selection_items, menuitem);
-
-       menuitem = gtk_image_menu_item_new_from_stock (GL_STOCK_ALIGN_RIGHT, NULL);
-       gtk_menu_shell_append (GTK_MENU_SHELL (submenu), menuitem);
-       gtk_widget_show (menuitem);
-       g_signal_connect_swapped (G_OBJECT (menuitem), "activate",
-                                 G_CALLBACK (gl_view_align_selection_right), view);
-       view->multi_selection_items =
-               g_list_prepend (view->multi_selection_items, menuitem);
-
-       menuitem = gtk_image_menu_item_new_from_stock (GL_STOCK_CENTER_HORIZ, NULL);
-       gtk_menu_shell_append (GTK_MENU_SHELL (submenu), menuitem);
-       gtk_widget_show (menuitem);
-       g_signal_connect_swapped (G_OBJECT (menuitem), "activate",
-                                 G_CALLBACK (gl_view_center_selection_horiz), view);
-
-       /*
-        * Submenu: Align Vertically
-        */
-       menuitem = gtk_menu_item_new_with_mnemonic (_("Align _Vertically"));
-       gtk_menu_shell_append (GTK_MENU_SHELL (menu), menuitem);
-       gtk_widget_show (menuitem);
-       submenu = gtk_menu_new ();
-       gtk_menu_item_set_submenu (GTK_MENU_ITEM (menuitem), submenu);
-
-       menuitem = gtk_image_menu_item_new_from_stock (GL_STOCK_ALIGN_TOP, NULL);
-       gtk_menu_shell_append (GTK_MENU_SHELL (submenu), menuitem);
-       gtk_widget_show (menuitem);
-       g_signal_connect_swapped (G_OBJECT (menuitem), "activate",
-                                 G_CALLBACK (gl_view_align_selection_top), view);
-       view->multi_selection_items =
-               g_list_prepend (view->multi_selection_items, menuitem);
-
-       menuitem = gtk_image_menu_item_new_from_stock (GL_STOCK_ALIGN_VCENTER, NULL);
-       gtk_menu_shell_append (GTK_MENU_SHELL (submenu), menuitem);
-       gtk_widget_show (menuitem);
-       g_signal_connect_swapped (G_OBJECT (menuitem), "activate",
-                                 G_CALLBACK (gl_view_align_selection_vcenter), view);
-       view->multi_selection_items =
-               g_list_prepend (view->multi_selection_items, menuitem);
-
-       menuitem = gtk_image_menu_item_new_from_stock (GL_STOCK_ALIGN_BOTTOM, NULL);
-       gtk_menu_shell_append (GTK_MENU_SHELL (submenu), menuitem);
-       gtk_widget_show (menuitem);
-       g_signal_connect_swapped (G_OBJECT (menuitem), "activate",
-                                 G_CALLBACK (gl_view_align_selection_bottom), view);
-       view->multi_selection_items =
-               g_list_prepend (view->multi_selection_items, menuitem);
-
-       menuitem = gtk_image_menu_item_new_from_stock (GL_STOCK_CENTER_VERT, NULL);
-       gtk_menu_shell_append (GTK_MENU_SHELL (submenu), menuitem);
-       gtk_widget_show (menuitem);
-       g_signal_connect_swapped (G_OBJECT (menuitem), "activate",
-                                 G_CALLBACK (gl_view_center_selection_vert), view);
-
-       /*
-        * Separator -------------------------
-        */
-       menuitem = gtk_menu_item_new ();
-       gtk_menu_shell_append (GTK_MENU_SHELL (menu), menuitem);
-       gtk_widget_show (menuitem);
-
-       menuitem = gtk_image_menu_item_new_from_stock (GTK_STOCK_CUT, NULL);
-       gtk_menu_shell_append (GTK_MENU_SHELL (menu), menuitem);
-       gtk_widget_show (menuitem);
-       g_signal_connect_swapped (G_OBJECT (menuitem), "activate",
-                                 G_CALLBACK (gl_view_cut), view);
-
-       menuitem = gtk_image_menu_item_new_from_stock (GTK_STOCK_COPY, NULL);
-       gtk_menu_shell_append (GTK_MENU_SHELL (menu), menuitem);
-       gtk_widget_show (menuitem);
-       g_signal_connect_swapped (G_OBJECT (menuitem), "activate",
-                                 G_CALLBACK (gl_view_copy), view);
-
-       menuitem = gtk_image_menu_item_new_from_stock (GTK_STOCK_PASTE, NULL);
-       gtk_menu_shell_append (GTK_MENU_SHELL (menu), menuitem);
-       gtk_widget_show (menuitem);
-       g_signal_connect_swapped (G_OBJECT (menuitem), "activate",
-                                 G_CALLBACK (gl_view_paste), view);
-
-       menuitem = gtk_menu_item_new_with_mnemonic (_("_Delete"));
-       gtk_menu_shell_append (GTK_MENU_SHELL (menu), menuitem);
-       gtk_widget_show (menuitem);
-       g_signal_connect_swapped (G_OBJECT (menuitem), "activate",
-                                 G_CALLBACK (gl_view_delete_selection), view);
-
-
-       view->selection_menu = menu;
-
-       gl_debug (DEBUG_VIEW, "END");
-}
-
-/*---------------------------------------------------------------------------*/
-/* PRIVATE.  create menu for empty selections.                               */
-/*---------------------------------------------------------------------------*/
-void
-construct_empty_selection_menu (glView *view)
-{
-       GtkWidget *menu, *menuitem, *submenu;
+       for (p = view->selected_object_list; p != NULL; p = p->next) {
 
-       gl_debug (DEBUG_VIEW, "START");
+               object = gl_view_object_get_object(GL_VIEW_OBJECT (p->data));
+               gl_label_object_set_line_width (object, line_width);
 
-       g_return_if_fail (GL_IS_VIEW (view));
+       }
 
-       menu = gtk_menu_new ();
+       gl_debug (DEBUG_VIEW, "END");
+}
 
-       menuitem = gtk_image_menu_item_new_from_stock (GTK_STOCK_PASTE, NULL);
-       gtk_menu_shell_append (GTK_MENU_SHELL (menu), menuitem);
-       gtk_widget_show (menuitem);
-       g_signal_connect_swapped (G_OBJECT (menuitem), "activate",
-                                 G_CALLBACK (gl_view_paste), view);
+/*****************************************************************************/
+/* "Cut" selected items and place in clipboard selections.                   */
+/*****************************************************************************/
+void
+gl_view_cut (glView *view)
+{
+       gl_debug (DEBUG_VIEW, "START");
 
+       g_return_if_fail (view && GL_IS_VIEW (view));
 
-       view->empty_selection_menu = menu;
+       gl_view_copy (view);
+       gl_view_delete_selection (view);
 
        gl_debug (DEBUG_VIEW, "END");
 }
 
-/*---------------------------------------------------------------------------*/
-/* PRIVATE.  popup menu for given item.                                      */
-/*---------------------------------------------------------------------------*/
-static void
-popup_menu (glView       *view,
-           GdkEvent     *event)
+/*****************************************************************************/
+/* "Copy" selected items to clipboard selections.                            */
+/*****************************************************************************/
+void
+gl_view_copy (glView *view)
 {
-       GtkMenu *menu;
-       GList   *p;
+       GList         *p;
+       glViewObject  *view_object;
+       glLabelObject *object;
 
        gl_debug (DEBUG_VIEW, "START");
 
-       g_return_if_fail (GL_IS_VIEW (view));
+       g_return_if_fail (view && GL_IS_VIEW (view));
 
-       if (gl_view_is_selection_empty (view)) {
+       if (view->selected_object_list) {
 
-               if (view->empty_selection_menu != NULL) {
-                       gtk_menu_popup (GTK_MENU (view->empty_selection_menu),
-                                       NULL, NULL, NULL, NULL,
-                                       event->button.button,
-                                       event->button.time);
+               if ( view->selection_data ) {
+                       g_object_unref (view->selection_data);
                }
+               view->selection_data = GL_LABEL(gl_label_new ());
+               gl_label_set_template (view->selection_data, view->label->template);
+               gl_label_set_rotate_flag (view->selection_data, view->label->rotate_flag);
 
-       } else {
+               for (p = view->selected_object_list; p != NULL; p = p->next) {
 
-               for (p=view->atomic_selection_items; p!=NULL; p=p->next) {
-                       gtk_widget_set_sensitive (GTK_WIDGET(p->data),
-                                                 gl_view_is_selection_atomic(view));
-               }
+                       view_object = GL_VIEW_OBJECT (p->data);
+                       object = gl_view_object_get_object (view_object);
 
-               for (p=view->multi_selection_items; p!=NULL; p=p->next) {
-                       gtk_widget_set_sensitive (GTK_WIDGET(p->data),
-                                                 !gl_view_is_selection_atomic(view));
-               }
+                       gl_label_object_dup (object, view->selection_data);
 
-               if (view->selection_menu != NULL) {
-                       gtk_menu_popup (GTK_MENU (view->selection_menu),
-                                       NULL, NULL, NULL, NULL,
-                                       event->button.button,
-                                       event->button.time);
                }
 
+               gtk_selection_owner_set (view->invisible,
+                                        clipboard_atom, GDK_CURRENT_TIME);
+               view->have_selection = TRUE;
+
        }
 
        gl_debug (DEBUG_VIEW, "END");
 }
 
-/*---------------------------------------------------------------------------*/
-/* PRIVATE.  Handle "selection-clear" signal.                                */
-/*---------------------------------------------------------------------------*/
-static void
-selection_clear_cb (GtkWidget         *widget,
-                   GdkEventSelection *event,
-                   gpointer          data)
+/*****************************************************************************/
+/* "Paste" from private clipboard selection.                                 */
+/*****************************************************************************/
+void
+gl_view_paste (glView *view)
 {
-       glView *view = GL_VIEW (data);
-
        gl_debug (DEBUG_VIEW, "START");
 
-       g_return_if_fail (GL_IS_VIEW (view));
+       g_return_if_fail (view && GL_IS_VIEW (view));
 
-       view->have_selection = FALSE;
-       g_object_unref (view->selection_data);
-       view->selection_data = NULL;
+       gtk_selection_convert (GTK_WIDGET (view->invisible),
+                              clipboard_atom, GDK_SELECTION_TYPE_STRING,
+                              GDK_CURRENT_TIME);
 
        gl_debug (DEBUG_VIEW, "END");
 }
 
-/*---------------------------------------------------------------------------*/
-/* PRIVATE.  Handle "selection-get" signal.                                  */
-/*---------------------------------------------------------------------------*/
-static void
-selection_get_cb (GtkWidget        *widget,
-                 GtkSelectionData *selection_data,
-                 guint            info,
-                 guint            time,
-                 gpointer         data)
+/*****************************************************************************/
+/* Zoom in one "notch"                                                       */
+/*****************************************************************************/
+void
+gl_view_zoom_in (glView *view)
 {
-       glView *view = GL_VIEW (data);
-       gchar *buffer;
-       glXMLLabelStatus status;
+       gint    i, i_min;
+       gdouble dist, dist_min;
 
        gl_debug (DEBUG_VIEW, "START");
 
-       g_return_if_fail (GL_IS_VIEW (view));
-
-       if (view->have_selection) {
+       g_return_if_fail (view && GL_IS_VIEW (view));
 
-               buffer = gl_xml_label_save_buffer (view->selection_data,
-                                                  &status);
-               gtk_selection_data_set (selection_data,
-                                       GDK_SELECTION_TYPE_STRING, 8, buffer,
-                                       strlen (buffer));
-               g_free (buffer);
+       /* Find index of current scale (or best match) */
+       i_min = 1;              /* start with 2nd largest scale */
+       dist_min = fabs (zooms[1] - view->zoom);
+       for (i = 2; i < N_ZOOMS; i++) {
+               dist = fabs (zooms[i] - view->zoom);
+               if (dist < dist_min) {
+                       i_min = i;
+                       dist_min = dist;
+               }
        }
 
+       /* zoom in one "notch" */
+       i = MAX (0, i_min - 1);
+       gl_debug (DEBUG_VIEW, "zoom[%d] = %g", i, zooms[i]);
+       set_zoom_real (view, zooms[i], FALSE);
+
        gl_debug (DEBUG_VIEW, "END");
 }
 
-/*---------------------------------------------------------------------------*/
-/* PRIVATE.  Handle "selection-received" signal.  (Result of Paste)          */
-/*---------------------------------------------------------------------------*/
-static void
-selection_received_cb (GtkWidget        *widget,
-                      GtkSelectionData *selection_data,
-                      guint            time,
-                      gpointer         data)
+/*****************************************************************************/
+/* Zoom out one "notch"                                                      */
+/*****************************************************************************/
+void
+gl_view_zoom_out (glView *view)
 {
-       glView *view = GL_VIEW (data);
-       glLabel *label = NULL;
-       glXMLLabelStatus status;
-       GList *p, *p_next;
-       glLabelObject *object, *newobject;
-       glViewObject *view_object;
+       gint    i, i_min;
+       gdouble dist, dist_min;
 
        gl_debug (DEBUG_VIEW, "START");
 
-       g_return_if_fail (GL_IS_VIEW (view));
+       g_return_if_fail (view && GL_IS_VIEW (view));
+
+       /* Find index of current scale (or best match) */
+       i_min = 0;              /* start with largest scale */
+       dist_min = fabs (zooms[0] - view->zoom);
+       for (i = 1; i < N_ZOOMS; i++) {
+               dist = fabs (zooms[i] - view->zoom);
+               if (dist < dist_min) {
+                       i_min = i;
+                       dist_min = dist;
+               }
+       }
+
+       /* zoom out one "notch" */
+       if (i_min >= N_ZOOMS)
+               return;
+       i = i_min + 1;
+       if (i >= N_ZOOMS)
+               return;
+       set_zoom_real (view, zooms[i], FALSE);
+
+       gl_debug (DEBUG_VIEW, "END");
+}
+
+/*****************************************************************************/
+/* Set zoom to best fit.                                                     */
+/*****************************************************************************/
+void
+gl_view_zoom_to_fit (glView *view)
+{
+       gint    w_view, h_view;
+       gdouble w_label, h_label;
+       gdouble x_scale, y_scale, scale;
+
+       gl_debug (DEBUG_VIEW, "");
+
+       if ( ! GTK_WIDGET_VISIBLE(view)) {
+               set_zoom_real (view, 1.0, TRUE);
+               return;
+       }
+
+       w_view = GTK_WIDGET(view)->allocation.width;
+       h_view = GTK_WIDGET(view)->allocation.height;
+
+       gl_label_get_size (GL_LABEL(view->label), &w_label, &h_label);
+
+       gl_debug (DEBUG_VIEW, "View size: %d, %d", w_view, h_view);
+       gl_debug (DEBUG_VIEW, "Label size: %g, %g", w_label, h_label);
+
+       /* Calculate best scale */
+       x_scale = (double)(w_view - ZOOMTOFIT_PAD) / w_label;
+       y_scale = (double)(h_view - ZOOMTOFIT_PAD) / h_label;
+       scale = MIN (x_scale, y_scale);
+       gl_debug (DEBUG_VIEW, "Candidate zooms: %g, %g => %g", x_scale, y_scale, scale);
+
+       /* Limit */
+       gl_debug (DEBUG_VIEW, "Scale: %g", scale);
+       scale = MIN (scale, zooms[0]*view->home_scale);
+       scale = MAX (scale, zooms[N_ZOOMS-1]*view->home_scale);
+       gl_debug (DEBUG_VIEW, "Limitted scale: %g", scale);
+
+       set_zoom_real (view, scale/view->home_scale, TRUE);
+}
+
+/*****************************************************************************/
+/* Set current zoom factor to explicit value.                                */
+/*****************************************************************************/
+void
+gl_view_set_zoom (glView  *view,
+                 gdouble  zoom)
+{
+       gl_debug (DEBUG_VIEW, "START");
+
+       set_zoom_real (view, zoom, FALSE);
+
+       gl_debug (DEBUG_VIEW, "END");
+}
+
+/*---------------------------------------------------------------------------*/
+/* PRIVATE.  Set canvas scale.                                               */
+/*---------------------------------------------------------------------------*/
+static void
+set_zoom_real (glView   *view,
+              gdouble   zoom,
+              gboolean  zoom_to_fit_flag)
+{
+       gl_debug (DEBUG_VIEW, "START");
+
+       g_return_if_fail (view && GL_IS_VIEW (view));
+       g_return_if_fail (zoom > 0.0);
+
+       /* Limit, if needed */
+       gl_debug (DEBUG_VIEW, "Zoom requested: %g", zoom);
+       zoom = MIN (zoom, zooms[0]);
+       zoom = MAX (zoom, zooms[N_ZOOMS-1]);
+       gl_debug (DEBUG_VIEW, "Limitted zoom: %g", zoom);
+
+       if ( zoom != view->zoom ) {
+
+               view->zoom = zoom;
+               view->zoom_to_fit_flag = zoom_to_fit_flag;
+
+                gl_view_update (view);
+
+               g_signal_emit (G_OBJECT(view), signals[ZOOM_CHANGED], 0, zoom);
+
+       }
+
+       gl_debug (DEBUG_VIEW, "END");
+
+}
+
+
+/*****************************************************************************/
+/* Get current zoom factor.                                                  */
+/*****************************************************************************/
+gdouble
+gl_view_get_zoom (glView *view)
+{
+       gl_debug (DEBUG_VIEW, "");
+
+       g_return_val_if_fail (view && GL_IS_VIEW (view), 1.0);
+
+       return view->zoom;
+}
+
+/*****************************************************************************/
+/* Is this the maximum zoom level.                                           */
+/*****************************************************************************/
+gboolean
+gl_view_is_zoom_max (glView *view)
+{
+       gl_debug (DEBUG_VIEW, "");
+
+       g_return_val_if_fail (GL_IS_VIEW (view), FALSE);
+
+       return view->zoom >= zooms[0];
+}
+
+/*****************************************************************************/
+/* Is this the minimum zoom level.                                           */
+/*****************************************************************************/
+gboolean
+gl_view_is_zoom_min (glView *view)
+{
+       gl_debug (DEBUG_VIEW, "");
+
+       g_return_val_if_fail (view && GL_IS_VIEW (view), FALSE);
+
+       return view->zoom <= zooms[N_ZOOMS-1];
+}
+
+/*---------------------------------------------------------------------------*/
+/* PRIVATE.  Handle "selection-clear" signal.                                */
+/*---------------------------------------------------------------------------*/
+static void
+selection_clear_cb (GtkWidget         *widget,
+                   GdkEventSelection *event,
+                   glView            *view)
+{
+       gl_debug (DEBUG_VIEW, "START");
+
+       g_return_if_fail (view && GL_IS_VIEW (view));
+
+       view->have_selection = FALSE;
+       g_object_unref (view->selection_data);
+       view->selection_data = NULL;
+
+       gl_debug (DEBUG_VIEW, "END");
+}
+
+/*---------------------------------------------------------------------------*/
+/* PRIVATE.  Handle "selection-get" signal.                                  */
+/*---------------------------------------------------------------------------*/
+static void
+selection_get_cb (GtkWidget        *widget,
+                 GtkSelectionData *selection_data,
+                 guint             info,
+                 guint             time,
+                 glView           *view)
+{
+       gchar            *buffer;
+       glXMLLabelStatus  status;
+
+       gl_debug (DEBUG_VIEW, "START");
+
+       g_return_if_fail (view && GL_IS_VIEW (view));
+
+       if (view->have_selection) {
+
+               buffer = gl_xml_label_save_buffer (view->selection_data,
+                                                  &status);
+               gtk_selection_data_set (selection_data,
+                                       GDK_SELECTION_TYPE_STRING, 8,
+                                       (guchar *)buffer, strlen (buffer));
+               g_free (buffer);
+       }
+
+       gl_debug (DEBUG_VIEW, "END");
+}
+
+/*---------------------------------------------------------------------------*/
+/* PRIVATE.  Handle "selection-received" signal.  (Result of Paste)          */
+/*---------------------------------------------------------------------------*/
+static void
+selection_received_cb (GtkWidget        *widget,
+                      GtkSelectionData *selection_data,
+                      guint             time,
+                      glView           *view)
+{
+       glLabel          *label = NULL;
+       glXMLLabelStatus  status;
+       GList            *p, *p_next;
+       glLabelObject    *object, *newobject;
+       glViewObject     *view_object;
+
+       gl_debug (DEBUG_VIEW, "START");
+
+       g_return_if_fail (view && GL_IS_VIEW (view));
 
        if (selection_data->length < 0) {
                return;
@@ -3164,37 +2775,37 @@ selection_received_cb (GtkWidget        *widget,
 
        gl_view_unselect_all (view);
 
-       label = gl_xml_label_open_buffer (selection_data->data, &status);
+       label = gl_xml_label_open_buffer ((gchar *)selection_data->data, &status);
        for (p = label->objects; p != NULL; p = p_next) {
                p_next = p->next;
 
                object = (glLabelObject *) p->data;
-               gl_label_object_set_parent (object, view->label);
+               newobject = gl_label_object_dup (object, view->label);
 
                gl_debug (DEBUG_VIEW, "object pasted");
 
-               if (GL_IS_LABEL_BOX (object)) {
-                       view_object = gl_view_box_new (GL_LABEL_BOX(object),
+               if (GL_IS_LABEL_BOX (newobject)) {
+                       view_object = gl_view_box_new (GL_LABEL_BOX(newobject),
                                                       view);
-               } else if (GL_IS_LABEL_ELLIPSE (object)) {
-                       view_object = gl_view_ellipse_new (GL_LABEL_ELLIPSE(object),
+               } else if (GL_IS_LABEL_ELLIPSE (newobject)) {
+                       view_object = gl_view_ellipse_new (GL_LABEL_ELLIPSE(newobject),
                                                           view);
-               } else if (GL_IS_LABEL_LINE (object)) {
-                       view_object = gl_view_line_new (GL_LABEL_LINE(object),
+               } else if (GL_IS_LABEL_LINE (newobject)) {
+                       view_object = gl_view_line_new (GL_LABEL_LINE(newobject),
                                                        view);
-               } else if (GL_IS_LABEL_IMAGE (object)) {
-                       view_object = gl_view_image_new (GL_LABEL_IMAGE(object),
+               } else if (GL_IS_LABEL_IMAGE (newobject)) {
+                       view_object = gl_view_image_new (GL_LABEL_IMAGE(newobject),
                                                         view);
-               } else if (GL_IS_LABEL_TEXT (object)) {
-                       view_object = gl_view_text_new (GL_LABEL_TEXT(object),
+               } else if (GL_IS_LABEL_TEXT (newobject)) {
+                       view_object = gl_view_text_new (GL_LABEL_TEXT(newobject),
                                                        view);
-               } else if (GL_IS_LABEL_BARCODE (object)) {
-                       view_object = gl_view_barcode_new (GL_LABEL_BARCODE(object),
+               } else if (GL_IS_LABEL_BARCODE (newobject)) {
+                       view_object = gl_view_barcode_new (GL_LABEL_BARCODE(newobject),
                                                           view);
                } else {
                        /* Should not happen! */
                        view_object = NULL;
-                       g_warning ("Invalid label object type.");
+                       g_message ("Invalid label object type.");
                }
                gl_view_select_object (view, view_object);
        }
@@ -3203,3 +2814,845 @@ selection_received_cb (GtkWidget        *widget,
        gl_debug (DEBUG_VIEW, "END");
 }
 
+/****************************************************************************/
+/* Set default font family.                                                 */
+/****************************************************************************/
+void
+gl_view_set_default_font_family (glView      *view,
+                                const gchar *font_family)
+{
+       gl_debug (DEBUG_VIEW, "START");
+
+       g_return_if_fail (view && GL_IS_VIEW (view));
+
+       if (view->default_font_family) {
+               g_free (view->default_font_family);
+       }
+       view->default_font_family = g_strdup (font_family);
+
+       gl_debug (DEBUG_VIEW, "END");
+}
+
+
+/****************************************************************************/
+/* Set default font size.                                                   */
+/****************************************************************************/
+void
+gl_view_set_default_font_size (glView  *view,
+                              gdouble  font_size)
+{
+       gl_debug (DEBUG_VIEW, "START");
+
+       g_return_if_fail (view && GL_IS_VIEW (view));
+
+       view->default_font_size = font_size;
+
+       gl_debug (DEBUG_VIEW, "END");
+}
+
+
+/****************************************************************************/
+/* Set default font weight.                                                 */
+/****************************************************************************/
+void
+gl_view_set_default_font_weight (glView      *view,
+                                PangoWeight  font_weight)
+{
+       gl_debug (DEBUG_VIEW, "START");
+
+       g_return_if_fail (view && GL_IS_VIEW (view));
+
+       view->default_font_weight = font_weight;
+
+       gl_debug (DEBUG_VIEW, "END");
+}
+
+
+/****************************************************************************/
+/* Set default font italic flag.                                            */
+/****************************************************************************/
+void
+gl_view_set_default_font_italic_flag (glView   *view,
+                                     gboolean  font_italic_flag)
+{
+       gl_debug (DEBUG_VIEW, "START");
+
+       g_return_if_fail (view && GL_IS_VIEW (view));
+
+       view->default_font_italic_flag = font_italic_flag;
+
+       gl_debug (DEBUG_VIEW, "END");
+}
+
+
+/****************************************************************************/
+/* Set default text color.                                                  */
+/****************************************************************************/
+void
+gl_view_set_default_text_color (glView *view,
+                               guint   text_color)
+{
+       gl_debug (DEBUG_VIEW, "START");
+
+       g_return_if_fail (view && GL_IS_VIEW (view));
+
+       view->default_text_color = text_color;
+
+       gl_debug (DEBUG_VIEW, "END");
+}
+
+
+/****************************************************************************/
+/* Set default text alignment.                                              */
+/****************************************************************************/
+void
+gl_view_set_default_text_alignment (glView           *view,
+                                   PangoAlignment    text_alignment)
+{
+       gl_debug (DEBUG_VIEW, "START");
+
+       g_return_if_fail (view && GL_IS_VIEW (view));
+
+       view->default_text_alignment = text_alignment;
+       gl_debug (DEBUG_VIEW, "END");
+}
+
+/****************************************************************************/
+/* Set default text line spacing.                                           */
+/****************************************************************************/
+void
+gl_view_set_default_text_line_spacing (glView  *view,
+                                      gdouble  text_line_spacing)
+{
+       gl_debug (DEBUG_VIEW, "START");
+
+       g_return_if_fail (view && GL_IS_VIEW (view));
+
+       view->default_text_line_spacing = text_line_spacing;
+
+       gl_debug (DEBUG_VIEW, "END");
+}
+
+
+/****************************************************************************/
+/* Set default line width.                                                  */
+/****************************************************************************/
+void
+gl_view_set_default_line_width (glView  *view,
+                               gdouble  line_width)
+{
+       gl_debug (DEBUG_VIEW, "START");
+
+       g_return_if_fail (view && GL_IS_VIEW (view));
+
+       view->default_line_width = line_width;
+
+       gl_debug (DEBUG_VIEW, "END");
+}
+
+
+/****************************************************************************/
+/* Set default line color.                                                  */
+/****************************************************************************/
+void
+gl_view_set_default_line_color (glView *view,
+                               guint   line_color)
+{
+       gl_debug (DEBUG_VIEW, "START");
+
+       g_return_if_fail (view && GL_IS_VIEW (view));
+
+       view->default_line_color = line_color;
+
+       gl_debug (DEBUG_VIEW, "END");
+}
+
+
+/****************************************************************************/
+/* Set default fill color.                                                  */
+/****************************************************************************/
+void
+gl_view_set_default_fill_color (glView *view,
+                               guint   fill_color)
+{
+       gl_debug (DEBUG_VIEW, "START");
+
+       g_return_if_fail (view && GL_IS_VIEW (view));
+
+       view->default_fill_color = fill_color;
+
+       gl_debug (DEBUG_VIEW, "END");
+}
+
+
+
+/****************************************************************************/
+/* Get default font family.                                                 */
+/****************************************************************************/
+gchar *
+gl_view_get_default_font_family (glView *view)
+{
+       gl_debug (DEBUG_VIEW, "START");
+
+       g_return_val_if_fail (view && GL_IS_VIEW (view), NULL);
+
+       gl_debug (DEBUG_VIEW, "END");
+
+       return g_strdup (view->default_font_family);
+}
+
+
+/****************************************************************************/
+/* Get default font size.                                                   */
+/****************************************************************************/
+gdouble
+gl_view_get_default_font_size (glView *view)
+{
+       gl_debug (DEBUG_VIEW, "START");
+
+       g_return_val_if_fail (view && GL_IS_VIEW (view), 12.0);
+
+       gl_debug (DEBUG_VIEW, "END");
+
+       return view->default_font_size;
+}
+
+
+/****************************************************************************/
+/* Get default font weight.                                                 */
+/****************************************************************************/
+PangoWeight
+gl_view_get_default_font_weight (glView *view)
+{
+       gl_debug (DEBUG_VIEW, "START");
+
+       g_return_val_if_fail (view && GL_IS_VIEW (view), PANGO_WEIGHT_NORMAL);
+
+       gl_debug (DEBUG_VIEW, "END");
+
+       return view->default_font_weight;
+}
+
+
+/****************************************************************************/
+/* Get default font italic flag.                                            */
+/****************************************************************************/
+gboolean
+gl_view_get_default_font_italic_flag (glView *view)
+{
+       gl_debug (DEBUG_VIEW, "START");
+
+       g_return_val_if_fail (view && GL_IS_VIEW (view), FALSE);
+
+       gl_debug (DEBUG_VIEW, "END");
+
+       return view->default_font_italic_flag;
+}
+
+
+/****************************************************************************/
+/* Get default text color.                                                  */
+/****************************************************************************/
+guint
+gl_view_get_default_text_color (glView *view)
+{
+       gl_debug (DEBUG_VIEW, "START");
+
+       g_return_val_if_fail (view && GL_IS_VIEW (view), 0);
+
+       gl_debug (DEBUG_VIEW, "END");
+
+       return view->default_text_color;
+}
+
+
+/****************************************************************************/
+/* Get default text alignment.                                              */
+/****************************************************************************/
+PangoAlignment
+gl_view_get_default_text_alignment (glView *view)
+{
+       gl_debug (DEBUG_VIEW, "START");
+
+       g_return_val_if_fail (view && GL_IS_VIEW (view), PANGO_ALIGN_LEFT);
+
+       gl_debug (DEBUG_VIEW, "END");
+
+       return view->default_text_alignment;
+}
+
+/****************************************************************************/
+/* Get default text line spacing.                                           */
+/****************************************************************************/
+gdouble
+gl_view_get_default_text_line_spacing (glView *view)
+{
+       gl_debug (DEBUG_VIEW, "START");
+
+       g_return_val_if_fail (view && GL_IS_VIEW (view), 1.0);
+
+       gl_debug (DEBUG_VIEW, "END");
+
+       return view->default_text_line_spacing;
+}
+
+
+
+/****************************************************************************/
+/* Get default line width.                                                  */
+/****************************************************************************/
+gdouble
+gl_view_get_default_line_width (glView *view)
+{
+       gl_debug (DEBUG_VIEW, "START");
+
+       g_return_val_if_fail (view && GL_IS_VIEW (view), 1.0);
+
+       gl_debug (DEBUG_VIEW, "END");
+
+       return view->default_line_width;
+}
+
+
+/****************************************************************************/
+/* Get default line color.                                                  */
+/****************************************************************************/
+guint
+gl_view_get_default_line_color (glView *view)
+{
+       gl_debug (DEBUG_VIEW, "START");
+
+       g_return_val_if_fail (view && GL_IS_VIEW (view), 0);
+
+       gl_debug (DEBUG_VIEW, "END");
+
+       return view->default_line_color;
+}
+
+
+/****************************************************************************/
+/* Get default fill color.                                                  */
+/****************************************************************************/
+guint
+gl_view_get_default_fill_color (glView *view)
+{
+       gl_debug (DEBUG_VIEW, "START");
+
+       g_return_val_if_fail (view && GL_IS_VIEW (view), 0);
+
+       gl_debug (DEBUG_VIEW, "END");
+
+       return view->default_fill_color;
+}
+
+/*---------------------------------------------------------------------------*/
+/* PRIVATE.  Focus in event handler.                                         */
+/*---------------------------------------------------------------------------*/
+static gboolean
+focus_in_event_cb (glView            *view,
+                   GdkEventFocus     *event)
+{
+        GTK_WIDGET_SET_FLAGS (GTK_WIDGET (view->canvas), GTK_HAS_FOCUS);
+
+        return FALSE;
+}
+
+/*---------------------------------------------------------------------------*/
+/* PRIVATE.  Focus out event handler.                                        */
+/*---------------------------------------------------------------------------*/
+static gboolean
+focus_out_event_cb (glView            *view,
+                    GdkEventFocus     *event)
+{
+        GTK_WIDGET_UNSET_FLAGS (GTK_WIDGET (view->canvas), GTK_HAS_FOCUS);
+
+        return FALSE;
+}
+
+/*---------------------------------------------------------------------------*/
+/* PRIVATE.  Enter notify event handler.                                     */
+/*---------------------------------------------------------------------------*/
+static gboolean
+enter_notify_event_cb (glView            *view,
+                       GdkEventCrossing  *event)
+{
+        gtk_widget_grab_focus(GTK_WIDGET (view->canvas));
+
+        return FALSE;
+}
+
+/*---------------------------------------------------------------------------*/
+/* PRIVATE.  Leave notify event handler.                                     */
+/*---------------------------------------------------------------------------*/
+static gboolean
+leave_notify_event_cb (glView            *view,
+                       GdkEventCrossing  *event)
+{
+
+        g_signal_emit (G_OBJECT(view), signals[POINTER_EXIT], 0);
+
+        return FALSE;
+}
+
+/*---------------------------------------------------------------------------*/
+/* PRIVATE.  Motion notify event handler.                                    */
+/*---------------------------------------------------------------------------*/
+static gboolean
+motion_notify_event_cb (glView            *view,
+                        GdkEventMotion    *event)
+{
+        gboolean            return_value = FALSE;
+       cairo_t            *cr;
+        gdouble             scale;
+        gdouble             x, y;
+        GdkCursor          *cursor;
+        glViewObjectHandle  handle;
+
+       cr = gdk_cairo_create (GTK_LAYOUT (view->canvas)->bin_window);
+
+        /*
+         * Translate to label coordinates
+         */
+        scale = view->zoom * view->home_scale;
+        cairo_scale (cr, scale, scale);
+        cairo_translate (cr, view->x0, view->y0);
+
+        x = event->x;
+        y = event->y;
+        cairo_device_to_user (cr, &x, &y);
+
+        /*
+         * Emit signal regardless of mode
+         */
+        g_signal_emit (G_OBJECT(view), signals[POINTER_MOVED], 0, x, y);
+
+        /*
+         * Handle event as appropriate for mode
+         */
+        switch (view->mode)
+        {
+
+        case GL_VIEW_MODE_ARROW:
+                switch (view->state)
+                {
+
+                case GL_VIEW_IDLE:
+                        if (view_handle_at (view, cr, event->x, event->y, &handle))
+                        {
+                                cursor = gdk_cursor_new (GDK_CROSSHAIR);
+                        }
+                        else if (view_view_object_at (view, cr, event->x, event->y))
+                        {
+                                cursor = gdk_cursor_new (GDK_FLEUR);
+                        }
+                        else
+                        {
+                                cursor = gdk_cursor_new (GDK_LEFT_PTR);
+                        }
+                        gdk_window_set_cursor (view->canvas->window, cursor);
+                        gdk_cursor_unref (cursor);
+                        break;
+
+                case GL_VIEW_ARROW_SELECT_REGION:
+#ifdef CLIP_UPDATES                                
+                        gl_view_update_region (view, cr, &view->select_region);
+#endif
+                        view->select_region.x2 = x;
+                        view->select_region.y2 = y;
+#ifdef CLIP_UPDATES                                
+                        gl_view_update_region (view, cr, &view->select_region);
+#else
+                        gl_view_update (view);
+#endif
+                        break;
+
+                case GL_VIEW_ARROW_MOVE:
+                        gl_view_move_selection (view,
+                                                (x - view->move_last_x),
+                                                (y - view->move_last_y));
+                        view->move_last_x = x;
+                        view->move_last_y = y;
+                        break;
+
+                case GL_VIEW_ARROW_RESIZE:
+                        gl_view_object_resize_event (view->resize_object,
+                                                     view->resize_handle,
+                                                     view->resize_honor_aspect,
+                                                     cr,
+                                                     event->x,
+                                                     event->y);
+                        break;
+
+                default:
+                        g_message ("Invalid arrow state.");      /*Should not happen!*/
+                }
+                return_value = TRUE;
+                break;
+
+
+        case GL_VIEW_MODE_OBJECT_CREATE:
+                if (view->state != GL_VIEW_IDLE)
+                {
+                        switch (view->create_type)
+                        {
+                        case GL_LABEL_OBJECT_BOX:
+                                gl_view_box_create_motion_event (view, x, y);
+                                break;
+                        case GL_LABEL_OBJECT_ELLIPSE:
+                                gl_view_ellipse_create_motion_event (view, x, y);
+                                break;
+                        case GL_LABEL_OBJECT_LINE: 
+                                gl_view_line_create_motion_event (view, x, y);
+                                break;
+                        case GL_LABEL_OBJECT_IMAGE:
+                                gl_view_image_create_motion_event (view, x, y);
+                                break;
+                        case GL_LABEL_OBJECT_TEXT:
+                                gl_view_text_create_motion_event (view, x, y);
+                                break;
+                        case GL_LABEL_OBJECT_BARCODE:
+                                gl_view_barcode_create_motion_event (view, x, y);
+                                break;
+                        default:
+                                g_message ("Invalid create type.");   /*Should not happen!*/
+                        }
+                }
+                break;
+
+
+        default:
+                g_message ("Invalid view mode.");      /*Should not happen!*/
+
+        }
+
+       cairo_destroy (cr);
+
+        /*
+         * FIXME: we re-establish grabs here if the grab has been lost.  We seem to be
+         *        losing grabs when we emit signals that lead to the manipulation of
+         *        the GtkUIManager.  Needs more investigation
+         */
+        if (view->grabbed_flag && !gdk_pointer_is_grabbed ())
+        {
+                gdk_pointer_grab (GTK_LAYOUT (view->canvas)->bin_window,
+                                  FALSE,
+                                  (GDK_BUTTON1_MOTION_MASK | GDK_BUTTON_RELEASE_MASK),
+                                  NULL,
+                                  NULL,
+                                  event->time);
+        }
+
+        return return_value;
+}
+
+/*---------------------------------------------------------------------------*/
+/* PRIVATE.  Button press event handler.                                     */
+/*---------------------------------------------------------------------------*/
+static gboolean
+button_press_event_cb (glView            *view,
+                       GdkEventButton    *event)
+{
+        gboolean            return_value = FALSE;
+       cairo_t            *cr;
+        gdouble             scale;
+        gdouble             x, y;
+        glViewObject       *view_object;
+        glViewObjectHandle  handle;
+
+       cr = gdk_cairo_create (GTK_LAYOUT (view->canvas)->bin_window);
+
+        /*
+         * Translate to label coordinates
+         */
+        scale = view->zoom * view->home_scale;
+        cairo_scale (cr, scale, scale);
+        cairo_translate (cr, view->x0, view->y0);
+
+        x = event->x;
+        y = event->y;
+        cairo_device_to_user (cr, &x, &y);
+
+        switch (event->button)
+        {
+
+        case 1:
+                /*
+                 * Handle event as appropriate for mode
+                 */
+                switch (view->mode)
+                {
+                case GL_VIEW_MODE_ARROW:
+                        if ((view_object = view_handle_at (view, cr, event->x, event->y, &handle)))
+                        {
+                                view->resize_object = view_object;
+                                view->resize_handle = handle;
+                                view->resize_honor_aspect = event->state & GDK_CONTROL_MASK;
+
+                                view->state = GL_VIEW_ARROW_RESIZE;
+                        }
+                        else if ((view_object = view_view_object_at (view, cr, event->x, event->y)))
+                        {
+                                if (event->state & GDK_CONTROL_MASK)
+                                {
+                                        if (gl_view_is_object_selected (view, view_object))
+                                        {
+                                                /* Un-selecting a selected item */
+                                                gl_view_unselect_object (view, view_object);
+                                        } else {
+                                                /* Add to current selection */
+                                                gl_view_select_object (view, view_object);
+                                        }
+                                }
+                                else
+                                {
+                                        if (!gl_view_is_object_selected (view, view_object))
+                                        {
+                                                /* remove any selections before adding */
+                                                gl_view_unselect_all (view);
+                                                /* Add to current selection */
+                                                gl_view_select_object (view, view_object);
+                                        }
+                                }
+                                view->move_last_x = x;
+                                view->move_last_y = y;
+
+                                view->state = GL_VIEW_ARROW_MOVE;
+                        }
+                        else
+                        {
+                                if (!(event->state & GDK_CONTROL_MASK))
+                                {
+                                        gl_view_unselect_all (view);
+                                }
+
+                                view->select_region_visible = TRUE;
+                                view->select_region.x1 = x;
+                                view->select_region.y1 = y;
+                                view->select_region.x2 = x;
+                                view->select_region.y2 = y;
+
+                                view->state = GL_VIEW_ARROW_SELECT_REGION;
+                        }
+
+
+                        return_value = TRUE;
+                        break;
+
+                case GL_VIEW_MODE_OBJECT_CREATE:
+                        switch (view->create_type)
+                        {
+                        case GL_LABEL_OBJECT_BOX:
+                                gl_view_box_create_button_press_event (view, x, y);
+                                break;
+                        case GL_LABEL_OBJECT_ELLIPSE:
+                                gl_view_ellipse_create_button_press_event (view, x, y);
+                                break;
+                        case GL_LABEL_OBJECT_LINE:
+                                gl_view_line_create_button_press_event (view, x, y);
+                                break;
+                        case GL_LABEL_OBJECT_IMAGE:
+                                gl_view_image_create_button_press_event (view, x, y);
+                                break;
+                        case GL_LABEL_OBJECT_TEXT:
+                                gl_view_text_create_button_press_event (view, x, y);
+                                break;
+                        case GL_LABEL_OBJECT_BARCODE:
+                                gl_view_barcode_create_button_press_event (view, x, y);
+                                break;
+                        default:
+                                g_message ("Invalid create type.");   /*Should not happen!*/
+                        }
+                        view->state = GL_VIEW_CREATE_DRAG;
+                        return_value = TRUE;
+                        break;
+
+                default:
+                        g_message ("Invalid view mode.");      /*Should not happen!*/
+                }
+
+                view->grabbed_flag = TRUE;
+                gdk_pointer_grab (GTK_LAYOUT (view->canvas)->bin_window,
+                                  FALSE,
+                                  (GDK_BUTTON1_MOTION_MASK | GDK_BUTTON_RELEASE_MASK),
+                                  NULL,
+                                  NULL,
+                                  event->time);
+                break;
+
+        case 3:
+                g_signal_emit (G_OBJECT (view),
+                               signals[CONTEXT_MENU_ACTIVATE], 0,
+                               event->button, event->time);
+                return_value = TRUE;
+                break;
+
+        }
+
+       cairo_destroy (cr);
+
+        return return_value;
+}
+
+/*---------------------------------------------------------------------------*/
+/* PRIVATE.  Button release event handler.                                   */
+/*---------------------------------------------------------------------------*/
+static gboolean
+button_release_event_cb (glView            *view,
+                         GdkEventButton    *event)
+{
+        gboolean     return_value = FALSE;
+       cairo_t     *cr;
+        gdouble      scale;
+        gdouble      x, y;
+        GdkCursor   *cursor;
+
+       cr = gdk_cairo_create (GTK_LAYOUT (view->canvas)->bin_window);
+
+        /*
+         * Translate to label coordinates
+         */
+        scale = view->zoom * view->home_scale;
+        cairo_scale (cr, scale, scale);
+        cairo_translate (cr, view->x0, view->y0);
+
+        x = event->x;
+        y = event->y;
+        cairo_device_to_user (cr, &x, &y);
+
+        switch (event->button)
+        {
+
+        case 1:
+                view->grabbed_flag = FALSE;
+                gdk_pointer_ungrab (event->time);
+                /*
+                 * Handle event as appropriate for mode
+                 */
+                switch (view->mode)
+                {
+                case GL_VIEW_MODE_ARROW:
+                        switch (view->state)
+                        {
+                        case GL_VIEW_ARROW_RESIZE:
+                                view->resize_object = NULL;
+
+                                view->state = GL_VIEW_IDLE;
+                                break;
+
+                        case GL_VIEW_ARROW_SELECT_REGION:
+#ifdef CLIP_UPDATES                                
+                                gl_view_update_region (view, cr, &view->select_region);
+#else
+                                gl_view_update (view);
+#endif
+
+                                view->select_region_visible = FALSE;
+                                view->select_region.x2 = x;
+                                view->select_region.y2 = y;
+
+                                gl_view_select_region (view, &view->select_region);
+
+                                view->state = GL_VIEW_IDLE;
+                                break;
+
+                        default:
+                                view->state = GL_VIEW_IDLE;
+                                break;
+                                
+                        }
+
+                        return_value = TRUE;
+                        break;
+
+
+                case GL_VIEW_MODE_OBJECT_CREATE:
+                        switch (view->create_type)
+                        {
+                        case GL_LABEL_OBJECT_BOX:
+                                gl_view_box_create_button_release_event (view, x, y);
+                                break;
+                        case GL_LABEL_OBJECT_ELLIPSE:
+                                gl_view_ellipse_create_button_release_event (view, x, y);
+                                break;
+                        case GL_LABEL_OBJECT_LINE:
+                                gl_view_line_create_button_release_event (view, x, y);
+                                break;
+                        case GL_LABEL_OBJECT_IMAGE:
+                                gl_view_image_create_button_release_event (view, x, y);
+                                break;
+                        case GL_LABEL_OBJECT_TEXT:
+                                gl_view_text_create_button_release_event (view, x, y);
+                                break;
+                        case GL_LABEL_OBJECT_BARCODE:
+                                gl_view_barcode_create_button_release_event (view, x, y);
+                                break;
+                        default:
+                                g_message ("Invalid create type.");   /*Should not happen!*/
+                        }
+                        view->mode = GL_VIEW_MODE_ARROW;
+                        view->state = GL_VIEW_IDLE;
+                        cursor = gdk_cursor_new (GDK_LEFT_PTR);
+                        gdk_window_set_cursor (view->canvas->window, cursor);
+                        gdk_cursor_unref (cursor);
+                        break;
+
+
+                default:
+                        g_message ("Invalid view mode.");      /*Should not happen!*/
+                }
+
+        }
+
+       cairo_destroy (cr);
+
+        return return_value;
+}
+
+/*---------------------------------------------------------------------------*/
+/* PRIVATE.  Key press event handler.                                        */
+/*---------------------------------------------------------------------------*/
+static gboolean
+key_press_event_cb (glView            *view,
+                    GdkEventKey       *event)
+{
+        GdkCursor *cursor;
+
+        gl_debug (DEBUG_VIEW, "");
+
+        if ( (view->mode == GL_VIEW_MODE_ARROW) &&
+             (view->state == GL_VIEW_IDLE) )
+        {
+                switch (event->keyval) {
+
+                case GDK_Left:
+                case GDK_KP_Left:
+                        gl_view_move_selection (view, -1.0 / (view->zoom), 0.0);
+                        break;
+                case GDK_Up:
+                case GDK_KP_Up:
+                        gl_view_move_selection (view, 0.0, -1.0 / (view->zoom));
+                        break;
+                case GDK_Right:
+                case GDK_KP_Right:
+                        gl_view_move_selection (view, 1.0 / (view->zoom), 0.0);
+                        break;
+                case GDK_Down:
+                case GDK_KP_Down:
+                        gl_view_move_selection (view, 0.0, 1.0 / (view->zoom));
+                        break;
+                case GDK_Delete:
+                case GDK_KP_Delete:
+                        gl_view_delete_selection (view);
+                        cursor = gdk_cursor_new (GDK_LEFT_PTR);
+                        gdk_window_set_cursor (GTK_WIDGET (view->canvas)->window
+, cursor);
+                        gdk_cursor_unref (cursor);
+                        break;
+                default:
+                        return FALSE;
+               }
+        }
+        return TRUE;    /* We handled this or we were dragging. */
+}
+