source: trunk/third/gtk/gtk/gtkmenufactory.c @ 14482

Revision 14482, 13.2 KB checked in by ghudson, 24 years ago (diff)
This commit was generated by cvs2svn to compensate for changes in r14481, which included commits to RCS files with non-trunk default branches.
Line 
1/* GTK - The GIMP Toolkit
2 * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
3 *
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.
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 * Library General Public License for more details.
13 *
14 * You should have received a copy of the GNU Library 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-1999.  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 <string.h>
28#include "gtkcheckmenuitem.h"
29#include "gtkmenu.h"
30#include "gtkmenubar.h"
31#include "gtkmenufactory.h"
32#include "gtkmenuitem.h"
33#include "gtksignal.h"
34
35
36enum
37{
38  CREATE  = 1 << 0,
39  DESTROY = 1 << 1,
40  CHECK   = 1 << 2
41};
42
43
44static void         gtk_menu_factory_create            (GtkMenuFactory *factory,
45                                                        GtkMenuEntry   *entry,
46                                                        GtkWidget      *parent,
47                                                        const gchar    *path);
48static void         gtk_menu_factory_remove            (GtkMenuFactory *factory,
49                                                        GtkWidget      *parent,
50                                                        const gchar    *path);
51static GtkWidget*   gtk_menu_factory_make_widget       (GtkMenuFactory *factory);
52static GtkMenuPath* gtk_menu_factory_get               (GtkWidget      *parent,
53                                                        const gchar    *path,
54                                                        gint            flags);
55static GtkMenuPath* gtk_menu_factory_find_recurse      (GtkMenuFactory *factory,
56                                                        GtkWidget      *parent,
57                                                        const gchar    *path);
58
59
60GtkMenuFactory*
61gtk_menu_factory_new (GtkMenuFactoryType type)
62{
63  GtkMenuFactory *factory;
64
65  g_warning ("gtk_menu_factory_new(): GtkMenuFactory is deprecated and will shortly vanish");
66 
67  factory = g_new (GtkMenuFactory, 1);
68  factory->path = NULL;
69  factory->type = type;
70  factory->accel_group = NULL;
71  factory->widget = NULL;
72  factory->subfactories = NULL;
73 
74  return factory;
75}
76
77void
78gtk_menu_factory_destroy (GtkMenuFactory *factory)
79{
80  GtkMenuFactory *subfactory;
81  GList *tmp_list;
82 
83  g_return_if_fail (factory != NULL);
84 
85  if (factory->path)
86    g_free (factory->path);
87 
88  tmp_list = factory->subfactories;
89  while (tmp_list)
90    {
91      subfactory = tmp_list->data;
92      tmp_list = tmp_list->next;
93     
94      gtk_menu_factory_destroy (subfactory);
95    }
96 
97  if (factory->accel_group)
98    {
99      gtk_accel_group_unref (factory->accel_group);
100      factory->accel_group = NULL;
101    }
102 
103  if (factory->widget)
104    gtk_widget_unref (factory->widget);
105}
106
107void
108gtk_menu_factory_add_entries (GtkMenuFactory *factory,
109                              GtkMenuEntry   *entries,
110                              int             nentries)
111{
112  int i;
113 
114  g_return_if_fail (factory != NULL);
115  g_return_if_fail (entries != NULL);
116  g_return_if_fail (nentries > 0);
117 
118  if (!factory->widget)
119    {
120      factory->widget = gtk_menu_factory_make_widget (factory);
121      gtk_widget_ref  (factory->widget);
122      gtk_object_sink (GTK_OBJECT (factory->widget));
123    }
124 
125  for (i = 0; i < nentries; i++)
126    gtk_menu_factory_create (factory, &entries[i], factory->widget, entries[i].path);
127}
128
129void
130gtk_menu_factory_add_subfactory (GtkMenuFactory *factory,
131                                 GtkMenuFactory *subfactory,
132                                 const char     *path)
133{
134  g_return_if_fail (factory != NULL);
135  g_return_if_fail (subfactory != NULL);
136  g_return_if_fail (path != NULL);
137 
138  if (subfactory->path)
139    g_free (subfactory->path);
140  subfactory->path = g_strdup (path);
141 
142  factory->subfactories = g_list_append (factory->subfactories, subfactory);
143}
144
145void
146gtk_menu_factory_remove_paths (GtkMenuFactory  *factory,
147                               char           **paths,
148                               int              npaths)
149{
150  int i;
151 
152  g_return_if_fail (factory != NULL);
153  g_return_if_fail (paths != NULL);
154  g_return_if_fail (npaths > 0);
155 
156  if (factory->widget)
157    {
158      for (i = 0; i < npaths; i++)
159        gtk_menu_factory_remove (factory, factory->widget, paths[i]);
160    }
161}
162
163void
164gtk_menu_factory_remove_entries (GtkMenuFactory *factory,
165                                 GtkMenuEntry   *entries,
166                                 int             nentries)
167{
168  int i;
169 
170  g_return_if_fail (factory != NULL);
171  g_return_if_fail (entries != NULL);
172  g_return_if_fail (nentries > 0);
173 
174  if (factory->widget)
175    {
176      for (i = 0; i < nentries; i++)
177        gtk_menu_factory_remove (factory, factory->widget, entries[i].path);
178    }
179}
180
181void
182gtk_menu_factory_remove_subfactory (GtkMenuFactory *factory,
183                                    GtkMenuFactory *subfactory,
184                                    const char     *path)
185{
186  g_return_if_fail (factory != NULL);
187  g_return_if_fail (subfactory != NULL);
188  g_return_if_fail (path != NULL);
189 
190  g_warning ("FIXME: gtk_menu_factory_remove_subfactory");
191}
192
193GtkMenuPath*
194gtk_menu_factory_find (GtkMenuFactory *factory,
195                       const char     *path)
196{
197  g_return_val_if_fail (factory != NULL, NULL);
198  g_return_val_if_fail (path != NULL, NULL);
199 
200  return gtk_menu_factory_find_recurse (factory, factory->widget, path);
201}
202
203
204static void
205gtk_menu_factory_create (GtkMenuFactory *factory,
206                         GtkMenuEntry   *entry,
207                         GtkWidget      *parent,
208                         const char     *path)
209{
210  GtkMenuFactory *subfactory;
211  GtkMenuPath *menu_path;
212  GtkWidget *menu;
213  GList *tmp_list;
214  char tmp_path[256];
215  guint accelerator_key;
216  guint accelerator_mods;
217  gchar *p;
218 
219  g_return_if_fail (factory != NULL);
220  g_return_if_fail (entry != NULL);
221 
222  /* If 'path' is empty, then simply return.
223   */
224  if (!path || path[0] == '\0')
225    return;
226  else if (strlen (path) >= 250)
227    {
228      /* security audit
229       */
230      g_warning ("gtk_menu_factory_create(): argument `path' exceeds maximum size.");
231      return;
232    }
233 
234  /* Strip off the next part of the path.
235   */
236  p = strchr (path, '/');
237 
238  /* If this is the last part of the path ('p' is
239   *  NULL), then we create an item.
240   */
241  if (!p)
242    {
243      /* Check to see if this item is a separator.
244       */
245      if (strcmp (path, "<separator>") == 0)
246        {
247          entry->widget = gtk_menu_item_new ();
248          gtk_container_add (GTK_CONTAINER (parent), entry->widget);
249          gtk_widget_show (entry->widget);
250        }
251      else
252        {
253          if (strncmp (path, "<check>", 7) == 0)
254            menu_path = gtk_menu_factory_get (parent, path + 7, CREATE | CHECK);
255          else
256            menu_path = gtk_menu_factory_get (parent, path, CREATE);
257          entry->widget = menu_path->widget;
258         
259          if (strcmp (path, "<nothing>") == 0)
260            gtk_widget_hide (entry->widget);
261         
262          if (entry->accelerator)
263            {
264              gtk_accelerator_parse (entry->accelerator,
265                                     &accelerator_key,
266                                     &accelerator_mods);
267              if (!factory->accel_group)
268                factory->accel_group = gtk_accel_group_new ();
269             
270              gtk_widget_add_accelerator (menu_path->widget,
271                                          "activate",
272                                          factory->accel_group,
273                                          accelerator_key,
274                                          accelerator_mods,
275                                          GTK_ACCEL_VISIBLE);
276            }
277         
278          if (entry->callback)
279            gtk_signal_connect (GTK_OBJECT (menu_path->widget), "activate",
280                                (GtkSignalFunc) entry->callback,
281                                entry->callback_data);
282        }
283    }
284  else
285    {
286      strncpy (tmp_path, path, (unsigned int) ((long) p - (long) path));
287      tmp_path[(long) p - (long) path] = '\0';
288     
289      menu_path = gtk_menu_factory_get (parent, tmp_path, 0);
290      if (!menu_path)
291        {
292          tmp_list = factory->subfactories;
293          while (tmp_list)
294            {
295              subfactory = tmp_list->data;
296              tmp_list = tmp_list->next;
297             
298              if (subfactory->path &&
299                  (strcmp (subfactory->path, tmp_path) == 0))
300                {
301                  if (!subfactory->widget)
302                    {
303                      subfactory->widget = gtk_menu_factory_make_widget (subfactory);
304                      gtk_widget_ref  (subfactory->widget);
305                      gtk_object_sink (GTK_OBJECT (subfactory->widget));
306                    }
307                 
308                  gtk_menu_factory_create (subfactory, entry, subfactory->widget, p + 1);
309                  return;
310                }
311            }
312         
313          menu_path = gtk_menu_factory_get (parent, tmp_path, CREATE);
314        }
315     
316      entry->widget = menu_path->widget;
317      menu = GTK_MENU_ITEM (menu_path->widget)->submenu;
318     
319      if (!menu)
320        {
321          menu = gtk_menu_new ();
322          gtk_menu_item_set_submenu (GTK_MENU_ITEM (menu_path->widget), menu);
323         
324          if (!factory->accel_group)
325            factory->accel_group = gtk_accel_group_new ();
326          gtk_menu_set_accel_group (GTK_MENU (menu), factory->accel_group);
327        }
328     
329      gtk_menu_factory_create (factory, entry, menu, p + 1);
330    }
331}
332
333static void
334gtk_menu_factory_remove (GtkMenuFactory *factory,
335                         GtkWidget      *parent,
336                         const char     *path)
337{
338  GtkMenuFactory *subfactory;
339  GtkMenuPath *menu_path;
340  GtkWidget *menu;
341  GList *tmp_list;
342  char tmp_path[256];
343  char *p;
344 
345  if (!path || path[0] == '\0')
346    return;
347  else if (strlen (path) >= 250)
348    {
349      /* security audit
350       */
351      g_warning ("gtk_menu_factory_remove(): argument `path' exceeds maximum size.");
352      return;
353    }
354 
355  p = strchr (path, '/');
356 
357  if (!p)
358    {
359      if (parent)
360        gtk_menu_factory_get (parent, path, DESTROY);
361    }
362  else
363    {
364      strncpy (tmp_path, path, (unsigned int) ((long) p - (long) path));
365      tmp_path[(long) p - (long) path] = '\0';
366     
367      menu_path = gtk_menu_factory_get (parent, tmp_path, 0);
368      if (!menu_path)
369        {
370          tmp_list = factory->subfactories;
371          while (tmp_list)
372            {
373              subfactory = tmp_list->data;
374              tmp_list = tmp_list->next;
375             
376              if (subfactory->path &&
377                  (strcmp (subfactory->path, tmp_path) == 0))
378                {
379                  if (!subfactory->widget)
380                    return;
381                  gtk_menu_factory_remove (subfactory, subfactory->widget, p + 1);
382                }
383            }
384        }
385      else
386        {
387          menu = GTK_MENU_ITEM (menu_path->widget)->submenu;
388          if (menu)
389            gtk_menu_factory_remove (factory, menu, p + 1);
390        }
391    }
392}
393
394static GtkWidget*
395gtk_menu_factory_make_widget (GtkMenuFactory *factory)
396{
397  GtkWidget *widget;
398 
399  g_return_val_if_fail (factory != NULL, NULL);
400 
401  switch (factory->type)
402    {
403    case GTK_MENU_FACTORY_MENU:
404      widget = gtk_menu_new ();
405     
406      if (!factory->accel_group)
407        factory->accel_group = gtk_accel_group_new ();
408      gtk_menu_set_accel_group (GTK_MENU (widget), factory->accel_group);
409      return widget;
410    case GTK_MENU_FACTORY_MENU_BAR:
411      return gtk_menu_bar_new ();
412    case GTK_MENU_FACTORY_OPTION_MENU:
413      g_error ("not implemented");
414      break;
415    }
416 
417  return NULL;
418}
419
420static GtkMenuPath*
421gtk_menu_factory_get (GtkWidget *parent,
422                      const char *path,
423                      int        flags)
424{
425  GtkMenuPath *menu_path;
426  GList *tmp_list;
427 
428  tmp_list = gtk_object_get_user_data (GTK_OBJECT (parent));
429  while (tmp_list)
430    {
431      menu_path = tmp_list->data;
432      tmp_list = tmp_list->next;
433     
434      if (strcmp (menu_path->path, path) == 0)
435        {
436          if (flags & DESTROY)
437            {
438              tmp_list = gtk_object_get_user_data (GTK_OBJECT (parent));
439              tmp_list = g_list_remove (tmp_list, menu_path);
440              gtk_object_set_user_data (GTK_OBJECT (parent), tmp_list);
441             
442              gtk_widget_destroy (menu_path->widget);
443              g_free (menu_path->path);
444              g_free (menu_path);
445             
446              return NULL;
447            }
448          else
449            {
450              return menu_path;
451            }
452        }
453    }
454 
455  if (flags & CREATE)
456    {
457      menu_path = g_new (GtkMenuPath, 1);
458      menu_path->path = g_strdup (path);
459     
460      if (flags & CHECK)
461        menu_path->widget = gtk_check_menu_item_new_with_label (path);
462      else
463        menu_path->widget = gtk_menu_item_new_with_label (path);
464     
465      gtk_container_add (GTK_CONTAINER (parent), menu_path->widget);
466      gtk_object_set_user_data (GTK_OBJECT (menu_path->widget), NULL);
467      gtk_widget_show (menu_path->widget);
468     
469      tmp_list = gtk_object_get_user_data (GTK_OBJECT (parent));
470      tmp_list = g_list_prepend (tmp_list, menu_path);
471      gtk_object_set_user_data (GTK_OBJECT (parent), tmp_list);
472     
473      return menu_path;
474    }
475 
476  return NULL;
477}
478
479static GtkMenuPath*
480gtk_menu_factory_find_recurse (GtkMenuFactory *factory,
481                               GtkWidget      *parent,
482                               const char     *path)
483{
484  GtkMenuFactory *subfactory;
485  GtkMenuPath *menu_path;
486  GtkWidget *menu;
487  GList *tmp_list;
488  char tmp_path[256];
489  char *p;
490 
491  if (!path || path[0] == '\0')
492    return NULL;
493  else if (strlen (path) >= 250)
494    {
495      /* security audit
496       */
497      g_warning ("gtk_menu_factory_find_recurse(): argument `path' exceeds maximum size.");
498      return NULL;
499    }
500 
501  p = strchr (path, '/');
502 
503  if (!p)
504    {
505      if (parent)
506        return gtk_menu_factory_get (parent, path, 0);
507    }
508  else
509    {
510      strncpy (tmp_path, path, (unsigned int) ((long) p - (long) path));
511      tmp_path[(long) p - (long) path] = '\0';
512     
513      menu_path = gtk_menu_factory_get (parent, tmp_path, 0);
514      if (!menu_path)
515        {
516          tmp_list = factory->subfactories;
517          while (tmp_list)
518            {
519              subfactory = tmp_list->data;
520              tmp_list = tmp_list->next;
521             
522              if (subfactory->path &&
523                  (strcmp (subfactory->path, tmp_path) == 0))
524                {
525                  if (!subfactory->widget)
526                    return NULL;
527                  return gtk_menu_factory_find_recurse (subfactory, subfactory->widget, p + 1);
528                }
529            }
530         
531          return NULL;
532        }
533     
534      menu = GTK_MENU_ITEM (menu_path->widget)->submenu;
535      if (menu)
536        return gtk_menu_factory_find_recurse (factory, menu, p + 1);
537    }
538 
539  return NULL;
540}
Note: See TracBrowser for help on using the repository browser.