Index: gimpdisplayshell.c
===================================================================
RCS file: /cvs/gnome/gimp/app/display/gimpdisplayshell.c,v
retrieving revision 1.322
diff -u -p -u -p -r1.322 gimpdisplayshell.c
--- a/gimpdisplayshell.c	1 Jun 2004 23:14:28 -0000	1.322
+++ b/gimpdisplayshell.c	17 Jun 2004 15:42:01 -0000
@@ -957,7 +957,7 @@ gimp_display_shell_new (GimpDisplay     
 
   /*  the statusbar  */
   shell->statusbar = gimp_statusbar_new (shell);
-  gtk_statusbar_set_has_resize_grip (GTK_STATUSBAR (shell->statusbar), FALSE);
+  gimp_statusbar_set_has_resize_grip (GIMP_STATUSBAR (shell->statusbar), FALSE);
   gimp_help_set_help_data (shell->statusbar, NULL,
                            GIMP_HELP_IMAGE_WINDOW_STATUS_BAR);
 
Index: gimpstatusbar.c
===================================================================
RCS file: /cvs/gnome/gimp/app/display/gimpstatusbar.c,v
retrieving revision 1.12
diff -u -p -u -p -r1.12 gimpstatusbar.c
--- a/gimpstatusbar.c	1 Jun 2004 22:04:19 -0000	1.12
+++ b/gimpstatusbar.c	17 Jun 2004 15:42:01 -0000
@@ -26,6 +26,7 @@
 
 #include "core/gimpimage.h"
 #include "core/gimpunit.h"
+#include "core/gimpmarshal.h"
 
 #include "widgets/gimpunitstore.h"
 #include "widgets/gimpunitcombobox.h"
@@ -38,29 +39,79 @@
 
 #include "gimp-intl.h"
 
+typedef struct _GimpStatusbarMsg GimpStatusbarMsg;
+
+struct _GimpStatusbarMsg
+{
+  gchar *text;
+  guint context_id;
+  guint message_id;
+};
+
+enum
+{
+  SIGNAL_TEXT_PUSHED,
+  SIGNAL_TEXT_POPPED,
+  SIGNAL_LAST
+};
+
+enum 
+{
+  PROP_ZERO,
+  PROP_HAS_RESIZE_GRIP
+};
 
 /* maximal width of the string holding the cursor-coordinates for
  * the status line
  */
 #define CURSOR_LEN 256
 
+static void     gimp_statusbar_class_init        (GimpStatusbarClass *klass);
+static void     gimp_statusbar_init              (GimpStatusbar      *statusbar);
+static void     gimp_statusbar_update            (GimpStatusbar      *statusbar,
+                                                  const gchar        *context_id,
+                                                  const gchar        *text);
+static void     gimp_statusbar_unit_changed      (GimpUnitComboBox   *combo,
+                                                  GimpStatusbar      *statusbar);
+static void     gimp_statusbar_scale_changed     (GimpScaleComboBox  *combo,
+                                                  GimpStatusbar      *statusbar);
+static void     gimp_statusbar_shell_scaled      (GimpDisplayShell   *shell,
+                                                  GimpStatusbar      *statusbar);                                            
+static void     gimp_statusbar_destroy           (GtkObject          *object);
+static void     gimp_statusbar_size_allocate     (GtkWidget          *widget,
+                                                  GtkAllocation      *allocation);
+static void     gimp_statusbar_realize           (GtkWidget          *widget);
+static void     gimp_statusbar_unrealize         (GtkWidget          *widget);
+static void     gimp_statusbar_map               (GtkWidget          *widget);
+static void     gimp_statusbar_unmap             (GtkWidget          *widget);
+static gboolean gimp_statusbar_button_press      (GtkWidget          *widget,
+                                                  GdkEventButton     *event);
+static gboolean gimp_statusbar_expose_event      (GtkWidget          *widget,
+                                                  GdkEventExpose     *event);
+static void     gimp_statusbar_size_request      (GtkWidget          *widget,
+                                                  GtkRequisition     *requisition);
+static void     gimp_statusbar_size_allocate     (GtkWidget          *widget,
+                                                  GtkAllocation      *allocation);
+static void     gimp_statusbar_direction_changed (GtkWidget          *widget,
+                                                  GtkTextDirection    prev_dir);
+static void     gimp_statusbar_create_window     (GimpStatusbar      *statusbar);
+static void     gimp_statusbar_destroy_window    (GimpStatusbar      *statusbar);
+static void     gimp_statusbar_get_property      (GObject            *object,
+                                                  guint               prop_id,
+                                                  GValue             *value,
+                                                  GParamSpec         *pspec);
+static void     gimp_statusbar_set_property      (GObject            *object,
+                                                  guint               prop_id,
+                                                  const GValue       *value,
+                                                  GParamSpec         *pspec);
+void            set_grip_cursor                  (GimpStatusbar      *statusbar);
+void            get_grip_rect                    (GimpStatusbar      *statusbar,
+                                                  GdkRectangle       *rect);
+GdkWindowEdge   get_grip_edge                    (GimpStatusbar      *statusbar);
+                                 
 
-static void   gimp_statusbar_class_init    (GimpStatusbarClass *klass);
-static void   gimp_statusbar_init          (GimpStatusbar      *statusbar);
-
-static void   gimp_statusbar_update        (GtkStatusbar       *gtk_statusbar,
-                                            guint               context_id,
-                                            const gchar        *text);
-static void   gimp_statusbar_unit_changed  (GimpUnitComboBox   *combo,
-                                            GimpStatusbar      *statusbar);
-static void   gimp_statusbar_scale_changed (GimpScaleComboBox  *combo,
-                                            GimpStatusbar      *statusbar);
-static void   gimp_statusbar_shell_scaled  (GimpDisplayShell   *shell,
-                                            GimpStatusbar      *statusbar);
-
-
-static GtkStatusbarClass *parent_class = NULL;
-
+static GtkContainerClass *parent_class;
+static guint              statusbar_signals[SIGNAL_LAST] = { 0 };
 
 GType
 gimp_statusbar_get_type (void)
@@ -82,7 +133,7 @@ gimp_statusbar_get_type (void)
 	(GInstanceInitFunc) gimp_statusbar_init,
       };
 
