diff --git a/docs/reference/ChangeLog b/docs/reference/ChangeLog index 6f9ff96287..6fa307e068 100644 --- a/docs/reference/ChangeLog +++ b/docs/reference/ChangeLog @@ -1,3 +1,12 @@ +2003-12-08 Federico Mena Quintero + + * gtk/migrating-GtkAction.sgml: New chapter about how to migrate + from gnome-ui/bonobo-ui/etc. to GtkAction. + + * gtk/gtk-docs.sgml: Integrated the above. + + * gtk/Makefile.am (content_files): Added migrating-GtkAction.sgml. + Sun Nov 23 20:59:57 2003 Matthias Clasen * gtk/tree_widget.sgml: Add a missing comma. diff --git a/docs/reference/gtk/Makefile.am b/docs/reference/gtk/Makefile.am index 206f117c3f..c5d3cf9603 100644 --- a/docs/reference/gtk/Makefile.am +++ b/docs/reference/gtk/Makefile.am @@ -85,6 +85,7 @@ content_files = \ changes-2.0.sgml \ compiling.sgml \ framebuffer.sgml \ + migrating-GtkAction.sgml \ migrating-GtkFileChooser.sgml \ objects_grouped.sgml \ question_index.sgml \ diff --git a/docs/reference/gtk/gtk-docs.sgml b/docs/reference/gtk/gtk-docs.sgml index 8cba90713a..221a1c6a79 100644 --- a/docs/reference/gtk/gtk-docs.sgml +++ b/docs/reference/gtk/gtk-docs.sgml @@ -180,6 +180,7 @@ + ]> @@ -545,6 +546,7 @@ that is, GUI components such as GtkButton or >k-migrating-GtkFileChooser; + >k-migrating-GtkAction; diff --git a/docs/reference/gtk/migrating-GtkAction.sgml b/docs/reference/gtk/migrating-GtkAction.sgml new file mode 100644 index 0000000000..a0ed93672b --- /dev/null +++ b/docs/reference/gtk/migrating-GtkAction.sgml @@ -0,0 +1,388 @@ + + + + Federico + Mena-Quintero + +
+ federico@ximian.com +
+
+
+
+ + Migrating from old menu and toolbar systems to GtkAction + + + Prior to GTK+ 2.4, there were several APIs in use to create menus + and toolbars. GTK+ itself included #GtkItemFactory, which was + historically used in the GIMP; libgnomeui provided the gnome-ui + set of macros; libbonoboui provided a complex mechanism to do menu + merging across embedded components. GTK+ 2.4 includes a system + for creating menus and toolbars, with merging of items, based + around the #GtkAction mechanism. + + +
+ Actions and Action Groups + + + A #GtkAction represents an operation that the user can perform + from the menus and toolbars of an application. It is similar to + "verbs" in other menu systems. A #GtkAction has a name, which + is its identifier, and it can have several widgets that + represent it in the user interface. For example, an action for + EditCopy can have a menu item as well as a + toolbar button associated to it. If there is nothing selected + in the document, the application can simply de-sensitize the + EditCopy action; this will cause both the menu + item and the toolbar button to be de-sensitized automatically. + Similarly, whenever the user selects the menu item or the + toolbar button associated to the EditCopy + action, the corresponding #GtkAction object will emit an + "activate" signal. + + + + #GtkActionGroup is simply a group of #GtkAction objects. An + application may want to have several groups: one for global + actions such as "new document", "about", and "exit"; then one + group for each open document with actions specific to the + document, such as "cut", "copy", "paste", and "print". + + + + Normal actions are simply commands, such as + FileSave or EditCopy. Toggle + actions can be active or inactive, such as + FormatBold or ViewShowRulers. + Radio actions define a set of items for which one and only one + can be active at a time, for example, { + ViewHighQuality, + ViewNormalQuality, + ViewLowQuality }. + +
+ +
+ User Interface Manager Object + + + #GtkUIManager is an object that can construct menu and toolbar + widgets from an XML description. These widgets are in turn + associated to corresponding actions and action groups. + + + + #GtkUIManager supports merging of menus and toolbars for + applications that have multiple components, each with separate + sets of commands. For example, a word processor that can embed + images may want to have toolbar buttons for Bold and Italic when + the cursor is on a text block, but Crop and Brightness/Contrast + buttons when the cursor is on an image. These actions, which + change depending on the state of the application, can be merged + and de-merged from a #GtkUIManager as appropriate. + +
+ +
+ Migrating from GnomeUIInfo + + + Prior to GTK+ 2.4, some applications used the GnomeUIInfo + mechanism from + <libgnomeui/gnome-app-helper.h> to + define their menus and toolbars. With it, a program decleres an + array of GnomeUIInfo structures, which + contain information for menu or toolbar items such as their + label, icon, and accelerator key. Then, one calls + gnome_app_fill_menu() or + gnome_app_fill_toolbar(), or one of the + related functions, to create the appropriate widgets based on + these structures. + + + + A downside of this API is that the same structures are used to + pass back pointers to the widgets that got created. This means + that the structures cannot simply be kept around if the program + requires multiple instances of the user interface (e.g. several + windows); each new invocation of + gnome_app_fill_menu() would overwrite the + widget fields of the structures. + + + + Another disadvantage is that there is no automatic way to + synchronize the state of related controls. If there are toolbar + toogle buttons for "Bold", "Italic", "Underline", and also + corresponding menu items under "Format/Bold", etc., one has to + synchronize their toggled states by hand whenever the user + selects any one of them. + + + + Finally, there is no way to do menu and toolbar merging for + applications that require embedded components. + + + + To convert an application that uses GnomeUIInfo into the new + GtkAction mechanism, you need to do several things: + + + + + + Separate your existing GnomeUIInfo entries into normal + actions, toggle actions, and radio actions, and then create a + separate array of #GtkActionEntry structures for each + group. This will allow you to create the necessary + #GtkActionGroup objects. Note that this does not describe + the actual "shape" that your menus and toolbars will have; + it simply defines the set of commands that will appear in them. + + + + + Create an XML description of your menus and toolbars for use + with #GtkUIManager. This defines the actual shape of the + menus and toolbars. + + + + + Port the code that uses gnome-app and gnome-app-helper to + #GtkAction and #GtkUIManager. + + + + + + GnomeUIInfo Example + + + The following code shows a declaration of a simple menu bar to + be used with gnome_app_fill_menu() or + similar. The menu hierarchy looks like this: + + + + + File + + Open + + Exit + + + + + View + + Zoom In + Zoom Out + + [ ] Full Screen + + ( ) High Quality + ( ) Normal Quality + ( ) Low Quality + + + + + +static GnomeUIInfo file_menu_items[] = { + { GNOME_APP_UI_ITEM, "_Open", "Open a file", + open_callback, NULL, NULL, GNOME_APP_PIXMAP_STOCK, GTK_STOCK_OPEN, + 'o', GDK_CONTROL_MASK, NULL }, + { GNOME_APP_UI_SEPARATOR }, + { GNOME_APP_UI_ITEM, "E_xit", "Exit the program", + exit_callback, NULL, NULL, GNOME_APP_PIXMAP_STOCK, GTK_STOCK_QUIT, + 'q', GDK_CONTROL_MASK, NULL}, + { GNOME_APP_UI_ENDOFINFO } +}; + +static GnomeUIInfo view_radio_items[] = { + { GNOME_APP_UI_ITEM, "_High Quality", "Display images in high quality, slow mode", + high_quality_callback, NULL, NULL, GNOME_APP_PIXMAP_NONE, NULL, + 0, 0, NULL }, + { GNOME_APP_UI_ITEM, "_Normal Quality", "Display images in normal quality", + normal_quality_callback, NULL, NULL, GNOME_APP_PIXMAP_NONE, NULL, + 0, 0, NULL }, + { GNOME_APP_UI_ITEM, "_Low Quality", "Display images in low quality, fast mode", + low_quality_callback, NULL, NULL, GNOME_APP_PIXMAP_NONE, NULL, + 0, 0, NULL }, + { GNOME_APP_UI_ENDOFINFO } +}; + +static GnomeUIInfo view_menu_items[] = { + { GNOME_APP_UI_ITEM, "Zoom _In", "Zoom into the image", + zoom_in_callback, NULL, NULL, GNOME_APP_PIXMAP_STOCK, GTK_STOCK_ZOOM_IN, + GDK_PLUS, 0, NULL }, + { GNOME_APP_UI_ITEM, "Zoom _Out", "Zoom away from the image", + zoom_out_callback, NULL, NULL, GNOME_APP_PIXMAP_STOCK, GTK_STOCK_ZOOM_OUT, + GDK_MINUS, 0, NULL }, + { GNOME_APP_UI_SEPARATOR }, + { GNOME_APP_UI_TOGGLEITEM, "_Full Screen", "Switch between full screen and windowed mode", + full_screen_callback, NULL, NULL, GNOME_APP_PIXMAP_NONE, NULL, + GDK_F11, 0, NULL }, + { GNOME_APP_UI_SEPARATOR }, + { GNOME_APP_UI_RADIOITEMS, NULL, NULL, view_radio_items }, + { GNOME_APP_UI_ENDOFINFO } +}; + +static GnomeUIInfo menubar[] = { + { GNOME_APP_UI_SUBTREE, "_File", NULL, file_menu_items }, + { GNOME_APP_UI_SUBTREE, "_View", NULL, view_menu_items }, + { GNOME_APP_UI_ENDOFINFO } +} + + + + + <structname>GtkActionEntry</structname> Structures + + + The following code is the set of actions that are present in + the previous + example. Note that the toggle and radio entries are + separate from normal actions. Also, note that #GtkActionEntry + structures take key names in the format of + gdk_accelerator_parse() rather than key values plus modifiers; + you will have to convert these values by hand. For example, + GDK_F11 with no modifiers is equivalent + to a key name of "F11". Likewise, + "o" with + GDK_CONTROL_MASK is equivalent to + "<ontrol>O". + + + +/* Normal items */ +static GtkActionEntry entries[] = { + { "FileMenu", NULL, "_File" }, + { "ViewMenu", NULL, "_View" }, + { "Open", GTK_STOCK_OPEN, "_Open", "<control>O", "Open a file", open_action_callback }, + { "Exit", GTK_STOCK_OPEN, "E_xit", "<control>Q", "Exit the program", exit_action_callback }, + { "ZoomIn", GTK_STOCK_ZOOM_IN, "Zoom _In", "plus", "Zoom into the image", zoom_in_action_callback }, + { "ZoomOut", GTK_STOCK_ZOOM_OUT, "Zoom _Out", "minus", "Zoom away from the image", zoom_out_action_callback }, +}; + +/* Toggle items */ +static GtkToggleActionEntry toggle_entries[] = { + { "FullScreen", NULL, "_Full Screen", "F11", "Switch between full screen and windowed mode", full_screen_action_callback, FALSE } +}; + +/* Radio items */ +static GtkRadioActionEntry radio_entries[] = { + { "HighQuality", NULL, "_High Quality", NULL, "Display images in high quality, slow mode", 0 }, + { "NormalQuality", NULL, "_Normal Quality", NULL, "Display images in normal quality", 1 }, + { "LowQuality", NULL, "_Low Quality", NULL, "Display images in low quality, fast mode", 2 } +}; + + + + + XML Description + + + After extracting the actions, you will need to create an XML + description of the actual layout of your menus and toolbars + for use with #GtkUIManager. The following code shows a simple + menu bar that corresponds to the previous example. Note + that the File and View + menus have their names specified in the action entries, + not in the XML itself. This is because the XML description + only contains identifiers for the items + in the GUI, rather than human-readable names. + + + +static const char *ui_description = +"<ui>" +" <menubar name="MainMenu">" +" <menu action="FileMenu">" +" <menuitem action="Open"/>" +" <menuitem action="Exit"/>" +" </menu>" +" <menu action="ViewMenu">" +" <menuitem action="ZoomIn"/>" +" <menuitem action="ZoomOut"/>" +" <separator/>" +" <menuitem action="FullScreen"/>" +" <separator/>" +" <menuitem action="HighQuality"/>" +" <menuitem action="NormalQuality"/>" +" <menuitem action="LowQuality"/>" +" </menu>" +" </menubar>" +"</ui>"; + + + + + Creating the Menu Bar + + + In this last example, we will create a #GtkActionGroup based + on the action + entries we created above. We will then create a + #GtkUIManager with the XML + description of the menu layout. We will also extract + the accelerator group and the widgets from the #GtkUIManager + put them into a window. + + + +GtkWidget *window; +GtkWidget *vbox; +GtkWidget *menubar; +GtkActionGroup *action_group; +GtkUIManager *ui_manager; +GtkAccelGroup *accel_group; +GError *error; + +window = gtk_window_new (GTK_WINDOW_TOPLEVEL); + +vbox = gtk_vbox_new (FALSE, 0); +gtk_container_add (GTK_CONTAINER (window), vbox); + +action_group = gtk_action_group_new ("MenuActions"); +gtk_action_group_add_actions (action_group, entries, G_N_ELEMENTS (entries), window); +gtk_action_group_add_toggle_actions (action_group, toggle_entries, G_N_ELEMENTS (toggle_entries), window); +gtk_action_group_add_radio_actions (action_group, radio_entries, G_N_ELEMENTS (radio_entries), 0, radio_action_callback, window); + +ui_manager = gtk_ui_manager_new (); +gtk_ui_manager_insert_action_group (ui_manager, action_group, 0); + +accel_group = gtk_ui_manager_get_accel_group (ui_manager); +gtk_window_add_accel_group (GTK_WINDOW (window), accel_group); + +error = NULL; +if (!gtk_ui_manager_add_ui_from_string (ui_manager, ui_description, -1, &error)) + { + g_message ("building menus failed: %s", error->message); + g_error_free (error); + exit (EXIT_FAILURE); + } + +menubar = gtk_ui_manager_get_widget ("/MainMenu"); +gtk_box_pack_start (GTK_BOX (vbox), menubar, FALSE, FALSE, 0); + +gtk_widget_show_all (window); + + +
+ +
+ +