346 lines
		
	
	
		
			7.6 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			346 lines
		
	
	
		
			7.6 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| /* GTK - The GIMP Toolkit
 | |
|  * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
 | |
|  *
 | |
|  * This library is free software; you can redistribute it and/or
 | |
|  * modify it under the terms of the GNU Library General Public
 | |
|  * License as published by the Free Software Foundation; either
 | |
|  * version 2 of the License, or (at your option) any later version.
 | |
|  *
 | |
|  * This library is distributed in the hope that it will be useful,
 | |
|  * but WITHOUT ANY WARRANTY; without even the implied warranty of
 | |
|  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 | |
|  * Library General Public License for more details.
 | |
|  *
 | |
|  * You should have received a copy of the GNU Library General Public
 | |
|  * License along with this library; if not, write to the Free
 | |
|  * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 | |
|  */
 | |
| #include <ctype.h>
 | |
| #include "gtkaccelerator.h"
 | |
| #include "gtksignal.h"
 | |
| #include "gtkwidget.h"
 | |
| 
 | |
| 
 | |
| typedef struct _GtkAcceleratorEntry GtkAcceleratorEntry;
 | |
| 
 | |
| struct _GtkAcceleratorEntry
 | |
| {
 | |
|   guint8 modifiers;
 | |
|   GtkObject *object;
 | |
|   gint signal_num;
 | |
| };
 | |
| 
 | |
| 
 | |
| static void gtk_accelerator_table_init  (GtkAcceleratorTable *table);
 | |
| static void gtk_accelerator_table_clean (GtkAcceleratorTable *table);
 | |
| 
 | |
| 
 | |
| static GtkAcceleratorTable *default_table = NULL;
 | |
| static GSList *tables = NULL;
 | |
| static guint8 gtk_accelerator_table_default_mod_mask = ~0;
 | |
| 
 | |
| 
 | |
| GtkAcceleratorTable*
 | |
| gtk_accelerator_table_new ()
 | |
| {
 | |
|   GtkAcceleratorTable *table;
 | |
| 
 | |
|   table = g_new (GtkAcceleratorTable, 1);
 | |
|   gtk_accelerator_table_init (table);
 | |
| 
 | |
|   tables = g_slist_prepend (tables, table);
 | |
| 
 | |
|   return table;
 | |
| }
 | |
| 
 | |
| GtkAcceleratorTable*
 | |
| gtk_accelerator_table_find (GtkObject   *object,
 | |
| 			    const gchar *signal_name,
 | |
| 			    guchar       accelerator_key,
 | |
| 			    guint8       accelerator_mods)
 | |
| {
 | |
|   GtkAcceleratorTable *table;
 | |
|   GtkAcceleratorEntry *entry;
 | |
|   GSList *tmp_list;
 | |
|   GList *entries;
 | |
|   gint signal_num;
 | |
|   guint hash;
 | |
| 
 | |
|   g_return_val_if_fail (object != NULL, NULL);
 | |
|   g_return_val_if_fail (signal_name != NULL, NULL);
 | |
| 
 | |
|   signal_num = gtk_signal_lookup (signal_name, GTK_OBJECT_TYPE (object));
 | |
|   hash = (guint) accelerator_key;
 | |
| 
 | |
|   tmp_list = tables;
 | |
|   while (tmp_list)
 | |
|     {
 | |
|       table = tmp_list->data;
 | |
|       tmp_list = tmp_list->next;
 | |
| 
 | |
|       entries = table->entries[hash];
 | |
|       while (entries)
 | |
| 	{
 | |
| 	  entry = entries->data;
 | |
| 	  entries = entries->next;
 | |
| 
 | |
| 	  if ((entry->object == object) &&
 | |
| 	      (entry->signal_num == signal_num) &&
 | |
| 	      ((entry->modifiers & table->modifier_mask) ==
 | |
| 	       (accelerator_mods & table->modifier_mask)))
 | |
| 	    return table;
 | |
| 	}
 | |
|     }
 | |
| 
 | |
|   return NULL;
 | |
| }
 | |
| 
 | |
| GtkAcceleratorTable*
 | |
| gtk_accelerator_table_ref (GtkAcceleratorTable *table)
 | |
| {
 | |
|   g_return_val_if_fail (table != NULL, NULL);
 | |
| 
 | |
|   table->ref_count += 1;
 | |
|   return table;
 | |
| }
 | |
| 
 | |
| void
 | |
