]> Pileus Git - ~andy/gtk/blob - gtk/gtkmenubar.c
Removed some GTK_WIDGET_DRAWABLE() tests - we need to update the value
[~andy/gtk] / gtk / gtkmenubar.c
1 /* GTK - The GIMP Toolkit
2  * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Library General Public
6  * License as published by the Free Software Foundation; either
7  * version 2 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Library General Public License for more details.
13  *
14  * You should have received a copy of the GNU Library General Public
15  * License along with this library; if not, write to the
16  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17  * Boston, MA 02111-1307, USA.
18  */
19 #include "gdk/gdkkeysyms.h"
20 #include "gtkbindings.h"
21 #include "gtkmain.h"
22 #include "gtkmenubar.h"
23 #include "gtkmenuitem.h"
24
25 enum {
26   ARG_0,
27   ARG_SHADOW
28 };
29
30
31 #define BORDER_SPACING  0
32 #define CHILD_SPACING   3
33
34
35 static void gtk_menu_bar_class_init    (GtkMenuBarClass *klass);
36 static void gtk_menu_bar_init          (GtkMenuBar      *menu_bar);
37 static void gtk_menu_bar_set_arg       (GtkObject      *object,
38                                         GtkArg         *arg,
39                                         guint           arg_id);
40 static void gtk_menu_bar_get_arg       (GtkObject      *object,
41                                         GtkArg         *arg,
42                                         guint           arg_id);
43 static void gtk_menu_bar_size_request  (GtkWidget       *widget,
44                                         GtkRequisition  *requisition);
45 static void gtk_menu_bar_size_allocate (GtkWidget       *widget,
46                                         GtkAllocation   *allocation);
47 static void gtk_menu_bar_paint         (GtkWidget       *widget,
48                                         GdkRectangle    *area);
49 static void gtk_menu_bar_draw          (GtkWidget       *widget,
50                                         GdkRectangle    *area);
51 static gint gtk_menu_bar_expose        (GtkWidget       *widget,
52                                         GdkEventExpose  *event);
53
54
55 GtkType
56 gtk_menu_bar_get_type (void)
57 {
58   static GtkType menu_bar_type = 0;
59
60   if (!menu_bar_type)
61     {
62       static const GtkTypeInfo menu_bar_info =
63       {
64         "GtkMenuBar",
65         sizeof (GtkMenuBar),
66         sizeof (GtkMenuBarClass),
67         (GtkClassInitFunc) gtk_menu_bar_class_init,
68         (GtkObjectInitFunc) gtk_menu_bar_init,
69         /* reserved_1 */ NULL,
70         /* reserved_2 */ NULL,
71         (GtkClassInitFunc) NULL,
72       };
73
74       menu_bar_type = gtk_type_unique (gtk_menu_shell_get_type (), &menu_bar_info);
75     }
76
77   return menu_bar_type;
78 }
79
80 static void
81 gtk_menu_bar_class_init (GtkMenuBarClass *class)
82 {
83   GtkObjectClass *object_class;
84   GtkWidgetClass *widget_class;
85   GtkMenuShellClass *menu_shell_class;
86
87   GtkBindingSet *binding_set;
88
89   object_class = (GtkObjectClass*) class;
90   widget_class = (GtkWidgetClass*) class;
91   menu_shell_class = (GtkMenuShellClass*) class;
92
93   gtk_object_add_arg_type ("GtkMenuBar::shadow", GTK_TYPE_SHADOW_TYPE, GTK_ARG_READWRITE, ARG_SHADOW);
94
95   object_class->set_arg = gtk_menu_bar_set_arg;
96   object_class->get_arg = gtk_menu_bar_get_arg;
97
98   widget_class->draw = gtk_menu_bar_draw;
99   widget_class->size_request = gtk_menu_bar_size_request;
100   widget_class->size_allocate = gtk_menu_bar_size_allocate;
101   widget_class->expose_event = gtk_menu_bar_expose;
102
103   menu_shell_class->submenu_placement = GTK_TOP_BOTTOM;
104
105   binding_set = gtk_binding_set_by_class (class);
106   gtk_binding_entry_add_signal (binding_set,
107                                 GDK_Left, 0,
108                                 "move_current", 1,
109                                 GTK_TYPE_MENU_DIRECTION_TYPE,
110                                 GTK_MENU_DIR_PREV);
111   gtk_binding_entry_add_signal (binding_set,
112                                 GDK_Right, 0,
113                                 "move_current", 1,
114                                 GTK_TYPE_MENU_DIRECTION_TYPE,
115                                 GTK_MENU_DIR_NEXT);
116   gtk_binding_entry_add_signal (binding_set,
117                                 GDK_Up, 0,
118                                 "move_current", 1,
119                                 GTK_TYPE_MENU_DIRECTION_TYPE,
120                                 GTK_MENU_DIR_PARENT);
121   gtk_binding_entry_add_signal (binding_set,
122                                 GDK_Down, 0,
123                                 "move_current", 1,
124                                 GTK_TYPE_MENU_DIRECTION_TYPE,
125                                 GTK_MENU_DIR_CHILD);
126 }
127
128 static void
129 gtk_menu_bar_init (GtkMenuBar *menu_bar)
130 {
131   menu_bar->shadow_type = GTK_SHADOW_OUT;
132 }
133
134 static void
135 gtk_menu_bar_set_arg (GtkObject      *object,
136                       GtkArg         *arg,
137                       guint           arg_id)
138 {
139   GtkMenuBar *menu_bar;
140
141   menu_bar = GTK_MENU_BAR (object);
142
143   switch (arg_id)
144     {
145     case ARG_SHADOW:
146       gtk_menu_bar_set_shadow_type (menu_bar, GTK_VALUE_ENUM (*arg));
147       break;
148     default:
149       break;
150     }
151 }
152
153 static void
154 gtk_menu_bar_get_arg (GtkObject      *object,
155                       GtkArg         *arg,
156                       guint           arg_id)
157 {
158   GtkMenuBar *menu_bar;
159
160   menu_bar = GTK_MENU_BAR (object);
161
162   switch (arg_id)
163     {
164     case ARG_SHADOW:
165       GTK_VALUE_ENUM (*arg) = menu_bar->shadow_type;
166       break;
167     default:
168       arg->type = GTK_TYPE_INVALID;
169       break;
170     }
171 }
172  
173 GtkWidget*
174 gtk_menu_bar_new (void)
175 {
176   return GTK_WIDGET (gtk_type_new (gtk_menu_bar_get_type ()));
177 }
178
179 void
180 gtk_menu_bar_append (GtkMenuBar *menu_bar,
181                      GtkWidget  *child)
182 {
183   gtk_menu_shell_append (GTK_MENU_SHELL (menu_bar), child);
184 }
185
186 void
187 gtk_menu_bar_prepend (GtkMenuBar *menu_bar,
188                       GtkWidget  *child)
189 {
190   gtk_menu_shell_prepend (GTK_MENU_SHELL (menu_bar), child);
191 }
192
193 void
194 gtk_menu_bar_insert (GtkMenuBar *menu_bar,
195                      GtkWidget  *child,
196                      gint        position)
197 {
198   gtk_menu_shell_insert (GTK_MENU_SHELL (menu_bar), child, position);
199 }
200
201
202 static void
203 gtk_menu_bar_size_request (GtkWidget      *widget,
204                            GtkRequisition *requisition)
205 {
206   GtkMenuBar *menu_bar;
207   GtkMenuShell *menu_shell;
208   GtkWidget *child;
209   GList *children;
210   gint nchildren;
211
212   g_return_if_fail (widget != NULL);
213   g_return_if_fail (GTK_IS_MENU_BAR (widget));
214   g_return_if_fail (requisition != NULL);
215
216   requisition->width = 0;
217   requisition->height = 0;
218
219   if (GTK_WIDGET_VISIBLE (widget))
220     {
221       menu_bar = GTK_MENU_BAR (widget);
222       menu_shell = GTK_MENU_SHELL (widget);
223
224       nchildren = 0;
225       children = menu_shell->children;
226
227       while (children)
228         {
229           child = children->data;
230           children = children->next;
231
232           if (GTK_WIDGET_VISIBLE (child))
233             {
234               GTK_MENU_ITEM (child)->show_submenu_indicator = FALSE;
235               gtk_widget_size_request (child, &child->requisition);
236
237               requisition->width += child->requisition.width;
238               requisition->height = MAX (requisition->height, child->requisition.height);
239               /* Support for the right justified help menu */
240               if ( (children == NULL) && (GTK_IS_MENU_ITEM(child))
241                    && (GTK_MENU_ITEM(child)->right_justify))
242                 {
243                   requisition->width += CHILD_SPACING;
244                 }
245
246               nchildren += 1;
247             }
248         }
249
250       requisition->width += (GTK_CONTAINER (menu_bar)->border_width +
251                              widget->style->klass->xthickness +
252                              BORDER_SPACING) * 2;
253       requisition->height += (GTK_CONTAINER (menu_bar)->border_width +
254                               widget->style->klass->ythickness +
255                               BORDER_SPACING) * 2;
256
257       if (nchildren > 0)
258         requisition->width += 2 * CHILD_SPACING * (nchildren - 1);
259     }
260 }
261
262 static void
263 gtk_menu_bar_size_allocate (GtkWidget     *widget,
264                             GtkAllocation *allocation)
265 {
266   GtkMenuBar *menu_bar;
267   GtkMenuShell *menu_shell;
268   GtkWidget *child;
269   GList *children;
270   GtkAllocation child_allocation;
271   guint offset;
272   
273   g_return_if_fail (widget != NULL);
274   g_return_if_fail (GTK_IS_MENU_BAR (widget));
275   g_return_if_fail (allocation != NULL);
276
277   menu_bar = GTK_MENU_BAR (widget);
278   menu_shell = GTK_MENU_SHELL (widget);
279
280   widget->allocation = *allocation;
281   if (GTK_WIDGET_REALIZED (widget))
282     gdk_window_move_resize (widget->window,
283                             allocation->x, allocation->y,
284                             allocation->width, allocation->height);
285
286   if (menu_shell->children)
287     {
288       child_allocation.x = (GTK_CONTAINER (menu_bar)->border_width +
289                             widget->style->klass->xthickness +
290                             BORDER_SPACING);
291       offset = child_allocation.x;      /* Window edge to menubar start */
292
293       child_allocation.y = (GTK_CONTAINER (menu_bar)->border_width +
294                             widget->style->klass->ythickness +
295                             BORDER_SPACING);
296       child_allocation.height = MAX (1, (gint)allocation->height - child_allocation.y * 2);
297
298       children = menu_shell->children;
299       while (children)
300         {
301           child = children->data;
302           children = children->next;
303
304           /* Support for the right justified help menu */
305           if ( (children == NULL) && (GTK_IS_MENU_ITEM(child))
306               && (GTK_MENU_ITEM(child)->right_justify)) 
307             {
308               child_allocation.x = allocation->width -
309                   child->requisition.width - CHILD_SPACING - offset;
310             }
311           if (GTK_WIDGET_VISIBLE (child))
312             {
313               child_allocation.width = child->requisition.width;
314
315               gtk_widget_size_allocate (child, &child_allocation);
316
317               child_allocation.x += child_allocation.width + CHILD_SPACING * 2;
318             }
319         }
320     }
321 }
322
323 void
324 gtk_menu_bar_set_shadow_type (GtkMenuBar    *menu_bar,
325                               GtkShadowType  type)
326 {
327   g_return_if_fail (menu_bar != NULL);
328   g_return_if_fail (GTK_IS_MENU_BAR (menu_bar));
329
330   if ((GtkShadowType) menu_bar->shadow_type != type)
331     {
332       menu_bar->shadow_type = type;
333
334       if (GTK_WIDGET_DRAWABLE (menu_bar))
335         {
336           gtk_widget_queue_clear (GTK_WIDGET (menu_bar));
337         }
338       gtk_widget_queue_resize (GTK_WIDGET (menu_bar));
339     }
340 }
341
342 static void
343 gtk_menu_bar_paint (GtkWidget *widget, GdkRectangle *area)
344 {
345   g_return_if_fail (widget != NULL);
346   g_return_if_fail (GTK_IS_MENU_BAR (widget));
347
348   if (GTK_WIDGET_DRAWABLE (widget))
349     {
350       gtk_paint_box (widget->style,
351                      widget->window,
352                      GTK_STATE_NORMAL,
353                      GTK_MENU_BAR (widget)->shadow_type,
354                      area, widget, "menubar",
355                      0, 0,
356                      -1,-1);
357     }
358 }
359
360 static void
361 gtk_menu_bar_draw (GtkWidget    *widget,
362                    GdkRectangle *area)
363 {
364   GtkMenuShell *menu_shell;
365   GtkWidget *child;
366   GdkRectangle child_area;
367   GList *children;
368
369   g_return_if_fail (widget != NULL);
370   g_return_if_fail (GTK_IS_MENU_BAR (widget));
371   g_return_if_fail (area != NULL);
372
373   if (GTK_WIDGET_DRAWABLE (widget))
374     {
375       gtk_menu_bar_paint (widget, area);
376
377       menu_shell = GTK_MENU_SHELL (widget);
378
379       children = menu_shell->children;
380       while (children)
381         {
382           child = children->data;
383           children = children->next;
384
385           if (gtk_widget_intersect (child, area, &child_area))
386             gtk_widget_draw (child, &child_area);
387         }
388     }
389 }
390
391 static gint
392 gtk_menu_bar_expose (GtkWidget      *widget,
393                      GdkEventExpose *event)
394 {
395   GtkMenuShell *menu_shell;
396   GdkEventExpose child_event;
397   GList *children;
398   GtkWidget *child;
399
400   g_return_val_if_fail (widget != NULL, FALSE);
401   g_return_val_if_fail (GTK_IS_MENU_BAR (widget), FALSE);
402   g_return_val_if_fail (event != NULL, FALSE);
403
404   if (GTK_WIDGET_DRAWABLE (widget))
405     {
406       gtk_menu_bar_paint (widget, &event->area);
407
408       menu_shell = GTK_MENU_SHELL (widget);
409       child_event = *event;
410
411       children = menu_shell->children;
412       while (children)
413         {
414           child = children->data;
415           children = children->next;
416
417           if (GTK_WIDGET_NO_WINDOW (child) &&
418               gtk_widget_intersect (child, &event->area, &child_event.area))
419             gtk_widget_event (child, (GdkEvent*) &child_event);
420         }
421     }
422
423   return FALSE;
424 }