]> Pileus Git - ~andy/gtk/blob - gtk/gtkstatusbar.c
I submitted this patch twice to gtk-devel-list, and received no comments,
[~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 Library 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  * Library General Public License for more details.
14  *
15  * You should have received a copy of the GNU Library 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 #include "gtkframe.h"
22 #include "gtklabel.h"
23 #include "gtksignal.h"
24 #include "gtkstatusbar.h"
25
26
27 enum
28 {
29   SIGNAL_TEXT_PUSHED,
30   SIGNAL_TEXT_POPPED,
31   SIGNAL_LAST
32 };
33
34 static void gtk_statusbar_class_init               (GtkStatusbarClass *class);
35 static void gtk_statusbar_init                     (GtkStatusbar      *statusbar);
36 static void gtk_statusbar_destroy                  (GtkObject         *object);
37 static void gtk_statusbar_finalize                 (GtkObject         *object);
38 static void gtk_statusbar_update                   (GtkStatusbar      *statusbar,
39                                                     guint              context_id,
40                                                     const gchar       *text);
41      
42 static GtkContainerClass *parent_class;
43 static guint              statusbar_signals[SIGNAL_LAST] = { 0 };
44
45 guint      
46 gtk_statusbar_get_type (void)
47 {
48   static guint statusbar_type = 0;
49
50   if (!statusbar_type)
51     {
52       static const GtkTypeInfo statusbar_info =
53       {
54         "GtkStatusbar",
55         sizeof (GtkStatusbar),
56         sizeof (GtkStatusbarClass),
57         (GtkClassInitFunc) gtk_statusbar_class_init,
58         (GtkObjectInitFunc) gtk_statusbar_init,
59         /* reserved_1 */ NULL,
60         /* reserved_2 */ NULL,
61         (GtkClassInitFunc) NULL,
62       };
63
64       statusbar_type = gtk_type_unique (gtk_hbox_get_type (), &statusbar_info);
65     }
66
67   return statusbar_type;
68 }
69
70 static void
71 gtk_statusbar_class_init (GtkStatusbarClass *class)
72 {
73   GtkObjectClass *object_class;
74   GtkWidgetClass *widget_class;
75   GtkContainerClass *container_class;
76
77   object_class = (GtkObjectClass *) class;
78   widget_class = (GtkWidgetClass *) class;
79   container_class = (GtkContainerClass *) class;
80
81   parent_class = gtk_type_class (gtk_hbox_get_type ());
82
83   statusbar_signals[SIGNAL_TEXT_PUSHED] =
84     gtk_signal_new ("text_pushed",
85                     GTK_RUN_LAST,
86                     object_class->type,
87                     GTK_SIGNAL_OFFSET (GtkStatusbarClass, text_pushed),
88                     gtk_marshal_NONE__UINT_STRING,
89                     GTK_TYPE_NONE, 2,
90                     GTK_TYPE_UINT,
91                     GTK_TYPE_STRING);
92   statusbar_signals[SIGNAL_TEXT_POPPED] =
93     gtk_signal_new ("text_popped",
94                     GTK_RUN_LAST,
95                     object_class->type,
96                     GTK_SIGNAL_OFFSET (GtkStatusbarClass, text_popped),
97                     gtk_marshal_NONE__UINT_STRING,
98                     GTK_TYPE_NONE, 2,
99                     GTK_TYPE_UINT,
100                     GTK_TYPE_STRING);
101   gtk_object_class_add_signals (object_class, statusbar_signals, SIGNAL_LAST);
102   
103   object_class->destroy = gtk_statusbar_destroy;
104   object_class->finalize = gtk_statusbar_finalize;
105
106   class->messages_mem_chunk = g_mem_chunk_new ("GtkStatusBar messages mem chunk",
107                                                sizeof (GtkStatusbarMsg),
108                                                sizeof (GtkStatusbarMsg) * 64,
109                                                G_ALLOC_AND_FREE);
110
111   class->text_pushed = gtk_statusbar_update;
112   class->text_popped = gtk_statusbar_update;
113 }
114
115 static void
116 gtk_statusbar_init (GtkStatusbar *statusbar)
117 {
118   GtkBox *box;
119
120   box = GTK_BOX (statusbar);
121
122   box->spacing = 2;
123   box->homogeneous = FALSE;
124
125   statusbar->frame = gtk_frame_new (NULL);
126   gtk_frame_set_shadow_type (GTK_FRAME (statusbar->frame), GTK_SHADOW_IN);
127   gtk_box_pack_start (box, statusbar->frame, TRUE, TRUE, 0);
128   gtk_widget_show (statusbar->frame);
129
130   statusbar->label = gtk_label_new ("");
131   gtk_misc_set_alignment (GTK_MISC (statusbar->label), 0.0, 0.0);
132   gtk_container_add (GTK_CONTAINER (statusbar->frame), statusbar->label);
133   gtk_widget_show (statusbar->label);
134
135   statusbar->seq_context_id = 1;
136   statusbar->seq_message_id = 1;
137   statusbar->messages = NULL;
138   statusbar->keys = NULL;
139 }
140
141 GtkWidget* 
142 gtk_statusbar_new (void)
143 {
144   return gtk_type_new (gtk_statusbar_get_type ());
145 }
146
147 static void
148 gtk_statusbar_update (GtkStatusbar *statusbar,
149                       guint         context_id,
150                       const gchar  *text)
151 {
152   g_return_if_fail (statusbar != NULL);
153   g_return_if_fail (GTK_IS_STATUSBAR (statusbar));
154
155   if (!text)
156     text = "";
157
158   gtk_label_set (GTK_LABEL (statusbar->label), text);
159 }
160
161 guint
162 gtk_statusbar_get_context_id (GtkStatusbar *statusbar,
163                               const gchar  *context_description)
164 {
165   gchar *string;
166   guint *id;
167   
168   g_return_val_if_fail (statusbar != NULL, 0);
169   g_return_val_if_fail (GTK_IS_STATUSBAR (statusbar), 0);
170   g_return_val_if_fail (context_description != NULL, 0);
171
172   /* we need to preserve namespaces on object datas */
173   string = g_strconcat ("gtk-status-bar-context:", context_description, NULL);
174
175   id = gtk_object_get_data (GTK_OBJECT (statusbar), string);
176   if (!id)
177     {
178       id = g_new (guint, 1);
179       *id = statusbar->seq_context_id++;
180       gtk_object_set_data_full (GTK_OBJECT (statusbar), string, id, (GtkDestroyNotify) g_free);
181       statusbar->keys = g_slist_prepend (statusbar->keys, string);
182     }
183   else
184     g_free (string);
185
186   return *id;
187 }
188
189 guint
190 gtk_statusbar_push (GtkStatusbar *statusbar,
191                     guint         context_id,
192                     const gchar  *text)
193 {
194   GtkStatusbarMsg *msg;
195   GtkStatusbarClass *class;
196
197   g_return_val_if_fail (statusbar != NULL, 0);
198   g_return_val_if_fail (GTK_IS_STATUSBAR (statusbar), 0);
199   g_return_val_if_fail (text != NULL, 0);
200   g_return_val_if_fail (context_id > 0, 0);
201
202   class = GTK_STATUSBAR_CLASS (GTK_OBJECT (statusbar)->klass);
203   msg = g_chunk_new (GtkStatusbarMsg, class->messages_mem_chunk);
204   msg->text = g_strdup (text);
205   msg->context_id = context_id;
206   msg->message_id = statusbar->seq_message_id++;
207
208   statusbar->messages = g_slist_prepend (statusbar->messages, msg);
209
210   gtk_signal_emit (GTK_OBJECT (statusbar),
211                    statusbar_signals[SIGNAL_TEXT_PUSHED],
212                    msg->context_id,
213                    msg->text);
214
215   return msg->message_id;
216 }
217
218 void
219 gtk_statusbar_pop (GtkStatusbar *statusbar,
220                    guint         context_id)
221 {
222   GtkStatusbarMsg *msg;
223
224   g_return_if_fail (statusbar != NULL);
225   g_return_if_fail (GTK_IS_STATUSBAR (statusbar));
226   g_return_if_fail (context_id > 0);
227
228   if (statusbar->messages)
229     {
230       GSList *list;
231
232       for (list = statusbar->messages; list; list = list->next)
233         {
234           msg = list->data;
235
236           if (msg->context_id == context_id)
237             {
238               GtkStatusbarClass *class;
239
240               class = GTK_STATUSBAR_CLASS (GTK_OBJECT (statusbar)->klass);
241
242               statusbar->messages = g_slist_remove_link (statusbar->messages,
243                                                          list);
244               g_free (msg->text);
245               g_mem_chunk_free (class->messages_mem_chunk, msg);
246               g_slist_free_1 (list);
247               break;
248             }
249         }
250     }
251
252   msg = statusbar->messages ? statusbar->messages->data : NULL;
253
254   gtk_signal_emit (GTK_OBJECT (statusbar),
255                    statusbar_signals[SIGNAL_TEXT_POPPED],
256                    (guint) (msg ? msg->context_id : 0),
257                    msg ? msg->text : NULL);
258 }
259
260 void
261 gtk_statusbar_remove (GtkStatusbar *statusbar,
262                       guint        context_id,
263                       guint        message_id)
264 {
265   GtkStatusbarMsg *msg;
266
267   g_return_if_fail (statusbar != NULL);
268   g_return_if_fail (GTK_IS_STATUSBAR (statusbar));
269   g_return_if_fail (context_id > 0);
270   g_return_if_fail (message_id > 0);
271
272   msg = statusbar->messages ? statusbar->messages->data : NULL;
273   if (msg)
274     {
275       GSList *list;
276
277       /* care about signal emission if the topmost item is removed */
278       if (msg->context_id == context_id &&
279           msg->message_id == message_id)
280         {
281           gtk_statusbar_pop (statusbar, context_id);
282           return;
283         }
284       
285       for (list = statusbar->messages; list; list = list->next)
286         {
287           msg = list->data;
288           
289           if (msg->context_id == context_id &&
290               msg->message_id == message_id)
291             {
292               GtkStatusbarClass *class;
293               
294               class = GTK_STATUSBAR_CLASS (GTK_OBJECT (statusbar)->klass);
295               statusbar->messages = g_slist_remove_link (statusbar->messages, list);
296               g_free (msg->text);
297               g_mem_chunk_free (class->messages_mem_chunk, msg);
298               g_slist_free_1 (list);
299               
300               break;
301             }
302         }
303     }
304 }
305
306 static void
307 gtk_statusbar_destroy (GtkObject *object)
308 {
309   GtkStatusbar *statusbar;
310   GtkStatusbarClass *class;
311   GSList *list;
312
313   g_return_if_fail (object != NULL);
314   g_return_if_fail (GTK_IS_STATUSBAR (object));
315
316   statusbar = GTK_STATUSBAR (object);
317   class = GTK_STATUSBAR_CLASS (GTK_OBJECT (statusbar)->klass);
318
319   for (list = statusbar->messages; list; list = list->next)
320     {
321       GtkStatusbarMsg *msg;
322
323       msg = list->data;
324       g_free (msg->text);
325       g_mem_chunk_free (class->messages_mem_chunk, msg);
326     }
327   g_slist_free (statusbar->messages);
328   statusbar->messages = NULL;
329
330   for (list = statusbar->keys; list; list = list->next)
331     g_free (list->data);
332   g_slist_free (statusbar->keys);
333   statusbar->keys = NULL;
334
335   GTK_OBJECT_CLASS (parent_class)->destroy (object);
336 }
337
338 static void
339 gtk_statusbar_finalize (GtkObject *object)
340 {
341   GtkStatusbar *statusbar;
342
343   g_return_if_fail (object != NULL);
344   g_return_if_fail (GTK_IS_STATUSBAR (object));
345
346   statusbar = GTK_STATUSBAR (object);
347
348   GTK_OBJECT_CLASS (parent_class)->finalize (object);
349 }