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
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.
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.
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.
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/.
30 #include "gtksignal.h"
31 #include "gtkstatusbar.h"
32 #include "gtkwindow.h"
34 typedef struct _GtkStatusbarMsg GtkStatusbarMsg;
36 struct _GtkStatusbarMsg
50 static void gtk_statusbar_class_init (GtkStatusbarClass *class);
51 static void gtk_statusbar_init (GtkStatusbar *statusbar);
52 static void gtk_statusbar_destroy (GtkObject *object);
53 static void gtk_statusbar_update (GtkStatusbar *statusbar,
56 static void gtk_statusbar_size_allocate (GtkWidget *widget,
57 GtkAllocation *allocation);
58 static void gtk_statusbar_realize (GtkWidget *widget);
59 static void gtk_statusbar_unrealize (GtkWidget *widget);
60 static void gtk_statusbar_map (GtkWidget *widget);
61 static void gtk_statusbar_unmap (GtkWidget *widget);
62 static gboolean gtk_statusbar_button_press (GtkWidget *widget,
63 GdkEventButton *event);
64 static gboolean gtk_statusbar_expose_event (GtkWidget *widget,
65 GdkEventExpose *event);
66 static void gtk_statusbar_create_window (GtkStatusbar *statusbar);
67 static void gtk_statusbar_destroy_window (GtkStatusbar *statusbar);
69 static GtkContainerClass *parent_class;
70 static guint statusbar_signals[SIGNAL_LAST] = { 0 };
73 gtk_statusbar_get_type (void)
75 static GtkType statusbar_type = 0;
79 static const GtkTypeInfo statusbar_info =
82 sizeof (GtkStatusbar),
83 sizeof (GtkStatusbarClass),
84 (GtkClassInitFunc) gtk_statusbar_class_init,
85 (GtkObjectInitFunc) gtk_statusbar_init,
86 /* reserved_1 */ NULL,
87 /* reserved_2 */ NULL,
88 (GtkClassInitFunc) NULL,
91 statusbar_type = gtk_type_unique (GTK_TYPE_HBOX, &statusbar_info);
94 return statusbar_type;
98 gtk_statusbar_class_init (GtkStatusbarClass *class)
100 GtkObjectClass *object_class;
101 GtkWidgetClass *widget_class;
102 GtkContainerClass *container_class;
104 object_class = (GtkObjectClass *) class;
105 widget_class = (GtkWidgetClass *) class;
106 container_class = (GtkContainerClass *) class;
108 parent_class = gtk_type_class (GTK_TYPE_HBOX);
110 object_class->destroy = gtk_statusbar_destroy;
112 widget_class->size_allocate = gtk_statusbar_size_allocate;
114 widget_class->realize = gtk_statusbar_realize;
115 widget_class->unrealize = gtk_statusbar_unrealize;
116 widget_class->map = gtk_statusbar_map;
117 widget_class->unmap = gtk_statusbar_unmap;
119 widget_class->button_press_event = gtk_statusbar_button_press;
120 widget_class->expose_event = gtk_statusbar_expose_event;
122 class->messages_mem_chunk = g_mem_chunk_new ("GtkStatusBar messages mem chunk",
123 sizeof (GtkStatusbarMsg),
124 sizeof (GtkStatusbarMsg) * 64,
127 class->text_pushed = gtk_statusbar_update;
128 class->text_popped = gtk_statusbar_update;
130 statusbar_signals[SIGNAL_TEXT_PUSHED] =
131 gtk_signal_new ("text_pushed",
133 GTK_CLASS_TYPE (object_class),
134 GTK_SIGNAL_OFFSET (GtkStatusbarClass, text_pushed),
135 gtk_marshal_VOID__UINT_STRING,
139 statusbar_signals[SIGNAL_TEXT_POPPED] =
140 gtk_signal_new ("text_popped",
142 GTK_CLASS_TYPE (object_class),
143 GTK_SIGNAL_OFFSET (GtkStatusbarClass, text_popped),
144 gtk_marshal_VOID__UINT_STRING,
151 gtk_statusbar_init (GtkStatusbar *statusbar)
155 box = GTK_BOX (statusbar);
158 box->homogeneous = FALSE;
160 statusbar->has_resize_grip = TRUE;
162 statusbar->frame = gtk_frame_new (NULL);
163 gtk_frame_set_shadow_type (GTK_FRAME (statusbar->frame), GTK_SHADOW_IN);
164 gtk_box_pack_start (box, statusbar->frame, TRUE, TRUE, 0);
165 gtk_widget_show (statusbar->frame);
167 statusbar->label = gtk_label_new ("");
168 gtk_misc_set_alignment (GTK_MISC (statusbar->label), 0.0, 0.0);
169 gtk_container_add (GTK_CONTAINER (statusbar->frame), statusbar->label);
170 gtk_widget_show (statusbar->label);
172 statusbar->seq_context_id = 1;
173 statusbar->seq_message_id = 1;
174 statusbar->messages = NULL;
175 statusbar->keys = NULL;
179 gtk_statusbar_new (void)
181 return gtk_type_new (GTK_TYPE_STATUSBAR);
185 gtk_statusbar_update (GtkStatusbar *statusbar,
189 g_return_if_fail (statusbar != NULL);
190 g_return_if_fail (GTK_IS_STATUSBAR (statusbar));
195 gtk_label_set_text (GTK_LABEL (statusbar->label), text);
199 gtk_statusbar_get_context_id (GtkStatusbar *statusbar,
200 const gchar *context_description)
205 g_return_val_if_fail (statusbar != NULL, 0);
206 g_return_val_if_fail (GTK_IS_STATUSBAR (statusbar), 0);
207 g_return_val_if_fail (context_description != NULL, 0);
209 /* we need to preserve namespaces on object datas */
210 string = g_strconcat ("gtk-status-bar-context:", context_description, NULL);
212 id = gtk_object_get_data (GTK_OBJECT (statusbar), string);
215 id = g_new (guint, 1);
216 *id = statusbar->seq_context_id++;
217 gtk_object_set_data_full (GTK_OBJECT (statusbar), string, id, (GtkDestroyNotify) g_free);
218 statusbar->keys = g_slist_prepend (statusbar->keys, string);
227 gtk_statusbar_push (GtkStatusbar *statusbar,
231 GtkStatusbarMsg *msg;
232 GtkStatusbarClass *class;
234 g_return_val_if_fail (statusbar != NULL, 0);
235 g_return_val_if_fail (GTK_IS_STATUSBAR (statusbar), 0);
236 g_return_val_if_fail (text != NULL, 0);
238 class = GTK_STATUSBAR_GET_CLASS (statusbar);
239 msg = g_chunk_new (GtkStatusbarMsg, class->messages_mem_chunk);
240 msg->text = g_strdup (text);
241 msg->context_id = context_id;
242 msg->message_id = statusbar->seq_message_id++;
244 statusbar->messages = g_slist_prepend (statusbar->messages, msg);
246 gtk_signal_emit (GTK_OBJECT (statusbar),
247 statusbar_signals[SIGNAL_TEXT_PUSHED],
251 return msg->message_id;
255 gtk_statusbar_pop (GtkStatusbar *statusbar,
258 GtkStatusbarMsg *msg;
260 g_return_if_fail (statusbar != NULL);
261 g_return_if_fail (GTK_IS_STATUSBAR (statusbar));
263 if (statusbar->messages)
267 for (list = statusbar->messages; list; list = list->next)
271 if (msg->context_id == context_id)
273 GtkStatusbarClass *class;
275 class = GTK_STATUSBAR_GET_CLASS (statusbar);
277 statusbar->messages = g_slist_remove_link (statusbar->messages,
280 g_mem_chunk_free (class->messages_mem_chunk, msg);
281 g_slist_free_1 (list);
287 msg = statusbar->messages ? statusbar->messages->data : NULL;
289 gtk_signal_emit (GTK_OBJECT (statusbar),
290 statusbar_signals[SIGNAL_TEXT_POPPED],
291 (guint) (msg ? msg->context_id : 0),
292 msg ? msg->text : NULL);
296 gtk_statusbar_remove (GtkStatusbar *statusbar,
300 GtkStatusbarMsg *msg;
302 g_return_if_fail (statusbar != NULL);
303 g_return_if_fail (GTK_IS_STATUSBAR (statusbar));
304 g_return_if_fail (message_id > 0);
306 msg = statusbar->messages ? statusbar->messages->data : NULL;
311 /* care about signal emission if the topmost item is removed */
312 if (msg->context_id == context_id &&
313 msg->message_id == message_id)
315 gtk_statusbar_pop (statusbar, context_id);
319 for (list = statusbar->messages; list; list = list->next)
323 if (msg->context_id == context_id &&
324 msg->message_id == message_id)
326 GtkStatusbarClass *class;
328 class = GTK_STATUSBAR_GET_CLASS (statusbar);
329 statusbar->messages = g_slist_remove_link (statusbar->messages, list);
331 g_mem_chunk_free (class->messages_mem_chunk, msg);
332 g_slist_free_1 (list);
341 gtk_statusbar_set_has_resize_grip (GtkStatusbar *statusbar,
344 g_return_if_fail (GTK_IS_STATUSBAR (statusbar));
346 setting = setting != FALSE;
348 if (setting != statusbar->has_resize_grip)
350 statusbar->has_resize_grip = setting;
351 gtk_widget_queue_draw (GTK_WIDGET (statusbar));
353 if (GTK_WIDGET_REALIZED (statusbar))
355 if (statusbar->has_resize_grip && statusbar->grip_window == NULL)
356 gtk_statusbar_create_window (statusbar);
357 else if (!statusbar->has_resize_grip && statusbar->grip_window != NULL)
358 gtk_statusbar_destroy_window (statusbar);
364 gtk_statusbar_get_has_resize_grip (GtkStatusbar *statusbar)
366 g_return_val_if_fail (GTK_IS_STATUSBAR (statusbar), FALSE);
368 return statusbar->has_resize_grip;
372 gtk_statusbar_destroy (GtkObject *object)
374 GtkStatusbar *statusbar;
375 GtkStatusbarClass *class;
378 g_return_if_fail (object != NULL);
379 g_return_if_fail (GTK_IS_STATUSBAR (object));
381 statusbar = GTK_STATUSBAR (object);
382 class = GTK_STATUSBAR_GET_CLASS (statusbar);
384 for (list = statusbar->messages; list; list = list->next)
386 GtkStatusbarMsg *msg;
390 g_mem_chunk_free (class->messages_mem_chunk, msg);
392 g_slist_free (statusbar->messages);
393 statusbar->messages = NULL;
395 for (list = statusbar->keys; list; list = list->next)
397 g_slist_free (statusbar->keys);
398 statusbar->keys = NULL;
400 GTK_OBJECT_CLASS (parent_class)->destroy (object);
404 get_grip_rect (GtkStatusbar *statusbar,
410 widget = GTK_WIDGET (statusbar);
412 /* These are in effect the max/default size of the grip. */
416 if (w > (widget->allocation.width))
417 w = widget->allocation.width;
419 if (h > (widget->allocation.height - widget->style->ythickness))
420 h = widget->allocation.height - widget->style->ythickness;
422 rect->x = widget->allocation.x + widget->allocation.width - w;
423 rect->y = widget->allocation.y + widget->allocation.height - h;
429 gtk_statusbar_size_allocate (GtkWidget *widget,
430 GtkAllocation *allocation)
432 GtkStatusbar *statusbar;
435 statusbar = GTK_STATUSBAR (widget);
437 GTK_WIDGET_CLASS (parent_class)->size_allocate (widget, allocation);
439 get_grip_rect (statusbar, &rect);
441 if (statusbar->grip_window)
442 gdk_window_move_resize (statusbar->grip_window,
444 rect.width, rect.height);
448 gtk_statusbar_create_window (GtkStatusbar *statusbar)
451 GdkWindowAttr attributes;
452 gint attributes_mask;
455 g_return_if_fail (GTK_WIDGET_REALIZED (statusbar));
456 g_return_if_fail (statusbar->has_resize_grip);
458 widget = GTK_WIDGET (statusbar);
460 get_grip_rect (statusbar, &rect);
462 attributes.x = rect.x;
463 attributes.y = rect.y;
464 attributes.width = rect.width;
465 attributes.height = rect.height;
466 attributes.window_type = GDK_WINDOW_CHILD;
467 attributes.wclass = GDK_INPUT_ONLY;
468 attributes.event_mask = gtk_widget_get_events (widget) |
469 GDK_BUTTON_PRESS_MASK;
471 attributes_mask = GDK_WA_X | GDK_WA_Y;
473 statusbar->grip_window = gdk_window_new (widget->window,
474 &attributes, attributes_mask);
475 gdk_window_set_user_data (statusbar->grip_window, widget);
479 gtk_statusbar_destroy_window (GtkStatusbar *statusbar)
481 gdk_window_set_user_data (statusbar->grip_window, NULL);
482 gdk_window_destroy (statusbar->grip_window);
483 statusbar->grip_window = NULL;
487 gtk_statusbar_realize (GtkWidget *widget)
489 GtkStatusbar *statusbar;
491 statusbar = GTK_STATUSBAR (widget);
493 (* GTK_WIDGET_CLASS (parent_class)->realize) (widget);
495 if (statusbar->has_resize_grip)
496 gtk_statusbar_create_window (statusbar);
500 gtk_statusbar_unrealize (GtkWidget *widget)
502 GtkStatusbar *statusbar;
504 statusbar = GTK_STATUSBAR (widget);
506 if (statusbar->grip_window)
507 gtk_statusbar_destroy_window (statusbar);
509 (* GTK_WIDGET_CLASS (parent_class)->unrealize) (widget);
513 gtk_statusbar_map (GtkWidget *widget)
515 GtkStatusbar *statusbar;
517 statusbar = GTK_STATUSBAR (widget);
519 (* GTK_WIDGET_CLASS (parent_class)->map) (widget);
521 if (statusbar->grip_window)
522 gdk_window_show (statusbar->grip_window);
526 gtk_statusbar_unmap (GtkWidget *widget)
528 GtkStatusbar *statusbar;
530 statusbar = GTK_STATUSBAR (widget);
532 if (statusbar->grip_window)
533 gdk_window_hide (statusbar->grip_window);
535 (* GTK_WIDGET_CLASS (parent_class)->unmap) (widget);
539 gtk_statusbar_button_press (GtkWidget *widget,
540 GdkEventButton *event)
542 GtkStatusbar *statusbar;
545 statusbar = GTK_STATUSBAR (widget);
547 if (!statusbar->has_resize_grip)
550 ancestor = gtk_widget_get_toplevel (widget);
552 if (!GTK_IS_WINDOW (ancestor))
555 if (event->button == 1)
556 gtk_window_begin_resize_drag (GTK_WINDOW (ancestor),
557 GDK_WINDOW_EDGE_SOUTH_EAST,
559 event->x_root, event->y_root,
561 else if (event->button == 2)
562 gtk_window_begin_move_drag (GTK_WINDOW (ancestor),
564 event->x_root, event->y_root,
573 gtk_statusbar_expose_event (GtkWidget *widget,
574 GdkEventExpose *event)
576 GtkStatusbar *statusbar;
579 statusbar = GTK_STATUSBAR (widget);
581 GTK_WIDGET_CLASS (parent_class)->expose_event (widget, event);
583 if (statusbar->has_resize_grip)
585 get_grip_rect (statusbar, &rect);
587 gtk_paint_resize_grip (widget->style,
589 GTK_WIDGET_STATE (widget),
593 GDK_WINDOW_EDGE_SOUTH_EAST,
595 /* don't draw grip over the frame, though you
596 * can click on the frame.
598 rect.width - widget->style->xthickness,
599 rect.height - widget->style->ythickness);