]> Pileus Git - ~andy/gtk/blob - gtk/gtkstatusbar.c
Remove resize grip handling from GtkStatusbar
[~andy/gtk] / gtk / gtkstatusbar.c
1 /* GTK - The GIMP Toolkit
2  * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
3  * GtkStatusbar Copyright (C) 1998 Shawn T. Amundson
4  *
5  * This library is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Lesser General Public
7  * License as published by the Free Software Foundation; either
8  * version 2 of the License, or (at your option) any later version.
9  *
10  * This library is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * Lesser General Public License for more details.
14  *
15  * You should have received a copy of the GNU Lesser General Public
16  * License along with this library; if not, write to the
17  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18  * Boston, MA 02111-1307, USA.
19  */
20
21 /*
22  * Modified by the GTK+ Team and others 1997-2000.  See the AUTHORS
23  * file for a list of people on the GTK+ Team.  See the ChangeLog
24  * files for a list of changes.  These files are distributed with
25  * GTK+ at ftp://ftp.gtk.org/pub/gtk/.
26  */
27
28 #include "config.h"
29 #include "gtkframe.h"
30 #include "gtklabel.h"
31 #include "gtkmarshalers.h"
32 #include "gtkstatusbar.h"
33 #include "gtkwindow.h"
34 #include "gtkprivate.h"
35 #include "gtkintl.h"
36 #include "gtkbuildable.h"
37
38 /**
39  * SECTION:gtkstatusbar
40  * @title: GtkStatusbar
41  * @short_description: Report messages of minor importance to the user
42  *
43  * A #GtkStatusbar is usually placed along the bottom of an application's
44  * main #GtkWindow. It may provide a regular commentary of the application's
45  * status (as is usually the case in a web browser, for example), or may be
46  * used to simply output a message when the status changes, (when an upload
47  * is complete in an FTP client, for example).
48  *
49  * Status bars in GTK+ maintain a stack of messages. The message at
50  * the top of the each bar's stack is the one that will currently be displayed.
51  *
52  * Any messages added to a statusbar's stack must specify a
53  * <emphasis>context id</emphasis> that is used to uniquely identify
54  * the source of a message. This context id can be generated by
55  * gtk_statusbar_get_context_id(), given a message and the statusbar that
56  * it will be added to. Note that messages are stored in a stack, and when
57  * choosing which message to display, the stack structure is adhered to,
58  * regardless of the context identifier of a message.
59  *
60  * One could say that a statusbar maintains one stack of messages for
61  * display purposes, but allows multiple message producers to maintain
62  * sub-stacks of the messages they produced (via context ids).
63  *
64  * Status bars are created using gtk_statusbar_new().
65  *
66  * Messages are added to the bar's stack with gtk_statusbar_push().
67  *
68  * The message at the top of the stack can be removed using
69  * gtk_statusbar_pop(). A message can be removed from anywhere in the
70  * stack if its message id was recorded at the time it was added. This
71  * is done using gtk_statusbar_remove().
72  */
73 typedef struct _GtkStatusbarMsg GtkStatusbarMsg;
74
75 struct _GtkStatusbarPrivate
76 {
77   GtkWidget     *frame;
78   GtkWidget     *label;
79
80   GSList        *messages;
81   GSList        *keys;
82
83   guint          seq_context_id;
84   guint          seq_message_id;
85 };
86
87
88 struct _GtkStatusbarMsg
89 {
90   gchar *text;
91   guint context_id;
92   guint message_id;
93 };
94
95 enum
96 {
97   SIGNAL_TEXT_PUSHED,
98   SIGNAL_TEXT_POPPED,
99   SIGNAL_LAST
100 };
101
102 static void     gtk_statusbar_buildable_interface_init    (GtkBuildableIface *iface);
103 static GObject *gtk_statusbar_buildable_get_internal_child (GtkBuildable *buildable,
104                                                             GtkBuilder   *builder,
105                                                             const gchar  *childname);
106 static void     gtk_statusbar_update            (GtkStatusbar      *statusbar,
107                                                  guint              context_id,
108                                                  const gchar       *text);
109 static void     gtk_statusbar_destroy           (GtkWidget         *widget);
110 static void     gtk_statusbar_size_allocate     (GtkWidget         *widget,
111                                                  GtkAllocation     *allocation);
112 static void     gtk_statusbar_hierarchy_changed (GtkWidget         *widget,
113                                                  GtkWidget         *previous_toplevel);
114
115
116 static guint              statusbar_signals[SIGNAL_LAST] = { 0 };
117
118 G_DEFINE_TYPE_WITH_CODE (GtkStatusbar, gtk_statusbar, GTK_TYPE_HBOX,
119                          G_IMPLEMENT_INTERFACE (GTK_TYPE_BUILDABLE,
120                                                 gtk_statusbar_buildable_interface_init));
121
122 static void
123 gtk_statusbar_class_init (GtkStatusbarClass *class)
124 {
125   GObjectClass *gobject_class;
126   GtkWidgetClass *widget_class;
127
128   gobject_class = (GObjectClass *) class;
129   widget_class = (GtkWidgetClass *) class;
130
131   widget_class->destroy = gtk_statusbar_destroy;
132   widget_class->size_allocate = gtk_statusbar_size_allocate;
133   widget_class->hierarchy_changed = gtk_statusbar_hierarchy_changed;
134
135   class->text_pushed = gtk_statusbar_update;
136   class->text_popped = gtk_statusbar_update;
137
138   /** 
139    * GtkStatusbar::text-pushed:
140    * @statusbar: the object which received the signal.
141    * @context_id: the context id of the relevant message/statusbar.
142    * @text: the message that was pushed.
143    * 
144    * Is emitted whenever a new message gets pushed onto a statusbar's stack.
145    */
146   statusbar_signals[SIGNAL_TEXT_PUSHED] =
147     g_signal_new (I_("text-pushed"),
148                   G_OBJECT_CLASS_TYPE (class),
149                   G_SIGNAL_RUN_LAST,
150                   G_STRUCT_OFFSET (GtkStatusbarClass, text_pushed),
151                   NULL, NULL,
152                   _gtk_marshal_VOID__UINT_STRING,
153                   G_TYPE_NONE, 2,
154                   G_TYPE_UINT,
155                   G_TYPE_STRING);
156
157   /**
158    * GtkStatusbar::text-popped:
159    * @statusbar: the object which received the signal.
160    * @context_id: the context id of the relevant message/statusbar.
161    * @text: the message that was just popped.
162    *
163    * Is emitted whenever a new message is popped off a statusbar's stack.
164    */
165   statusbar_signals[SIGNAL_TEXT_POPPED] =
166     g_signal_new (I_("text-popped"),
167                   G_OBJECT_CLASS_TYPE (class),
168                   G_SIGNAL_RUN_LAST,
169                   G_STRUCT_OFFSET (GtkStatusbarClass, text_popped),
170                   NULL, NULL,
171                   _gtk_marshal_VOID__UINT_STRING,
172                   G_TYPE_NONE, 2,
173                   G_TYPE_UINT,
174                   G_TYPE_STRING);
175
176   gtk_widget_class_install_style_property (widget_class,
177                                            g_param_spec_enum ("shadow-type",
178                                                               P_("Shadow type"),
179                                                               P_("Style of bevel around the statusbar text"),
180                                                               GTK_TYPE_SHADOW_TYPE,
181                                                               GTK_SHADOW_IN,
182                                                               GTK_PARAM_READABLE));
183
184    g_type_class_add_private (class, sizeof (GtkStatusbarPrivate));
185 }
186
187 static void
188 gtk_statusbar_init (GtkStatusbar *statusbar)
189 {
190   GtkStatusbarPrivate *priv;
191   GtkBox *box = GTK_BOX (statusbar);
192   GtkWidget *message_area;
193   GtkShadowType shadow_type;
194
195   statusbar->priv = G_TYPE_INSTANCE_GET_PRIVATE (statusbar,
196                                                  GTK_TYPE_STATUSBAR,
197                                                  GtkStatusbarPrivate);
198   priv = statusbar->priv;
199
200   gtk_widget_set_redraw_on_allocate (GTK_WIDGET (box), TRUE);
201
202   gtk_box_set_spacing (box, 2);
203   gtk_box_set_homogeneous (box, FALSE);
204
205   gtk_widget_style_get (GTK_WIDGET (statusbar), "shadow-type", &shadow_type, NULL);
206
207   priv->frame = gtk_frame_new (NULL);
208   gtk_frame_set_shadow_type (GTK_FRAME (priv->frame), shadow_type);
209   gtk_box_pack_start (box, priv->frame, TRUE, TRUE, 0);
210   gtk_widget_show (priv->frame);
211
212   message_area = gtk_hbox_new (FALSE, 4);
213   gtk_container_add (GTK_CONTAINER (priv->frame), message_area);
214   gtk_widget_show (message_area);
215
216   priv->label = gtk_label_new ("");
217   gtk_label_set_single_line_mode (GTK_LABEL (priv->label), TRUE);
218   gtk_misc_set_alignment (GTK_MISC (priv->label), 0.0, 0.5);
219   gtk_label_set_ellipsize (GTK_LABEL (priv->label), PANGO_ELLIPSIZE_END);
220   gtk_container_add (GTK_CONTAINER (message_area), priv->label);
221   gtk_widget_show (priv->label);
222
223   priv->seq_context_id = 1;
224   priv->seq_message_id = 1;
225   priv->messages = NULL;
226   priv->keys = NULL;
227 }
228
229 static GtkBuildableIface *parent_buildable_iface;
230
231 static void
232 gtk_statusbar_buildable_interface_init (GtkBuildableIface *iface)
233 {
234   parent_buildable_iface = g_type_interface_peek_parent (iface);
235   iface->get_internal_child = gtk_statusbar_buildable_get_internal_child;
236 }
237
238 static GObject *
239 gtk_statusbar_buildable_get_internal_child (GtkBuildable *buildable,
240                                             GtkBuilder   *builder,
241                                             const gchar  *childname)
242 {
243   GtkStatusbar *statusbar = GTK_STATUSBAR (buildable);
244   GtkStatusbarPrivate *priv = statusbar->priv;
245
246     if (strcmp (childname, "message_area") == 0)
247       return G_OBJECT (gtk_bin_get_child (GTK_BIN (priv->frame)));
248
249     return parent_buildable_iface->get_internal_child (buildable,
250                                                        builder,
251                                                        childname);
252 }
253
254 /**
255  * gtk_statusbar_new:
256  *
257  * Creates a new #GtkStatusbar ready for messages.
258  *
259  * Returns: the new #GtkStatusbar
260  */
261 GtkWidget* 
262 gtk_statusbar_new (void)
263 {
264   return g_object_new (GTK_TYPE_STATUSBAR, NULL);
265 }
266
267 static void
268 gtk_statusbar_update (GtkStatusbar *statusbar,
269                       guint         context_id,
270                       const gchar  *text)
271 {
272   GtkStatusbarPrivate *priv;
273
274   g_return_if_fail (GTK_IS_STATUSBAR (statusbar));
275
276   priv = statusbar->priv;
277
278   if (!text)
279     text = "";
280
281   gtk_label_set_text (GTK_LABEL (priv->label), text);
282 }
283
284 /**
285  * gtk_statusbar_get_context_id:
286  * @statusbar: a #GtkStatusbar
287  * @context_description: textual description of what context 
288  *                       the new message is being used in
289  *
290  * Returns a new context identifier, given a description 
291  * of the actual context. Note that the description is 
292  * <emphasis>not</emphasis> shown in the UI.
293  *
294  * Returns: an integer id
295  */
296 guint
297 gtk_statusbar_get_context_id (GtkStatusbar *statusbar,
298                               const gchar  *context_description)
299 {
300   GtkStatusbarPrivate *priv;
301   gchar *string;
302   guint id;
303   
304   g_return_val_if_fail (GTK_IS_STATUSBAR (statusbar), 0);
305   g_return_val_if_fail (context_description != NULL, 0);
306
307   priv = statusbar->priv;
308
309   /* we need to preserve namespaces on object datas */
310   string = g_strconcat ("gtk-status-bar-context:", context_description, NULL);
311
312   id = GPOINTER_TO_UINT (g_object_get_data (G_OBJECT (statusbar), string));
313   if (id == 0)
314     {
315       id = priv->seq_context_id++;
316       g_object_set_data_full (G_OBJECT (statusbar), string, GUINT_TO_POINTER (id), NULL);
317       priv->keys = g_slist_prepend (priv->keys, string);
318     }
319   else
320     g_free (string);
321
322   return id;
323 }
324
325 /**
326  * gtk_statusbar_push:
327  * @statusbar: a #GtkStatusbar
328  * @context_id: the message's context id, as returned by
329  *              gtk_statusbar_get_context_id()
330  * @text: the message to add to the statusbar
331  * 
332  * Pushes a new message onto a statusbar's stack.
333  *
334  * Returns: a message id that can be used with 
335  *          gtk_statusbar_remove().
336  */
337 guint
338 gtk_statusbar_push (GtkStatusbar *statusbar,
339                     guint         context_id,
340                     const gchar  *text)
341 {
342   GtkStatusbarPrivate *priv;
343   GtkStatusbarMsg *msg;
344
345   g_return_val_if_fail (GTK_IS_STATUSBAR (statusbar), 0);
346   g_return_val_if_fail (text != NULL, 0);
347
348   priv = statusbar->priv;
349
350   msg = g_slice_new (GtkStatusbarMsg);
351   msg->text = g_strdup (text);
352   msg->context_id = context_id;
353   msg->message_id = priv->seq_message_id++;
354
355   priv->messages = g_slist_prepend (priv->messages, msg);
356
357   g_signal_emit (statusbar,
358                  statusbar_signals[SIGNAL_TEXT_PUSHED],
359                  0,
360                  msg->context_id,
361                  msg->text);
362
363   return msg->message_id;
364 }
365
366 /**
367  * gtk_statusbar_pop:
368  * @statusbar: a #GtkStatusBar
369  * @context_id: a context identifier
370  * 
371  * Removes the first message in the #GtkStatusBar's stack
372  * with the given context id. 
373  *
374  * Note that this may not change the displayed message, if 
375  * the message at the top of the stack has a different 
376  * context id.
377  */
378 void
379 gtk_statusbar_pop (GtkStatusbar *statusbar,
380                    guint         context_id)
381 {
382   GtkStatusbarPrivate *priv;
383   GtkStatusbarMsg *msg;
384
385   g_return_if_fail (GTK_IS_STATUSBAR (statusbar));
386
387   priv = statusbar->priv;
388
389   if (priv->messages)
390     {
391       GSList *list;
392
393       for (list = priv->messages; list; list = list->next)
394         {
395           msg = list->data;
396
397           if (msg->context_id == context_id)
398             {
399               priv->messages = g_slist_remove_link (priv->messages,
400                                                          list);
401               g_free (msg->text);
402               g_slice_free (GtkStatusbarMsg, msg);
403               g_slist_free_1 (list);
404               break;
405             }
406         }
407     }
408
409   msg = priv->messages ? priv->messages->data : NULL;
410
411   g_signal_emit (statusbar,
412                  statusbar_signals[SIGNAL_TEXT_POPPED],
413                  0,
414                  (guint) (msg ? msg->context_id : 0),
415                  msg ? msg->text : NULL);
416 }
417
418 /**
419  * gtk_statusbar_remove:
420  * @statusbar: a #GtkStatusBar
421  * @context_id: a context identifier
422  * @message_id: a message identifier, as returned by gtk_statusbar_push()
423  *
424  * Forces the removal of a message from a statusbar's stack. 
425  * The exact @context_id and @message_id must be specified.
426  */
427 void
428 gtk_statusbar_remove (GtkStatusbar *statusbar,
429                       guint        context_id,
430                       guint        message_id)
431 {
432   GtkStatusbarPrivate *priv;
433   GtkStatusbarMsg *msg;
434
435   g_return_if_fail (GTK_IS_STATUSBAR (statusbar));
436   g_return_if_fail (message_id > 0);
437
438   priv = statusbar->priv;
439
440   msg = priv->messages ? priv->messages->data : NULL;
441   if (msg)
442     {
443       GSList *list;
444
445       /* care about signal emission if the topmost item is removed */
446       if (msg->context_id == context_id &&
447           msg->message_id == message_id)
448         {
449           gtk_statusbar_pop (statusbar, context_id);
450           return;
451         }
452       
453       for (list = priv->messages; list; list = list->next)
454         {
455           msg = list->data;
456           
457           if (msg->context_id == context_id &&
458               msg->message_id == message_id)
459             {
460               priv->messages = g_slist_remove_link (priv->messages, list);
461               g_free (msg->text);
462               g_slice_free (GtkStatusbarMsg, msg);
463               g_slist_free_1 (list);
464               
465               break;
466             }
467         }
468     }
469 }
470
471 /**
472  * gtk_statusbar_remove_all:
473  * @statusbar: a #GtkStatusBar
474  * @context_id: a context identifier
475  *
476  * Forces the removal of all messages from a statusbar's
477  * stack with the exact @context_id.
478  *
479  * Since: 2.22
480  */
481 void
482 gtk_statusbar_remove_all (GtkStatusbar *statusbar,
483                           guint         context_id)
484 {
485   GtkStatusbarPrivate *priv;
486   GtkStatusbarMsg *msg;
487   GSList *prev, *list;
488
489   g_return_if_fail (GTK_IS_STATUSBAR (statusbar));
490
491   priv = statusbar->priv;
492
493   if (priv->messages == NULL)
494     return;
495
496   msg = priv->messages->data;
497
498   /* care about signal emission if the topmost item is removed */
499   if (msg->context_id == context_id)
500     {
501       gtk_statusbar_pop (statusbar, context_id);
502
503       prev = NULL;
504       list = priv->messages;
505     }
506   else
507     {
508       prev = priv->messages;
509       list = prev->next;
510     }
511
512   while (list != NULL)
513     {
514       msg = list->data;
515
516       if (msg->context_id == context_id)
517         {
518           if (prev == NULL)
519             priv->messages = list->next;
520           else
521             prev->next = list->next;
522
523           g_free (msg->text);
524           g_slice_free (GtkStatusbarMsg, msg);
525           g_slist_free_1 (list);
526
527           if (prev == NULL)
528             prev = priv->messages;
529
530           list = prev->next;
531         }
532       else
533         {
534           prev = list;
535           list = prev->next;
536         }
537     }
538 }
539
540 /**
541  * gtk_statusbar_get_message_area:
542  * @statusbar: a #GtkStatusBar
543  *
544  * Retrieves the box containing the label widget.
545  *
546  * Returns: (transfer none): a #GtkBox
547  *
548  * Since: 2.20
549  */
550 GtkWidget*
551 gtk_statusbar_get_message_area (GtkStatusbar *statusbar)
552 {
553   GtkStatusbarPrivate *priv;
554
555   g_return_val_if_fail (GTK_IS_STATUSBAR (statusbar), NULL);
556
557   priv = statusbar->priv;
558
559   return gtk_bin_get_child (GTK_BIN (priv->frame));
560 }
561
562 static void
563 gtk_statusbar_destroy (GtkWidget *widget)
564 {
565   GtkStatusbar *statusbar = GTK_STATUSBAR (widget);
566   GtkStatusbarPrivate *priv = statusbar->priv;
567   GSList *list;
568
569   for (list = priv->messages; list; list = list->next)
570     {
571       GtkStatusbarMsg *msg;
572
573       msg = list->data;
574       g_free (msg->text);
575       g_slice_free (GtkStatusbarMsg, msg);
576     }
577   g_slist_free (priv->messages);
578   priv->messages = NULL;
579
580   for (list = priv->keys; list; list = list->next)
581     g_free (list->data);
582   g_slist_free (priv->keys);
583   priv->keys = NULL;
584
585   GTK_WIDGET_CLASS (gtk_statusbar_parent_class)->destroy (widget);
586 }
587
588 /* look for extra children between the frame containing
589  * the label and where we want to draw the resize grip
590  */
591 static gboolean
592 has_extra_children (GtkStatusbar *statusbar)
593 {
594   GtkStatusbarPrivate *priv = statusbar->priv;
595   GtkPackType child_pack_type, frame_pack_type;
596   GtkWidget *child, *frame;
597   GList *l, *children;
598   gboolean retval = FALSE;
599
600   frame = NULL;
601   children = _gtk_box_get_children (GTK_BOX (statusbar));
602   for (l = children; l; l = l->next)
603     {
604       frame = l->data;
605
606       if (frame == priv->frame)
607         break;
608     }
609
610   gtk_box_query_child_packing (GTK_BOX (statusbar), frame,
611                                NULL, NULL, NULL, &frame_pack_type);
612
613   for (l = l->next; l; l = l->next)
614     {
615       child = l->data;
616
617       if (!gtk_widget_get_visible (child))
618         continue;
619
620       gtk_box_query_child_packing (GTK_BOX (statusbar), child,
621                                    NULL, NULL, NULL, &child_pack_type);
622
623       if (frame_pack_type == GTK_PACK_START || child_pack_type == GTK_PACK_END)
624         {
625           retval = TRUE;
626           break;
627         }
628     }
629
630   g_list_free (children);
631
632   return retval;
633 }
634
635 static void
636 gtk_statusbar_size_allocate (GtkWidget     *widget,
637                              GtkAllocation *allocation)
638 {
639   GtkStatusbar *statusbar = GTK_STATUSBAR (widget);
640   GtkStatusbarPrivate *priv = statusbar->priv;
641   gboolean extra_children = FALSE;
642   gboolean has_resize_grip = FALSE;
643   GdkRectangle rect;
644   GtkWidget *window;
645   gint x, y;
646   GdkRectangle translated_rect;
647
648   window = gtk_widget_get_toplevel (widget);
649   if (GTK_IS_WINDOW (window) &&
650       gtk_window_resize_grip_is_visible (GTK_WINDOW (window)))
651     {
652       gtk_window_get_resize_grip_area (GTK_WINDOW (window), &rect);
653
654       if (gtk_widget_translate_coordinates (gtk_widget_get_parent (widget),
655                                             window,
656                                             allocation->x,
657                                             allocation->y,
658                                             &x,
659                                             &y))
660         {
661           translated_rect.x = x;
662           translated_rect.y = y;
663           translated_rect.width = allocation->width;
664           translated_rect.height = allocation->height;
665
666           if (gdk_rectangle_intersect (&rect, &translated_rect, NULL))
667             {
668               has_resize_grip = TRUE;
669               extra_children = has_extra_children (statusbar);
670
671               /* If there are extra children, we don't want them to occupy
672                * the space where we draw the resize grip, so we temporarily
673                * shrink the allocation.
674                * If there are no extra children, we want the frame to get
675                * the full allocation, and we fix up the allocation of the
676                * label afterwards to make room for the grip.
677                */
678               if (extra_children)
679                 {
680                   allocation->width -= rect.width;
681                   if (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL)
682                     allocation->x += rect.width;
683                 }
684             }
685         }
686     }
687
688   /* chain up normally */
689   GTK_WIDGET_CLASS (gtk_statusbar_parent_class)->size_allocate (widget, allocation);
690
691   if (has_resize_grip)
692     {
693       if (extra_children)
694         {
695           allocation->width += rect.width;
696           if (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL)
697             allocation->x -= rect.width;
698
699           gtk_widget_set_allocation (widget, allocation);
700         }
701       else
702         {
703           GtkAllocation child_allocation, frame_allocation;
704           GtkWidget *child;
705
706           /* Use the frame's child instead of statusbar->label directly, in case
707            * the label has been replaced by a container as the frame's child
708            * (and the label reparented into that container).
709            */
710           child = gtk_bin_get_child (GTK_BIN (priv->frame));
711
712           gtk_widget_get_allocation (child, &child_allocation);
713           gtk_widget_get_allocation (priv->frame, &frame_allocation);
714           if (child_allocation.width + rect.width > frame_allocation.width)
715             {
716               /* shrink the label to make room for the grip */
717               *allocation = child_allocation;
718               allocation->width = MAX (1, allocation->width - rect.width);
719               if (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL)
720                 allocation->x += child_allocation.width - allocation->width;
721
722               gtk_widget_size_allocate (child, allocation);
723             }
724         }
725     }
726 }
727
728 static void
729 resize_grip_visible_changed (GObject    *object,
730                              GParamSpec *pspec,
731                              gpointer    user_data)
732 {
733   GtkStatusbar *statusbar = GTK_STATUSBAR (user_data);
734   GtkStatusbarPrivate *priv = statusbar->priv;
735
736   gtk_widget_queue_resize (GTK_WIDGET (statusbar));
737   gtk_widget_queue_resize (priv->label);
738   gtk_widget_queue_resize (priv->frame);
739 }
740
741 static void
742 gtk_statusbar_hierarchy_changed (GtkWidget *widget,
743                                  GtkWidget *previous_toplevel)
744 {
745   GtkWidget *window;
746
747   if (previous_toplevel)
748     g_signal_handlers_disconnect_by_func (previous_toplevel,
749                                           G_CALLBACK (resize_grip_visible_changed),
750                                           widget);
751   window = gtk_widget_get_toplevel (widget);
752   if (GTK_IS_WINDOW (window))
753     g_signal_connect (window, "notify::resize-grip-visible",
754                       G_CALLBACK (resize_grip_visible_changed), widget);
755 }