-      statusbar_type = g_type_register_static (GTK_TYPE_STATUSBAR,
+      statusbar_type = g_type_register_static (GTK_TYPE_HBOX,
                                                "GimpStatusbar",
                                                &statusbar_info, 0);
     }
@@ -93,30 +144,105 @@ gimp_statusbar_get_type (void)
 static void
 gimp_statusbar_class_init (GimpStatusbarClass *klass)
 {
-  GtkStatusbarClass *gtk_statusbar_class;
+
+      
+  GObjectClass *g_object_class;
+  GtkObjectClass *gtk_object_class;
+  GtkWidgetClass *gtk_widget_class;
+  GtkContainerClass *gtk_container_class;
+
+  g_object_class = (GObjectClass *) klass;
+  gtk_object_class = (GtkObjectClass *) klass;
+  gtk_widget_class = (GtkWidgetClass *) klass;
+  gtk_container_class = (GtkContainerClass *) klass;
 
   parent_class = g_type_class_peek_parent (klass);
+  
+  g_object_class->set_property = gimp_statusbar_set_property;
+  g_object_class->get_property = gimp_statusbar_get_property;
+
+  gtk_object_class->destroy = gimp_statusbar_destroy;
+
+  gtk_widget_class->realize = gimp_statusbar_realize;
+  gtk_widget_class->unrealize = gimp_statusbar_unrealize;
+  gtk_widget_class->map = gimp_statusbar_map;
+  gtk_widget_class->unmap = gimp_statusbar_unmap;
+  
+  gtk_widget_class->button_press_event = gimp_statusbar_button_press;
+  gtk_widget_class->expose_event = gimp_statusbar_expose_event;
+
+  gtk_widget_class->size_request = gimp_statusbar_size_request;
+  gtk_widget_class->size_allocate = gimp_statusbar_size_allocate;
+
+  gtk_widget_class->direction_changed = gimp_statusbar_direction_changed;
+  
+  klass->messages_mem_chunk = g_mem_chunk_new ("GimpStatusbar messages mem chunk",
+                                               sizeof (GimpStatusbarMsg),
+                                               sizeof (GimpStatusbarMsg) * 64,
+                                               G_ALLOC_AND_FREE);
 
-  gtk_statusbar_class = GTK_STATUSBAR_CLASS (klass);
+  /**
+   * GimpStatusbar:has-resize-grip:
+   *
+   * Whether the statusbar has a grip for resizing the toplevel window.
+   *
+   * Since: 2.4
+   */
+  g_object_class_install_property (g_object_class,
+                                   PROP_HAS_RESIZE_GRIP,
+                                   g_param_spec_boolean ("has_resize_grip",
+                                   _("Has Resize Grip"),
+                                   _("Whether the statusbar has a grip for resizing the toplevel"),
+                                   TRUE,
+                                   G_PARAM_READWRITE));
+  statusbar_signals[SIGNAL_TEXT_PUSHED] =
+    g_signal_new ("text_pushed",
+                  G_OBJECT_CLASS_TYPE (klass),
+                  G_SIGNAL_RUN_LAST,
+                  G_STRUCT_OFFSET (GimpStatusbarClass, text_pushed),
+                  NULL, NULL,
+                  gimp_marshal_VOID__UINT_STRING,
+                  G_TYPE_NONE, 2,
+                  G_TYPE_UINT,
+                  G_TYPE_STRING);
+  statusbar_signals[SIGNAL_TEXT_POPPED] =
+    g_signal_new ("text_popped",
+                  G_OBJECT_CLASS_TYPE (klass),
+                  G_SIGNAL_RUN_LAST,
+                  G_STRUCT_OFFSET (GimpStatusbarClass, text_popped),
+                  NULL, NULL,
+                  gimp_marshal_VOID__UINT_STRING,
+                  G_TYPE_NONE, 2,
+                  G_TYPE_UINT,
+                  G_TYPE_STRING);
+
+  gtk_widget_class_install_style_property (gtk_widget_class,
+                                           g_param_spec_enum ("shadow_type",
+                                           _("Shadow type"),
+                                           _("Style of bevel around the statusbar text"),
+                                           GTK_TYPE_SHADOW_TYPE,
+                                           GTK_SHADOW_IN,
+                                           G_PARAM_READABLE));                                                                 
 
-  gtk_statusbar_class->text_pushed = gimp_statusbar_update;
-  gtk_statusbar_class->text_popped = gimp_statusbar_update;
+  klass->text_pushed = gimp_statusbar_update;
+  klass->text_popped = gimp_statusbar_update;                                           
 }
 
 static void
 gimp_statusbar_init (GimpStatusbar *statusbar)
 {
-  GtkStatusbar  *gtk_statusbar;
   GtkBox        *box;
   GtkWidget     *hbox;
   GtkWidget     *frame;
   GimpUnitStore *store;
   GtkShadowType  shadow_type;
 
-  gtk_statusbar = GTK_STATUSBAR (statusbar);
-  box           = GTK_BOX (statusbar);
+  box = GTK_BOX (statusbar);
 
-  gtk_widget_hide (gtk_statusbar->frame);
+  box->spacing = 2;
+  box->homogeneous = FALSE;
+
+  statusbar->has_resize_grip = TRUE;
 
   statusbar->shell                 = NULL;
   statusbar->cursor_format_str[0]  = '\0';
@@ -190,15 +316,18 @@ gimp_statusbar_init (GimpStatusbar *stat
 
   gtk_progress_bar_set_text (GTK_PROGRESS_BAR (statusbar->progressbar),
                              "GIMP");
+  
+  statusbar->seq_context_id = 1;
+  statusbar->seq_message_id = 1;
+  statusbar->messages = NULL;
+  statusbar->keys = NULL;
 }
 
 static void
-gimp_statusbar_update (GtkStatusbar *gtk_statusbar,
-                       guint         context_id,
-                       const gchar  *text)
+gimp_statusbar_update (GimpStatusbar *statusbar,
+                       const gchar   *context_id,
+                       const gchar   *text)
 {
-  GimpStatusbar *statusbar = GIMP_STATUSBAR (gtk_statusbar);
-
   if (! text)
     text = "";
 
@@ -223,39 +352,129 @@ gimp_statusbar_new (GimpDisplayShell *sh
   return GTK_WIDGET (statusbar);
 }
 
-void
+guint     
 gimp_statusbar_push (GimpStatusbar *statusbar,
-                     const gchar   *context_id,
+                     const gchar   *context,
                      const gchar   *message)
 {
-  GtkStatusbar *bar;
+  GimpStatusbarMsg *msg;
+  GimpStatusbarClass *class;
+  guint context_id;
+  
+  g_return_val_if_fail (GIMP_IS_STATUSBAR (statusbar), 0);
+  g_return_val_if_fail (message != NULL, 0);
+  
+  class = GIMP_STATUSBAR_GET_CLASS (statusbar);
+  context_id = gimp_statusbar_get_context_id (statusbar, context);
+   
+  msg = g_chunk_new (GimpStatusbarMsg, class->messages_mem_chunk);
+  msg->text = g_strdup (message);
+  msg->context_id = context_id;
+  msg->message_id = statusbar->seq_message_id++;
+
+  statusbar->messages = g_slist_prepend (statusbar->messages, msg);
+
+  g_signal_emit (statusbar,
+                 statusbar_signals[SIGNAL_TEXT_PUSHED],
+                 0,
+                 msg->context_id,
+                 msg->text);
+  return msg->message_id;
+}
 
+void
+gimp_statusbar_pop (GimpStatusbar *statusbar,
+                    const gchar   *context)
+{
+  GimpStatusbarMsg *msg;
+  guint context_id;
+     
   g_return_if_fail (GIMP_IS_STATUSBAR (statusbar));
+  context_id = gimp_statusbar_get_context_id (statusbar, context);
+  if (statusbar->messages)
+    {
+      GSList *list;
 
-  bar = GTK_STATUSBAR (statusbar);
+      for (list = statusbar->messages; list; list = list->next)
+        {
+           msg = list->data;
+
+           if (msg->context_id == context_id)
+             {
+               GimpStatusbarClass *class;
+
+               class = GIMP_STATUSBAR_GET_CLASS (statusbar);
+
+               statusbar->messages = g_slist_remove_link (statusbar->messages,
+                                                          list);
+               g_free (msg->text);
+               g_mem_chunk_free (class->messages_mem_chunk, msg);
+               g_slist_free_1 (list);
+               break;
+             }
+        }
+    }
+
+  msg = statusbar->messages ? statusbar->messages->data : NULL;
 
-  gtk_statusbar_push (bar,
-                      gtk_statusbar_get_context_id (bar, context_id),
-                      message);
+  g_signal_emit (statusbar,
+                 statusbar_signals[SIGNAL_TEXT_POPPED],
+                 0,
+                 (guint) (msg ? msg->context_id : 0),
+                 msg ? msg->text : NULL);
 }
 
+
 void
-gimp_statusbar_pop (GimpStatusbar *statusbar,
-                    const gchar   *context_id)
+gimp_statusbar_remove (GimpStatusbar *statusbar,
+                       const gchar   *context,
+                       guint          message_id)
 {
-  GtkStatusbar *bar;
-
+  GimpStatusbarMsg *msg;
+  guint context_id;
+     
   g_return_if_fail (GIMP_IS_STATUSBAR (statusbar));
+  g_return_if_fail (message_id > 0);
+  context_id = gimp_statusbar_get_context_id (statusbar, context);
+  
+  
+  msg = statusbar->messages ? statusbar->messages->data : NULL;
+  if (msg)
+    {
+      GSList *list;
 
-  bar = GTK_STATUSBAR (statusbar);
-
-  gtk_statusbar_pop (bar,
-                     gtk_statusbar_get_context_id (bar, context_id));
+      /* care about signal emission if the topmost item is removed */
+      if (msg->context_id == context_id &&
+          msg->message_id == message_id)
+        {
+           gimp_statusbar_pop (statusbar, context);
+           return;
+        }
+      
+      for (list = statusbar->messages; list; list = list->next)
+        {
+           msg = list->data;
+      
+           if (msg->context_id == context_id &&
+               msg->message_id == message_id)
+             {
+                GimpStatusbarClass *class;
+              
+                class = GIMP_STATUSBAR_GET_CLASS (statusbar);
+                statusbar->messages = g_slist_remove_link (statusbar->messages, list);
+                g_free (msg->text);
+                g_mem_chunk_free (class->messages_mem_chunk, msg);
+                g_slist_free_1 (list);         
+                break;
+             }
+        }
+    }
 }
 
-void
+
+guint
 gimp_statusbar_push_coords (GimpStatusbar *statusbar,
-                            const gchar   *context_id,
+                            const gchar   *context,
                             const gchar   *title,
                             gdouble        x,
                             const gchar   *separator,
@@ -264,16 +483,16 @@ gimp_statusbar_push_coords (GimpStatusba
   GimpDisplayShell *shell;
   gchar             buf[CURSOR_LEN];
 
-  g_return_if_fail (GIMP_IS_STATUSBAR (statusbar));
-  g_return_if_fail (title != NULL);
-  g_return_if_fail (separator != NULL);
+  g_return_val_if_fail  (GIMP_IS_STATUSBAR (statusbar), 0);
+  g_return_val_if_fail (title != NULL, 0);
+  g_return_val_if_fail (separator != NULL, 0);
 
   shell = statusbar->shell;
 
   if (shell->unit == GIMP_UNIT_PIXEL)
     {
       g_snprintf (buf, sizeof (buf), statusbar->cursor_format_str,
-		  title,
+               title,
                   ROUND (x),
                   separator,
                   ROUND (y));
@@ -285,15 +504,16 @@ gimp_statusbar_push_coords (GimpStatusba
                                                       shell->unit);
 
       g_snprintf (buf, sizeof (buf), statusbar->cursor_format_str,
-		  title,
-		  x * unit_factor / image->xresolution,
-		  separator,
-		  y * unit_factor / image->yresolution);
+                  title,
+                 x * unit_factor / image->xresolution,
+                  separator,
+             y * unit_factor / image->yresolution);
     }
 
-  gimp_statusbar_push (statusbar, context_id, buf);
+  return gimp_statusbar_push (statusbar, context, buf);
 }
 
+
 void
 gimp_statusbar_set_cursor (GimpStatusbar *statusbar,
                            gdouble        x,
@@ -425,3 +645,432 @@ gimp_statusbar_scale_changed (GimpScaleC
                             GIMP_ZOOM_TO,
                             gimp_scale_combo_box_get_scale (combo));
 }
+static void
+gimp_statusbar_size_allocate (GtkWidget     *widget,
+                              GtkAllocation *allocation)
+{
+  GimpStatusbar *statusbar;
+  
+  statusbar = GIMP_STATUSBAR (widget);
+
+  if (statusbar->has_resize_grip)
+    {
+      GdkRectangle rect;
+      GtkRequisition saved_req;
+      
+      widget->allocation = *allocation; /* get_grip_rect needs this info */
+      get_grip_rect (statusbar, &rect);
+  
+      if (statusbar->grip_window)
+        gdk_window_move_resize (statusbar->grip_window,
+                                rect.x, rect.y,
+                                rect.width, rect.height);
+      
+      /* enter the bad hack zone */      
+      saved_req = widget->requisition;
+      widget->requisition.width -= rect.width; /* HBox::size_allocate needs this */
+      if (widget->requisition.width < 0)
+        widget->requisition.width = 0;
+      GTK_WIDGET_CLASS (parent_class)->size_allocate (widget, allocation);
+      widget->requisition = saved_req;
+    }
+  else
+    {
+      /* chain up normally */
+      GTK_WIDGET_CLASS (parent_class)->size_allocate (widget, allocation);
+    }
+}
+
+static gboolean
+gimp_statusbar_button_press (GtkWidget      *widget,
+                             GdkEventButton *event)
+{
+  GimpStatusbar *statusbar;
+  GtkWidget *ancestor;
+  GdkWindowEdge edge;
+  
+  statusbar = GIMP_STATUSBAR (widget);
+  
+  if (!statusbar->has_resize_grip ||
+    event->type != GDK_BUTTON_PRESS)
+    return FALSE;
+  
+  ancestor = gtk_widget_get_toplevel (widget);
+
+  if (!GTK_IS_WINDOW (ancestor))
+    return FALSE;
+
+  edge = get_grip_edge (statusbar);
+
+  if (event->button == 1)
+    gtk_window_begin_resize_drag (GTK_WINDOW (ancestor),
+                                  edge,
+                                  event->button,
+                                  event->x_root, event->y_root,
+                                  event->time);
+  else if (event->button == 2)
+    gtk_window_begin_move_drag (GTK_WINDOW (ancestor),
+                                event->button,
+                                event->x_root, event->y_root,
+                                event->time);
+  else
+    return FALSE;
+  
+  return TRUE;
+}
+
+static gboolean
+gimp_statusbar_expose_event (GtkWidget      *widget,
+                             GdkEventExpose *event)
+{
+  GimpStatusbar *statusbar;
+  GdkRectangle rect;
+  
+  statusbar = GIMP_STATUSBAR (widget);
+
+  GTK_WIDGET_CLASS (parent_class)->expose_event (widget, event);
+
+  if (statusbar->has_resize_grip)
+    {
+      GdkWindowEdge edge;
+      
+      edge = get_grip_edge (statusbar);
+
+      get_grip_rect (statusbar, &rect);
+
+      gtk_paint_resize_grip (widget->style,
+                             widget->window,
+                             GTK_WIDGET_STATE (widget),
+                             NULL,
+                             widget,
+                             "statusbar",
+                             edge,
+                             rect.x, rect.y,
+                             /* don't draw grip over the frame, though you
+                              * can click on the frame.
+                              */
+                             rect.width - widget->style->xthickness,
+                             rect.height - widget->style->ythickness);
+    }
+
+  return FALSE;
+}
+
+static void
+gimp_statusbar_size_request (GtkWidget      *widget,
+                             GtkRequisition *requisition)
+{
+  GimpStatusbar *statusbar;
+  GtkShadowType shadow_type;
+  
+  statusbar = GIMP_STATUSBAR (widget);
+
+  gtk_widget_style_get (GTK_WIDGET (statusbar), "shadow_type", &shadow_type, NULL);  
+  gtk_frame_set_shadow_type (GTK_FRAME (statusbar->cursor_frame), shadow_type);
+  
+  GTK_WIDGET_CLASS (parent_class)->size_request (widget, requisition);
+
+  if (statusbar->has_resize_grip)
+    {
+      GdkRectangle rect;
+
+      /* x, y in the grip rect depend on size allocation, but
+       * w, h do not so this is OK
+       */
+      get_grip_rect (statusbar, &rect);
+      
+      requisition->width += rect.width;
+      requisition->height = MAX (requisition->height, rect.height);
+    }
+}
+static void
+gimp_statusbar_realize (GtkWidget *widget)
+{
+  GimpStatusbar *statusbar;
+
+  statusbar = GIMP_STATUSBAR (widget);
+  
+  (* GTK_WIDGET_CLASS (parent_class)->realize) (widget);
+
+  if (statusbar->has_resize_grip)
+    gimp_statusbar_create_window (statusbar);
+}
+
+static void
+gimp_statusbar_unrealize (GtkWidget *widget)
+{
+  GimpStatusbar *statusbar;
+
+  statusbar = GIMP_STATUSBAR (widget);
+
+  if (statusbar->grip_window)
+    gimp_statusbar_destroy_window (statusbar);
+  
+  (* GTK_WIDGET_CLASS (parent_class)->unrealize) (widget);
+}
+
+static void
+gimp_statusbar_map (GtkWidget *widget)
+{
+  GimpStatusbar *statusbar;
+
+  statusbar = GIMP_STATUSBAR (widget);
+  
+  (* GTK_WIDGET_CLASS (parent_class)->map) (widget);
+  
+  if (statusbar->grip_window)
+    gdk_window_show (statusbar->grip_window);
+}
+
+static void
+gimp_statusbar_unmap (GtkWidget *widget)
+{
+  GimpStatusbar *statusbar;
+
+  statusbar = GIMP_STATUSBAR (widget);
+
+  if (statusbar->grip_window)
+    gdk_window_hide (statusbar->grip_window);
+  
+  (* GTK_WIDGET_CLASS (parent_class)->unmap) (widget);
+}
+static void
+gimp_statusbar_create_window (GimpStatusbar *statusbar)
+{
+  GtkWidget *widget;
+  GdkWindowAttr attributes;
+  gint attributes_mask;
+  GdkRectangle rect;
+  
+  g_return_if_fail (GTK_WIDGET_REALIZED (statusbar));
+  g_return_if_fail (statusbar->has_resize_grip);
+  
+  widget = GTK_WIDGET (statusbar);
+
+  get_grip_rect (statusbar, &rect);
+
+  attributes.x = rect.x;
+  attributes.y = rect.y;
+  attributes.width = rect.width;
+  attributes.height = rect.height;
+  attributes.window_type = GDK_WINDOW_CHILD;
+  attributes.wclass = GDK_INPUT_ONLY;
+  attributes.event_mask = gtk_widget_get_events (widget) |
+    GDK_BUTTON_PRESS_MASK;
+
+  attributes_mask = GDK_WA_X | GDK_WA_Y;
+
+  statusbar->grip_window = gdk_window_new (widget->window,
+                                           &attributes, attributes_mask);
+  gdk_window_set_user_data (statusbar->grip_window, widget);
+
+  set_grip_cursor (statusbar);
+}
+
+static void
+gimp_statusbar_direction_changed (GtkWidget        *widget,
+                                  GtkTextDirection  prev_dir)
+{
+  GimpStatusbar *statusbar = GIMP_STATUSBAR (widget);
+
+  set_grip_cursor (statusbar);
+}
+
+static void
+gimp_statusbar_destroy_window (GimpStatusbar *statusbar)
+{
+  gdk_window_set_user_data (statusbar->grip_window, NULL);
+  gdk_window_destroy (statusbar->grip_window);
+  statusbar->grip_window = NULL;
+}
+
+void
+gimp_statusbar_set_has_resize_grip (GimpStatusbar *statusbar,
+                                    gboolean       setting)
+{
+  g_return_if_fail (GIMP_IS_STATUSBAR (statusbar));
+
+  setting = setting != FALSE;
+
+  if (setting != statusbar->has_resize_grip)
+    {
+      statusbar->has_resize_grip = setting;
+      gtk_widget_queue_draw (GTK_WIDGET (statusbar));
+
+      if (GTK_WIDGET_REALIZED (statusbar))
+        {
+          if (statusbar->has_resize_grip && statusbar->grip_window == NULL)
+            gimp_statusbar_create_window (statusbar);
+          else if (!statusbar->has_resize_grip && statusbar->grip_window != NULL)
+            gimp_statusbar_destroy_window (statusbar);
+        }
+
+      g_object_notify (G_OBJECT (statusbar), "has_resize_grip");
+    }
+}
+
+gboolean
+gimp_statusbar_get_has_resize_grip (GimpStatusbar *statusbar)
+{
+  g_return_val_if_fail (GIMP_IS_STATUSBAR (statusbar), FALSE);
+
+  return statusbar->has_resize_grip;
+}
+
+static void
+gimp_statusbar_destroy (GtkObject *object)
+{
+  GimpStatusbar *statusbar;
+  GimpStatusbarClass *class;
+  GSList *list;
+
+  g_return_if_fail (GIMP_IS_STATUSBAR (object));
+
+  statusbar = GIMP_STATUSBAR (object);
+  class = GIMP_STATUSBAR_GET_CLASS (statusbar);
+
+  for (list = statusbar->messages; list; list = list->next)
+    {
+      GimpStatusbarMsg *msg;
+
+      msg = list->data;
+      g_free (msg->text);
+      g_mem_chunk_free (class->messages_mem_chunk, msg);
+    }
+  g_slist_free (statusbar->messages);
+  statusbar->messages = NULL;
+
+  for (list = statusbar->keys; list; list = list->next)
+    g_free (list->data);
+  g_slist_free (statusbar->keys);
+  statusbar->keys = NULL;
+
+  GTK_OBJECT_CLASS (parent_class)->destroy (object);
+}
+
+static void
+gimp_statusbar_set_property (GObject      *object, 
+                             guint         prop_id, 
+                             const GValue *value, 
+                             GParamSpec   *pspec)
+{
+  GimpStatusbar *statusbar = GIMP_STATUSBAR (object);
+
+  switch (prop_id) 
+    {
+    case PROP_HAS_RESIZE_GRIP:
+      gimp_statusbar_set_has_resize_grip (statusbar, g_value_get_boolean (value));
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+    }
+}
+
+static void
+gimp_statusbar_get_property (GObject    *object, 
+                             guint       prop_id, 
+                             GValue     *value, 
+                             GParamSpec *pspec)
+{
+  GimpStatusbar *statusbar = GIMP_STATUSBAR (object);
+   
+  switch (prop_id) 
+    {
+    case PROP_HAS_RESIZE_GRIP:
+      g_value_set_boolean (value, statusbar->has_resize_grip);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+    }
+}
+
+GdkWindowEdge
+get_grip_edge (GimpStatusbar *statusbar)
+{
+  GtkWidget *widget = GTK_WIDGET (statusbar);
+
+  if (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_LTR) 
+    return GDK_WINDOW_EDGE_SOUTH_EAST; 
+  else
+    return GDK_WINDOW_EDGE_SOUTH_WEST; 
+}
+
+void
+get_grip_rect (GimpStatusbar *statusbar,
+               GdkRectangle *rect)
+{
+  GtkWidget *widget;
+  gint w, h;
+  
+  widget = GTK_WIDGET (statusbar);
+
+  /* These are in effect the max/default size of the grip. */
+  w = 18;
+  h = 18;
+
+  if (w > (widget->allocation.width))
+    w = widget->allocation.width;
+
+  if (h > (widget->allocation.height - widget->style->ythickness))
+    h = widget->allocation.height - widget->style->ythickness;
+  
+  rect->width = w;
+  rect->height = h;
+  rect->y = widget->allocation.y + widget->allocation.height - h;
+
+  if (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_LTR) 
+    rect->x = widget->allocation.x + widget->allocation.width - w;
+  else 
+    rect->x = widget->allocation.x + widget->style->xthickness;
+}
+
+void
+set_grip_cursor (GimpStatusbar *statusbar)
+{
+  if (statusbar->has_resize_grip)
+    {
+      GtkWidget *widget = GTK_WIDGET (statusbar);
+      GdkDisplay *display = gtk_widget_get_display (widget);
+      GdkCursorType cursor_type;
+      GdkCursor *cursor;
+      
+      if (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_LTR)
+        cursor_type = GDK_BOTTOM_RIGHT_CORNER;
+      else
+        cursor_type = GDK_BOTTOM_LEFT_CORNER;
+
+      cursor = gdk_cursor_new_for_display (display, cursor_type);
+      gdk_window_set_cursor (statusbar->grip_window, cursor);
+      gdk_cursor_unref (cursor);
+    }
+}
+
+guint
+gimp_statusbar_get_context_id (GimpStatusbar *statusbar,
+                               const gchar  *context_description)
+{
+  gchar *string;
+  guint *id;
+  
+  g_return_val_if_fail (GIMP_IS_STATUSBAR (statusbar), 0);
+  g_return_val_if_fail (context_description != NULL, 0);
+
+  /* we need to preserve namespaces on object datas */
+  string = g_strconcat ("gimp-status-bar-context:", context_description, NULL);
+
+  id = g_object_get_data (G_OBJECT (statusbar), string);
+  if (!id)
+    {
+      id = g_new (guint, 1);
+      *id = statusbar->seq_context_id++;
+      g_object_set_data_full (G_OBJECT (statusbar), string, id, g_free);
+      statusbar->keys = g_slist_prepend (statusbar->keys, string);
+    }
+  else
+    g_free (string);
+
+  return *id;
+}
+
Index: gimpstatusbar.h
===================================================================
RCS file: /cvs/gnome/gimp/app/display/gimpstatusbar.h,v
retrieving revision 1.5
diff -u -p -u -p -r1.5 gimpstatusbar.h
--- a/gimpstatusbar.h	10 May 2004 10:33:21 -0000	1.5
+++ b/gimpstatusbar.h	17 Jun 2004 15:42:01 -0000
@@ -19,11 +19,11 @@
 #ifndef __GIMP_STATUSBAR_H__
 #define __GIMP_STATUSBAR_H__
 
-#include <gtk/gtkstatusbar.h>
+#include <gtk/gtk.h>
+#include <gtk/gtkhbox.h>
 
 G_BEGIN_DECLS
 
-
 /*  maximal length of the format string for the cursor-coordinates  */
 #define CURSOR_FORMAT_LENGTH 32
 
@@ -35,12 +35,16 @@ G_BEGIN_DECLS
 #define GIMP_IS_STATUSBAR_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GIMP_TYPE_STATUSBAR))
 #define GIMP_STATUSBAR_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS ((obj), GIMP_TYPE_STATUSBAR, GimpStatusbarClass))
 
-
 typedef struct _GimpStatusbarClass GimpStatusbarClass;
 
 struct _GimpStatusbar
 {
-  GtkStatusbar      parent_instance;
+  GtkHBox parent_widget;
+
+  GSList *messages;
+  GSList *keys;
+  guint seq_context_id;
+  guint seq_message_id;
 
   GimpDisplayShell *shell;
 
@@ -53,35 +57,58 @@ struct _GimpStatusbar
   GtkWidget        *progressbar;
   guint             progressid;
   GtkWidget        *cancelbutton;
+
+  GdkWindow *grip_window;
+  
+  guint has_resize_grip : 1;
 };
 
 struct _GimpStatusbarClass
 {
-  GtkStatusbarClass  parent_class;
-};
-
+  GtkHBoxClass parent_class;
 
-GType       gimp_statusbar_get_type     (void) G_GNUC_CONST;
+  GMemChunk *messages_mem_chunk;
 
-GtkWidget * gimp_statusbar_new          (GimpDisplayShell *shell);
+  void  (*text_pushed) (GimpStatusbar   *statusbar,
+                        const gchar     *context_id,
+                        const gchar     *text);
+  void  (*text_popped) (GimpStatusbar   *statusbar,
+                        const gchar     *context_id,
+                        const gchar     *text);
+
+  /* Padding for future expansion */
+  void (*_gimp_reserved1) (void);
+  void (*_gimp_reserved2) (void);
+  void (*_gimp_reserved3) (void);
+  void (*_gimp_reserved4) (void);
+};
 
-void        gimp_statusbar_push         (GimpStatusbar    *statusbar,
-                                         const gchar      *context_id,
-                                         const gchar      *message);
-void        gimp_statusbar_push_coords  (GimpStatusbar    *statusbar,
-                                         const gchar      *context_id,
-                                         const gchar      *title,
-                                         gdouble           x,
-                                         const gchar      *separator,
-                                         gdouble           y);
-void        gimp_statusbar_pop          (GimpStatusbar    *statusbar,
-                                         const gchar      *context_id);
-
-void	    gimp_statusbar_set_cursor   (GimpStatusbar    *statusbar,
-                                         gdouble           x,
-                                         gdouble           y);
-void	    gimp_statusbar_clear_cursor (GimpStatusbar    *statusbar);
 
+GType       gimp_statusbar_get_type            (void) G_GNUC_CONST;
+GtkWidget * gimp_statusbar_new                 (GimpDisplayShell *shell);
+void        gimp_statusbar_pop                 (GimpStatusbar    *statusbar,
+                                                const gchar      *context);
+void        gimp_statusbar_remove              (GimpStatusbar    *statusbar,
+                                                const gchar      *context,
+                                                guint             message_id);
+guint       gimp_statusbar_push_coords         (GimpStatusbar    *statusbar,
+                                                const gchar      *context,
+                                                const gchar      *title,
+                                                gdouble           x,
+                                                const gchar      *separator,
+                                                gdouble           y);
+guint       gimp_statusbar_push                (GimpStatusbar    *statusbar,
+                                                const gchar      *context,
+                                                const gchar      *message);
+void	    gimp_statusbar_set_cursor          (GimpStatusbar    *statusbar,
+                                                gdouble           x,
+                                                gdouble           y);
+void	    gimp_statusbar_clear_cursor        (GimpStatusbar    *statusbar);
+guint       gimp_statusbar_get_context_id      (GimpStatusbar    *statusbar,
+                                                const gchar      *context_description);
+void        gimp_statusbar_set_has_resize_grip (GimpStatusbar    *statusbar,
+                                                gboolean          setting);
+gboolean    gimp_statusbar_get_has_resize_grip (GimpStatusbar    *statusbar);
 
 G_END_DECLS
 
