]> Pileus Git - ~andy/gtk/blob - gtk/gtkimagemenuitem.c
Bug 322932 – Always show icons on panel menus
[~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 "gtkactivatable.h"
38 #include "gtkprivate.h"
39 #include "gtkalias.h"
40
41 static void gtk_image_menu_item_destroy              (GtkObject        *object);
42 static void gtk_image_menu_item_size_request         (GtkWidget        *widget,
43                                                       GtkRequisition   *requisition);
44 static void gtk_image_menu_item_size_allocate        (GtkWidget        *widget,
45                                                       GtkAllocation    *allocation);
46 static void gtk_image_menu_item_map                  (GtkWidget        *widget);
47 static void gtk_image_menu_item_remove               (GtkContainer     *container,
48                                                       GtkWidget        *child);
49 static void gtk_image_menu_item_toggle_size_request  (GtkMenuItem      *menu_item,
50                                                       gint             *requisition);
51 static void gtk_image_menu_item_set_label            (GtkMenuItem      *menu_item,
52                                                       const gchar      *label);
53 static G_CONST_RETURN gchar *gtk_image_menu_item_get_label (GtkMenuItem *menu_item);
54
55 static void gtk_image_menu_item_forall               (GtkContainer    *container,
56                                                       gboolean         include_internals,
57                                                       GtkCallback      callback,
58                                                       gpointer         callback_data);
59
60 static void gtk_image_menu_item_finalize             (GObject         *object);
61 static void gtk_image_menu_item_set_property         (GObject         *object,
62                                                       guint            prop_id,
63                                                       const GValue    *value,
64                                                       GParamSpec      *pspec);
65 static void gtk_image_menu_item_get_property         (GObject         *object,
66                                                       guint            prop_id,
67                                                       GValue          *value,
68                                                       GParamSpec      *pspec);
69 static void gtk_image_menu_item_screen_changed       (GtkWidget        *widget,
70                                                       GdkScreen        *previous_screen);
71
72 static void gtk_image_menu_item_recalculate          (GtkImageMenuItem *image_menu_item);
73
74 static void gtk_image_menu_item_activatable_interface_init (GtkActivatableIface  *iface);
75 static void gtk_image_menu_item_activatable_update         (GtkActivatable       *activatable,
76                                                             GtkAction            *action,
77                                                             const gchar          *property_name);
78 static void gtk_image_menu_item_activatable_reset          (GtkActivatable       *activatable,
79                                                             GtkAction            *action);
80
81 typedef struct {
82   gchar *label;
83   guint  use_stock         : 1;
84   guint  always_show_image : 1;
85 } GtkImageMenuItemPrivate;
86
87 enum {
88   PROP_0,
89   PROP_IMAGE,
90   PROP_USE_STOCK,
91   PROP_ACCEL_GROUP,
92   PROP_ALWAYS_SHOW_IMAGE
93 };
94
95 static GtkActivatableIface *parent_activatable_iface;
96
97
98 G_DEFINE_TYPE_WITH_CODE (GtkImageMenuItem, gtk_image_menu_item, GTK_TYPE_MENU_ITEM,
99                          G_IMPLEMENT_INTERFACE (GTK_TYPE_ACTIVATABLE,
100                                                 gtk_image_menu_item_activatable_interface_init))
101
102 #define GET_PRIVATE(object)  \
103   (G_TYPE_INSTANCE_GET_PRIVATE ((object), GTK_TYPE_IMAGE_MENU_ITEM, GtkImageMenuItemPrivate))
104
105 static void
106 gtk_image_menu_item_class_init (GtkImageMenuItemClass *klass)
107 {
108   GObjectClass *gobject_class = (GObjectClass*) klass;
109   GtkObjectClass *object_class = (GtkObjectClass*) klass;
110   GtkWidgetClass *widget_class = (GtkWidgetClass*) klass;
111   GtkMenuItemClass *menu_item_class = (GtkMenuItemClass*) klass;
112   GtkContainerClass *container_class = (GtkContainerClass*) klass;
113
114   object_class->destroy = gtk_image_menu_item_destroy;
115
116   widget_class->screen_changed = gtk_image_menu_item_screen_changed;
117   widget_class->size_request = gtk_image_menu_item_size_request;
118   widget_class->size_allocate = gtk_image_menu_item_size_allocate;
119   widget_class->map = gtk_image_menu_item_map;
120
121   container_class->forall = gtk_image_menu_item_forall;
122   container_class->remove = gtk_image_menu_item_remove;
123   
124   menu_item_class->toggle_size_request = gtk_image_menu_item_toggle_size_request;
125   menu_item_class->set_label           = gtk_image_menu_item_set_label;
126   menu_item_class->get_label           = gtk_image_menu_item_get_label;
127
128   gobject_class->finalize     = gtk_image_menu_item_finalize;
129   gobject_class->set_property = gtk_image_menu_item_set_property;
130   gobject_class->get_property = gtk_image_menu_item_get_property;
131   
132   g_object_class_install_property (gobject_class,
133                                    PROP_IMAGE,
134                                    g_param_spec_object ("image",
135                                                         P_("Image widget"),
136                                                         P_("Child widget to appear next to the menu text"),
137                                                         GTK_TYPE_WIDGET,
138                                                         GTK_PARAM_READWRITE));
139   /**
140    * GtkImageMenuItem:use-stock:
141    *
142    * If %TRUE, the label set in the menuitem is used as a
143    * stock id to select the stock item for the item.
144    *
145    * Since: 2.16
146    **/
147   g_object_class_install_property (gobject_class,
148                                    PROP_USE_STOCK,
149                                    g_param_spec_boolean ("use-stock",
150                                                          P_("Use stock"),
151                                                          P_("Whether to use the label text to create a stock menu item"),
152                                                          FALSE,
153                                                          GTK_PARAM_READWRITE | G_PARAM_CONSTRUCT));
154
155   /**
156    * GtkImageMenuItem:always-show-image:
157    *
158    * If %TRUE, the menu item will ignore the #GtkSettings:gtk-menu-images 
159    * setting and always show the image, if available.
160    *
161    * Use this property if the menuitem would be useless or hard to use
162    * without the image. 
163    *
164    * Since: 2.16
165    **/
166   g_object_class_install_property (gobject_class,
167                                    PROP_ALWAYS_SHOW_IMAGE,
168                                    g_param_spec_boolean ("always-show-image",
169                                                          P_("Always show image"),
170                                                          P_("Whether the image will always be shown"),
171                                                          FALSE,
172                                                          GTK_PARAM_READWRITE | G_PARAM_CONSTRUCT));
173
174   /**
175    * GtkImageMenuItem:accel-group:
176    *
177    * The Accel Group to use for stock accelerator keys
178    *
179    * Since: 2.16
180    **/
181   g_object_class_install_property (gobject_class,
182                                    PROP_ACCEL_GROUP,
183                                    g_param_spec_object ("accel-group",
184                                                         P_("Accel Group"),
185                                                         P_("The Accel Group to use for stock accelerator keys"),
186                                                         GTK_TYPE_ACCEL_GROUP,
187                                                         GTK_PARAM_WRITABLE));
188
189   gtk_settings_install_property (g_param_spec_boolean ("gtk-menu-images",
190                                                        P_("Show menu images"),
191                                                        P_("Whether images should be shown in menus"),
192                                                        TRUE,
193                                                        GTK_PARAM_READWRITE));
194   
195
196   g_type_class_add_private (object_class, sizeof (GtkImageMenuItemPrivate));
197
198 }
199
200 static void
201 gtk_image_menu_item_init (GtkImageMenuItem *image_menu_item)
202 {
203   GtkImageMenuItemPrivate *priv = GET_PRIVATE (image_menu_item);
204
205   priv->use_stock   = FALSE;
206   priv->label  = NULL;
207
208   image_menu_item->image = NULL;
209 }
210
211 static void 
212 gtk_image_menu_item_finalize (GObject *object)
213 {
214   GtkImageMenuItemPrivate *priv = GET_PRIVATE (object);
215
216   g_free (priv->label);
217   priv->label  = NULL;
218
219   G_OBJECT_CLASS (gtk_image_menu_item_parent_class)->finalize (object);
220 }
221
222 static void
223 gtk_image_menu_item_set_property (GObject         *object,
224                                   guint            prop_id,
225                                   const GValue    *value,
226                                   GParamSpec      *pspec)
227 {
228   GtkImageMenuItem *image_menu_item = GTK_IMAGE_MENU_ITEM (object);
229   
230   switch (prop_id)
231     {
232     case PROP_IMAGE:
233       gtk_image_menu_item_set_image (image_menu_item, (GtkWidget *) g_value_get_object (value));
234       break;
235     case PROP_USE_STOCK:
236       gtk_image_menu_item_set_use_stock (image_menu_item, g_value_get_boolean (value));
237       break;
238     case PROP_ALWAYS_SHOW_IMAGE:
239       gtk_image_menu_item_set_always_show_image (image_menu_item, g_value_get_boolean (value));
240       break;
241     case PROP_ACCEL_GROUP:
242       gtk_image_menu_item_set_accel_group (image_menu_item, g_value_get_object (value));
243       break;
244     default:
245       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
246       break;
247     }
248 }
249
250 static void
251 gtk_image_menu_item_get_property (GObject         *object,
252                                   guint            prop_id,
253                                   GValue          *value,
254                                   GParamSpec      *pspec)
255 {
256   GtkImageMenuItem *image_menu_item = GTK_IMAGE_MENU_ITEM (object);
257   
258   switch (prop_id)
259     {
260     case PROP_IMAGE:
261       g_value_set_object (value, gtk_image_menu_item_get_image (image_menu_item));
262       break;
263     case PROP_USE_STOCK:
264       g_value_set_boolean (value, gtk_image_menu_item_get_use_stock (image_menu_item));      
265       break;
266     case PROP_ALWAYS_SHOW_IMAGE:
267       g_value_set_boolean (value, gtk_image_menu_item_get_always_show_image (image_menu_item));
268       break;
269     default:
270       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
271       break;
272     }
273 }
274
275 static gboolean
276 show_image (GtkImageMenuItem *image_menu_item)
277 {
278   GtkImageMenuItemPrivate *priv = GET_PRIVATE (image_menu_item);
279   GtkSettings *settings = gtk_widget_get_settings (GTK_WIDGET (image_menu_item));
280   gboolean show;
281
282   if (priv->always_show_image)
283     show = TRUE;
284   else
285     g_object_get (settings, "gtk-menu-images", &show, NULL);
286
287   return show;
288 }
289
290 static void
291 gtk_image_menu_item_map (GtkWidget *widget)
292 {
293   GtkImageMenuItem *image_menu_item = GTK_IMAGE_MENU_ITEM (widget);
294
295   GTK_WIDGET_CLASS (gtk_image_menu_item_parent_class)->map (widget);
296
297   if (image_menu_item->image)
298     g_object_set (image_menu_item->image,
299                   "visible", show_image (image_menu_item),
300                   NULL);
301 }
302
303 static void
304 gtk_image_menu_item_destroy (GtkObject *object)
305 {
306   GtkImageMenuItem *image_menu_item = GTK_IMAGE_MENU_ITEM (object);
307
308   if (image_menu_item->image)
309     gtk_container_remove (GTK_CONTAINER (image_menu_item),
310                           image_menu_item->image);
311
312   GTK_OBJECT_CLASS (gtk_image_menu_item_parent_class)->destroy (object);
313 }
314
315 static void
316 gtk_image_menu_item_toggle_size_request (GtkMenuItem *menu_item,
317                                          gint        *requisition)
318 {
319   GtkImageMenuItem *image_menu_item = GTK_IMAGE_MENU_ITEM (menu_item);
320   GtkPackDirection pack_dir;
321   
322   if (GTK_IS_MENU_BAR (GTK_WIDGET (menu_item)->parent))
323     pack_dir = gtk_menu_bar_get_child_pack_direction (GTK_MENU_BAR (GTK_WIDGET (menu_item)->parent));
324   else
325     pack_dir = GTK_PACK_DIRECTION_LTR;
326
327   *requisition = 0;
328
329   if (image_menu_item->image && GTK_WIDGET_VISIBLE (image_menu_item->image))
330     {
331       GtkRequisition image_requisition;
332       guint toggle_spacing;
333       gtk_widget_get_child_requisition (image_menu_item->image,
334                                         &image_requisition);
335
336       gtk_widget_style_get (GTK_WIDGET (menu_item),
337                             "toggle-spacing", &toggle_spacing,
338                             NULL);
339       
340       if (pack_dir == GTK_PACK_DIRECTION_LTR || pack_dir == GTK_PACK_DIRECTION_RTL)
341         {
342           if (image_requisition.width > 0)
343             *requisition = image_requisition.width + toggle_spacing;
344         }
345       else
346         {
347           if (image_requisition.height > 0)
348             *requisition = image_requisition.height + toggle_spacing;
349         }
350     }
351 }
352
353 static void
354 gtk_image_menu_item_recalculate (GtkImageMenuItem *image_menu_item)
355 {
356   GtkImageMenuItemPrivate *priv = GET_PRIVATE (image_menu_item);
357   GtkStockItem             stock_item;
358   GtkWidget               *image;
359   const gchar             *resolved_label = priv->label;
360
361   if (priv->use_stock && priv->label)
362     {
363
364       if (!image_menu_item->image)
365         {
366           image = gtk_image_new_from_stock (priv->label, GTK_ICON_SIZE_MENU);
367           gtk_image_menu_item_set_image (image_menu_item, image);
368         }
369
370       if (gtk_stock_lookup (priv->label, &stock_item))
371           resolved_label = stock_item.label;
372
373         gtk_menu_item_set_use_underline (GTK_MENU_ITEM (image_menu_item), TRUE);
374     }
375
376   GTK_MENU_ITEM_CLASS
377     (gtk_image_menu_item_parent_class)->set_label (GTK_MENU_ITEM (image_menu_item), resolved_label);
378
379 }
380
381 static void 
382 gtk_image_menu_item_set_label (GtkMenuItem      *menu_item,
383                                const gchar      *label)
384 {
385   GtkImageMenuItemPrivate *priv = GET_PRIVATE (menu_item);
386
387   if (priv->label != label)
388     {
389       g_free (priv->label);
390       priv->label = g_strdup (label);
391
392       gtk_image_menu_item_recalculate (GTK_IMAGE_MENU_ITEM (menu_item));
393
394       g_object_notify (G_OBJECT (menu_item), "label");
395
396     }
397 }
398
399 static G_CONST_RETURN gchar *
400 gtk_image_menu_item_get_label (GtkMenuItem *menu_item)
401 {
402   GtkImageMenuItemPrivate *priv = GET_PRIVATE (menu_item);
403   
404   return priv->label;
405 }
406
407 static void
408 gtk_image_menu_item_size_request (GtkWidget      *widget,
409                                   GtkRequisition *requisition)
410 {
411   GtkImageMenuItem *image_menu_item;
412   gint child_width = 0;
413   gint child_height = 0;
414   GtkPackDirection pack_dir;
415   
416   if (GTK_IS_MENU_BAR (widget->parent))
417     pack_dir = gtk_menu_bar_get_child_pack_direction (GTK_MENU_BAR (widget->parent));
418   else
419     pack_dir = GTK_PACK_DIRECTION_LTR;
420
421   image_menu_item = GTK_IMAGE_MENU_ITEM (widget);
422
423   if (image_menu_item->image && GTK_WIDGET_VISIBLE (image_menu_item->image))
424     {
425       GtkRequisition child_requisition;
426       
427       gtk_widget_size_request (image_menu_item->image,
428                                &child_requisition);
429
430       child_width = child_requisition.width;
431       child_height = child_requisition.height;
432     }
433
434   GTK_WIDGET_CLASS (gtk_image_menu_item_parent_class)->size_request (widget, requisition);
435
436   /* not done with height since that happens via the
437    * toggle_size_request
438    */
439   if (pack_dir == GTK_PACK_DIRECTION_LTR || pack_dir == GTK_PACK_DIRECTION_RTL)
440     requisition->height = MAX (requisition->height, child_height);
441   else
442     requisition->width = MAX (requisition->width, child_width);
443     
444   
445   /* Note that GtkMenuShell always size requests before
446    * toggle_size_request, so toggle_size_request will be able to use
447    * image_menu_item->image->requisition
448    */
449 }
450
451 static void
452 gtk_image_menu_item_size_allocate (GtkWidget     *widget,
453                                    GtkAllocation *allocation)
454 {
455   GtkImageMenuItem *image_menu_item;
456   GtkPackDirection pack_dir;
457   
458   if (GTK_IS_MENU_BAR (widget->parent))
459     pack_dir = gtk_menu_bar_get_child_pack_direction (GTK_MENU_BAR (widget->parent));
460   else
461     pack_dir = GTK_PACK_DIRECTION_LTR;
462   
463   image_menu_item = GTK_IMAGE_MENU_ITEM (widget);  
464
465   GTK_WIDGET_CLASS (gtk_image_menu_item_parent_class)->size_allocate (widget, allocation);
466
467   if (image_menu_item->image && GTK_WIDGET_VISIBLE (image_menu_item->image))
468     {
469       gint x, y, offset;
470       GtkRequisition child_requisition;
471       GtkAllocation child_allocation;
472       guint horizontal_padding, toggle_spacing;
473
474       gtk_widget_style_get (widget,
475                             "horizontal-padding", &horizontal_padding,
476                             "toggle-spacing", &toggle_spacing,
477                             NULL);
478       
479       /* Man this is lame hardcoding action, but I can't
480        * come up with a solution that's really better.
481        */
482
483       gtk_widget_get_child_requisition (image_menu_item->image,
484                                         &child_requisition);
485
486       if (pack_dir == GTK_PACK_DIRECTION_LTR ||
487           pack_dir == GTK_PACK_DIRECTION_RTL)
488         {
489           offset = GTK_CONTAINER (image_menu_item)->border_width +
490             widget->style->xthickness;
491           
492           if ((gtk_widget_get_direction (widget) == GTK_TEXT_DIR_LTR) ==
493               (pack_dir == GTK_PACK_DIRECTION_LTR))
494             x = offset + horizontal_padding +
495               (GTK_MENU_ITEM (image_menu_item)->toggle_size -
496                toggle_spacing - child_requisition.width) / 2;
497           else
498             x = widget->allocation.width - offset - horizontal_padding -
499               GTK_MENU_ITEM (image_menu_item)->toggle_size + toggle_spacing +
500               (GTK_MENU_ITEM (image_menu_item)->toggle_size -
501                toggle_spacing - child_requisition.width) / 2;
502           
503           y = (widget->allocation.height - child_requisition.height) / 2;
504         }
505       else
506         {
507           offset = GTK_CONTAINER (image_menu_item)->border_width +
508             widget->style->ythickness;
509           
510           if ((gtk_widget_get_direction (widget) == GTK_TEXT_DIR_LTR) ==
511               (pack_dir == GTK_PACK_DIRECTION_TTB))
512             y = offset + horizontal_padding +
513               (GTK_MENU_ITEM (image_menu_item)->toggle_size -
514                toggle_spacing - child_requisition.height) / 2;
515           else
516             y = widget->allocation.height - offset - horizontal_padding -
517               GTK_MENU_ITEM (image_menu_item)->toggle_size + toggle_spacing +
518               (GTK_MENU_ITEM (image_menu_item)->toggle_size -
519                toggle_spacing - child_requisition.height) / 2;
520
521           x = (widget->allocation.width - child_requisition.width) / 2;
522         }
523       
524       child_allocation.width = child_requisition.width;
525       child_allocation.height = child_requisition.height;
526       child_allocation.x = widget->allocation.x + MAX (x, 0);
527       child_allocation.y = widget->allocation.y + MAX (y, 0);
528
529       gtk_widget_size_allocate (image_menu_item->image, &child_allocation);
530     }
531 }
532
533 static void
534 gtk_image_menu_item_forall (GtkContainer   *container,
535                             gboolean        include_internals,
536                             GtkCallback     callback,
537                             gpointer        callback_data)
538 {
539   GtkImageMenuItem *image_menu_item = GTK_IMAGE_MENU_ITEM (container);
540
541   GTK_CONTAINER_CLASS (gtk_image_menu_item_parent_class)->forall (container,
542                                                                   include_internals,
543                                                                   callback,
544                                                                   callback_data);
545
546   if (include_internals && image_menu_item->image)
547     (* callback) (image_menu_item->image, callback_data);
548 }
549
550
551 static void 
552 gtk_image_menu_item_activatable_interface_init (GtkActivatableIface  *iface)
553 {
554   parent_activatable_iface = g_type_interface_peek_parent (iface);
555   iface->update = gtk_image_menu_item_activatable_update;
556   iface->reset = gtk_image_menu_item_activatable_reset;
557 }
558
559 static gboolean
560 activatable_update_stock_id (GtkImageMenuItem *image_menu_item, GtkAction *action)
561 {
562   GtkWidget   *image;
563   const gchar *stock_id  = gtk_action_get_stock_id (action);
564
565   image = gtk_image_menu_item_get_image (image_menu_item);
566           
567   if (GTK_IS_IMAGE (image) &&
568       stock_id && gtk_icon_factory_lookup_default (stock_id))
569     {
570       gtk_image_set_from_stock (GTK_IMAGE (image), stock_id, GTK_ICON_SIZE_MENU);
571       return TRUE;
572     }
573
574   return FALSE;
575 }
576
577 static gboolean
578 activatable_update_gicon (GtkImageMenuItem *image_menu_item, GtkAction *action)
579 {
580   GtkWidget   *image;
581   GIcon       *icon = gtk_action_get_gicon (action);
582   const gchar *stock_id = gtk_action_get_stock_id (action);
583
584   image = gtk_image_menu_item_get_image (image_menu_item);
585
586   if (icon && GTK_IS_IMAGE (image) &&
587       !(stock_id && gtk_icon_factory_lookup_default (stock_id)))
588     {
589       gtk_image_set_from_gicon (GTK_IMAGE (image), icon, GTK_ICON_SIZE_MENU);
590       return TRUE;
591     }
592
593   return FALSE;
594 }
595
596 static void
597 activatable_update_icon_name (GtkImageMenuItem *image_menu_item, GtkAction *action)
598 {
599   GtkWidget   *image;
600   const gchar *icon_name = gtk_action_get_icon_name (action);
601
602   image = gtk_image_menu_item_get_image (image_menu_item);
603           
604   if (GTK_IS_IMAGE (image) && icon_name &&
605       (gtk_image_get_storage_type (GTK_IMAGE (image)) == GTK_IMAGE_EMPTY ||
606        gtk_image_get_storage_type (GTK_IMAGE (image)) == GTK_IMAGE_ICON_NAME))
607     {
608       gtk_image_set_from_icon_name (GTK_IMAGE (image), icon_name, GTK_ICON_SIZE_MENU);
609     }
610 }
611
612 static void 
613 gtk_image_menu_item_activatable_update (GtkActivatable       *activatable,
614                                         GtkAction            *action,
615                                         const gchar          *property_name)
616 {
617   GtkImageMenuItem *image_menu_item;
618   GtkWidget *image;
619   gboolean   use_appearance;
620
621   image_menu_item = GTK_IMAGE_MENU_ITEM (activatable);
622
623   parent_activatable_iface->update (activatable, action, property_name);
624
625   use_appearance = gtk_activatable_get_use_action_appearance (activatable);
626   if (!use_appearance)
627     return;
628
629   if (strcmp (property_name, "stock-id") == 0)
630     activatable_update_stock_id (image_menu_item, action);
631   else if (strcmp (property_name, "gicon") == 0)
632     activatable_update_gicon (image_menu_item, action);
633   else if (strcmp (property_name, "icon-name") == 0)
634     activatable_update_icon_name (image_menu_item, action);
635 }
636
637 static void 
638 gtk_image_menu_item_activatable_reset (GtkActivatable       *activatable,
639                                        GtkAction            *action)
640 {
641   GtkImageMenuItem *image_menu_item;
642   GtkWidget *image;
643   gboolean   use_appearance;
644
645   image_menu_item = GTK_IMAGE_MENU_ITEM (activatable);
646
647   parent_activatable_iface->reset (activatable, action);
648
649   if (!action)
650     return;
651
652   use_appearance = gtk_activatable_get_use_action_appearance (activatable);
653   if (!use_appearance)
654     return;
655
656   image = gtk_image_menu_item_get_image (image_menu_item);
657   if (image && !GTK_IS_IMAGE (image))
658     {
659       gtk_image_menu_item_set_image (image_menu_item, NULL);
660       image = NULL;
661     }
662   
663   if (!image)
664     {
665       image = gtk_image_new ();
666       gtk_widget_show (image);
667       gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (activatable),
668                                      image);
669     }
670   
671   if (!activatable_update_stock_id (image_menu_item, action) &&
672       !activatable_update_gicon (image_menu_item, action))
673     activatable_update_icon_name (image_menu_item, action);
674
675 }
676
677
678 /**
679  * gtk_image_menu_item_new:
680  * @returns: a new #GtkImageMenuItem.
681  *
682  * Creates a new #GtkImageMenuItem with an empty label.
683  **/
684 GtkWidget*
685 gtk_image_menu_item_new (void)
686 {
687   return g_object_new (GTK_TYPE_IMAGE_MENU_ITEM, NULL);
688 }
689
690 /**
691  * gtk_image_menu_item_new_with_label:
692  * @label: the text of the menu item.
693  * @returns: a new #GtkImageMenuItem.
694  *
695  * Creates a new #GtkImageMenuItem containing a label. 
696  **/
697 GtkWidget*
698 gtk_image_menu_item_new_with_label (const gchar *label)
699 {
700   return g_object_new (GTK_TYPE_IMAGE_MENU_ITEM, 
701                        "label", label,
702                        NULL);
703 }
704
705
706 /**
707  * gtk_image_menu_item_new_with_mnemonic:
708  * @label: the text of the menu item, with an underscore in front of the
709  *         mnemonic character
710  * @returns: a new #GtkImageMenuItem
711  *
712  * Creates a new #GtkImageMenuItem containing a label. The label
713  * will be created using gtk_label_new_with_mnemonic(), so underscores
714  * in @label indicate the mnemonic for the menu item.
715  **/
716 GtkWidget*
717 gtk_image_menu_item_new_with_mnemonic (const gchar *label)
718 {
719   return g_object_new (GTK_TYPE_IMAGE_MENU_ITEM, 
720                        "use-underline", TRUE,
721                        "label", label,
722                        NULL);
723 }
724
725 /**
726  * gtk_image_menu_item_new_from_stock:
727  * @stock_id: the name of the stock item.
728  * @accel_group: the #GtkAccelGroup to add the menu items accelerator to,
729  *   or %NULL.
730  * @returns: a new #GtkImageMenuItem.
731  *
732  * Creates a new #GtkImageMenuItem containing the image and text from a 
733  * stock item. Some stock ids have preprocessor macros like #GTK_STOCK_OK 
734  * and #GTK_STOCK_APPLY.
735  *
736  * If you want this menu item to have changeable accelerators, then pass in
737  * %NULL for accel_group. Next call gtk_menu_item_set_accel_path() with an
738  * appropriate path for the menu item, use gtk_stock_lookup() to look up the
739  * standard accelerator for the stock item, and if one is found, call
740  * gtk_accel_map_add_entry() to register it.
741  **/
742 GtkWidget*
743 gtk_image_menu_item_new_from_stock (const gchar      *stock_id,
744                                     GtkAccelGroup    *accel_group)
745 {
746   return g_object_new (GTK_TYPE_IMAGE_MENU_ITEM, 
747                        "label", stock_id,
748                        "use-stock", TRUE,
749                        "accel-group", accel_group,
750                        NULL);
751 }
752
753 /**
754  * gtk_image_menu_item_set_use_stock:
755  * @image_menu_item: a #GtkImageMenuItem
756  * @use_stock: %TRUE if the menuitem should use a stock item
757  *
758  * If %TRUE, the label set in the menuitem is used as a
759  * stock id to select the stock item for the item.
760  *
761  * Since: 2.16
762  */
763 void
764 gtk_image_menu_item_set_use_stock (GtkImageMenuItem *image_menu_item,
765                                    gboolean          use_stock)
766 {
767   GtkImageMenuItemPrivate *priv;
768
769   g_return_if_fail (GTK_IS_IMAGE_MENU_ITEM (image_menu_item));
770
771   priv = GET_PRIVATE (image_menu_item);
772
773   if (priv->use_stock != use_stock)
774     {
775       priv->use_stock = use_stock;
776
777       gtk_image_menu_item_recalculate (image_menu_item);
778
779       g_object_notify (G_OBJECT (image_menu_item), "use-stock");
780     }
781 }
782
783 /**
784  * gtk_image_menu_item_get_use_stock:
785  * @image_menu_item: a #GtkImageMenuItem
786  *
787  * Checks whether the label set in the menuitem is used as a
788  * stock id to select the stock item for the item.
789  *
790  * Returns: %TRUE if the label set in the menuitem is used as a
791  *     stock id to select the stock item for the item
792  *
793  * Since: 2.16
794  */
795 gboolean
796 gtk_image_menu_item_get_use_stock (GtkImageMenuItem *image_menu_item)
797 {
798   GtkImageMenuItemPrivate *priv;
799
800   g_return_val_if_fail (GTK_IS_IMAGE_MENU_ITEM (image_menu_item), FALSE);
801
802   priv = GET_PRIVATE (image_menu_item);
803
804   return priv->use_stock;
805 }
806
807 /**
808  * gtk_image_menu_item_set_always_show_image:
809  * @image_menu_item: a #GtkImageMenuItem
810  * @always_show: %TRUE if the menuitem should always show the image
811  *
812  * If %TRUE, the menu item will ignore the #GtkSettings:gtk-menu-images 
813  * setting and always show the image, if available.
814  *
815  * Use this property if the menuitem would be useless or hard to use
816  * without the image. 
817  * 
818  * Since: 2.16
819  */
820 void
821 gtk_image_menu_item_set_always_show_image (GtkImageMenuItem *image_menu_item,
822                                            gboolean          always_show)
823 {
824   GtkImageMenuItemPrivate *priv;
825
826   g_return_if_fail (GTK_IS_IMAGE_MENU_ITEM (image_menu_item));
827
828   priv = GET_PRIVATE (image_menu_item);
829
830   if (priv->always_show_image != always_show)
831     {
832       priv->always_show_image = always_show;
833
834       if (image_menu_item->image)
835         {
836           if (show_image (image_menu_item))
837             gtk_widget_show (image_menu_item->image);
838           else
839             gtk_widget_hide (image_menu_item->image);
840         }
841
842       g_object_notify (G_OBJECT (image_menu_item), "always-show-image");
843     }
844 }
845
846 /**
847  * gtk_image_menu_item_get_always_show_image:
848  * @image_menu_item: a #GtkImageMenuItem
849  * @always_show: %TRUE if the menuitem should always show the image
850  *
851  * Returns whether the menu item will ignore the #GtkSettings:gtk-menu-images 
852  * setting and always show the image, if available.
853  * 
854  * Returns: %TRUE if the menu item will always show the image
855  *
856  * Since: 2.16
857  */
858 gboolean
859 gtk_image_menu_item_get_always_show_image (GtkImageMenuItem *image_menu_item)
860 {
861   GtkImageMenuItemPrivate *priv;
862
863   g_return_val_if_fail (GTK_IS_IMAGE_MENU_ITEM (image_menu_item), FALSE);
864
865   priv = GET_PRIVATE (image_menu_item);
866
867   return priv->always_show_image;
868 }
869
870
871 /**
872  * gtk_image_menu_item_set_accel_group:
873  * @image_menu_item: a #GtkImageMenuItem
874  * @accel_group: the #GtkAccelGroup
875  *
876  * Specifies an @accel_group to add the menu items accelerator to
877  * (this only applies to stock items so a stock item must already
878  * be set, make sure to call gtk_image_menu_item_set_use_stock()
879  * and gtk_menu_item_set_label() with a valid stock item first).
880  *
881  * If you want this menu item to have changeable accelerators then
882  * you shouldnt need this (see gtk_image_menu_item_new_from_stock()).
883  *
884  * Since: 2.16
885  */
886 void
887 gtk_image_menu_item_set_accel_group (GtkImageMenuItem *image_menu_item, 
888                                      GtkAccelGroup    *accel_group)
889 {
890   GtkImageMenuItemPrivate *priv;
891   GtkStockItem             stock_item;
892
893   /* Silent return for the constructor */
894   if (!accel_group) 
895     return;
896   
897   g_return_if_fail (GTK_IS_IMAGE_MENU_ITEM (image_menu_item));
898   g_return_if_fail (GTK_IS_ACCEL_GROUP (accel_group));
899
900   priv = GET_PRIVATE (image_menu_item);
901
902   if (priv->use_stock && priv->label && gtk_stock_lookup (priv->label, &stock_item))
903     if (stock_item.keyval)
904       {
905         gtk_widget_add_accelerator (GTK_WIDGET (image_menu_item),
906                                     "activate",
907                                     accel_group,
908                                     stock_item.keyval,
909                                     stock_item.modifier,
910                                     GTK_ACCEL_VISIBLE);
911         
912         g_object_notify (G_OBJECT (image_menu_item), "accel-group");
913       }
914 }
915
916 /** 
917  * gtk_image_menu_item_set_image:
918  * @image_menu_item: a #GtkImageMenuItem.
919  * @image: a widget to set as the image for the menu item.
920  * 
921  * Sets the image of @image_menu_item to the given widget.
922  * Note that it depends on the show-menu-images setting whether
923  * the image will be displayed or not.
924  **/ 
925 void
926 gtk_image_menu_item_set_image (GtkImageMenuItem *image_menu_item,
927                                GtkWidget        *image)
928 {
929   g_return_if_fail (GTK_IS_IMAGE_MENU_ITEM (image_menu_item));
930
931   if (image == image_menu_item->image)
932     return;
933
934   if (image_menu_item->image)
935     gtk_container_remove (GTK_CONTAINER (image_menu_item),
936                           image_menu_item->image);
937
938   image_menu_item->image = image;
939
940   if (image == NULL)
941     return;
942
943   gtk_widget_set_parent (image, GTK_WIDGET (image_menu_item));
944   g_object_set (image,
945                 "visible", show_image (image_menu_item),
946                 "no-show-all", TRUE,
947                 NULL);
948
949   g_object_notify (G_OBJECT (image_menu_item), "image");
950 }
951
952 /**
953  * gtk_image_menu_item_get_image:
954  * @image_menu_item: a #GtkImageMenuItem.
955  * @returns: the widget set as image of @image_menu_item.
956  *
957  * Gets the widget that is currently set as the image of @image_menu_item.
958  * See gtk_image_menu_item_set_image().
959  **/
960 GtkWidget*
961 gtk_image_menu_item_get_image (GtkImageMenuItem *image_menu_item)
962 {
963   g_return_val_if_fail (GTK_IS_IMAGE_MENU_ITEM (image_menu_item), NULL);
964
965   return image_menu_item->image;
966 }
967
968 static void
969 gtk_image_menu_item_remove (GtkContainer *container,
970                             GtkWidget    *child)
971 {
972   GtkImageMenuItem *image_menu_item;
973
974   image_menu_item = GTK_IMAGE_MENU_ITEM (container);
975
976   if (child == image_menu_item->image)
977     {
978       gboolean widget_was_visible;
979       
980       widget_was_visible = GTK_WIDGET_VISIBLE (child);
981       
982       gtk_widget_unparent (child);
983       image_menu_item->image = NULL;
984       
985       if (GTK_WIDGET_VISIBLE (container) && widget_was_visible)
986         gtk_widget_queue_resize (GTK_WIDGET (container));
987
988       g_object_notify (G_OBJECT (image_menu_item), "image");
989     }
990   else
991     {
992       GTK_CONTAINER_CLASS (gtk_image_menu_item_parent_class)->remove (container, child);
993     }
994 }
995
996 static void 
997 show_image_change_notify (GtkImageMenuItem *image_menu_item)
998 {
999   if (image_menu_item->image)
1000     {
1001       if (show_image (image_menu_item))
1002         gtk_widget_show (image_menu_item->image);
1003       else
1004         gtk_widget_hide (image_menu_item->image);
1005     }
1006 }
1007
1008 static void
1009 traverse_container (GtkWidget *widget,
1010                     gpointer   data)
1011 {
1012   if (GTK_IS_IMAGE_MENU_ITEM (widget))
1013     show_image_change_notify (GTK_IMAGE_MENU_ITEM (widget));
1014   else if (GTK_IS_CONTAINER (widget))
1015     gtk_container_forall (GTK_CONTAINER (widget), traverse_container, NULL);
1016 }
1017
1018 static void
1019 gtk_image_menu_item_setting_changed (GtkSettings *settings)
1020 {
1021   GList *list, *l;
1022
1023   list = gtk_window_list_toplevels ();
1024
1025   for (l = list; l; l = l->next)
1026     gtk_container_forall (GTK_CONTAINER (l->data), 
1027                           traverse_container, NULL);
1028
1029   g_list_free (list);  
1030 }
1031
1032 static void
1033 gtk_image_menu_item_screen_changed (GtkWidget *widget,
1034                                     GdkScreen *previous_screen)
1035 {
1036   GtkSettings *settings;
1037   guint show_image_connection;
1038
1039   if (!gtk_widget_has_screen (widget))
1040     return;
1041
1042   settings = gtk_widget_get_settings (widget);
1043   
1044   show_image_connection = 
1045     GPOINTER_TO_UINT (g_object_get_data (G_OBJECT (settings), 
1046                                          "gtk-image-menu-item-connection"));
1047   
1048   if (show_image_connection)
1049     return;
1050
1051   show_image_connection =
1052     g_signal_connect (settings, "notify::gtk-menu-images",
1053                       G_CALLBACK (gtk_image_menu_item_setting_changed), NULL);
1054   g_object_set_data (G_OBJECT (settings), 
1055                      I_("gtk-image-menu-item-connection"),
1056                      GUINT_TO_POINTER (show_image_connection));
1057
1058   show_image_change_notify (GTK_IMAGE_MENU_ITEM (widget));
1059 }
1060
1061 #define __GTK_IMAGE_MENU_ITEM_C__
1062 #include "gtkaliasdef.c"