]> Pileus Git - ~andy/gtk/blob - gtk/gtkimagemenuitem.c
Deprecate widget flag: GTK_WIDGET_VISIBLE
[~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_update                     (GtkActivatable       *activatable,
76                                                             GtkAction            *action,
77                                                             const gchar          *property_name);
78 static void gtk_image_menu_item_sync_action_properties     (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_get_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_get_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_get_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_update;
556   iface->sync_action_properties = gtk_image_menu_item_sync_action_properties;
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) && 
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_update (GtkActivatable *activatable,
614                             GtkAction      *action,
615                             const gchar    *property_name)
616 {
617   GtkImageMenuItem *image_menu_item;
618   gboolean   use_appearance;
619
620   image_menu_item = GTK_IMAGE_MENU_ITEM (activatable);
621
622   parent_activatable_iface->update (activatable, action, property_name);
623
624   use_appearance = gtk_activatable_get_use_action_appearance (activatable);
625   if (!use_appearance)
626     return;
627
628   if (strcmp (property_name, "stock-id") == 0)
629     activatable_update_stock_id (image_menu_item, action);
630   else if (strcmp (property_name, "gicon") == 0)
631     activatable_update_gicon (image_menu_item, action);
632   else if (strcmp (property_name, "icon-name") == 0)
633     activatable_update_icon_name (image_menu_item, action);
634 }
635
636 static void 
637 gtk_image_menu_item_sync_action_properties (GtkActivatable *activatable,
638                                             GtkAction      *action)
639 {
640   GtkImageMenuItem *image_menu_item;
641   GtkWidget *image;
642   gboolean   use_appearance;
643
644   image_menu_item = GTK_IMAGE_MENU_ITEM (activatable);
645
646   parent_activatable_iface->sync_action_properties (activatable, action);
647
648   if (!action)
649     return;
650
651   use_appearance = gtk_activatable_get_use_action_appearance (activatable);
652   if (!use_appearance)
653     return;
654
655   image = gtk_image_menu_item_get_image (image_menu_item);
656   if (image && !GTK_IS_IMAGE (image))
657     {
658       gtk_image_menu_item_set_image (image_menu_item, NULL);
659       image = NULL;
660     }
661   
662   if (!image)
663     {
664       image = gtk_image_new ();
665       gtk_widget_show (image);
666       gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (activatable),
667                                      image);
668     }
669   
670   if (!activatable_update_stock_id (image_menu_item, action) &&
671       !activatable_update_gicon (image_menu_item, action))
672     activatable_update_icon_name (image_menu_item, action);
673
674   gtk_image_menu_item_set_always_show_image (image_menu_item,
675                                              gtk_action_get_always_show_image (action));
676 }
677
678
679 /**
680  * gtk_image_menu_item_new:
681  * @returns: a new #GtkImageMenuItem.
682  *
683  * Creates a new #GtkImageMenuItem with an empty label.
684  **/
685 GtkWidget*
686 gtk_image_menu_item_new (void)
687 {
688   return g_object_new (GTK_TYPE_IMAGE_MENU_ITEM, NULL);
689 }
690
691 /**
692  * gtk_image_menu_item_new_with_label:
693  * @label: the text of the menu item.
694  * @returns: a new #GtkImageMenuItem.
695  *
696  * Creates a new #GtkImageMenuItem containing a label. 
697  **/
698 GtkWidget*
699 gtk_image_menu_item_new_with_label (const gchar *label)
700 {
701   return g_object_new (GTK_TYPE_IMAGE_MENU_ITEM, 
702                        "label", label,
703                        NULL);
704 }
705
706
707 /**
708  * gtk_image_menu_item_new_with_mnemonic:
709  * @label: the text of the menu item, with an underscore in front of the
710  *         mnemonic character
711  * @returns: a new #GtkImageMenuItem
712  *
713  * Creates a new #GtkImageMenuItem containing a label. The label
714  * will be created using gtk_label_new_with_mnemonic(), so underscores
715  * in @label indicate the mnemonic for the menu item.
716  **/
717 GtkWidget*
718 gtk_image_menu_item_new_with_mnemonic (const gchar *label)
719 {
720   return g_object_new (GTK_TYPE_IMAGE_MENU_ITEM, 
721                        "use-underline", TRUE,
722                        "label", label,
723                        NULL);
724 }
725
726 /**
727  * gtk_image_menu_item_new_from_stock:
728  * @stock_id: the name of the stock item.
729  * @accel_group: the #GtkAccelGroup to add the menu items accelerator to,
730  *   or %NULL.
731  * @returns: a new #GtkImageMenuItem.
732  *
733  * Creates a new #GtkImageMenuItem containing the image and text from a 
734  * stock item. Some stock ids have preprocessor macros like #GTK_STOCK_OK 
735  * and #GTK_STOCK_APPLY.
736  *
737  * If you want this menu item to have changeable accelerators, then pass in
738  * %NULL for accel_group. Next call gtk_menu_item_set_accel_path() with an
739  * appropriate path for the menu item, use gtk_stock_lookup() to look up the
740  * standard accelerator for the stock item, and if one is found, call
741  * gtk_accel_map_add_entry() to register it.
742  **/
743 GtkWidget*
744 gtk_image_menu_item_new_from_stock (const gchar      *stock_id,
745                                     GtkAccelGroup    *accel_group)
746 {
747   return g_object_new (GTK_TYPE_IMAGE_MENU_ITEM, 
748                        "label", stock_id,
749                        "use-stock", TRUE,
750                        "accel-group", accel_group,
751                        NULL);
752 }
753
754 /**
755  * gtk_image_menu_item_set_use_stock:
756  * @image_menu_item: a #GtkImageMenuItem
757  * @use_stock: %TRUE if the menuitem should use a stock item
758  *
759  * If %TRUE, the label set in the menuitem is used as a
760  * stock id to select the stock item for the item.
761  *
762  * Since: 2.16
763  */
764 void
765 gtk_image_menu_item_set_use_stock (GtkImageMenuItem *image_menu_item,
766                                    gboolean          use_stock)
767 {
768   GtkImageMenuItemPrivate *priv;
769
770   g_return_if_fail (GTK_IS_IMAGE_MENU_ITEM (image_menu_item));
771
772   priv = GET_PRIVATE (image_menu_item);
773
774   if (priv->use_stock != use_stock)
775     {
776       priv->use_stock = use_stock;
777
778       gtk_image_menu_item_recalculate (image_menu_item);
779
780       g_object_notify (G_OBJECT (image_menu_item), "use-stock");
781     }
782 }
783
784 /**
785  * gtk_image_menu_item_get_use_stock:
786  * @image_menu_item: a #GtkImageMenuItem
787  *
788  * Checks whether the label set in the menuitem is used as a
789  * stock id to select the stock item for the item.
790  *
791  * Returns: %TRUE if the label set in the menuitem is used as a
792  *     stock id to select the stock item for the item
793  *
794  * Since: 2.16
795  */
796 gboolean
797 gtk_image_menu_item_get_use_stock (GtkImageMenuItem *image_menu_item)
798 {
799   GtkImageMenuItemPrivate *priv;
800
801   g_return_val_if_fail (GTK_IS_IMAGE_MENU_ITEM (image_menu_item), FALSE);
802
803   priv = GET_PRIVATE (image_menu_item);
804
805   return priv->use_stock;
806 }
807
808 /**
809  * gtk_image_menu_item_set_always_show_image:
810  * @image_menu_item: a #GtkImageMenuItem
811  * @always_show: %TRUE if the menuitem should always show the image
812  *
813  * If %TRUE, the menu item will ignore the #GtkSettings:gtk-menu-images 
814  * setting and always show the image, if available.
815  *
816  * Use this property if the menuitem would be useless or hard to use
817  * without the image. 
818  * 
819  * Since: 2.16
820  */
821 void
822 gtk_image_menu_item_set_always_show_image (GtkImageMenuItem *image_menu_item,
823                                            gboolean          always_show)
824 {
825   GtkImageMenuItemPrivate *priv;
826
827   g_return_if_fail (GTK_IS_IMAGE_MENU_ITEM (image_menu_item));
828
829   priv = GET_PRIVATE (image_menu_item);
830
831   if (priv->always_show_image != always_show)
832     {
833       priv->always_show_image = always_show;
834
835       if (image_menu_item->image)
836         {
837           if (show_image (image_menu_item))
838             gtk_widget_show (image_menu_item->image);
839           else
840             gtk_widget_hide (image_menu_item->image);
841         }
842
843       g_object_notify (G_OBJECT (image_menu_item), "always-show-image");
844     }
845 }
846
847 /**
848  * gtk_image_menu_item_get_always_show_image:
849  * @image_menu_item: a #GtkImageMenuItem
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: (allow-none): 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_get_visible (child);
981       
982       gtk_widget_unparent (child);
983       image_menu_item->image = NULL;
984       
985       if (widget_was_visible &&
986           gtk_widget_get_visible (GTK_WIDGET (container)))
987         gtk_widget_queue_resize (GTK_WIDGET (container));
988
989       g_object_notify (G_OBJECT (image_menu_item), "image");
990     }
991   else
992     {
993       GTK_CONTAINER_CLASS (gtk_image_menu_item_parent_class)->remove (container, child);
994     }
995 }
996
997 static void 
998 show_image_change_notify (GtkImageMenuItem *image_menu_item)
999 {
1000   if (image_menu_item->image)
1001     {
1002       if (show_image (image_menu_item))
1003         gtk_widget_show (image_menu_item->image);
1004       else
1005         gtk_widget_hide (image_menu_item->image);
1006     }
1007 }
1008
1009 static void
1010 traverse_container (GtkWidget *widget,
1011                     gpointer   data)
1012 {
1013   if (GTK_IS_IMAGE_MENU_ITEM (widget))
1014     show_image_change_notify (GTK_IMAGE_MENU_ITEM (widget));
1015   else if (GTK_IS_CONTAINER (widget))
1016     gtk_container_forall (GTK_CONTAINER (widget), traverse_container, NULL);
1017 }
1018
1019 static void
1020 gtk_image_menu_item_setting_changed (GtkSettings *settings)
1021 {
1022   GList *list, *l;
1023
1024   list = gtk_window_list_toplevels ();
1025
1026   for (l = list; l; l = l->next)
1027     gtk_container_forall (GTK_CONTAINER (l->data), 
1028                           traverse_container, NULL);
1029
1030   g_list_free (list);  
1031 }
1032
1033 static void
1034 gtk_image_menu_item_screen_changed (GtkWidget *widget,
1035                                     GdkScreen *previous_screen)
1036 {
1037   GtkSettings *settings;
1038   guint show_image_connection;
1039
1040   if (!gtk_widget_has_screen (widget))
1041     return;
1042
1043   settings = gtk_widget_get_settings (widget);
1044   
1045   show_image_connection = 
1046     GPOINTER_TO_UINT (g_object_get_data (G_OBJECT (settings), 
1047                                          "gtk-image-menu-item-connection"));
1048   
1049   if (show_image_connection)
1050     return;
1051
1052   show_image_connection =
1053     g_signal_connect (settings, "notify::gtk-menu-images",
1054                       G_CALLBACK (gtk_image_menu_item_setting_changed), NULL);
1055   g_object_set_data (G_OBJECT (settings), 
1056                      I_("gtk-image-menu-item-connection"),
1057                      GUINT_TO_POINTER (show_image_connection));
1058
1059   show_image_change_notify (GTK_IMAGE_MENU_ITEM (widget));
1060 }
1061
1062 #define __GTK_IMAGE_MENU_ITEM_C__
1063 #include "gtkaliasdef.c"