1 /* GTK - The GIMP Toolkit
2 * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Library 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.
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 * Library General Public License for more details.
14 * You should have received a copy of the GNU Library General Public
15 * License along with this library; if not, write to the Free
16 * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19 #include "gtkcheckmenuitem.h"
21 #include "gtkmenubar.h"
22 #include "gtkmenufactory.h"
23 #include "gtkmenuitem.h"
24 #include "gtksignal.h"
35 static void gtk_menu_factory_create (GtkMenuFactory *factory,
39 static void gtk_menu_factory_remove (GtkMenuFactory *factory,
42 static GtkWidget* gtk_menu_factory_make_widget (GtkMenuFactory *factory);
43 static GtkMenuPath* gtk_menu_factory_get (GtkWidget *parent,
46 static GtkMenuPath* gtk_menu_factory_find_recurse (GtkMenuFactory *factory,
49 static void gtk_menu_factory_parse_accelerator (const char *accelerator,
50 char *accelerator_key,
51 guint8 *accelerator_mods);
55 gtk_menu_factory_new (GtkMenuFactoryType type)
57 GtkMenuFactory *factory;
59 factory = g_new (GtkMenuFactory, 1);
62 factory->table = NULL;
63 factory->widget = NULL;
64 factory->subfactories = NULL;
70 gtk_menu_factory_destroy (GtkMenuFactory *factory)
72 GtkMenuFactory *subfactory;
75 g_return_if_fail (factory != NULL);
78 g_free (factory->path);
80 tmp_list = factory->subfactories;
83 subfactory = tmp_list->data;
84 tmp_list = tmp_list->next;
86 gtk_menu_factory_destroy (subfactory);
91 gtk_menu_factory_add_entries (GtkMenuFactory *factory,
92 GtkMenuEntry *entries,
97 g_return_if_fail (factory != NULL);
98 g_return_if_fail (entries != NULL);
99 g_return_if_fail (nentries > 0);
101 if (!factory->widget)
102 factory->widget = gtk_menu_factory_make_widget (factory);
104 for (i = 0; i < nentries; i++)
105 gtk_menu_factory_create (factory, &entries[i], factory->widget, entries[i].path);
109 gtk_menu_factory_add_subfactory (GtkMenuFactory *factory,
110 GtkMenuFactory *subfactory,
113 g_return_if_fail (factory != NULL);
114 g_return_if_fail (subfactory != NULL);
115 g_return_if_fail (path != NULL);
117 if (subfactory->path)
118 g_free (subfactory->path);
119 subfactory->path = g_strdup (path);
121 factory->subfactories = g_list_append (factory->subfactories, subfactory);
125 gtk_menu_factory_remove_paths (GtkMenuFactory *factory,
131 g_return_if_fail (factory != NULL);
132 g_return_if_fail (paths != NULL);
133 g_return_if_fail (npaths > 0);
137 for (i = 0; i < npaths; i++)
138 gtk_menu_factory_remove (factory, factory->widget, paths[i]);
143 gtk_menu_factory_remove_entries (GtkMenuFactory *factory,
144 GtkMenuEntry *entries,
149 g_return_if_fail (factory != NULL);
150 g_return_if_fail (entries != NULL);
151 g_return_if_fail (nentries > 0);
155 for (i = 0; i < nentries; i++)
156 gtk_menu_factory_remove (factory, factory->widget, entries[i].path);
161 gtk_menu_factory_remove_subfactory (GtkMenuFactory *factory,
162 GtkMenuFactory *subfactory,
165 g_return_if_fail (factory != NULL);
166 g_return_if_fail (subfactory != NULL);
167 g_return_if_fail (path != NULL);
169 g_warning ("FIXME: gtk_menu_factory_remove_subfactory");
173 gtk_menu_factory_find (GtkMenuFactory *factory,
176 g_return_val_if_fail (factory != NULL, NULL);
177 g_return_val_if_fail (path != NULL, NULL);
179 return gtk_menu_factory_find_recurse (factory, factory->widget, path);
184 gtk_menu_factory_create (GtkMenuFactory *factory,
189 GtkMenuFactory *subfactory;
190 GtkMenuPath *menu_path;
194 char accelerator_key;
195 guint8 accelerator_mods;
198 g_return_if_fail (factory != NULL);
199 g_return_if_fail (entry != NULL);
201 /* If 'path' is empty, then simply return.
203 if (!path || path[0] == '\0')
206 /* Strip off the next part of the path.
208 p = strchr (path, '/');
210 /* If this is the last part of the path ('p' is
211 * NULL), then we create an item.
215 /* Check to see if this item is a separator.
217 if (strcmp (path, "<separator>") == 0)
219 entry->widget = gtk_menu_item_new ();
220 gtk_container_add (GTK_CONTAINER (parent), entry->widget);
221 gtk_widget_show (entry->widget);
225 if (strncmp (path, "<check>", 7) == 0)
226 menu_path = gtk_menu_factory_get (parent, path + 7, CREATE | CHECK);
228 menu_path = gtk_menu_factory_get (parent, path, CREATE);
229 entry->widget = menu_path->widget;
231 if (strcmp (path, "<nothing>") == 0)
232 gtk_widget_hide (entry->widget);
234 if (entry->accelerator)
236 gtk_menu_factory_parse_accelerator (entry->accelerator,
241 factory->table = gtk_accelerator_table_new ();
242 gtk_accelerator_table_ref (factory->table);
245 gtk_widget_install_accelerator (menu_path->widget,
253 gtk_signal_connect (GTK_OBJECT (menu_path->widget), "activate",
254 (GtkSignalFunc) entry->callback,
255 entry->callback_data);
260 strncpy (tmp_path, path, (unsigned int) ((long) p - (long) path));
261 tmp_path[(long) p - (long) path] = '\0';
263 menu_path = gtk_menu_factory_get (parent, tmp_path, 0);
266 tmp_list = factory->subfactories;
269 subfactory = tmp_list->data;
270 tmp_list = tmp_list->next;
272 if (subfactory->path &&
273 (strcmp (subfactory->path, tmp_path) == 0))
275 if (!subfactory->widget)
276 subfactory->widget = gtk_menu_factory_make_widget (subfactory);
277 gtk_menu_factory_create (subfactory, entry, subfactory->widget, p + 1);
282 menu_path = gtk_menu_factory_get (parent, tmp_path, CREATE);
285 entry->widget = menu_path->widget;
286 menu = GTK_MENU_ITEM (menu_path->widget)->submenu;
290 menu = gtk_menu_new ();
291 gtk_menu_item_set_submenu (GTK_MENU_ITEM (menu_path->widget), menu);
295 factory->table = gtk_accelerator_table_new ();
296 gtk_accelerator_table_ref (factory->table);
298 gtk_menu_set_accelerator_table (GTK_MENU (menu), factory->table);
301 gtk_menu_factory_create (factory, entry, menu, p + 1);
306 gtk_menu_factory_remove (GtkMenuFactory *factory,
310 GtkMenuFactory *subfactory;
311 GtkMenuPath *menu_path;
317 if (!path || path[0] == '\0')
320 p = strchr (path, '/');
325 gtk_menu_factory_get (parent, path, DESTROY);
329 strncpy (tmp_path, path, (unsigned int) ((long) p - (long) path));
330 tmp_path[(long) p - (long) path] = '\0';
332 menu_path = gtk_menu_factory_get (parent, tmp_path, 0);
335 tmp_list = factory->subfactories;
338 subfactory = tmp_list->data;
339 tmp_list = tmp_list->next;
341 if (subfactory->path &&
342 (strcmp (subfactory->path, tmp_path) == 0))
344 if (!subfactory->widget)
346 gtk_menu_factory_remove (subfactory, subfactory->widget, p + 1);
352 menu = GTK_MENU_ITEM (menu_path->widget)->submenu;
354 gtk_menu_factory_remove (factory, menu, p + 1);
360 gtk_menu_factory_make_widget (GtkMenuFactory *factory)
364 g_return_val_if_fail (factory != NULL, NULL);
366 switch (factory->type)
368 case GTK_MENU_FACTORY_MENU:
369 widget = gtk_menu_new ();
373 factory->table = gtk_accelerator_table_new ();
374 gtk_accelerator_table_ref (factory->table);
376 gtk_menu_set_accelerator_table (GTK_MENU (widget), factory->table);
378 case GTK_MENU_FACTORY_MENU_BAR:
379 return gtk_menu_bar_new ();
380 case GTK_MENU_FACTORY_OPTION_MENU:
381 g_error ("not implemented");
389 gtk_menu_factory_get (GtkWidget *parent,
393 GtkMenuPath *menu_path;
396 tmp_list = gtk_object_get_user_data (GTK_OBJECT (parent));
399 menu_path = tmp_list->data;
400 tmp_list = tmp_list->next;
402 if (strcmp (menu_path->path, path) == 0)
406 tmp_list = gtk_object_get_user_data (GTK_OBJECT (parent));
407 tmp_list = g_list_remove (tmp_list, menu_path);
408 gtk_object_set_user_data (GTK_OBJECT (parent), tmp_list);
410 gtk_widget_destroy (menu_path->widget);
411 g_free (menu_path->path);
425 menu_path = g_new (GtkMenuPath, 1);
426 menu_path->path = g_strdup (path);
429 menu_path->widget = gtk_check_menu_item_new_with_label (path);
431 menu_path->widget = gtk_menu_item_new_with_label (path);
433 gtk_container_add (GTK_CONTAINER (parent), menu_path->widget);
434 gtk_object_set_user_data (GTK_OBJECT (menu_path->widget), NULL);
435 gtk_widget_show (menu_path->widget);
437 tmp_list = gtk_object_get_user_data (GTK_OBJECT (parent));
438 tmp_list = g_list_prepend (tmp_list, menu_path);
439 gtk_object_set_user_data (GTK_OBJECT (parent), tmp_list);
448 gtk_menu_factory_find_recurse (GtkMenuFactory *factory,
452 GtkMenuFactory *subfactory;
453 GtkMenuPath *menu_path;
459 if (!path || path[0] == '\0')
462 p = strchr (path, '/');
467 return gtk_menu_factory_get (parent, path, 0);
471 strncpy (tmp_path, path, (unsigned int) ((long) p - (long) path));
472 tmp_path[(long) p - (long) path] = '\0';
474 menu_path = gtk_menu_factory_get (parent, tmp_path, 0);
477 tmp_list = factory->subfactories;
480 subfactory = tmp_list->data;
481 tmp_list = tmp_list->next;
483 if (subfactory->path &&
484 (strcmp (subfactory->path, tmp_path) == 0))
486 if (!subfactory->widget)
488 return gtk_menu_factory_find_recurse (subfactory, subfactory->widget, p + 1);
495 menu = GTK_MENU_ITEM (menu_path->widget)->submenu;
497 return gtk_menu_factory_find_recurse (factory, menu, p + 1);
504 gtk_menu_factory_parse_accelerator (const char *accelerator,
505 char *accelerator_key,
506 guint8 *accelerator_mods)
510 g_return_if_fail (accelerator != NULL);
511 g_return_if_fail (accelerator_key != NULL);
512 g_return_if_fail (accelerator_mods != NULL);
514 *accelerator_key = 0;
515 *accelerator_mods = 0;
520 if (strncmp (accelerator, "<shift>", 7) == 0)
523 *accelerator_mods |= GDK_SHIFT_MASK;
525 else if (strncmp (accelerator, "<alt>", 5) == 0)
528 *accelerator_mods |= GDK_MOD1_MASK;
530 else if (strncmp (accelerator, "<control>", 9) == 0)
533 *accelerator_mods |= GDK_CONTROL_MASK;
538 *accelerator_key = accelerator[0];