X-Git-Url: http://pileus.org/git/?a=blobdiff_plain;f=gtk%2Fgtkuimanager.c;h=75189aac3ecc695ec664994f695a554f1f5c795c;hb=3c8e1c92a85b2e41161698f141747ced2c574f32;hp=4b0b0dbac1ba81b88008817a644c65d92461b7bc;hpb=e0aa12eb0ab8d20a2bc9de7d89c779d3566ee669;p=~andy%2Fgtk diff --git a/gtk/gtkuimanager.c b/gtk/gtkuimanager.c index 4b0b0dbac..75189aac3 100644 --- a/gtk/gtkuimanager.c +++ b/gtk/gtkuimanager.c @@ -14,9 +14,7 @@ * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public - * License along with the Gnome Library; see the file COPYING.LIB. If not, - * write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. + * License along with this library. If not, see . */ /* @@ -38,16 +36,276 @@ #include "gtkintl.h" #include "gtkmarshalers.h" #include "gtkmenu.h" +#include "gtkmenushellprivate.h" #include "gtkmenubar.h" #include "gtkmenutoolbutton.h" #include "gtkseparatormenuitem.h" #include "gtkseparatortoolitem.h" -#include "gtktearoffmenuitem.h" #include "gtktoolbar.h" -#include "gtkuimanager.h" #include "gtkwindow.h" #include "gtkprivate.h" +#undef GDK_DEPRECATED +#undef GDK_DEPRECATED_FOR +#define GDK_DEPRECATED +#define GDK_DEPRECATED_FOR(f) + +#include "gtkuimanager.h" +#include "deprecated/gtktearoffmenuitem.h" + +/** + * SECTION:gtkuimanager + * @Short_description: Constructing menus and toolbars from an XML description + * @Title: GtkUIManager + * @See_also:#GtkBuilder + * + * A #GtkUIManager constructs a user interface (menus and toolbars) from + * one or more UI definitions, which reference actions from one or more + * action groups. + * + * + * UI Definitions + * + * The UI definitions are specified in an XML format which can be + * roughly described by the following DTD. + * + * + * Do not confuse the GtkUIManager UI Definitions described here with + * the similarly named GtkBuilder UI + * Definitions. + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * ]]> + * + * There are some additional restrictions beyond those specified in the + * DTD, e.g. every toolitem must have a toolbar in its anchestry and + * every menuitem must have a menubar or popup in its anchestry. Since + * a #GMarkup parser is used to parse the UI description, it must not only + * be valid XML, but valid #GMarkup. + * + * If a name is not specified, it defaults to the action. If an action is + * not specified either, the element name is used. The name and action + * attributes must not contain '/' characters after parsing (since that + * would mess up path lookup) and must be usable as XML attributes when + * enclosed in doublequotes, thus they must not '"' characters or references + * to the " entity. + * + * + * A UI definition + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * ]]> + * + * + * The constructed widget hierarchy is very similar to the element tree + * of the XML, with the exception that placeholders are merged into their + * parents. The correspondence of XML elements to widgets should be + * almost obvious: + * + * + * menubar + * a #GtkMenuBar + * + * + * toolbar + * a #GtkToolbar + * + * + * popup + * a toplevel #GtkMenu + * + * + * menu + * a #GtkMenu attached to a menuitem + * + * + * menuitem + * a #GtkMenuItem subclass, the exact type depends on the + * action + * + * + * toolitem + * a #GtkToolItem subclass, the exact type depends on the + * action. Note that toolitem elements may contain a menu element, but only + * if their associated action specifies a #GtkMenuToolButton as proxy. + * + * + * separator + * a #GtkSeparatorMenuItem or + * #GtkSeparatorToolItem + * + * + * accelerator + * a keyboard accelerator + * + * + * + * The "position" attribute determines where a constructed widget is positioned + * wrt. to its siblings in the partially constructed tree. If it is + * "top", the widget is prepended, otherwise it is appended. + * + * + * + * UI Merging + * + * The most remarkable feature of #GtkUIManager is that it can overlay a set + * of menuitems and toolitems over another one, and demerge them later. + * + * Merging is done based on the names of the XML elements. Each element is + * identified by a path which consists of the names of its anchestors, separated + * by slashes. For example, the menuitem named "Left" in the example above + * has the path /ui/menubar/JustifyMenu/Left and the + * toolitem with the same name has path + * /ui/toolbar1/JustifyToolItems/Left. + * + * + * + * Accelerators + * + * Every action has an accelerator path. Accelerators are installed together with + * menuitem proxies, but they can also be explicitly added with <accelerator> + * elements in the UI definition. This makes it possible to have accelerators for + * actions even if they have no visible proxies. + * + * + * + * Smart Separators + * + * The separators created by #GtkUIManager are "smart", i.e. they do not show up + * in the UI unless they end up between two visible menu or tool items. Separators + * which are located at the very beginning or end of the menu or toolbar + * containing them, or multiple separators next to each other, are hidden. This + * is a useful feature, since the merging of UI elements from multiple sources + * can make it hard or impossible to determine in advance whether a separator + * will end up in such an unfortunate position. + * + * For separators in toolbars, you can set expand="true" to + * turn them from a small, visible separator to an expanding, invisible one. + * Toolitems following an expanding separator are effectively right-aligned. + * + * + * + * Empty Menus + * + * Submenus pose similar problems to separators inconnection with merging. It is + * impossible to know in advance whether they will end up empty after merging. + * #GtkUIManager offers two ways to treat empty submenus: + * + * + * make them disappear by hiding the menu item they're attached to + * + * + * add an insensitive "Empty" item + * + * + * The behaviour is chosen based on the "hide_if_empty" property of the action + * to which the submenu is associated. + * + * + * + * GtkUIManager as GtkBuildable + * + * The GtkUIManager implementation of the GtkBuildable interface accepts + * GtkActionGroup objects as <child> elements in UI definitions. + * + * A GtkUIManager UI definition as described above can be embedded in + * an GtkUIManager <object> element in a GtkBuilder UI definition. + * + * The widgets that are constructed by a GtkUIManager can be embedded in + * other parts of the constructed user interface with the help of the + * "constructor" attribute. See the example below. + * + * + * An embedded GtkUIManager UI definition + * + * + * + * + * + * _File + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * ]]> + * + * + * + */ + + #undef DEBUG_UI_MANAGER typedef enum @@ -167,6 +425,8 @@ static void gtk_ui_manager_buildable_custom_tag_end (GtkBuildable *buildab GObject *child, const gchar *tagname, gpointer *data); +static void gtk_ui_manager_do_set_add_tearoffs (GtkUIManager *manager, + gboolean add_tearoffs); @@ -217,6 +477,9 @@ gtk_ui_manager_class_init (GtkUIManagerClass *klass) * menus never have tearoff menu items. * * Since: 2.4 + * + * Deprecated: 3.4: Tearoff menus are deprecated and should not + * be used in newly written code. */ g_object_class_install_property (gobject_class, PROP_ADD_TEAROFFS, @@ -224,7 +487,7 @@ gtk_ui_manager_class_init (GtkUIManagerClass *klass) P_("Add tearoffs to menus"), P_("Whether tearoff menu items should be added to menus"), FALSE, - GTK_PARAM_READWRITE)); + GTK_PARAM_READWRITE | G_PARAM_DEPRECATED)); g_object_class_install_property (gobject_class, PROP_UI, @@ -420,9 +683,7 @@ gtk_ui_manager_finalize (GObject *object) g_node_destroy (manager->private_data->root_node); manager->private_data->root_node = NULL; - g_list_foreach (manager->private_data->action_groups, - (GFunc) g_object_unref, NULL); - g_list_free (manager->private_data->action_groups); + g_list_free_full (manager->private_data->action_groups, g_object_unref); manager->private_data->action_groups = NULL; g_object_unref (manager->private_data->accel_group); @@ -453,7 +714,6 @@ gtk_ui_manager_buildable_add_child (GtkBuildable *buildable, pos = g_list_length (manager->private_data->action_groups); - g_object_ref (child); gtk_ui_manager_insert_action_group (manager, GTK_ACTION_GROUP (child), pos); @@ -517,7 +777,7 @@ gtk_ui_manager_set_property (GObject *object, switch (prop_id) { case PROP_ADD_TEAROFFS: - gtk_ui_manager_set_add_tearoffs (manager, g_value_get_boolean (value)); + gtk_ui_manager_do_set_add_tearoffs (manager, g_value_get_boolean (value)); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); @@ -610,6 +870,9 @@ gtk_ui_manager_new (void) * Return value: whether tearoff menu items are added * * Since: 2.4 + * + * Deprecated: 3.4: Tearoff menus are deprecated and should not + * be used in newly written code. **/ gboolean gtk_ui_manager_get_add_tearoffs (GtkUIManager *manager) @@ -632,19 +895,29 @@ gtk_ui_manager_get_add_tearoffs (GtkUIManager *manager) * menus never have tearoff menu items. * * Since: 2.4 + * + * Deprecated: 3.4: Tearoff menus are deprecated and should not + * be used in newly written code. **/ -void +void gtk_ui_manager_set_add_tearoffs (GtkUIManager *manager, - gboolean add_tearoffs) + gboolean add_tearoffs) { g_return_if_fail (GTK_IS_UI_MANAGER (manager)); + gtk_ui_manager_do_set_add_tearoffs (manager, add_tearoffs); +} + +static void +gtk_ui_manager_do_set_add_tearoffs (GtkUIManager *manager, + gboolean add_tearoffs) +{ add_tearoffs = add_tearoffs != FALSE; if (add_tearoffs != manager->private_data->add_tearoffs) { manager->private_data->add_tearoffs = add_tearoffs; - + dirty_all_nodes (manager); g_object_notify (G_OBJECT (manager), "add-tearoffs"); @@ -695,6 +968,10 @@ cb_proxy_post_activate (GtkActionGroup *group, * with @manager. Actions in earlier groups hide actions with the same * name in later groups. * + * If @pos is larger than the number of action groups in @manager, or + * negative, @action_group will be inserted at the end of the internal + * list. + * * Since: 2.4 **/ void @@ -1118,18 +1395,16 @@ static gboolean free_node (GNode *node) { Node *info = NODE_INFO (node); - - g_list_foreach (info->uifiles, (GFunc) node_ui_reference_free, NULL); - g_list_free (info->uifiles); - if (info->action) - g_object_unref (info->action); - if (info->proxy) - g_object_unref (info->proxy); - if (info->extra) - g_object_unref (info->extra); - g_free (info->name); + g_list_free_full (info->uifiles, node_ui_reference_free); + info->uifiles = NULL; + + g_clear_object (&info->action); + g_clear_object (&info->proxy); + g_clear_object (&info->extra); + g_clear_pointer (&info->name, g_free); g_slice_free (Node, info); + node->data = NULL; return FALSE; } @@ -1699,7 +1974,7 @@ gtk_ui_manager_add_ui_from_string (GtkUIManager *manager, /** * gtk_ui_manager_add_ui_from_file: * @manager: a #GtkUIManager object - * @filename: the name of the file to parse + * @filename: (type filename): the name of the file to parse * @error: return location for an error * * Parses a file containing a UI definition and @@ -1731,6 +2006,41 @@ gtk_ui_manager_add_ui_from_file (GtkUIManager *manager, return res; } +/** + * gtk_ui_manager_add_ui_from_resource: + * @manager: a #GtkUIManager object + * @resource_path: the resource path of the file to parse + * @error: return location for an error + * + * Parses a resource file containing a UI definition and + * merges it with the current contents of @manager. + * + * Return value: The merge id for the merged UI. The merge id can be used + * to unmerge the UI with gtk_ui_manager_remove_ui(). If an error occurred, + * the return value is 0. + * + * Since: 3.4 + **/ +guint +gtk_ui_manager_add_ui_from_resource (GtkUIManager *manager, + const gchar *resource_path, + GError **error) +{ + GBytes *data; + guint res; + + g_return_val_if_fail (GTK_IS_UI_MANAGER (manager), 0); + + data = g_resources_lookup_data (resource_path, 0, error); + if (data == NULL) + return 0; + + res = add_ui_from_string (manager, g_bytes_get_data (data, NULL), g_bytes_get_size (data), FALSE, error); + g_bytes_unref (data); + + return res; +} + /** * gtk_ui_manager_add_ui: * @manager: a #GtkUIManager @@ -1955,9 +2265,9 @@ get_action_by_name (GtkUIManager *merge, } static gboolean -find_menu_position (GNode *node, - GtkWidget **menushell_p, - gint *pos_p) +find_menu_position (GNode *node, + GtkWidget **menushell_p, + gint *pos_p) { GtkWidget *menushell; gint pos = 0; @@ -1998,7 +2308,7 @@ find_menu_position (GNode *node, case NODE_TYPE_MENU_PLACEHOLDER: menushell = gtk_widget_get_parent (NODE_INFO (parent)->proxy); g_return_val_if_fail (GTK_IS_MENU_SHELL (menushell), FALSE); - pos = g_list_index (GTK_MENU_SHELL (menushell)->children, + pos = g_list_index (GTK_MENU_SHELL (menushell)->priv->children, NODE_INFO (parent)->proxy) + 1; break; default: @@ -2025,7 +2335,7 @@ find_menu_position (GNode *node, if (!GTK_IS_MENU_SHELL (menushell)) return FALSE; - pos = g_list_index (GTK_MENU_SHELL (menushell)->children, prev_child) + 1; + pos = g_list_index (GTK_MENU_SHELL (menushell)->priv->children, prev_child) + 1; } if (menushell_p) @@ -2105,50 +2415,6 @@ find_toolbar_position (GNode *node, return TRUE; } -/** - * _gtk_menu_is_empty: - * @menu: (allow-none): a #GtkMenu or %NULL - * - * Determines whether @menu is empty. A menu is considered empty if it - * the only visible children are tearoff menu items or "filler" menu - * items which were inserted to mark the menu as empty. - * - * This function is used by #GtkAction. - * - * Return value: whether @menu is empty. - **/ -gboolean -_gtk_menu_is_empty (GtkWidget *menu) -{ - GList *children, *cur; - gboolean result = TRUE; - - g_return_val_if_fail (menu == NULL || GTK_IS_MENU (menu), TRUE); - - if (!menu) - return FALSE; - - children = gtk_container_get_children (GTK_CONTAINER (menu)); - - cur = children; - while (cur) - { - if (gtk_widget_get_visible (cur->data)) - { - if (!GTK_IS_TEAROFF_MENU_ITEM (cur->data) && - !g_object_get_data (cur->data, "gtk-empty-menu-item")) - { - result = FALSE; - break; - } - } - cur = cur->next; - } - g_list_free (children); - - return result; -} - enum { SEPARATOR_MODE_SMART, SEPARATOR_MODE_VISIBLE,