]> Pileus Git - ~andy/gtk/blob - gtk/gtkaccellabel.c
More conversion to C_()
[~andy/gtk] / gtk / gtkaccellabel.c
1 /* GTK - The GIMP Toolkit
2  * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
3  *
4  * GtkAccelLabel: GtkLabel with accelerator monitoring facilities.
5  * Copyright (C) 1998 Tim Janik
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public
9  * License as published by the Free Software Foundation; either
10  * version 2 of the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public
18  * License along with this library; if not, write to the
19  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
20  * Boston, MA 02111-1307, USA.
21  */
22
23 /*
24  * Modified by the GTK+ Team and others 1997-2001.  See the AUTHORS
25  * file for a list of people on the GTK+ Team.  See the ChangeLog
26  * files for a list of changes.  These files are distributed with
27  * GTK+ at ftp://ftp.gtk.org/pub/gtk/. 
28  */
29
30 #include "config.h"
31 #include <string.h>
32
33 #include "gtkaccellabel.h"
34 #include "gtkaccelmap.h"
35 #include "gtkmain.h"
36 #include "gtkprivate.h"
37 #include "gtkintl.h"
38 #include "gtkalias.h"
39 #include <gdk/gdkkeysyms.h>
40
41 enum {
42   PROP_0,
43   PROP_ACCEL_CLOSURE,
44   PROP_ACCEL_WIDGET
45 };
46
47 static void         gtk_accel_label_set_property (GObject            *object,
48                                                   guint               prop_id,
49                                                   const GValue       *value,
50                                                   GParamSpec         *pspec);
51 static void         gtk_accel_label_get_property (GObject            *object,
52                                                   guint               prop_id,
53                                                   GValue             *value,
54                                                   GParamSpec         *pspec);
55 static void         gtk_accel_label_destroy      (GtkObject          *object);
56 static void         gtk_accel_label_finalize     (GObject            *object);
57 static void         gtk_accel_label_size_request (GtkWidget          *widget,
58                                                   GtkRequisition     *requisition);
59 static gboolean     gtk_accel_label_expose_event (GtkWidget          *widget,
60                                                   GdkEventExpose     *event);
61 static const gchar *gtk_accel_label_get_string   (GtkAccelLabel      *accel_label);
62
63
64 G_DEFINE_TYPE (GtkAccelLabel, gtk_accel_label, GTK_TYPE_LABEL)
65
66 static void
67 gtk_accel_label_class_init (GtkAccelLabelClass *class)
68 {
69   GObjectClass *gobject_class = G_OBJECT_CLASS (class);
70   GtkObjectClass *object_class = GTK_OBJECT_CLASS (class);
71   GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (class);
72   
73   gobject_class->finalize = gtk_accel_label_finalize;
74   gobject_class->set_property = gtk_accel_label_set_property;
75   gobject_class->get_property = gtk_accel_label_get_property;
76   
77   object_class->destroy = gtk_accel_label_destroy;
78    
79   widget_class->size_request = gtk_accel_label_size_request;
80   widget_class->expose_event = gtk_accel_label_expose_event;
81
82   class->signal_quote1 = g_strdup ("<:");
83   class->signal_quote2 = g_strdup (":>");
84
85 #ifndef GDK_WINDOWING_QUARTZ
86   /* This is the text that should appear next to menu accelerators
87    * that use the shift key. If the text on this key isn't typically
88    * translated on keyboards used for your language, don't translate
89    * this.
90    */
91   class->mod_name_shift = g_strdup (C_("keyboard label", "Shift"));
92   /* This is the text that should appear next to menu accelerators
93    * that use the control key. If the text on this key isn't typically
94    * translated on keyboards used for your language, don't translate
95    * this.
96    */
97   class->mod_name_control = g_strdup (C_("keyboard label", "Ctrl"));
98   /* This is the text that should appear next to menu accelerators
99    * that use the alt key. If the text on this key isn't typically
100    * translated on keyboards used for your language, don't translate
101    * this.
102    */
103   class->mod_name_alt = g_strdup (C_("keyboard label", "Alt"));
104   class->mod_separator = g_strdup ("+");
105 #else /* GDK_WINDOWING_QUARTZ */
106
107   /* U+21E7 UPWARDS WHITE ARROW */
108   class->mod_name_shift = g_strdup ("\xe2\x87\xa7");
109   /* U+2303 UP ARROWHEAD */
110   class->mod_name_control = g_strdup ("\xe2\x8c\x83");
111   /* U+2325 OPTION KEY */
112   class->mod_name_alt = g_strdup ("\xe2\x8c\xa5");
113   class->mod_separator = g_strdup ("");
114
115 #endif /* GDK_WINDOWING_QUARTZ */
116
117   class->accel_seperator = g_strdup (" / ");
118   class->latin1_to_char = TRUE;
119   
120   g_object_class_install_property (gobject_class,
121                                    PROP_ACCEL_CLOSURE,
122                                    g_param_spec_boxed ("accel-closure",
123                                                        P_("Accelerator Closure"),
124                                                        P_("The closure to be monitored for accelerator changes"),
125                                                        G_TYPE_CLOSURE,
126                                                        GTK_PARAM_READWRITE));
127   g_object_class_install_property (gobject_class,
128                                    PROP_ACCEL_WIDGET,
129                                    g_param_spec_object ("accel-widget",
130                                                         P_("Accelerator Widget"),
131                                                         P_("The widget to be monitored for accelerator changes"),
132                                                         GTK_TYPE_WIDGET,
133                                                         GTK_PARAM_READWRITE));
134 }
135
136 static void
137 gtk_accel_label_set_property (GObject      *object,
138                               guint         prop_id,
139                               const GValue *value,
140                               GParamSpec   *pspec)
141 {
142   GtkAccelLabel  *accel_label;
143
144   accel_label = GTK_ACCEL_LABEL (object);
145
146   switch (prop_id)
147     {
148     case PROP_ACCEL_CLOSURE:
149       gtk_accel_label_set_accel_closure (accel_label, g_value_get_boxed (value));
150       break;
151     case PROP_ACCEL_WIDGET:
152       gtk_accel_label_set_accel_widget (accel_label, g_value_get_object (value));
153       break;
154     default:
155       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
156       break;
157     }
158 }
159
160 static void
161 gtk_accel_label_get_property (GObject    *object,
162                               guint       prop_id,
163                               GValue     *value,
164                               GParamSpec *pspec)
165 {
166   GtkAccelLabel  *accel_label;
167
168   accel_label = GTK_ACCEL_LABEL (object);
169
170   switch (prop_id)
171     {
172     case PROP_ACCEL_CLOSURE:
173       g_value_set_boxed (value, accel_label->accel_closure);
174       break;
175     case PROP_ACCEL_WIDGET:
176       g_value_set_object (value, accel_label->accel_widget);
177       break;
178     default:
179       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
180       break;
181     }
182 }
183
184 static void
185 gtk_accel_label_init (GtkAccelLabel *accel_label)
186 {
187   accel_label->accel_padding = 3;
188   accel_label->accel_widget = NULL;
189   accel_label->accel_closure = NULL;
190   accel_label->accel_group = NULL;
191   accel_label->accel_string = NULL;
192 }
193
194 GtkWidget*
195 gtk_accel_label_new (const gchar *string)
196 {
197   GtkAccelLabel *accel_label;
198   
199   g_return_val_if_fail (string != NULL, NULL);
200   
201   accel_label = g_object_new (GTK_TYPE_ACCEL_LABEL, NULL);
202   
203   gtk_label_set_text (GTK_LABEL (accel_label), string);
204   
205   return GTK_WIDGET (accel_label);
206 }
207
208 static void
209 gtk_accel_label_destroy (GtkObject *object)
210 {
211   GtkAccelLabel *accel_label = GTK_ACCEL_LABEL (object);
212
213   gtk_accel_label_set_accel_widget (accel_label, NULL);
214   gtk_accel_label_set_accel_closure (accel_label, NULL);
215   
216   GTK_OBJECT_CLASS (gtk_accel_label_parent_class)->destroy (object);
217 }
218
219 static void
220 gtk_accel_label_finalize (GObject *object)
221 {
222   GtkAccelLabel *accel_label = GTK_ACCEL_LABEL (object);
223
224   g_free (accel_label->accel_string);
225   
226   G_OBJECT_CLASS (gtk_accel_label_parent_class)->finalize (object);
227 }
228
229 /**
230  * gtk_accel_label_get_accel_widget:
231  * @accel_label: a #GtkAccelLabel
232  *
233  * Fetches the widget monitored by this accelerator label. See
234  * gtk_accel_label_set_accel_widget().
235  *
236  * Return value: the object monitored by the accelerator label,
237  *               or %NULL.
238  **/
239 GtkWidget*
240 gtk_accel_label_get_accel_widget (GtkAccelLabel *accel_label)
241 {
242   g_return_val_if_fail (GTK_IS_ACCEL_LABEL (accel_label), NULL);
243
244   return accel_label->accel_widget;
245 }
246
247 guint
248 gtk_accel_label_get_accel_width (GtkAccelLabel *accel_label)
249 {
250   g_return_val_if_fail (GTK_IS_ACCEL_LABEL (accel_label), 0);
251   
252   return (accel_label->accel_string_width +
253           (accel_label->accel_string_width ? accel_label->accel_padding : 0));
254 }
255
256 static void
257 gtk_accel_label_size_request (GtkWidget      *widget,
258                               GtkRequisition *requisition)
259 {
260   GtkAccelLabel *accel_label = GTK_ACCEL_LABEL (widget);
261   PangoLayout *layout;
262   gint width;
263
264   GTK_WIDGET_CLASS (gtk_accel_label_parent_class)->size_request (widget, requisition);
265
266   layout = gtk_widget_create_pango_layout (widget, gtk_accel_label_get_string (accel_label));
267   pango_layout_get_pixel_size (layout, &width, NULL);
268   accel_label->accel_string_width = width;
269   
270   g_object_unref (layout);
271 }
272
273 static gint
274 get_first_baseline (PangoLayout *layout)
275 {
276   PangoLayoutIter *iter;
277   gint result;
278
279   iter = pango_layout_get_iter (layout);
280   result = pango_layout_iter_get_baseline (iter);
281   pango_layout_iter_free (iter);
282
283   return PANGO_PIXELS (result);
284 }
285
286 static gboolean 
287 gtk_accel_label_expose_event (GtkWidget      *widget,
288                               GdkEventExpose *event)
289 {
290   GtkAccelLabel *accel_label = GTK_ACCEL_LABEL (widget);
291   GtkMisc *misc = GTK_MISC (accel_label);
292   GtkTextDirection direction;
293
294   direction = gtk_widget_get_direction (widget);
295
296   if (GTK_WIDGET_DRAWABLE (accel_label))
297     {
298       guint ac_width;
299       
300       ac_width = gtk_accel_label_get_accel_width (accel_label);
301       
302       if (widget->allocation.width >= widget->requisition.width + ac_width)
303         {
304           PangoLayout *label_layout;
305           PangoLayout *accel_layout;
306           GtkLabel *label = GTK_LABEL (widget);
307
308           gint x;
309           gint y;
310           
311           label_layout = gtk_label_get_layout (GTK_LABEL (accel_label));
312
313           if (direction == GTK_TEXT_DIR_RTL)
314             widget->allocation.x += ac_width;
315           widget->allocation.width -= ac_width;
316           if (gtk_label_get_ellipsize (label))
317             pango_layout_set_width (label_layout,
318                                     pango_layout_get_width (label_layout) 
319                                     - ac_width * PANGO_SCALE);
320           
321           if (GTK_WIDGET_CLASS (gtk_accel_label_parent_class)->expose_event)
322             GTK_WIDGET_CLASS (gtk_accel_label_parent_class)->expose_event (widget, event);
323           if (direction == GTK_TEXT_DIR_RTL)
324             widget->allocation.x -= ac_width;
325           widget->allocation.width += ac_width;
326           if (gtk_label_get_ellipsize (label))
327             pango_layout_set_width (label_layout,
328                                     pango_layout_get_width (label_layout) 
329                                     + ac_width * PANGO_SCALE);
330           
331           if (direction == GTK_TEXT_DIR_RTL)
332             x = widget->allocation.x + misc->xpad;
333           else
334             x = widget->allocation.x + widget->allocation.width - misc->xpad - ac_width;
335
336           gtk_label_get_layout_offsets (GTK_LABEL (accel_label), NULL, &y);
337
338           accel_layout = gtk_widget_create_pango_layout (widget, gtk_accel_label_get_string (accel_label));
339
340           y += get_first_baseline (label_layout) - get_first_baseline (accel_layout);
341
342           gtk_paint_layout (widget->style,
343                             widget->window,
344                             GTK_WIDGET_STATE (widget),
345                             FALSE,
346                             &event->area,
347                             widget,
348                             "accellabel",
349                             x, y,
350                             accel_layout);                            
351
352           g_object_unref (accel_layout);
353         }
354       else
355         {
356           if (GTK_WIDGET_CLASS (gtk_accel_label_parent_class)->expose_event)
357             GTK_WIDGET_CLASS (gtk_accel_label_parent_class)->expose_event (widget, event);
358         }
359     }
360   
361   return FALSE;
362 }
363
364 static void
365 refetch_widget_accel_closure (GtkAccelLabel *accel_label)
366 {
367   GClosure *closure = NULL;
368   GList *clist, *list;
369   
370   g_return_if_fail (GTK_IS_ACCEL_LABEL (accel_label));
371   g_return_if_fail (GTK_IS_WIDGET (accel_label->accel_widget));
372   
373   clist = gtk_widget_list_accel_closures (accel_label->accel_widget);
374   for (list = clist; list; list = list->next)
375     {
376       /* we just take the first closure used */
377       closure = list->data;
378       break;
379     }
380   g_list_free (clist);
381   gtk_accel_label_set_accel_closure (accel_label, closure);
382 }
383
384 /**
385  * gtk_accel_label_set_accel_widget:
386  * @accel_label: a #GtkAccelLabel
387  * @accel_widget: the widget to be monitored.
388  *
389  * Sets the widget to be monitored by this accelerator label. 
390  **/
391 void
392 gtk_accel_label_set_accel_widget (GtkAccelLabel *accel_label,
393                                   GtkWidget     *accel_widget)
394 {
395   g_return_if_fail (GTK_IS_ACCEL_LABEL (accel_label));
396   if (accel_widget)
397     g_return_if_fail (GTK_IS_WIDGET (accel_widget));
398     
399   if (accel_widget != accel_label->accel_widget)
400     {
401       if (accel_label->accel_widget)
402         {
403           gtk_accel_label_set_accel_closure (accel_label, NULL);
404           g_signal_handlers_disconnect_by_func (accel_label->accel_widget,
405                                                 refetch_widget_accel_closure,
406                                                 accel_label);
407           g_object_unref (accel_label->accel_widget);
408         }
409       accel_label->accel_widget = accel_widget;
410       if (accel_label->accel_widget)
411         {
412           g_object_ref (accel_label->accel_widget);
413           g_signal_connect_object (accel_label->accel_widget, "accel-closures-changed",
414                                    G_CALLBACK (refetch_widget_accel_closure),
415                                    accel_label, G_CONNECT_SWAPPED);
416           refetch_widget_accel_closure (accel_label);
417         }
418       g_object_notify (G_OBJECT (accel_label), "accel-widget");
419     }
420 }
421
422 static void
423 gtk_accel_label_reset (GtkAccelLabel *accel_label)
424 {
425   if (accel_label->accel_string)
426     {
427       g_free (accel_label->accel_string);
428       accel_label->accel_string = NULL;
429     }
430   
431   gtk_widget_queue_resize (GTK_WIDGET (accel_label));
432 }
433
434 static void
435 check_accel_changed (GtkAccelGroup  *accel_group,
436                      guint           keyval,
437                      GdkModifierType modifier,
438                      GClosure       *accel_closure,
439                      GtkAccelLabel  *accel_label)
440 {
441   if (accel_closure == accel_label->accel_closure)
442     gtk_accel_label_reset (accel_label);
443 }
444
445 /**
446  * gtk_accel_label_set_accel_closure:
447  * @accel_label: a #GtkAccelLabel
448  * @accel_closure: the closure to monitor for accelerator changes.
449  *
450  * Sets the closure to be monitored by this accelerator label. The closure
451  * must be connected to an accelerator group; see gtk_accel_group_connect().
452  **/
453 void
454 gtk_accel_label_set_accel_closure (GtkAccelLabel *accel_label,
455                                    GClosure      *accel_closure)
456 {
457   g_return_if_fail (GTK_IS_ACCEL_LABEL (accel_label));
458   if (accel_closure)
459     g_return_if_fail (gtk_accel_group_from_accel_closure (accel_closure) != NULL);
460
461   if (accel_closure != accel_label->accel_closure)
462     {
463       if (accel_label->accel_closure)
464         {
465           g_signal_handlers_disconnect_by_func (accel_label->accel_group,
466                                                 check_accel_changed,
467                                                 accel_label);
468           accel_label->accel_group = NULL;
469           g_closure_unref (accel_label->accel_closure);
470         }
471       accel_label->accel_closure = accel_closure;
472       if (accel_label->accel_closure)
473         {
474           g_closure_ref (accel_label->accel_closure);
475           accel_label->accel_group = gtk_accel_group_from_accel_closure (accel_closure);
476           g_signal_connect_object (accel_label->accel_group, "accel-changed",
477                                    G_CALLBACK (check_accel_changed),
478                                    accel_label, 0);
479         }
480       gtk_accel_label_reset (accel_label);
481       g_object_notify (G_OBJECT (accel_label), "accel-closure");
482     }
483 }
484
485 static gboolean
486 find_accel (GtkAccelKey *key,
487             GClosure    *closure,
488             gpointer     data)
489 {
490   return data == (gpointer) closure;
491 }
492
493 static const gchar *
494 gtk_accel_label_get_string (GtkAccelLabel *accel_label)
495 {
496   if (!accel_label->accel_string)
497     gtk_accel_label_refetch (accel_label);
498   
499   return accel_label->accel_string;
500 }
501
502 /* Underscores in key names are better displayed as spaces
503  * E.g., Page_Up should be "Page Up"
504  */
505 static void
506 substitute_underscores (char *str)
507 {
508   char *p;
509
510   for (p = str; *p; p++)
511     if (*p == '_')
512       *p = ' ';
513 }
514
515 /* On Mac, if the key has symbolic representation (e.g. arrow keys),
516  * append it to gstring and return TRUE; otherwise return FALSE.
517  * See http://docs.info.apple.com/article.html?path=Mac/10.5/en/cdb_symbs.html 
518  * for the list of special keys. */
519 static gboolean
520 append_keyval_symbol (guint    accelerator_key,
521                       GString *gstring)
522 {
523 #ifdef GDK_WINDOWING_QUARTZ
524   switch (accelerator_key)
525   {
526   case GDK_Return:
527     /* U+21A9 LEFTWARDS ARROW WITH HOOK */
528     g_string_append (gstring, "\xe2\x86\xa9");
529     return TRUE;
530
531   case GDK_ISO_Enter:
532     /* U+2324 UP ARROWHEAD BETWEEN TWO HORIZONTAL BARS */
533     g_string_append (gstring, "\xe2\x8c\xa4");
534     return TRUE;
535
536   case GDK_Left:
537     /* U+2190 LEFTWARDS ARROW */
538     g_string_append (gstring, "\xe2\x86\x90");
539     return TRUE;
540
541   case GDK_Up:
542     /* U+2191 UPWARDS ARROW */
543     g_string_append (gstring, "\xe2\x86\x91");
544     return TRUE;
545
546   case GDK_Right:
547     /* U+2192 RIGHTWARDS ARROW */
548     g_string_append (gstring, "\xe2\x86\x92");
549     return TRUE;
550
551   case GDK_Down:
552     /* U+2193 DOWNWARDS ARROW */
553     g_string_append (gstring, "\xe2\x86\x93");
554     return TRUE;
555
556   case GDK_Page_Up:
557     /* U+21DE UPWARDS ARROW WITH DOUBLE STROKE */
558     g_string_append (gstring, "\xe2\x87\x9e");
559     return TRUE;
560
561   case GDK_Page_Down:
562     /* U+21DF DOWNWARDS ARROW WITH DOUBLE STROKE */
563     g_string_append (gstring, "\xe2\x87\x9f");
564     return TRUE;
565
566   case GDK_Home:
567     /* U+2196 NORTH WEST ARROW */
568     g_string_append (gstring, "\xe2\x86\x96");
569     return TRUE;
570
571   case GDK_End:
572     /* U+2198 SOUTH EAST ARROW */
573     g_string_append (gstring, "\xe2\x86\x98");
574     return TRUE;
575
576   case GDK_Escape:
577     /* U+238B BROKEN CIRCLE WITH NORTHWEST ARROW */
578     g_string_append (gstring, "\xe2\x8e\x8b");
579     return TRUE;
580
581   case GDK_BackSpace:
582     /* U+232B ERASE TO THE LEFT */
583     g_string_append (gstring, "\xe2\x8c\xab");
584     return TRUE;
585
586   case GDK_Delete:
587     /* U+2326 ERASE TO THE RIGHT */
588     g_string_append (gstring, "\xe2\x8c\xa6");
589     return TRUE;
590
591   default:
592     return FALSE;
593   }
594 #else /* !GDK_WINDOWING_QUARTZ */
595   return FALSE;
596 #endif
597 }
598
599 gchar *
600 _gtk_accel_label_class_get_accelerator_label (GtkAccelLabelClass *klass,
601                                               guint               accelerator_key,
602                                               GdkModifierType     accelerator_mods)
603 {
604   GString *gstring;
605   gboolean seen_mod = FALSE;
606   gunichar ch;
607   
608   gstring = g_string_new ("");
609   
610   if (accelerator_mods & GDK_SHIFT_MASK)
611     {
612       g_string_append (gstring, klass->mod_name_shift);
613       seen_mod = TRUE;
614     }
615   if (accelerator_mods & GDK_CONTROL_MASK)
616     {
617       if (seen_mod)
618         g_string_append (gstring, klass->mod_separator);
619       g_string_append (gstring, klass->mod_name_control);
620       seen_mod = TRUE;
621     }
622   if (accelerator_mods & GDK_MOD1_MASK)
623     {
624       if (seen_mod)
625         g_string_append (gstring, klass->mod_separator);
626       g_string_append (gstring, klass->mod_name_alt);
627       seen_mod = TRUE;
628     }
629   if (accelerator_mods & GDK_MOD2_MASK)
630     {
631       if (seen_mod)
632         g_string_append (gstring, klass->mod_separator);
633
634       g_string_append (gstring, "Mod2");
635       seen_mod = TRUE;
636     }
637   if (accelerator_mods & GDK_MOD3_MASK)
638     {
639       if (seen_mod)
640         g_string_append (gstring, klass->mod_separator);
641
642       g_string_append (gstring, "Mod3");
643       seen_mod = TRUE;
644     }
645   if (accelerator_mods & GDK_MOD4_MASK)
646     {
647       if (seen_mod)
648         g_string_append (gstring, klass->mod_separator);
649
650       g_string_append (gstring, "Mod4");
651       seen_mod = TRUE;
652     }
653   if (accelerator_mods & GDK_MOD5_MASK)
654     {
655       if (seen_mod)
656         g_string_append (gstring, klass->mod_separator);
657
658       g_string_append (gstring, "Mod5");
659       seen_mod = TRUE;
660     }
661   if (accelerator_mods & GDK_SUPER_MASK)
662     {
663       if (seen_mod)
664         g_string_append (gstring, klass->mod_separator);
665
666       /* This is the text that should appear next to menu accelerators
667        * that use the super key. If the text on this key isn't typically
668        * translated on keyboards used for your language, don't translate
669        * this.
670        */
671       g_string_append (gstring, C_("keyboard label", "Super"));
672       seen_mod = TRUE;
673     }
674   if (accelerator_mods & GDK_HYPER_MASK)
675     {
676       if (seen_mod)
677         g_string_append (gstring, klass->mod_separator);
678
679       /* This is the text that should appear next to menu accelerators
680        * that use the hyper key. If the text on this key isn't typically
681        * translated on keyboards used for your language, don't translate
682        * this.
683        */
684       g_string_append (gstring, C_("keyboard label", "Hyper"));
685       seen_mod = TRUE;
686     }
687   if (accelerator_mods & GDK_META_MASK)
688     {
689       if (seen_mod)
690         g_string_append (gstring, klass->mod_separator);
691
692 #ifndef GDK_WINDOWING_QUARTZ
693       /* This is the text that should appear next to menu accelerators
694        * that use the meta key. If the text on this key isn't typically
695        * translated on keyboards used for your language, don't translate
696        * this.
697        */
698       g_string_append (gstring, C_("keyboard label", "Meta"));
699 #else
700       /* Command key symbol U+2318 PLACE OF INTEREST SIGN */
701       g_string_append (gstring, "\xe2\x8c\x98");
702 #endif
703       seen_mod = TRUE;
704     }
705   if (seen_mod)
706     g_string_append (gstring, klass->mod_separator);
707   
708   ch = gdk_keyval_to_unicode (accelerator_key);
709   if (ch && (g_unichar_isgraph (ch) || ch == ' ') &&
710       (ch < 0x80 || klass->latin1_to_char))
711     {
712       switch (ch)
713         {
714         case ' ':
715           g_string_append (gstring, C_("keyboard label", "Space"));
716           break;
717         case '\\':
718           g_string_append (gstring, C_("keyboard label", "Backslash"));
719           break;
720         default:
721           g_string_append_unichar (gstring, g_unichar_toupper (ch));
722           break;
723         }
724     }
725   else if (!append_keyval_symbol (accelerator_key, gstring))
726     {
727       gchar *tmp;
728
729       tmp = gdk_keyval_name (gdk_keyval_to_lower (accelerator_key));
730       if (tmp != NULL)
731         {
732           if (tmp[0] != 0 && tmp[1] == 0)
733             g_string_append_c (gstring, g_ascii_toupper (tmp[0]));
734           else
735             {
736               const gchar *str;
737               str = g_dpgettext2 (GETTEXT_PACKAGE, "keyboard label", tmp);
738               if (str == tmp)
739                 {
740                   g_string_append (gstring, tmp);
741                   substitute_underscores (gstring->str);
742                 }
743               else
744                 g_string_append (gstring, str);
745             }
746         }
747     }
748
749   return g_string_free (gstring, FALSE);
750 }
751
752 gboolean
753 gtk_accel_label_refetch (GtkAccelLabel *accel_label)
754 {
755   gboolean enable_accels;
756
757   g_return_val_if_fail (GTK_IS_ACCEL_LABEL (accel_label), FALSE);
758
759   if (accel_label->accel_string)
760     {
761       g_free (accel_label->accel_string);
762       accel_label->accel_string = NULL;
763     }
764
765   g_object_get (gtk_widget_get_settings (GTK_WIDGET (accel_label)),
766                 "gtk-enable-accels", &enable_accels,
767                 NULL);
768
769   if (enable_accels && accel_label->accel_closure)
770     {
771       GtkAccelKey *key = gtk_accel_group_find (accel_label->accel_group, find_accel, accel_label->accel_closure);
772
773       if (key && key->accel_flags & GTK_ACCEL_VISIBLE)
774         {
775           GtkAccelLabelClass *klass;
776           gchar *tmp;
777
778           klass = GTK_ACCEL_LABEL_GET_CLASS (accel_label);
779           tmp = _gtk_accel_label_class_get_accelerator_label (klass,
780                                                               key->accel_key,
781                                                               key->accel_mods);
782           accel_label->accel_string = g_strconcat ("   ", tmp, NULL);
783           g_free (tmp);
784         }
785       if (!accel_label->accel_string)
786         accel_label->accel_string = g_strdup ("-/-");
787     }
788   
789   if (!accel_label->accel_string)
790     accel_label->accel_string = g_strdup ("");
791
792   gtk_widget_queue_resize (GTK_WIDGET (accel_label));
793
794   return FALSE;
795 }
796
797 #define __GTK_ACCEL_LABEL_C__
798 #include "gtkaliasdef.c"