metaaccellabel.c

Go to the documentation of this file.
00001 /* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
00002 
00003 /* Metacity hacked-up GtkAccelLabel */
00004 /* Copyright (C) 2002 Red Hat, Inc. */
00005 /* GTK - The GIMP Toolkit
00006  * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
00007  *
00008  * MetaAccelLabel: GtkLabel with accelerator monitoring facilities.
00009  * Copyright (C) 1998 Tim Janik
00010  *
00011  * This library is free software; you can redistribute it and/or
00012  * modify it under the terms of the GNU Lesser General Public
00013  * License as published by the Free Software Foundation; either
00014  * version 2 of the License, or (at your option) any later version.
00015  *
00016  * This library is distributed in the hope that it will be useful,
00017  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00018  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00019  * Lesser General Public License for more details.
00020  *
00021  * You should have received a copy of the GNU Lesser General Public
00022  * License along with this library; if not, write to the
00023  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
00024  * Boston, MA 02111-1307, USA.
00025  */
00026 
00027 /*
00028  * Modified by the GTK+ Team and others 1997-2001.  See the AUTHORS
00029  * file for a list of people on the GTK+ Team.  See the ChangeLog
00030  * files for a list of changes.  These files are distributed with
00031  * GTK+ at ftp://ftp.gtk.org/pub/gtk/.
00032  */
00033 
00034 #include <config.h>
00035 #include "metaaccellabel.h"
00036 #include <gtk/gtkmain.h>
00037 #include <gtk/gtkaccelmap.h>
00038 #include <string.h>
00039 #include "util.h"
00040 
00041 static void     meta_accel_label_class_init   (MetaAccelLabelClass *klass);
00042 static void     meta_accel_label_init         (MetaAccelLabel      *accel_label);
00043 static void     meta_accel_label_destroy      (GtkObject           *object);
00044 static void     meta_accel_label_finalize     (GObject             *object);
00045 static void     meta_accel_label_size_request (GtkWidget           *widget,
00046                                                GtkRequisition      *requisition);
00047 static gboolean meta_accel_label_expose_event (GtkWidget           *widget,
00048                                                GdkEventExpose      *event);
00049 
00050 static void  meta_accel_label_update          (MetaAccelLabel *accel_label);
00051 static int   meta_accel_label_get_accel_width (MetaAccelLabel *accel_label);
00052 
00053 
00054 static GtkLabelClass *parent_class = NULL;
00055 
00056 
00057 GtkType
00058 meta_accel_label_get_type (void)
00059 {
00060   static GtkType accel_label_type = 0;
00061 
00062   if (!accel_label_type)
00063     {
00064       static const GtkTypeInfo accel_label_info =
00065       {
00066         "MetaAccelLabel",
00067         sizeof (MetaAccelLabel),
00068         sizeof (MetaAccelLabelClass),
00069         (GtkClassInitFunc) meta_accel_label_class_init,
00070         (GtkObjectInitFunc) meta_accel_label_init,
00071         /* reserved_1 */ NULL,
00072         /* reserved_2 */ NULL,
00073         (GtkClassInitFunc) NULL,
00074       };
00075 
00076       accel_label_type = gtk_type_unique (GTK_TYPE_LABEL, &accel_label_info);
00077     }
00078 
00079   return accel_label_type;
00080 }
00081 
00082 static void
00083 meta_accel_label_class_init (MetaAccelLabelClass *class)
00084 {
00085   GObjectClass *gobject_class = G_OBJECT_CLASS (class);
00086   GtkObjectClass *object_class = GTK_OBJECT_CLASS (class);
00087   GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (class);
00088 
00089   parent_class = g_type_class_peek_parent (class);
00090 
00091   gobject_class->finalize = meta_accel_label_finalize;
00092 
00093   object_class->destroy = meta_accel_label_destroy;
00094 
00095   widget_class->size_request = meta_accel_label_size_request;
00096   widget_class->expose_event = meta_accel_label_expose_event;
00097 
00098   class->signal_quote1 = g_strdup ("<:");
00099   class->signal_quote2 = g_strdup (":>");
00100   /* This is the text that should appear next to menu accelerators
00101    * that use the shift key. If the text on this key isn't typically
00102    * translated on keyboards used for your language, don't translate
00103    * this.
00104    */
00105   class->mod_name_shift = g_strdup (_("Shift"));
00106   /* This is the text that should appear next to menu accelerators
00107    * that use the control key. If the text on this key isn't typically
00108    * translated on keyboards used for your language, don't translate
00109    * this.
00110    */
00111   class->mod_name_control = g_strdup (_("Ctrl"));
00112   /* This is the text that should appear next to menu accelerators
00113    * that use the alt key. If the text on this key isn't typically
00114    * translated on keyboards used for your language, don't translate
00115    * this.
00116    */
00117   class->mod_name_alt = g_strdup (_("Alt"));
00118   /* This is the text that should appear next to menu accelerators
00119    * that use the meta key. If the text on this key isn't typically
00120    * translated on keyboards used for your language, don't translate
00121    * this.
00122    */
00123   class->mod_name_meta = g_strdup (_("Meta"));
00124   /* This is the text that should appear next to menu accelerators
00125    * that use the super key. If the text on this key isn't typically
00126    * translated on keyboards used for your language, don't translate
00127    * this.
00128    */
00129   class->mod_name_super = g_strdup (_("Super"));
00130   /* This is the text that should appear next to menu accelerators
00131    * that use the hyper key. If the text on this key isn't typically
00132    * translated on keyboards used for your language, don't translate
00133    * this.
00134    */
00135   class->mod_name_hyper = g_strdup (_("Hyper"));
00136   /* This is the text that should appear next to menu accelerators
00137    * that use the mod2 key. If the text on this key isn't typically
00138    * translated on keyboards used for your language, don't translate
00139    * this.
00140    */
00141   class->mod_name_mod2 = g_strdup (_("Mod2"));
00142   /* This is the text that should appear next to menu accelerators
00143    * that use the mod3 key. If the text on this key isn't typically
00144    * translated on keyboards used for your language, don't translate
00145    * this.
00146    */
00147   class->mod_name_mod3 = g_strdup (_("Mod3"));
00148   /* This is the text that should appear next to menu accelerators
00149    * that use the mod4 key. If the text on this key isn't typically
00150    * translated on keyboards used for your language, don't translate
00151    * this.
00152    */
00153   class->mod_name_mod4 = g_strdup (_("Mod4"));
00154   /* This is the text that should appear next to menu accelerators
00155    * that use the mod5 key. If the text on this key isn't typically
00156    * translated on keyboards used for your language, don't translate
00157    * this.
00158    */
00159   class->mod_name_mod5 = g_strdup (_("Mod5"));
00160 
00161   class->mod_separator = g_strdup ("+");
00162   class->accel_seperator = g_strdup (" / ");
00163   class->latin1_to_char = TRUE;
00164 }
00165 
00166 static void
00167 meta_accel_label_init (MetaAccelLabel *accel_label)
00168 {
00169   accel_label->accel_padding = 3;
00170   accel_label->accel_string = NULL;
00171 
00172   meta_accel_label_update (accel_label);
00173 }
00174 
00175 GtkWidget*
00176 meta_accel_label_new_with_mnemonic (const gchar *string)
00177 {
00178   MetaAccelLabel *accel_label;
00179 
00180   g_return_val_if_fail (string != NULL, NULL);
00181 
00182   accel_label = g_object_new (META_TYPE_ACCEL_LABEL, NULL);
00183 
00184   gtk_label_set_text_with_mnemonic (GTK_LABEL (accel_label), string);
00185 
00186   return GTK_WIDGET (accel_label);
00187 }
00188 
00189 static void
00190 meta_accel_label_destroy (GtkObject *object)
00191 {
00192   MetaAccelLabel *accel_label = META_ACCEL_LABEL (object);
00193 
00194 
00195   g_free (accel_label->accel_string);
00196   accel_label->accel_string = NULL;
00197 
00198   accel_label->accel_mods = 0;
00199   accel_label->accel_key = 0;
00200 
00201   GTK_OBJECT_CLASS (parent_class)->destroy (object);
00202 }
00203 
00204 static void
00205 meta_accel_label_finalize (GObject *object)
00206 {
00207   MetaAccelLabel *accel_label = META_ACCEL_LABEL (object);
00208 
00209   g_free (accel_label->accel_string);
00210 
00211   G_OBJECT_CLASS (parent_class)->finalize (object);
00212 }
00213 
00214 void
00215 meta_accel_label_set_accelerator (MetaAccelLabel         *accel_label,
00216                                   guint                   accelerator_key,
00217                                   MetaVirtualModifier     accelerator_mods)
00218 {
00219   g_return_if_fail (META_IS_ACCEL_LABEL (accel_label));
00220 
00221   if (accelerator_key != accel_label->accel_key ||
00222       accelerator_mods != accel_label->accel_mods)
00223     {
00224       accel_label->accel_mods = accelerator_mods;
00225       accel_label->accel_key = accelerator_key;
00226 
00227       meta_accel_label_update (accel_label);
00228     }
00229 }
00230 
00231 static int
00232 meta_accel_label_get_accel_width (MetaAccelLabel *accel_label)
00233 {
00234   g_return_val_if_fail (META_IS_ACCEL_LABEL (accel_label), 0);
00235 
00236   return (accel_label->accel_string_width +
00237           (accel_label->accel_string_width ? accel_label->accel_padding : 0));
00238 }
00239 
00240 static void
00241 meta_accel_label_size_request (GtkWidget             *widget,
00242                               GtkRequisition *requisition)
00243 {
00244   MetaAccelLabel *accel_label = META_ACCEL_LABEL (widget);
00245   PangoLayout *layout;
00246   gint width;
00247 
00248   if (GTK_WIDGET_CLASS (parent_class)->size_request)
00249     GTK_WIDGET_CLASS (parent_class)->size_request (widget, requisition);
00250 
00251   layout = gtk_widget_create_pango_layout (widget, accel_label->accel_string);
00252   pango_layout_get_pixel_size (layout, &width, NULL);
00253   accel_label->accel_string_width = width;
00254 
00255   g_object_unref (G_OBJECT (layout));
00256 }
00257 
00258 static gboolean
00259 meta_accel_label_expose_event (GtkWidget      *widget,
00260                               GdkEventExpose *event)
00261 {
00262   MetaAccelLabel *accel_label = META_ACCEL_LABEL (widget);
00263   GtkMisc *misc = GTK_MISC (accel_label);
00264   PangoLayout *layout;
00265 
00266   if (GTK_WIDGET_DRAWABLE (accel_label))
00267     {
00268       int ac_width;
00269 
00270       ac_width = meta_accel_label_get_accel_width (accel_label);
00271 
00272       if (widget->allocation.width >= widget->requisition.width + ac_width)
00273         {
00274           GtkTextDirection direction = gtk_widget_get_direction (widget);
00275           gint x;
00276           gint y;
00277 
00278           if (direction == GTK_TEXT_DIR_RTL)
00279             {
00280               widget->allocation.x += ac_width;
00281             }
00282           widget->allocation.width -= ac_width;
00283 
00284           if (GTK_WIDGET_CLASS (parent_class)->expose_event)
00285             GTK_WIDGET_CLASS (parent_class)->expose_event (widget, event);
00286 
00287           if (direction == GTK_TEXT_DIR_RTL)
00288             {
00289               widget->allocation.x -= ac_width;
00290             }
00291           widget->allocation.width += ac_width;
00292 
00293           if (direction == GTK_TEXT_DIR_RTL)
00294             {
00295               x = widget->allocation.x + misc->xpad;
00296             }
00297           else
00298             {
00299               x = widget->allocation.x + widget->allocation.width - misc->xpad - ac_width;
00300             }
00301 
00302           y = (widget->allocation.y * (1.0 - misc->yalign) +
00303                (widget->allocation.y + widget->allocation.height -
00304                 (widget->requisition.height - misc->ypad * 2)) *
00305                misc->yalign) + 1.5;
00306 
00307           layout = gtk_widget_create_pango_layout (widget, accel_label->accel_string);
00308 
00309           gtk_paint_layout (widget->style,
00310                             widget->window,
00311                             GTK_WIDGET_STATE (widget),
00312                             FALSE,
00313                             &event->area,
00314                             widget,
00315                             "accellabel",
00316                             x, y,
00317                             layout);
00318 
00319           g_object_unref (G_OBJECT (layout));
00320         }
00321       else
00322         {
00323           if (GTK_WIDGET_CLASS (parent_class)->expose_event)
00324             GTK_WIDGET_CLASS (parent_class)->expose_event (widget, event);
00325         }
00326     }
00327 
00328   return FALSE;
00329 }
00330 
00331 static void
00332 meta_accel_label_update (MetaAccelLabel *accel_label)
00333 {
00334   MetaAccelLabelClass *class;
00335   GString *gstring;
00336   gboolean seen_mod = FALSE;
00337   gunichar ch;
00338 
00339   g_return_if_fail (META_IS_ACCEL_LABEL (accel_label));
00340 
00341   class = META_ACCEL_LABEL_GET_CLASS (accel_label);
00342 
00343   g_free (accel_label->accel_string);
00344   accel_label->accel_string = NULL;
00345 
00346   gstring = g_string_new (accel_label->accel_string);
00347   g_string_append (gstring, gstring->len ? class->accel_seperator : "   ");
00348 
00349   if (accel_label->accel_mods & META_VIRTUAL_SHIFT_MASK)
00350     {
00351       g_string_append (gstring, class->mod_name_shift);
00352       seen_mod = TRUE;
00353     }
00354   if (accel_label->accel_mods & META_VIRTUAL_CONTROL_MASK)
00355     {
00356       if (seen_mod)
00357         g_string_append (gstring, class->mod_separator);
00358       g_string_append (gstring, class->mod_name_control);
00359       seen_mod = TRUE;
00360     }
00361   if (accel_label->accel_mods & META_VIRTUAL_ALT_MASK)
00362     {
00363       if (seen_mod)
00364         g_string_append (gstring, class->mod_separator);
00365       g_string_append (gstring, class->mod_name_alt);
00366       seen_mod = TRUE;
00367     }
00368   if (accel_label->accel_mods & META_VIRTUAL_META_MASK)
00369     {
00370       if (seen_mod)
00371         g_string_append (gstring, class->mod_separator);
00372       g_string_append (gstring, class->mod_name_meta);
00373       seen_mod = TRUE;
00374     }
00375   if (accel_label->accel_mods & META_VIRTUAL_SUPER_MASK)
00376     {
00377       if (seen_mod)
00378         g_string_append (gstring, class->mod_separator);
00379       g_string_append (gstring, class->mod_name_super);
00380       seen_mod = TRUE;
00381     }
00382   if (accel_label->accel_mods & META_VIRTUAL_HYPER_MASK)
00383     {
00384       if (seen_mod)
00385         g_string_append (gstring, class->mod_separator);
00386       g_string_append (gstring, class->mod_name_hyper);
00387       seen_mod = TRUE;
00388     }
00389   if (accel_label->accel_mods & META_VIRTUAL_MOD2_MASK)
00390     {
00391       if (seen_mod)
00392         g_string_append (gstring, class->mod_separator);
00393       g_string_append (gstring, class->mod_name_mod2);
00394       seen_mod = TRUE;
00395     }
00396   if (accel_label->accel_mods & META_VIRTUAL_MOD3_MASK)
00397     {
00398       if (seen_mod)
00399         g_string_append (gstring, class->mod_separator);
00400       g_string_append (gstring, class->mod_name_mod3);
00401       seen_mod = TRUE;
00402     }
00403   if (accel_label->accel_mods & META_VIRTUAL_MOD4_MASK)
00404     {
00405       if (seen_mod)
00406         g_string_append (gstring, class->mod_separator);
00407       g_string_append (gstring, class->mod_name_mod4);
00408       seen_mod = TRUE;
00409     }
00410   if (accel_label->accel_mods & META_VIRTUAL_MOD5_MASK)
00411     {
00412       if (seen_mod)
00413         g_string_append (gstring, class->mod_separator);
00414       g_string_append (gstring, class->mod_name_mod5);
00415       seen_mod = TRUE;
00416     }
00417 
00418   if (seen_mod)
00419     g_string_append (gstring, class->mod_separator);
00420 
00421   ch = gdk_keyval_to_unicode (accel_label->accel_key);
00422   if (ch && (g_unichar_isgraph (ch) || ch == ' ') &&
00423       (ch < 0x80 || class->latin1_to_char))
00424     {
00425       switch (ch)
00426         {
00427         case ' ':
00428           g_string_append (gstring, "Space");
00429           break;
00430         case '\\':
00431           g_string_append (gstring, "Backslash");
00432           break;
00433         default:
00434           g_string_append_unichar (gstring, g_unichar_toupper (ch));
00435           break;
00436         }
00437     }
00438   else
00439     {
00440       gchar *tmp;
00441 
00442       tmp = gtk_accelerator_name (accel_label->accel_key, 0);
00443       if (tmp[0] != 0 && tmp[1] == 0)
00444         tmp[0] = g_ascii_toupper (tmp[0]);
00445       g_string_append (gstring, tmp);
00446       g_free (tmp);
00447     }
00448 
00449   g_free (accel_label->accel_string);
00450   accel_label->accel_string = gstring->str;
00451   g_string_free (gstring, FALSE);
00452 
00453   g_assert (accel_label->accel_string);
00454   /* accel_label->accel_string = g_strdup ("-/-"); */
00455 
00456   gtk_widget_queue_resize (GTK_WIDGET (accel_label));
00457 }

Generated on Sat Aug 23 22:04:18 2008 for metacity by  doxygen 1.5.5