| gtk_accelerator_table_unref (GtkAcceleratorTable *table)
 | |
| {
 | |
|   g_return_if_fail (table != NULL);
 | |
| 
 | |
|   table->ref_count -= 1;
 | |
|   if (table->ref_count <= 0)
 | |
|     {
 | |
|       tables = g_slist_remove (tables, table);
 | |
|       gtk_accelerator_table_clean (table);
 | |
|       g_free (table);
 | |
|     }
 | |
| }
 | |
| 
 | |
| void
 | |
| gtk_accelerator_table_install (GtkAcceleratorTable *table,
 | |
| 			       GtkObject           *object,
 | |
| 			       const gchar         *signal_name,
 | |
| 			       guchar               accelerator_key,
 | |
| 			       guint8               accelerator_mods)
 | |
| {
 | |
|   GtkAcceleratorEntry *entry;
 | |
|   GList *entries;
 | |
|   gchar *signame;
 | |
|   gint signal_num;
 | |
|   guint hash;
 | |
| 
 | |
|   g_return_if_fail (object != NULL);
 | |
| 
 | |
|   if (!table)
 | |
|     {
 | |
|       if (!default_table)
 | |
| 	default_table = gtk_accelerator_table_new ();
 | |
|       table = default_table;
 | |
|     }
 | |
| 
 | |
|   signal_num = gtk_signal_lookup (signal_name, GTK_OBJECT_TYPE (object));
 | |
|   g_return_if_fail (signal_num != 0);
 | |
| 
 | |
|   hash = (guint) accelerator_key;
 | |
|   entries = table->entries[hash];
 | |
| 
 | |
|   while (entries)
 | |
|     {
 | |
|       entry = entries->data;
 | |
| 
 | |
|       if ((entry->modifiers & table->modifier_mask) ==
 | |
|           (accelerator_mods & table->modifier_mask))
 | |
| 	{
 | |
| 	  if (GTK_IS_WIDGET (entry->object))
 | |
| 	    {
 | |
| 	      signame = gtk_signal_name (entry->signal_num);
 | |
| 	      gtk_signal_emit_by_name (entry->object,
 | |
| 				       "remove_accelerator",
 | |
| 				       signame);
 | |
| 	    }
 | |
| 
 | |
| 	  entry->modifiers = accelerator_mods;
 | |
| 	  entry->object = object;
 | |
| 	  entry->signal_num = signal_num;
 | |
| 	  return;
 | |
| 	}
 | |
| 
 | |
|       entries = entries->next;
 | |
|     }
 | |
| 
 | |
|   entry = g_new (GtkAcceleratorEntry, 1);
 | |
|   entry->modifiers = accelerator_mods;
 | |
|   entry->object = object;
 | |
|   entry->signal_num = signal_num;
 | |
| 
 | |
|   table->entries[hash] = g_list_prepend (table->entries[hash], entry);
 | |
| }
 | |
| 
 | |
| void
 | |
| gtk_accelerator_table_remove (GtkAcceleratorTable *table,
 | |
| 			      GtkObject           *object,
 | |
| 			      const gchar         *signal_name)
 | |
| {
 | |
|   GtkAcceleratorEntry *entry;
 | |
|   GList *entries;
 | |
|   GList *temp_list;
 | |
|   gint signal_num;
 | |
|   gint i;
 | |
| 
 | |
|   g_return_if_fail (object != NULL);
 | |
| 
 | |
|   if (!table)
 | |
|     {
 | |
|       if (!default_table)
 | |
| 	default_table = gtk_accelerator_table_new ();
 | |
|       table = default_table;
 | |
|     }
 | |
| 
 | |
|   signal_num = gtk_signal_lookup (signal_name, GTK_OBJECT_TYPE (object));
 | |
|   g_return_if_fail (signal_num != 0);
 | |
| 
 | |
|   for (i = 0; i < 256; i++)
 | |
|     {
 | |
|       entries = table->entries[i];
 | |
| 
 | |
|       while (entries)
 | |
| 	{
 | |
| 	  entry = entries->data;
 | |
| 
 | |
| 	  if ((entry->object == object) && (entry->signal_num == signal_num))
 | |
| 	    {
 | |
| 	      g_free (entry);
 | |
| 
 | |
| 	      temp_list = entries;
 | |
| 	      if (entries->next)
 | |
| 		entries->next->prev = entries->prev;
 | |
| 	      if (entries->prev)
 | |
| 		entries->prev->next = entries->next;
 | |
| 	      if (table->entries[i] == entries)
 | |
| 		table->entries[i] = entries->next;
 | |
| 
 | |
| 	      temp_list->next = NULL;
 | |
| 	      temp_list->prev = NULL;
 | |
| 	      g_list_free (temp_list);
 | |
| 
 | |
| 	      return;
 | |
| 	    }
 | |
| 
 | |
| 	  entries = entries->next;
 | |
| 	}
 | |
|     }
 | |
| }
 | |
