Nuke GtkMenuFactory in favour of GtkItemFactory
- From: Tim Janik <timj gtk org>
- To: Gtk+ MList <gtk-list redhat com>
- Subject: Nuke GtkMenuFactory in favour of GtkItemFactory
- Date: Sat, 18 Apr 1998 12:03:46 +0200 (CEST)
hi all.
since the first time i tried to use GtkMenuFactory, i've found
it's concept fundamentally broken. here is a short (but by no means
comprehensive) list of what i personally dislike about it:
- GtkMenuFactory is a structure allocated and destructed on demand,
which is used in many places (windows) in multi-widnow applications,
but does not honour the reference counting scheme.
- therefore automatic destruction for menu fectories is *not* possible.
- there is no way to track whether a GtkMenuFactory adds/removes new
entries (i.e. signal connections are *not* possible).
- accelerator saving/parsing is not supported, though that is really
easy to implement (along the lines gtk_rc_* work).
- accelerator tables are only supported on a per menu basis, not a
per window basis (this creates problems when using different menus
e.g. a popup and a menubar for the same window).
- a certain menu entry can only have one instance, so one cannot use
the same menu factory entry table for two different windows that need
the same menubar.
- right justification for menuitems on a menubar is not supported (though
that could eventually be implemented).
- there is no easy way to have a menuitem callback operate on a certain
widget (without iterating through the entries array and setting
callback_data to the widget prior to adding them to GtkMenuFactory).
- there is no clean way to use the same callback function for multiple
menuitems and switch() to a specific intended behaviour (one could
use ((gpointer)1) ((gpointer)2) etc. for the callback_data, but then
this interferes with the above mentioned point).
no as a result of the problems i encountered with GtkMenuFactory, i decided to
reimplement it as GtkItemFactory.
GtkItemFactory basically is a GtkObject, which nukes the idea of subfactories
and suports automatic accelerator handling.
that means accelerators can automatically be parsed from a menurc file and
dumped via a print function. also, multiple menubars on different windows
can share the same item factory entries, and therefore adjust their
accelerators automatically.
since i've only began to write on the code a few hours ago, nothing is really
set in stone already, and i'm curious to hear about people's comments.
i've appended the current gtkitemfactory.h file and will answer questions
(extend on this issue) after i got a couple of hours sleep. anyways, the
current test implementation i have so far works like a charme (except for the
unimplemented parsing ;) and will be used in BEAST/BSE and GLE (once both get
into a state where they can be consumed by a variety of people). it is also
a whole lot faster since i'm doing only hash lookups on the path lookup and
on the item_types.
now for the API side of GtkItemFactory, i'm quoting the GtkItemFactoryEntry
definition and give a short example:
[from gtkitemfactory.h]
struct _GtkItemFactoryEntry
{
gchar *path;
gchar *accelerator;
GtkItemFactoryCallback callback;
guint callback_action;
/* possible values:
* NULL -> "<Item>"
* "" -> "<Item>"
* "<Item>" -> create a simple item
* "<CheckItem>" -> create a check item
* "<ToggleItem>" -> create a toggle item
* "<RadioItem>" -> create a radio item
* <path> -> path to a radio item to link against
* "<Separator>" -> create a separator
* "<Branch>" -> create an item to hold sub items
* "<LastBranch>" -> create a right justified item to hold sub items
*/
gchar *item_type;
};
[application side]
static void
my_file_callback (gpointer callback_data,
guint callback_action,
GtkWidget *menu_item)
{
GImage *image;
image = callback_data;
gtk_widget_set_sensitive (menu_item, FALSE);
switch (callback_action)
{
case CB_OPEN:
spawn_open_dialog (image);
break;
case CB_SAVE:
spawn_save_dialog (image, image->filename);
break;
case CB_SAVE_AS:
spawn_save_dialog (image, NULL);
break;
}
}
static GtkItemFactoryEntry menubar_entries[] =
{
{ "/File", NULL, NULL, 0, NULL /* this line could be omitted */},
{ "/File/Open...", "<ctrl>O", my_file_callback, CB_OPEN, NULL },
{ "/File/Save...", "<ctrl>S", my_file_callback, CB_SAVE, NULL },
{ "/File/Save As...", "<ctrl>A", my_file_callback, CB_SAVE_AS, NULL },
{ "/File/", NULL, NULL, 0, "<Separator>" },
{ "/File/About...", NULL, spawn_about_box, 0, NULL },
{ "/File/", NULL, NULL, 0, "<Separator>" },
{ "/File/Show Tips", NULL, NULL, 0, "<CheckItem>" },
{ "/File/Dialogs/Gradians", "<ctrl>G", NULL, 0, NULL },
{ "/File/this is ignored", NULL, NULL, 0, "<Separator>" },
{ "/File/Destroy Image", NULL, gtk_widget_destroy, 0, NULL },
{ "/Help", NULL, NULL, 0, "<LastBranch>" /* this one cannot */},
{ "/Help/Authors", NULL, spawn_authors_dialog, 0, NULL },
};
static guint n_menubar_entries = sizeof (menubar_entries) /
sizeof (menubar_entries[0]);
static GtkItemFactoryEntry popup_entries[] =
{
{ "/Choose 1", NULL, NULL, 0, "<RadioItem>" },
{ "/Choose 2", NULL, NULL, 0, "/Choose 1" },
{ "/Choose 3", NULL, NULL, 0, "/Choose 1" },
{ "/Choose 4", NULL, NULL, 0, "/Choose 1" },
{ "/Stale Radio", NULL,NULL, 0, "<RadioItem>" },
{ "/Quit Popup", NULL, NULL, 0, NULL },
};
static guint n_popup_entries = sizeof (popup_entries) /
sizeof (popup_entries[0]);
static void
create_factories (GImage *image)
{
GtkObject *ifactory_mbar;
GtkObject *ifactory_popup;
ifactory_mbar = gtk_item_factory_new (gtk_menu_bar_get_type (),
"<Image-MenuBar>",
NULL);
gtk_window_add_accelerator_table (image->window,
GTK_ITEM_FACTORY (ifactory_mbar)->table);
gtk_item_factory_create_items (GTK_ITEM_FACTORY (ifactory_mbar),
n_menubar_entries,
menubar_entries,
image);
ifactory_popup = gtk_item_factory_new (gtk_menu_bar_get_type (),
"<Image-Popup>",
GTK_ITEM_FACTORY (ifactory_mbar)->table);
gtk_item_factory_create_items (GTK_ITEM_FACTORY (ifactory_popup),
n_popup_entries,
popup_entries,
image);
image->popup = GTK_ITEM_FACTORY (ifactory_popup);
}
[...]
image_spawn_popup (GImage *image, GdkEventButton *event)
{
gtk_item_factory_popup (image->ifactory_popup,
event->x_root, event->y_root,
event->button, event->time);
}
boy, that became longer than i wanted it to ;)
anyways, still need to get some sleep. i'll pay attention to your flames
later this day ;)
PS.: i don't really want to nuke GtkMenuFactory ;) GtkItemFactory should
go into the 1.1.x tree, and GtkMenuFactory should be kept around
as long as there are applications using it (though its use should be
discouraged).
---
ciaoTJ
/* GTK - The GIMP Toolkit
* Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
*
* GtkItemFactory: Flexible item factory with automatic rc handling
* Copyright (C) 1998 Tim Janik
*
* 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., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
#ifndef __GTK_ITEM_FACTORY_H__
#define __GTK_ITEM_FACTORY_H__
#include <gtk/gtkwidget.h>
#ifdef __cplusplus
extern "C" {
#pragma }
#endif /* __cplusplus */
typedef void (*GtkPrintFunc) (gpointer func_data,
gchar *str);
typedef void (*GtkItemFactoryCallback) (gpointer callback_data,
guint callback_action,
GtkWidget *widget);
#define GTK_ITEM_FACTORY(object) (GTK_CHECK_CAST (object, gtk_item_factory_get_type (), GtkItemFactory))
#define GTK_ITEM_FACTORY_CLASS(klass) (GTK_CHECK_CLASS_CAST (klass, gtk_item_factory_get_type (), GtkItemFactoryClass))
#define GTK_IS_ITEM_FACTORY(object) (GTK_CHECK_TYPE (object, gtk_item_factory_get_type ()))
typedef struct _GtkItemFactory GtkItemFactory;
typedef struct _GtkItemFactoryClass GtkItemFactoryClass;
typedef struct _GtkItemFactoryEntry GtkItemFactoryEntry;
typedef struct _GtkItemFactoryItem GtkItemFactoryItem;
struct _GtkItemFactory
{
GtkObject object;
gchar *path;
GtkAcceleratorTable *table;
GtkWidget *widget;
};
struct _GtkItemFactoryClass
{
GtkObjectClass object_class;
GHashTable *item_ht;
void (*create_item) (GtkItemFactory *ifactory,
GtkItemFactoryEntry *entry,
gpointer callback_data);
void (*delete_item) (GtkItemFactory *ifactory,
gchar *path);
};
struct _GtkItemFactoryEntry
{
gchar *path;
gchar *accelerator;
GtkItemFactoryCallback callback;
guint callback_action;
/* possible values:
* NULL -> "<Item>"
* "" -> "<Item>"
* "<Item>" -> create a simple item
* "<CheckItem>" -> create a check item
* "<ToggleItem>" -> create a toggle item
* "<RadioItem>" -> create a radio item
* <path> -> path to a radio item to link against
* "<Separator>" -> create a separator
* "<Branch>" -> create an item to hold sub items
* "<LastBranch>" -> create a right justified item to hold sub items
*/
gchar *item_type;
};
struct _GtkItemFactoryItem
{
gchar *path;
gchar *accelerator;
gchar *item_type;
GSList *widgets;
};
GtkType gtk_item_factory_get_type (void);
/* `container_type' currently has to be of gtk_menu_bar_get_type (),
* gtk_menu_get_type () or gtk_option_menu_get_type ().
*/
GtkObject* gtk_item_factory_new (GtkType container_type,
const gchar *path,
GtkAcceleratorTable *table);
void gtk_item_factory_construct (GtkItemFactory *ifactory,
GtkType container_type,
const gchar *path,
GtkAcceleratorTable *table);
/* These functions operate on GtkItemFactoryClass basis.
*/
void gtk_item_factory_parse_rc (const gchar *filename);
void gtk_item_factory_parse_rc_string (const gchar *rc_string);
/* If `ifactory' is passed as `NULL', this function will iterate over all
* hash entries.
*/
void gtk_item_factory_dump_rc (GtkItemFactory *ifactory,
GtkPrintFunc print_func,
gpointer func_data);
GtkItemFactory* gtk_item_factory_from_widget (GtkWidget *widget);
gchar* gtk_item_factory_path_from_widget (GtkWidget *widget);
GtkWidget* gtk_item_factory_get_widget (GtkItemFactory *ifactory,
const gchar *path);
void gtk_item_factory_create_item (GtkItemFactory *ifactory,
GtkItemFactoryEntry *entry,
gpointer callback_data);
void gtk_item_factory_create_items (GtkItemFactory *ifactory,
guint n_entries,
GtkItemFactoryEntry *entries,
gpointer callback_data);
void gtk_item_factory_delete_path (GtkItemFactory *ifactory,
const gchar *path);
void gtk_item_factory_delete_entry (GtkItemFactory *ifactory,
GtkItemFactoryEntry *entry);
void gtk_item_factory_delete_entries (GtkItemFactory *ifactory,
guint n_entries,
GtkItemFactoryEntry *entries);
void gtk_item_factory_popup (GtkItemFactory *ifactory,
guint x,
guint y,
guint mouse_button,
guint32 time);
#ifdef __cplusplus
#pragma {
}
#endif /* __cplusplus */
#endif /* __GTK_ITEM_FACTORY_H__ */
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]