]> Pileus Git - ~andy/gtk/blob - gtk/gtkimagemenuitem.c
f328224357561a3faaaf6c8024b446ad64041ed0
[~andy/gtk] / gtk / gtkimagemenuitem.c
1 /* GTK - The GIMP Toolkit
2  * Copyright (C) 2001 Red Hat, Inc.
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Lesser 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  * Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser 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
20 /*
21  * Modified by the GTK+ Team and others 1997-2000.  See the AUTHORS
22  * file for a list of people on the GTK+ Team.  See the ChangeLog
23  * files for a list of changes.  These files are distributed with
24  * GTK+ at ftp://ftp.gtk.org/pub/gtk/.
25  */
26
27 #include "config.h"
28 #include "gtkimagemenuitem.h"
29 #include "gtkaccellabel.h"
30 #include "gtkintl.h"
31 #include "gtkstock.h"
32 #include "gtkiconfactory.h"
33 #include "gtkimage.h"
34 #include "gtkmenubar.h"
35 #include "gtkcontainer.h"
36 #include "gtkwindow.h"
37 #include "gtkprivate.h"
38 #include "gtkalias.h"
39
40 static void gtk_image_menu_item_destroy              (GtkObject        *object);
41 static void gtk_image_menu_item_size_request         (GtkWidget        *widget,
42                                                       GtkRequisition   *requisition);
43 static void gtk_image_menu_item_size_allocate        (GtkWidget        *widget,
44                                                       GtkAllocation    *allocation);
45 static void gtk_image_menu_item_map                  (GtkWidget        *widget);
46 static void gtk_image_menu_item_remove               (GtkContainer     *container,
47                                                       GtkWidget        *child);
48 static void gtk_image_menu_item_toggle_size_request  (GtkMenuItem      *menu_item,
49                                                       gint             *requisition);
50 static void gtk_image_menu_item_set_label            (GtkMenuItem      *menu_item,
51                                                       const gchar      *label);
52 static G_CONST_RETURN gchar *gtk_image_menu_item_get_label (GtkMenuItem *menu_item);
53
54 static void gtk_image_menu_item_forall               (GtkContainer    *container,
55                                                       gboolean         include_internals,
56                                                       GtkCallback      callback,
57                                                       gpointer         callback_data);
58
59 static void gtk_image_menu_item_finalize             (GObject         *object);
60 static void gtk_image_menu_item_set_property         (GObject         *object,
61                                                       guint            prop_id,
62                                                       const GValue    *value,
63                                                       GParamSpec      *pspec);
64 static void gtk_image_menu_item_get_property         (GObject         *object,
65                                                       guint            prop_id,
66                                                       GValue          *value,
67                                                       GParamSpec      *pspec);
68 static void gtk_image_menu_item_screen_changed       (GtkWidget        *widget,
69                                                       GdkScreen        *previous_screen);
70
71 static void gtk_image_menu_item_recalculate          (GtkImageMenuItem *image_menu_item);
72
73
74 typedef struct {
75   gchar          *label;
76   gboolean        use_stock;
77 } GtkImageMenuItemPrivate;
78
79 enum {
80   PROP_0,
81   PROP_IMAGE,
82   PROP_USE_STOCK,
83   PROP_ACCEL_GROUP
84 };
85
86 G_DEFINE_TYPE (GtkImageMenuItem, gtk_image_menu_item, GTK_TYPE_MENU_ITEM)
87
88 #define GET_PRIVATE(object)  \
89   (G_TYPE_INSTANCE_GET_PRIVATE ((object), GTK_TYPE_IMAGE_MENU_ITEM, GtkImageMenuItemPrivate))
90
91 static void
92 gtk_image_menu_item_class_init (GtkImageMenuItemClass *klass)
93 {
94   GObjectClass *gobject_class = (GObjectClass*) klass;
95   GtkObjectClass *object_class = (GtkObjectClass*) klass;
96   GtkWidgetClass *widget_class = (GtkWidgetClass*) klass;
97   GtkMenuItemClass *menu_item_class = (GtkMenuItemClass*) klass;
98   GtkContainerClass *container_class = (GtkContainerClass*) klass;
99
100   object_class->destroy = gtk_image_menu_item_destroy;
101
102   widget_class->screen_changed = gtk_image_menu_item_screen_changed;
103   widget_class->size_request = gtk_image_menu_item_size_request;
104   widget_class->size_allocate = gtk_image_menu_item_size_allocate;
105   widget_class->map = gtk_image_menu_item_map;
106
107   container_class->forall = gtk_image_menu_item_forall;
108   container_class->remove = gtk_image_menu_item_remove;
109   
110   menu_item_class->toggle_size_request = gtk_image_menu_item_toggle_size_request;
111   menu_item_class->set_label           = gtk_image_menu_item_set_label;
112   menu_item_class->get_label           = gtk_image_menu_item_get_label;
113
114   gobject_class->finalize     = gtk_image_menu_item_finalize;
115   gobject_class->set_property = gtk_image_menu_item_set_property;
116   gobject_class->get_property = gtk_image_menu_item_get_property;
117   
118   g_object_class_install_property (gobject_class,
119                                    PROP_IMAGE,
120                                    g_param_spec_object ("image",
121                                                         P_("Image widget"),
122                                                         P_("Child widget to appear next to the menu text"),
123                                                         GTK_TYPE_WIDGET,
124                                                         GTK_PARAM_READWRITE));
125   /**
126    * GtkImageMenuItem:use-stock:
127    *
128    * If %TRUE, the label set in the menuitem is used as a
129    * stock id to select the stock item for the item.
130    *
131    * Since: 2.16
132    **/
133   g_object_class_install_property (gobject_class,
134                                    PROP_USE_STOCK,
135                                    g_param_spec_boolean ("use-stock",
136                                                          P_("Use stock"),
137                                                          P_("Whether to use the label text to create a stock menu item"),
138                                                          FALSE,
139                                                          GTK_PARAM_READWRITE | G_PARAM_CONSTRUCT));
140
141   /**
142    * GtkImageMenuItem:accel-group:
143    *
144    * The Accel Group to use for stock accelerator keys
145    *
146    * Since: 2.16
147    **/
148   g_object_class_install_property (gobject_class,
149                                    PROP_ACCEL_GROUP,
150                                    g_param_spec_object ("accel-group",
151                                                         P_("Accel Group"),
152                                                         P_("The Accel Group to use for stock accelerator keys"),
153                                                         GTK_TYPE_ACCEL_GROUP,
154                                                         GTK_PARAM_WRITABLE));
155
156   gtk_settings_install_property (g_param_spec_boolean ("gtk-menu-images",
157                                                        P_("Show menu images"),
158                                                        P_("Whether images should be shown in menus"),
159                                                        TRUE,
160                                                        GTK_PARAM_READWRITE));
161   
162
163   g_type_class_add_private (object_class, sizeof (GtkImageMenuItemPrivate));
164
165 }
166
167 static void
168 gtk_image_menu_item_init (GtkImageMenuItem *image_menu_item)
169 {
170   GtkImageMenuItemPrivate *priv = GET_PRIVATE (image_menu_item);
171
172   priv->use_stock   = FALSE;
173   priv->label  = NULL;
174
175   image_menu_item->image = NULL;
176 }
177
178 static void 
179 gtk_image_menu_item_finalize (GObject *object)
180 {
181   GtkImageMenuItemPrivate *priv = GET_PRIVATE (object);
182
183   g_free (priv->label);
184   priv->label  = NULL;
185
186   G_OBJECT_CLASS (gtk_image_menu_item_parent_class)->finalize (object);
187 }
188
189 static void
190 gtk_image_menu_item_set_property (GObject         *object,
191                                   guint            prop_id,
192                                   const GValue    *value,
193                                   GParamSpec      *pspec)
194 {
195   GtkImageMenuItem *image_menu_item = GTK_IMAGE_MENU_ITEM (object);
196   
197   switch (prop_id)
198     {
199     case PROP_IMAGE:
200       gtk_image_menu_item_set_image (image_menu_item, (GtkWidget *) g_value_get_object (value));
201       break;
202     case PROP_USE_STOCK:
203       gtk_image_menu_item_set_use_stock (image_menu_item, g_value_get_boolean (value));
204       break;
205     case PROP_ACCEL_GROUP:
206       gtk_image_menu_item_set_accel_group (image_menu_item, g_value_get_object (value));
207       break;
208     default:
209       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
210       break;
211     }
212 }
213
214 static void
215 gtk_image_menu_item_get_property (GObject         *object,
216                                   guint            prop_id,
217                                   GValue          *value,
218                                   GParamSpec      *pspec)
219 {
220   GtkImageMenuItem *image_menu_item = GTK_IMAGE_MENU_ITEM (object);
221   
222   switch (prop_id)
223     {
224     case PROP_IMAGE:
225       g_value_set_object (value, gtk_image_menu_item_get_image (image_menu_item));
226       break;
227     case PROP_USE_STOCK:
228       g_value_set_boolean (value, gtk_image_menu_item_get_use_stock (image_menu_item));      
229       break;
230     default:
231       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
232       break;
233     }
234 }
235
236 static gboolean
237 show_image (GtkImageMenuItem *image_menu_item)
238 {
239   GtkSettings *settings = gtk_widget_get_settings (GTK_WIDGET (image_menu_item));
240   gboolean show;
241
242   g_object_get (settings, "gtk-menu-images", &show, NULL);
243
244   return show;
245 }
246
247 static void
248 gtk_image_menu_item_map (GtkWidget *widget)
249 {
250   GtkImageMenuItem *image_menu_item = GTK_IMAGE_MENU_ITEM (widget);
251
252   GTK_WIDGET_CLASS (gtk_image_menu_item_parent_class)->map (widget);
253
254   if (image_menu_item->image)
255     g_object_set (image_menu_item->image,
256                   "visible", show_image (image_menu_item),
257                   NULL);
258 }
259
260 static void
261 gtk_image_menu_item_destroy (GtkObject *object)
262 {
263   GtkImageMenuItem *image_menu_item = GTK_IMAGE_MENU_ITEM (object);
264
265   if (image_menu_item->image)
266     gtk_container_remove (GTK_CONTAINER (image_menu_item),
267                           image_menu_item->image);
268
269   GTK_OBJECT_CLASS (gtk_image_menu_item_parent_class)->destroy (object);
270 }
271
272 static void
273 gtk_image_menu_item_toggle_size_request (GtkMenuItem *menu_item,
274                                          gint        *requisition)
275 {
276   GtkImageMenuItem *image_menu_item = GTK_IMAGE_MENU_ITEM (menu_item);
277   GtkPackDirection pack_dir;
278   
279   if (GTK_IS_MENU_BAR (GTK_WIDGET (menu_item)->parent))
280     pack_dir = gtk_menu_bar_get_child_pack_direction (GTK_MENU_BAR (GTK_WIDGET (menu_item)->parent));
281   else
282     pack_dir = GTK_PACK_DIRECTION_LTR;
283
284   *requisition = 0;
285
286   if (image_menu_item->image && GTK_WIDGET_VISIBLE (image_menu_item->image))
287     {
288       GtkRequisition image_requisition;
289       guint toggle_spacing;
290       gtk_widget_get_child_requisition (image_menu_item->image,
291                                         &image_requisition);
292
293       gtk_widget_style_get (GTK_WIDGET (menu_item),
294                             "toggle-spacing", &toggle_spacing,
295                             NULL);
296       
297       if (pack_dir == GTK_PACK_DIRECTION_LTR || pack_dir == GTK_PACK_DIRECTION_RTL)
298         {
299           if (image_requisition.width > 0)
300             *requisition = image_requisition.width + toggle_spacing;
301         }
302       else
303         {
304           if (image_requisition.height > 0)
305             *requisition = image_requisition.height + toggle_spacing;
306         }
307     }
308 }
309
310 static void
311 gtk_image_menu_item_recalculate (GtkImageMenuItem *image_menu_item)
312 {
313   GtkImageMenuItemPrivate *priv = GET_PRIVATE (image_menu_item);
314   GtkStockItem             stock_item;
315   GtkWidget               *image;
316   const gchar             *resolved_label = priv->label;
317
318   if (priv->use_stock && priv->label)
319     {
320
321       if (!image_menu_item->image)
322         {
323           image = gtk_image_new_from_stock (priv->label, GTK_ICON_SIZE_MENU);
324           gtk_image_menu_item_set_image (image_menu_item, image);
325         }
326
327       if (gtk_stock_lookup (priv->label, &stock_item))
328           resolved_label = stock_item.label;
329
330         gtk_menu_item_set_use_underline (GTK_MENU_ITEM (image_menu_item), TRUE);
331     }
332
333   GTK_MENU_ITEM_CLASS
334     (gtk_image_menu_item_parent_class)->set_label (GTK_MENU_ITEM (image_menu_item), resolved_label);
335
336 }
337
338 static void 
339 gtk_image_menu_item_set_label (GtkMenuItem      *menu_item,
340                                const gchar      *label)
341 {
342   GtkImageMenuItemPrivate *priv = GET_PRIVATE (menu_item);
343
344   if (priv->label != label)
345     {
346       g_free (priv->label);
347       priv->label = g_strdup (label);
348
349       gtk_image_menu_item_recalculate (GTK_IMAGE_MENU_ITEM (menu_item));
350
351       g_object_notify (G_OBJECT (menu_item), "label");
352
353     }
354 }
355
356 static G_CONST_RETURN gchar *
357 gtk_image_menu_item_get_label (GtkMenuItem *menu_item)
358 {
359   GtkImageMenuItemPrivate *priv = GET_PRIVATE (menu_item);
360   
361   return priv->label;
362 }
363
364 static void
365 gtk_image_menu_item_size_request (GtkWidget      *widget,
366                                   GtkRequisition *requisition)
367 {
368   GtkImageMenuItem *image_menu_item;
369   gint child_width = 0;
370   gint child_height = 0;
371   GtkPackDirection pack_dir;
372   
373   if (GTK_IS_MENU_BAR (widget->parent))
374     pack_dir = gtk_menu_bar_get_child_pack_direction (GTK_MENU_BAR (widget->parent));
375   else
376     pack_dir = GTK_PACK_DIRECTION_LTR;
377
378   image_menu_item = GTK_IMAGE_MENU_ITEM (widget);
379
380   if (image_menu_item->image && GTK_WIDGET_VISIBLE (image_menu_item->image))
381     {
382       GtkRequisition child_requisition;
383       
384       gtk_widget_size_request (image_menu_item->image,
385                                &child_requisition);
386
387       child_width = child_requisition.width;
388       child_height = child_requisition.height;
389     }
390
391   GTK_WIDGET_CLASS (gtk_image_menu_item_parent_class)->size_request (widget, requisition);
392
393   /* not done with height since that happens via the
394    * toggle_size_request
395    */
396   if (pack_dir == GTK_PACK_DIRECTION_LTR || pack_dir == GTK_PACK_DIRECTION_RTL)
397     requisition->height = MAX (requisition->height, child_height);
398   else
399     requisition->width = MAX (requisition->width, child_width);
400     
401   
402   /* Note that GtkMenuShell always size requests before
403    * toggle_size_request, so toggle_size_request will be able to use
404    * image_menu_item->image->requisition
405    */
406 }
407
408 static void
409 gtk_image_menu_item_size_allocate (GtkWidget     *widget,
410                                    GtkAllocation *allocation)
411 {
412   GtkImageMenuItem *image_menu_item;
413   GtkPackDirection pack_dir;
414   
415   if (GTK_IS_MENU_BAR (widget->parent))
416     pack_dir = gtk_menu_bar_get_child_pack_direction (GTK_MENU_BAR (widget->parent));
417   else
418     pack_dir = GTK_PACK_DIRECTION_LTR;
419   
420   image_menu_item = GTK_IMAGE_MENU_ITEM (widget);  
421
422   GTK_WIDGET_CLASS (gtk_image_menu_item_parent_class)->size_allocate (widget, allocation);
423
424   if (image_menu_item->image && GTK_WIDGET_VISIBLE (image_menu_item->image))
425     {
426       gint x, y, offset;
427       GtkRequisition child_requisition;
428       GtkAllocation child_allocation;
429       guint horizontal_padding, toggle_spacing;
430
431       gtk_widget_style_get (widget,
432                             "horizontal-padding", &horizontal_padding,
433                             "toggle-spacing", &toggle_spacing,
434                             NULL);
435       
436       /* Man this is lame hardcoding action, but I can't
437        * come up with a solution that's really better.
438        */
439
440       gtk_widget_get_child_requisition (image_menu_item->image,
441                                         &child_requisition);
442
443       if (pack_dir == GTK_PACK_DIRECTION_LTR ||
444           pack_dir == GTK_PACK_DIRECTION_RTL)
445         {
446           offset = GTK_CONTAINER (image_menu_item)->border_width +
447             widget->style->xthickness;
448           
449           if ((gtk_widget_get_direction (widget) == GTK_TEXT_DIR_LTR) ==
450               (pack_dir == GTK_PACK_DIRECTION_LTR))
451             x = offset + horizontal_padding +
452               (GTK_MENU_ITEM (image_menu_item)->toggle_size -
453                toggle_spacing - child_requisition.width) / 2;
454           else
455             x = widget->allocation.width - offset - horizontal_padding -
456               GTK_MENU_ITEM (image_menu_item)->toggle_size + toggle_spacing +
457               (GTK_MENU_ITEM (image_menu_item)->toggle_size -
458                toggle_spacing - child_requisition.width) / 2;
459           
460           y = (widget->allocation.height - child_requisition.height) / 2;
461         }
462       else
463         {
464           offset = GTK_CONTAINER (image_menu_item)->border_width +
465             widget->style->ythickness;
466           
467           if ((gtk_widget_get_direction (widget) == GTK_TEXT_DIR_LTR) ==
468               (pack_dir == GTK_PACK_DIRECTION_TTB))
469             y = offset + horizontal_padding +
470               (GTK_MENU_ITEM (image_menu_item)->toggle_size -
471                toggle_spacing - child_requisition.height) / 2;
472           else
473             y = widget->allocation.height - offset - horizontal_padding -
474               GTK_MENU_ITEM (image_menu_item)->toggle_size + toggle_spacing +
475               (GTK_MENU_ITEM (image_menu_item)->toggle_size -
476                toggle_spacing - child_requisition.height) / 2;
477
478           x = (widget->allocation.width - child_requisition.width) / 2;
479         }
480       
481       child_allocation.width = child_requisition.width;
482       child_allocation.height = child_requisition.height;
483       child_allocation.x = widget->allocation.x + MAX (x, 0);
484       child_allocation.y = widget->allocation.y + MAX (y, 0);
485
486       gtk_widget_size_allocate (image_menu_item->image, &child_allocation);
487     }
488 }
489
490 static void
491 gtk_image_menu_item_forall (GtkContainer   *container,
492                             gboolean        include_internals,
493                             GtkCallback     callback,
494                             gpointer        callback_data)
495 {
496   GtkImageMenuItem *image_menu_item = GTK_IMAGE_MENU_ITEM (container);
497
498   GTK_CONTAINER_CLASS (gtk_image_menu_item_parent_class)->forall (container,
499                                                                   include_internals,
500                                                                   callback,
501                                                                   callback_data);
502
503   if (include_internals && image_menu_item->image)
504     (* callback) (image_menu_item->image, callback_data);
505 }
506
507 /**
508  * gtk_image_menu_item_new:
509  * @returns: a new #GtkImageMenuItem.
510  *
511  * Creates a new #GtkImageMenuItem with an empty label.
512  **/
513 GtkWidget*
514 gtk_image_menu_item_new (void)
515 {
516   return g_object_new (GTK_TYPE_IMAGE_MENU_ITEM, NULL);
517 }
518
519 /**
520  * gtk_image_menu_item_new_with_label:
521  * @label: the text of the menu item.
522  * @returns: a new #GtkImageMenuItem.
523  *
524  * Creates a new #GtkImageMenuItem containing a label. 
525  **/
526 GtkWidget*
527 gtk_image_menu_item_new_with_label (const gchar *label)
528 {
529   return g_object_new (GTK_TYPE_IMAGE_MENU_ITEM, 
530                        "label", label,
531                        NULL);
532 }
533
534
535 /**
536  * gtk_image_menu_item_new_with_mnemonic:
537  * @label: the text of the menu item, with an underscore in front of the
538  *         mnemonic character
539  * @returns: a new #GtkImageMenuItem
540  *
541  * Creates a new #GtkImageMenuItem containing a label. The label
542  * will be created using gtk_label_new_with_mnemonic(), so underscores
543  * in @label indicate the mnemonic for the menu item.
544  **/
545 GtkWidget*
546 gtk_image_menu_item_new_with_mnemonic (const gchar *label)
547 {
548   return g_object_new (GTK_TYPE_IMAGE_MENU_ITEM, 
549                        "use-underline", TRUE,
550                        "label", label,
551                        NULL);
552 }
553
554 /**
555  * gtk_image_menu_item_new_from_stock:
556  * @stock_id: the name of the stock item.
557  * @accel_group: the #GtkAccelGroup to add the menu items accelerator to,
558  *   or %NULL.
559  * @returns: a new #GtkImageMenuItem.
560  *
561  * Creates a new #GtkImageMenuItem containing the image and text from a 
562  * stock item. Some stock ids have preprocessor macros like #GTK_STOCK_OK 
563  * and #GTK_STOCK_APPLY.
564  *
565  * If you want this menu item to have changeable accelerators, then pass in
566  * %NULL for accel_group. Next call gtk_menu_item_set_accel_path() with an
567  * appropriate path for the menu item, use gtk_stock_lookup() to look up the
568  * standard accelerator for the stock item, and if one is found, call
569  * gtk_accel_map_add_entry() to register it.
570  **/
571 GtkWidget*
572 gtk_image_menu_item_new_from_stock (const gchar      *stock_id,
573                                     GtkAccelGroup    *accel_group)
574 {
575   return g_object_new (GTK_TYPE_IMAGE_MENU_ITEM, 
576                        "label", stock_id,
577                        "use-stock", TRUE,
578                        "accel-group", accel_group,
579                        NULL);
580 }
581
582 /**
583  * gtk_image_menu_item_set_use_stock:
584  * @image_menu_item: a #GtkImageMenuItem
585  * @use_stock: %TRUE if the menuitem should use a stock item
586  *
587  * If %TRUE, the label set in the menuitem is used as a
588  * stock id to select the stock item for the item.
589  *
590  * Since: 2.16
591  */
592 void
593 gtk_image_menu_item_set_use_stock (GtkImageMenuItem *image_menu_item,
594                                    gboolean          use_stock)
595 {
596   GtkImageMenuItemPrivate *priv;
597
598   g_return_if_fail (GTK_IS_IMAGE_MENU_ITEM (image_menu_item));
599
600   priv = GET_PRIVATE (image_menu_item);
601
602   if (priv->use_stock != use_stock)
603     {
604       priv->use_stock = use_stock;
605
606       gtk_image_menu_item_recalculate (image_menu_item);
607
608       g_object_notify (G_OBJECT (image_menu_item), "use-stock");
609     }
610 }
611
612 /**
613  * gtk_image_menu_item_get_use_stock:
614  * @image_menu_item: a #GtkImageMenuItem
615  * @use_stock: %TRUE if the menuitem should use a stock item
616  *
617  * Checks whether the label set in the menuitem is used as a
618  * stock id to select the stock item for the item.
619  *
620  * Returns: %TRUE if the label set in the menuitem is used as a
621  * stock id to select the stock item for the item
622  *
623  * Since: 2.16
624  */
625 gboolean
626 gtk_image_menu_item_get_use_stock (GtkImageMenuItem *image_menu_item)
627 {
628   GtkImageMenuItemPrivate *priv;
629
630   g_return_val_if_fail (GTK_IS_IMAGE_MENU_ITEM (image_menu_item), FALSE);
631
632   priv = GET_PRIVATE (image_menu_item);
633
634   return priv->use_stock;
635 }
636
637
638 /**
639  * gtk_image_menu_item_set_accel_group:
640  * @image_menu_item: a #GtkImageMenuItem
641  * @accel_group: the #GtkAccelGroup
642  *
643  * Specifies an @accel_group to add the menu items accelerator to
644  * (this only applies to stock items so a stock item must already
645  * be set, make sure to call gtk_image_menu_item_set_use_stock()
646  * and gtk_menu_item_set_label() with a valid stock item first).
647  *
648  * If you want this menu item to have changeable accelerators then
649  * you shouldnt need this (see gtk_image_menu_item_new_from_stock()).
650  *
651  * Returns: whether an accelerator from the stock was successfully added.
652  *
653  * Since: 2.16
654  */
655 void
656 gtk_image_menu_item_set_accel_group (GtkImageMenuItem *image_menu_item, 
657                                      GtkAccelGroup    *accel_group)
658 {
659   GtkImageMenuItemPrivate *priv;
660   GtkStockItem             stock_item;
661
662   /* Silent return for the constructor */
663   if (!accel_group) 
664     return;
665   
666   g_return_if_fail (GTK_IS_IMAGE_MENU_ITEM (image_menu_item));
667   g_return_if_fail (GTK_IS_ACCEL_GROUP (accel_group));
668
669   priv = GET_PRIVATE (image_menu_item);
670
671   if (priv->use_stock && priv->label && gtk_stock_lookup (priv->label, &stock_item))
672     if (stock_item.keyval)
673       {
674         gtk_widget_add_accelerator (GTK_WIDGET (image_menu_item),
675                                     "activate",
676                                     accel_group,
677                                     stock_item.keyval,
678                                     stock_item.modifier,
679                                     GTK_ACCEL_VISIBLE);
680         
681         g_object_notify (G_OBJECT (image_menu_item), "accel-group");
682       }
683 }
684
685 /** 
686  * gtk_image_menu_item_set_image:
687  * @image_menu_item: a #GtkImageMenuItem.
688  * @image: a widget to set as the image for the menu item.
689  * 
690  * Sets the image of @image_menu_item to the given widget.
691  * Note that it depends on the show-menu-images setting whether
692  * the image will be displayed or not.
693  **/ 
694 void
695 gtk_image_menu_item_set_image (GtkImageMenuItem *image_menu_item,
696                                GtkWidget        *image)
697 {
698   g_return_if_fail (GTK_IS_IMAGE_MENU_ITEM (image_menu_item));
699
700   if (image == image_menu_item->image)
701     return;
702
703   if (image_menu_item->image)
704     gtk_container_remove (GTK_CONTAINER (image_menu_item),
705                           image_menu_item->image);
706
707   image_menu_item->image = image;
708
709   if (image == NULL)
710     return;
711
712   gtk_widget_set_parent (image, GTK_WIDGET (image_menu_item));
713   g_object_set (image,
714                 "visible", show_image (image_menu_item),
715                 "no-show-all", TRUE,
716                 NULL);
717
718   g_object_notify (G_OBJECT (image_menu_item), "image");
719 }
720
721 /**
722  * gtk_image_menu_item_get_image:
723  * @image_menu_item: a #GtkImageMenuItem.
724  * @returns: the widget set as image of @image_menu_item.
725  *
726  * Gets the widget that is currently set as the image of @image_menu_item.
727  * See gtk_image_menu_item_set_image().
728  **/
729 GtkWidget*
730 gtk_image_menu_item_get_image (GtkImageMenuItem *image_menu_item)
731 {
732   g_return_val_if_fail (GTK_IS_IMAGE_MENU_ITEM (image_menu_item), NULL);
733
734   return image_menu_item->image;
735 }
736
737 static void
738 gtk_image_menu_item_remove (GtkContainer *container,
739                             GtkWidget    *child)
740 {
741   GtkImageMenuItem *image_menu_item;
742
743   image_menu_item = GTK_IMAGE_MENU_ITEM (container);
744
745   if (child == image_menu_item->image)
746     {
747       gboolean widget_was_visible;
748       
749       widget_was_visible = GTK_WIDGET_VISIBLE (child);
750       
751       gtk_widget_unparent (child);
752       image_menu_item->image = NULL;
753       
754       if (GTK_WIDGET_VISIBLE (container) && widget_was_visible)
755         gtk_widget_queue_resize (GTK_WIDGET (container));
756
757       g_object_notify (G_OBJECT (image_menu_item), "image");
758     }
759   else
760     {
761       GTK_CONTAINER_CLASS (gtk_image_menu_item_parent_class)->remove (container, child);
762     }
763 }
764
765 static void 
766 show_image_change_notify (GtkImageMenuItem *image_menu_item)
767 {
768   if (image_menu_item->image)
769     {
770       if (show_image (image_menu_item))
771         gtk_widget_show (image_menu_item->image);
772       else
773         gtk_widget_hide (image_menu_item->image);
774     }
775 }
776
777 static void
778 traverse_container (GtkWidget *widget,
779                     gpointer   data)
780 {
781   if (GTK_IS_IMAGE_MENU_ITEM (widget))
782     show_image_change_notify (GTK_IMAGE_MENU_ITEM (widget));
783   else if (GTK_IS_CONTAINER (widget))
784     gtk_container_forall (GTK_CONTAINER (widget), traverse_container, NULL);
785 }
786
787 static void
788 gtk_image_menu_item_setting_changed (GtkSettings *settings)
789 {
790   GList *list, *l;
791
792   list = gtk_window_list_toplevels ();
793
794   for (l = list; l; l = l->next)
795     gtk_container_forall (GTK_CONTAINER (l->data), 
796                           traverse_container, NULL);
797
798   g_list_free (list);  
799 }
800
801 static void
802 gtk_image_menu_item_screen_changed (GtkWidget *widget,
803                                     GdkScreen *previous_screen)
804 {
805   GtkSettings *settings;
806   guint show_image_connection;
807
808   if (!gtk_widget_has_screen (widget))
809     return;
810
811   settings = gtk_widget_get_settings (widget);
812   
813   show_image_connection = 
814     GPOINTER_TO_UINT (g_object_get_data (G_OBJECT (settings), 
815                                          "gtk-image-menu-item-connection"));
816   
817   if (show_image_connection)
818     return;
819
820   show_image_connection =
821     g_signal_connect (settings, "notify::gtk-menu-images",
822                       G_CALLBACK (gtk_image_menu_item_setting_changed), NULL);
823   g_object_set_data (G_OBJECT (settings), 
824                      I_("gtk-image-menu-item-connection"),
825                      GUINT_TO_POINTER (show_image_connection));
826
827   show_image_change_notify (GTK_IMAGE_MENU_ITEM (widget));
828 }
829
830 #define __GTK_IMAGE_MENU_ITEM_C__
831 #include "gtkaliasdef.c"