| 
 | |
| gint
 | |
| gtk_accelerator_table_check (GtkAcceleratorTable *table,
 | |
| 			     const guchar         accelerator_key,
 | |
| 			     guint8               accelerator_mods)
 | |
| {
 | |
|   GtkAcceleratorEntry *entry;
 | |
|   GList *entries;
 | |
|   guint hash;
 | |
| 
 | |
|   if (!table)
 | |
|     {
 | |
|       if (!default_table)
 | |
| 	default_table = gtk_accelerator_table_new ();
 | |
|       table = default_table;
 | |
|     }
 | |
| 
 | |
|   hash = (guint) accelerator_key;
 | |
|   entries = table->entries[hash];
 | |
| 
 | |
|   while (entries)
 | |
|     {
 | |
|       entry = entries->data;
 | |
| 
 | |
|       if ((entry->modifiers & table->modifier_mask) ==
 | |
|           (accelerator_mods & table->modifier_mask))
 | |
| 	{
 | |
| 	  gtk_signal_emit (entry->object, entry->signal_num);
 | |
| 	  return TRUE;
 | |
| 	}
 | |
| 
 | |
|       entries = entries->next;
 | |
|     }
 | |
| 
 | |
|   if (!isupper (hash))
 | |
|     {
 | |
|       hash = toupper (hash);
 | |
|       entries = table->entries[hash];
 | |
| 
 | |
|       while (entries)
 | |
| 	{
 | |
| 	  entry = entries->data;
 | |
| 
 | |
| 	  if (((entry->modifiers & table->modifier_mask) ==
 | |
| 	       (accelerator_mods & table->modifier_mask)) &&
 | |
| 	      (GTK_IS_WIDGET (entry->object) &&
 | |
| 	       GTK_WIDGET_SENSITIVE (entry->object)))
 | |
| 	    {
 | |
| 	      gtk_signal_emit (entry->object, entry->signal_num);
 | |
| 	      return TRUE;
 | |
| 	    }
 | |
| 
 | |
| 	  entries = entries->next;
 | |
| 	}
 | |
|     }
 | |
| 
 | |
|   return FALSE;
 | |
| }
 | |
| 
 | |
| void
 | |
| gtk_accelerator_table_set_mod_mask (GtkAcceleratorTable *table,
 | |
|                                     guint8               modifier_mask)
 | |
| {
 | |
|   if (table == NULL)
 | |
|     {
 | |
|       gtk_accelerator_table_default_mod_mask = modifier_mask;
 | |
|     }
 | |
|   else
 | |
|     {
 | |
|       table->modifier_mask = modifier_mask;
 | |
|     }
 | |
| }
 | |
| 
 | |
| static void
 | |
| gtk_accelerator_table_init (GtkAcceleratorTable *table)
 | |
| {
 | |
|   gint i;
 | |
| 
 | |
|   g_return_if_fail (table != NULL);
 | |
| 
 | |
|   for (i = 0; i < 256; i++)
 | |
|     table->entries[i] = NULL;
 | |
| 
 | |
|   table->ref_count = 1;
 | |
|   table->modifier_mask = gtk_accelerator_table_default_mod_mask;
 | |
| }
 | |
| 
 | |
| static void
 | |
| gtk_accelerator_table_clean (GtkAcceleratorTable *table)
 | |
| {
 | |
|   GtkAcceleratorEntry *entry;
 | |
|   GList *entries;
 | |
|   gint i;
 | |
| 
 | |
|   g_return_if_fail (table != NULL);
 | |
| 
 | |
|   for (i = 0; i < 256; i++)
 | |
|     {
 | |
|       entries = table->entries[i];
 | |
|       while (entries)
 | |
| 	{
 | |
| 	  entry = entries->data;
 | |
| 	  entries = entries->next;
 | |
| 
 | |
| 	  g_free (entry);
 | |
| 	}
 | |
| 
 | |
|       g_list_free (table->entries[i]);
 | |
|       table->entries[i] = NULL;
 | |
|     }
 | |
| }
 | 
