Compare commits

...

21 Commits

Author SHA1 Message Date
Ryan Lortie
4ca9f40769 GtkMenuTrackerItem: track submenu shown state
Before, the best you could do is request submenu shown and then just
show the submenu.  It's now possible to track when the application tells
you that it has become ready.
2013-05-13 09:22:39 -04:00
Ryan Lortie
26e5e44dc6 GtkMenuTracker: add new_from_item_submenu()
Creates a menu tracker for the submenu of an existing item, filling in
about half of the parameters for the new tracker from the correct values
in the menuitem.

Add also a "has-submenu" boolean property so implementations can just
use this to check if they should do the submenu, without having to
handle a GMenuModel at all.
2013-05-10 14:52:59 -04:00
Ryan Lortie
c2b9d3f5db fix indentation in gtkmenutracker.h 2013-05-10 14:52:58 -04:00
Jasper St. Pierre
cbc844e7ca menushell: Drop support for all items but label for submenus 2013-05-10 14:52:58 -04:00
Jasper St. Pierre
c818cc431a menushell: Rearrange and fix indentation 2013-05-10 14:52:58 -04:00
Jasper St. Pierre
c1eeb96126 Add more introspection fixes 2013-05-10 14:52:58 -04:00
Jasper St. Pierre
0d05a8f37a Add some more introspection / doc fixes 2013-05-10 14:52:58 -04:00
Jasper St. Pierre
39e99b0987 docs: Fix section names
for the new class names
2013-05-10 14:52:58 -04:00
Jasper St. Pierre
2258dd9a75 gtkactionmuxer: Fix introspection issues 2013-05-10 14:52:58 -04:00
Ryan Lortie
6b394b89ba Action/menu stuff: remove G_GNUC_INTERNAL use
We don't need this anymore with Gtk's new export handling and it's
causing trouble for other users of these files.
2013-05-10 14:52:58 -04:00
Ryan Lortie
9e9bccbaaf Change include style for another file
The shell wants to transplant our GtkActionObserver/GtkActionObservable
code now as well, so change to ""-style #includes there.
2013-05-10 14:52:57 -04:00
Ryan Lortie
ab2129016b stop abusing GLib's namespace
Rename our internal GActionMuxer, GActionObserver and GActionObservable
classes and interfaces to have names in our own namespace.

These classes were originally intended for GIO but turned out to be too
special-purpose to be useful there, so we never made them public API but
have just been copying them around (without bothering to properly rename
them).  Now that other people will be copying them out of Gtk, it's even
more important to prevent this namespace abuse from spreading further.
2013-05-10 14:52:57 -04:00
Ryan Lortie
357a390fe9 GtkMenuTrackerItem: clean up "role" a bit
This property was combining something static (item is separator?) with
something dynamic (which state indicator shall we draw?).  Split that
out by making is_separator a separate property and clarify things a bit
by renaming the "toggle" role to "check".
2013-05-10 14:52:57 -04:00
Ryan Lortie
691b37adb2 Revert "GtkMenuTracker: become a proper GObject"
This reverts commit df502861bd09ef269c5ed2edd95ac55852bee06e.

It turns out that Jasper is happier wrapping this object than using it
directly which means we can avoid some of the overhead when using it
inside of Gtk as well.
2013-05-10 14:52:57 -04:00
Ryan Lortie
972374cc30 GtkMenuTracker: Change #include style to ""
The #include <gtk/...> lines were causing trouble for Jasper as he tried
to copy/paste this code into gnome-shell, so switch to using "" instead.
2013-05-10 14:52:57 -04:00
Ryan Lortie
2869f3c492 Fix a leak in GtkMenuTrackerItem 2013-05-10 14:52:57 -04:00
Ryan Lortie
7520eb6996 Fix logic error in GtkMenuTrackerItem 2013-05-10 14:52:57 -04:00
Ryan Lortie
7d3b8ad9bc GtkMenuTrackerItem: Unbreak accels
Forgot to port this one small part over.  Add it back.
2013-05-10 14:52:57 -04:00
Ryan Lortie
a96fc95d6d GtkMenuTracker: become a proper GObject
Turn GtkMenuTracker into a GObject with "insert" and "remove" signals
for the sake of accessibility from language bindings.
2013-05-10 14:52:57 -04:00
Ryan Lortie
81845aded9 add GtkMenuTrackerItem
Add a new class, GtkMenuTrackerItem that represents a menu item, to be
used with GtkMenuTracker.

GtkMenuTracker's insert callback now works in terms of this new type
(instead of passing reference to the model and an index to the item).

GtkMenuShell now handles all of the binding tasks internally, mostly
through the use of property bindings.  Having bindings for the label and
visibility attributes, in partiular, will help with supporting upcoming
extensions to GMenuModel.

GtkModelMenu has been reduced to a helper class that has nothing to do
with GMenuModel.  It represents something closer to an "ideal" API for
GtkMenuItem if we didn't have compatibility concerns (eg: not emitting
"activate" when setting toggle state, no separate subclasses per menu
item type, supporting icons, etc.) Improvements to GtkMenuItem could
eventually shrink the size of this class or remove the need for it
entirely.

Some GtkActionHelper functionality has been duplicated in
GtkMenuTracker, which is suboptimal.  The duplication exists so that
other codebases (such as Unity and gnome-shell) can reuse the
GtkMenuTracker code, whereas GtkActionHelper is very much tied to
GtkWidget.  Supporting binding arbitrary GtkWidgets to actions vs.
supporting the full range of GMenuModel features for menu items turns
out to be two overlapping but not entirely similar problems.  Some of
the duplication (such as roles) can be removed from GtkActionHelper once
Gtk's internal Mac OS menubar support is ported to GtkMenuTracker.

The intent to reuse the code outside of Gtk is also the reason for the
unusual treatment of the enum type introduced in this comment.
2013-05-10 14:52:56 -04:00
Ryan Lortie
71e221e51a tests: make GtkMenu test more flexible
We were using gtk_menu_item_get_label() from a testcase to determine the
label associated with a menu item.  Future changes to GtkModelMenuItem
will cause this to stop working, so try a bit harder to find a label
inside of the item.
2013-05-10 14:52:56 -04:00
21 changed files with 1760 additions and 807 deletions

View File

@@ -402,9 +402,9 @@ gtk_private_type_h_sources = \
# GTK+ header files that don't get installed
gtk_private_h_sources = \
gactionmuxer.h \
gactionobserver.h \
gactionobservable.h \
gtkactionmuxer.h \
gtkactionobserver.h \
gtkactionobservable.h \
gtkapplicationprivate.h \
gtkaccelgroupprivate.h \
gtkaccelmapprivate.h \
@@ -497,6 +497,7 @@ gtk_private_h_sources = \
gtkmenuitemprivate.h \
gtkmenushellprivate.h \
gtkmenutracker.h \
gtkmenutrackeritem.h \
gtkmnemonichash.h \
gtkmodelmenuitem.h \
gtkmodifierstyle.h \
@@ -584,9 +585,9 @@ deprecated_c_sources = \
gtk_base_c_sources = \
$(deprecated_c_sources) \
gactionmuxer.c \
gactionobserver.c \
gactionobservable.c \
gtkactionmuxer.c \
gtkactionobserver.c \
gtkactionobservable.c \
gtkactionable.c \
gtkquery.c \
gtksearchentry.c \
@@ -764,6 +765,7 @@ gtk_base_c_sources = \
gtkmenuitem.c \
gtkmenushell.c \
gtkmenutracker.c \
gtkmenutrackeritem.c \
gtkmenutoolbutton.c \
gtkmessagedialog.c \
gtkmisc.c \

View File

@@ -1,58 +0,0 @@
/*
* Copyright © 2011 Canonical Limited
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the licence, 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
*
* Author: Ryan Lortie <desrt@desrt.ca>
*/
#ifndef __G_ACTION_MUXER_H__
#define __G_ACTION_MUXER_H__
#include <gio/gio.h>
G_BEGIN_DECLS
#define G_TYPE_ACTION_MUXER (g_action_muxer_get_type ())
#define G_ACTION_MUXER(inst) (G_TYPE_CHECK_INSTANCE_CAST ((inst), \
G_TYPE_ACTION_MUXER, GActionMuxer))
#define G_IS_ACTION_MUXER(inst) (G_TYPE_CHECK_INSTANCE_TYPE ((inst), \
G_TYPE_ACTION_MUXER))
typedef struct _GActionMuxer GActionMuxer;
G_GNUC_INTERNAL
GType g_action_muxer_get_type (void);
G_GNUC_INTERNAL
GActionMuxer * g_action_muxer_new (void);
G_GNUC_INTERNAL
void g_action_muxer_insert (GActionMuxer *muxer,
const gchar *prefix,
GActionGroup *group);
G_GNUC_INTERNAL
void g_action_muxer_remove (GActionMuxer *muxer,
const gchar *prefix);
G_GNUC_INTERNAL
GActionMuxer * g_action_muxer_get_parent (GActionMuxer *muxer);
G_GNUC_INTERNAL
void g_action_muxer_set_parent (GActionMuxer *muxer,
GActionMuxer *parent);
G_END_DECLS
#endif /* __G_ACTION_MUXER_H__ */

View File

@@ -1,62 +0,0 @@
/*
* Copyright © 2011 Canonical Limited
*
* This library is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2 of the
* licence 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
*
* Authors: Ryan Lortie <desrt@desrt.ca>
*/
#ifndef __G_ACTION_OBSERVABLE_H__
#define __G_ACTION_OBSERVABLE_H__
#include <gtk/gactionobserver.h>
G_BEGIN_DECLS
#define G_TYPE_ACTION_OBSERVABLE (g_action_observable_get_type ())
#define G_ACTION_OBSERVABLE(inst) (G_TYPE_CHECK_INSTANCE_CAST ((inst), \
G_TYPE_ACTION_OBSERVABLE, GActionObservable))
#define G_IS_ACTION_OBSERVABLE(inst) (G_TYPE_CHECK_INSTANCE_TYPE ((inst), \
G_TYPE_ACTION_OBSERVABLE))
#define G_ACTION_OBSERVABLE_GET_IFACE(inst) (G_TYPE_INSTANCE_GET_INTERFACE ((inst), \
G_TYPE_ACTION_OBSERVABLE, GActionObservableInterface))
typedef struct _GActionObservableInterface GActionObservableInterface;
struct _GActionObservableInterface
{
GTypeInterface g_iface;
void (* register_observer) (GActionObservable *observable,
const gchar *action_name,
GActionObserver *observer);
void (* unregister_observer) (GActionObservable *observable,
const gchar *action_name,
GActionObserver *observer);
};
G_GNUC_INTERNAL
GType g_action_observable_get_type (void);
G_GNUC_INTERNAL
void g_action_observable_register_observer (GActionObservable *observable,
const gchar *action_name,
GActionObserver *observer);
G_GNUC_INTERNAL
void g_action_observable_unregister_observer (GActionObservable *observable,
const gchar *action_name,
GActionObserver *observer);
G_END_DECLS
#endif /* __G_ACTION_OBSERVABLE_H__ */

View File

@@ -1,88 +0,0 @@
/*
* Copyright © 2011 Canonical Limited
*
* This library is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2 of the
* licence 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
*
* Authors: Ryan Lortie <desrt@desrt.ca>
*/
#ifndef __G_ACTION_OBSERVER_H__
#define __G_ACTION_OBSERVER_H__
#include <gio/gio.h>
G_BEGIN_DECLS
#define G_TYPE_ACTION_OBSERVER (g_action_observer_get_type ())
#define G_ACTION_OBSERVER(inst) (G_TYPE_CHECK_INSTANCE_CAST ((inst), \
G_TYPE_ACTION_OBSERVER, GActionObserver))
#define G_IS_ACTION_OBSERVER(inst) (G_TYPE_CHECK_INSTANCE_TYPE ((inst), \
G_TYPE_ACTION_OBSERVER))
#define G_ACTION_OBSERVER_GET_IFACE(inst) (G_TYPE_INSTANCE_GET_INTERFACE ((inst), \
G_TYPE_ACTION_OBSERVER, GActionObserverInterface))
typedef struct _GActionObserverInterface GActionObserverInterface;
typedef struct _GActionObservable GActionObservable;
typedef struct _GActionObserver GActionObserver;
struct _GActionObserverInterface
{
GTypeInterface g_iface;
void (* action_added) (GActionObserver *observer,
GActionObservable *observable,
const gchar *action_name,
const GVariantType *parameter_type,
gboolean enabled,
GVariant *state);
void (* action_enabled_changed) (GActionObserver *observer,
GActionObservable *observable,
const gchar *action_name,
gboolean enabled);
void (* action_state_changed) (GActionObserver *observer,
GActionObservable *observable,
const gchar *action_name,
GVariant *state);
void (* action_removed) (GActionObserver *observer,
GActionObservable *observable,
const gchar *action_name);
};
G_GNUC_INTERNAL
GType g_action_observer_get_type (void);
G_GNUC_INTERNAL
void g_action_observer_action_added (GActionObserver *observer,
GActionObservable *observable,
const gchar *action_name,
const GVariantType *parameter_type,
gboolean enabled,
GVariant *state);
G_GNUC_INTERNAL
void g_action_observer_action_enabled_changed (GActionObserver *observer,
GActionObservable *observable,
const gchar *action_name,
gboolean enabled);
G_GNUC_INTERNAL
void g_action_observer_action_state_changed (GActionObserver *observer,
GActionObservable *observable,
const gchar *action_name,
GVariant *state);
G_GNUC_INTERNAL
void g_action_observer_action_removed (GActionObserver *observer,
GActionObservable *observable,
const gchar *action_name);
G_END_DECLS
#endif /* __G_ACTION_OBSERVER_H__ */

View File

@@ -18,7 +18,7 @@
*/
#include "gtkactionhelper.h"
#include "gactionobservable.h"
#include "gtkactionobservable.h"
#include "gtkwidget.h"
#include "gtkwidgetprivate.h"
@@ -57,7 +57,7 @@ struct _GtkActionHelper
GtkActionHelperGroup *group;
GActionMuxer *action_context;
GtkActionMuxer *action_context;
gchar *action_name;
GVariant *target;
@@ -81,10 +81,10 @@ enum
static GParamSpec *gtk_action_helper_pspecs[N_PROPS];
static void gtk_action_helper_observer_iface_init (GActionObserverInterface *iface);
static void gtk_action_helper_observer_iface_init (GtkActionObserverInterface *iface);
G_DEFINE_TYPE_WITH_CODE (GtkActionHelper, gtk_action_helper, G_TYPE_OBJECT,
G_IMPLEMENT_INTERFACE (G_TYPE_ACTION_OBSERVER, gtk_action_helper_observer_iface_init))
G_IMPLEMENT_INTERFACE (GTK_TYPE_ACTION_OBSERVER, gtk_action_helper_observer_iface_init))
static void
gtk_action_helper_report_change (GtkActionHelper *helper,
@@ -288,38 +288,38 @@ gtk_action_helper_finalize (GObject *object)
}
static void
gtk_action_helper_observer_action_added (GActionObserver *observer,
GActionObservable *observable,
const gchar *action_name,
const GVariantType *parameter_type,
gboolean enabled,
GVariant *state)
gtk_action_helper_observer_action_added (GtkActionObserver *observer,
GtkActionObservable *observable,
const gchar *action_name,
const GVariantType *parameter_type,
gboolean enabled,
GVariant *state)
{
gtk_action_helper_action_added (GTK_ACTION_HELPER (observer), enabled, parameter_type, state, TRUE);
}
static void
gtk_action_helper_observer_action_enabled_changed (GActionObserver *observer,
GActionObservable *observable,
const gchar *action_name,
gboolean enabled)
gtk_action_helper_observer_action_enabled_changed (GtkActionObserver *observer,
GtkActionObservable *observable,
const gchar *action_name,
gboolean enabled)
{
gtk_action_helper_action_enabled_changed (GTK_ACTION_HELPER (observer), enabled);
}
static void
gtk_action_helper_observer_action_state_changed (GActionObserver *observer,
GActionObservable *observable,
const gchar *action_name,
GVariant *state)
gtk_action_helper_observer_action_state_changed (GtkActionObserver *observer,
GtkActionObservable *observable,
const gchar *action_name,
GVariant *state)
{
gtk_action_helper_action_state_changed (GTK_ACTION_HELPER (observer), state);
}
static void
gtk_action_helper_observer_action_removed (GActionObserver *observer,
GActionObservable *observable,
const gchar *action_name)
gtk_action_helper_observer_action_removed (GtkActionObserver *observer,
GtkActionObservable *observable,
const gchar *action_name)
{
gtk_action_helper_action_removed (GTK_ACTION_HELPER (observer));
}
@@ -345,7 +345,7 @@ gtk_action_helper_class_init (GtkActionHelperClass *class)
}
static void
gtk_action_helper_observer_iface_init (GActionObserverInterface *iface)
gtk_action_helper_observer_iface_init (GtkActionObserverInterface *iface)
{
iface->action_added = gtk_action_helper_observer_action_added;
iface->action_enabled_changed = gtk_action_helper_observer_action_enabled_changed;
@@ -401,7 +401,7 @@ gtk_action_helper_active_window_changed (GObject *object,
gpointer user_data)
{
GtkActionHelper *helper = user_data;
GActionMuxer *parent;
GtkActionMuxer *parent;
if (helper->widget)
g_object_unref (helper->widget);
@@ -415,11 +415,11 @@ gtk_action_helper_active_window_changed (GObject *object,
}
else
{
parent = g_action_muxer_new ();
g_action_muxer_insert (parent, "app", G_ACTION_GROUP (helper->application));
parent = gtk_action_muxer_new ();
gtk_action_muxer_insert (parent, "app", G_ACTION_GROUP (helper->application));
}
g_action_muxer_set_parent (helper->action_context, parent);
gtk_action_muxer_set_parent (helper->action_context, parent);
g_object_unref (parent);
}
@@ -433,7 +433,7 @@ gtk_action_helper_new_with_application (GtkApplication *application)
helper = g_object_new (GTK_TYPE_ACTION_HELPER, NULL);
helper->application = g_object_ref (application);
helper->action_context = g_action_muxer_new ();
helper->action_context = gtk_action_muxer_new ();
g_signal_connect (application, "notify::active-window", G_CALLBACK (gtk_action_helper_active_window_changed), helper);
gtk_action_helper_active_window_changed (NULL, NULL, helper);
@@ -455,17 +455,17 @@ gtk_action_helper_set_action_name (GtkActionHelper *helper,
if (helper->action_name)
{
g_action_observable_unregister_observer (G_ACTION_OBSERVABLE (helper->action_context),
helper->action_name,
G_ACTION_OBSERVER (helper));
gtk_action_observable_unregister_observer (GTK_ACTION_OBSERVABLE (helper->action_context),
helper->action_name,
GTK_ACTION_OBSERVER (helper));
g_free (helper->action_name);
}
helper->action_name = g_strdup (action_name);
g_action_observable_register_observer (G_ACTION_OBSERVABLE (helper->action_context),
helper->action_name,
G_ACTION_OBSERVER (helper));
gtk_action_observable_register_observer (GTK_ACTION_OBSERVABLE (helper->action_context),
helper->action_name,
GTK_ACTION_OBSERVER (helper));
/* Start by recording the current state of our properties so we know
* what notify signals we will need to send.

View File

@@ -19,18 +19,18 @@
#include "config.h"
#include "gactionmuxer.h"
#include "gtkactionmuxer.h"
#include "gactionobservable.h"
#include "gactionobserver.h"
#include "gtkactionobservable.h"
#include "gtkactionobserver.h"
#include <string.h>
/*
* SECTION:gactionmuxer
/**
* SECTION:gtkactionmuxer
* @short_description: Aggregate and monitor several action groups
*
* #GActionMuxer is a #GActionGroup and #GActionObservable that is
* #GtkActionMuxer is a #GActionGroup and #GtkActionObservable that is
* capable of containing other #GActionGroup instances.
*
* The typical use is aggregating all of the actions applicable to a
@@ -42,11 +42,11 @@
* application (such as 'fullscreen').
*
* In this case, each of these action groups could be added to a
* #GActionMuxer with the prefixes "app" and "win", respectively. This
* #GtkActionMuxer with the prefixes "app" and "win", respectively. This
* would expose the actions as "app.quit" and "win.fullscreen" on the
* #GActionGroup interface presented by the #GActionMuxer.
* #GActionGroup interface presented by the #GtkActionMuxer.
*
* Activations and state change requests on the #GActionMuxer are wired
* Activations and state change requests on the #GtkActionMuxer are wired
* through to the underlying action group in the expected way.
*
* This class is typically only used at the site of "consumption" of
@@ -54,23 +54,23 @@
* different objects).
*/
static void g_action_muxer_group_iface_init (GActionGroupInterface *iface);
static void g_action_muxer_observable_iface_init (GActionObservableInterface *iface);
static void gtk_action_muxer_group_iface_init (GActionGroupInterface *iface);
static void gtk_action_muxer_observable_iface_init (GtkActionObservableInterface *iface);
typedef GObjectClass GActionMuxerClass;
typedef GObjectClass GtkActionMuxerClass;
struct _GActionMuxer
struct _GtkActionMuxer
{
GObject parent_instance;
GHashTable *observed_actions;
GHashTable *groups;
GActionMuxer *parent;
GtkActionMuxer *parent;
};
G_DEFINE_TYPE_WITH_CODE (GActionMuxer, g_action_muxer, G_TYPE_OBJECT,
G_IMPLEMENT_INTERFACE (G_TYPE_ACTION_GROUP, g_action_muxer_group_iface_init)
G_IMPLEMENT_INTERFACE (G_TYPE_ACTION_OBSERVABLE, g_action_muxer_observable_iface_init))
G_DEFINE_TYPE_WITH_CODE (GtkActionMuxer, gtk_action_muxer, G_TYPE_OBJECT,
G_IMPLEMENT_INTERFACE (G_TYPE_ACTION_GROUP, gtk_action_muxer_group_iface_init)
G_IMPLEMENT_INTERFACE (GTK_TYPE_ACTION_OBSERVABLE, gtk_action_muxer_observable_iface_init))
enum
{
@@ -83,23 +83,23 @@ static GParamSpec *properties[NUM_PROPERTIES];
typedef struct
{
GActionMuxer *muxer;
GtkActionMuxer *muxer;
GSList *watchers;
gchar *fullname;
} Action;
typedef struct
{
GActionMuxer *muxer;
GtkActionMuxer *muxer;
GActionGroup *group;
gchar *prefix;
gulong handler_ids[4];
} Group;
static void
g_action_muxer_append_group_actions (gpointer key,
gpointer value,
gpointer user_data)
gtk_action_muxer_append_group_actions (gpointer key,
gpointer value,
gpointer user_data)
{
const gchar *prefix = key;
Group *group = value;
@@ -120,9 +120,9 @@ g_action_muxer_append_group_actions (gpointer key,
}
static gchar **
g_action_muxer_list_actions (GActionGroup *action_group)
gtk_action_muxer_list_actions (GActionGroup *action_group)
{
GActionMuxer *muxer = G_ACTION_MUXER (action_group);
GtkActionMuxer *muxer = GTK_ACTION_MUXER (action_group);
GArray *actions;
actions = g_array_new (TRUE, FALSE, sizeof (gchar *));
@@ -130,7 +130,7 @@ g_action_muxer_list_actions (GActionGroup *action_group)
for ( ; muxer != NULL; muxer = muxer->parent)
{
g_hash_table_foreach (muxer->groups,
g_action_muxer_append_group_actions,
gtk_action_muxer_append_group_actions,
actions);
}
@@ -138,9 +138,9 @@ g_action_muxer_list_actions (GActionGroup *action_group)
}
static Group *
g_action_muxer_find_group (GActionMuxer *muxer,
const gchar *full_name,
const gchar **action_name)
gtk_action_muxer_find_group (GtkActionMuxer *muxer,
const gchar *full_name,
const gchar **action_name)
{
const gchar *dot;
gchar *prefix;
@@ -162,90 +162,90 @@ g_action_muxer_find_group (GActionMuxer *muxer,
}
static void
g_action_muxer_action_enabled_changed (GActionMuxer *muxer,
const gchar *action_name,
gboolean enabled)
gtk_action_muxer_action_enabled_changed (GtkActionMuxer *muxer,
const gchar *action_name,
gboolean enabled)
{
Action *action;
GSList *node;
action = g_hash_table_lookup (muxer->observed_actions, action_name);
for (node = action ? action->watchers : NULL; node; node = node->next)
g_action_observer_action_enabled_changed (node->data, G_ACTION_OBSERVABLE (muxer), action_name, enabled);
gtk_action_observer_action_enabled_changed (node->data, GTK_ACTION_OBSERVABLE (muxer), action_name, enabled);
g_action_group_action_enabled_changed (G_ACTION_GROUP (muxer), action_name, enabled);
}
static void
g_action_muxer_group_action_enabled_changed (GActionGroup *action_group,
gtk_action_muxer_group_action_enabled_changed (GActionGroup *action_group,
const gchar *action_name,
gboolean enabled,
gpointer user_data)
{
Group *group = user_data;
gchar *fullname;
fullname = g_strconcat (group->prefix, ".", action_name, NULL);
gtk_action_muxer_action_enabled_changed (group->muxer, fullname, enabled);
g_free (fullname);
}
static void
gtk_action_muxer_parent_action_enabled_changed (GActionGroup *action_group,
const gchar *action_name,
gboolean enabled,
gpointer user_data)
{
GtkActionMuxer *muxer = user_data;
gtk_action_muxer_action_enabled_changed (muxer, action_name, enabled);
}
static void
gtk_action_muxer_action_state_changed (GtkActionMuxer *muxer,
const gchar *action_name,
GVariant *state)
{
Action *action;
GSList *node;
action = g_hash_table_lookup (muxer->observed_actions, action_name);
for (node = action ? action->watchers : NULL; node; node = node->next)
gtk_action_observer_action_state_changed (node->data, GTK_ACTION_OBSERVABLE (muxer), action_name, state);
g_action_group_action_state_changed (G_ACTION_GROUP (muxer), action_name, state);
}
static void
gtk_action_muxer_group_action_state_changed (GActionGroup *action_group,
const gchar *action_name,
gboolean enabled,
GVariant *state,
gpointer user_data)
{
Group *group = user_data;
gchar *fullname;
fullname = g_strconcat (group->prefix, ".", action_name, NULL);
g_action_muxer_action_enabled_changed (group->muxer, fullname, enabled);
gtk_action_muxer_action_state_changed (group->muxer, fullname, state);
g_free (fullname);
}
static void
g_action_muxer_parent_action_enabled_changed (GActionGroup *action_group,
gtk_action_muxer_parent_action_state_changed (GActionGroup *action_group,
const gchar *action_name,
gboolean enabled,
GVariant *state,
gpointer user_data)
{
GActionMuxer *muxer = user_data;
GtkActionMuxer *muxer = user_data;
g_action_muxer_action_enabled_changed (muxer, action_name, enabled);
gtk_action_muxer_action_state_changed (muxer, action_name, state);
}
static void
g_action_muxer_action_state_changed (GActionMuxer *muxer,
const gchar *action_name,
GVariant *state)
{
Action *action;
GSList *node;
action = g_hash_table_lookup (muxer->observed_actions, action_name);
for (node = action ? action->watchers : NULL; node; node = node->next)
g_action_observer_action_state_changed (node->data, G_ACTION_OBSERVABLE (muxer), action_name, state);
g_action_group_action_state_changed (G_ACTION_GROUP (muxer), action_name, state);
}
static void
g_action_muxer_group_action_state_changed (GActionGroup *action_group,
const gchar *action_name,
GVariant *state,
gpointer user_data)
{
Group *group = user_data;
gchar *fullname;
fullname = g_strconcat (group->prefix, ".", action_name, NULL);
g_action_muxer_action_state_changed (group->muxer, fullname, state);
g_free (fullname);
}
static void
g_action_muxer_parent_action_state_changed (GActionGroup *action_group,
const gchar *action_name,
GVariant *state,
gpointer user_data)
{
GActionMuxer *muxer = user_data;
g_action_muxer_action_state_changed (muxer, action_name, state);
}
static void
g_action_muxer_action_added (GActionMuxer *muxer,
const gchar *action_name,
GActionGroup *original_group,
const gchar *orignal_action_name)
gtk_action_muxer_action_added (GtkActionMuxer *muxer,
const gchar *action_name,
GActionGroup *original_group,
const gchar *orignal_action_name)
{
const GVariantType *parameter_type;
gboolean enabled;
@@ -261,8 +261,8 @@ g_action_muxer_action_added (GActionMuxer *muxer,
GSList *node;
for (node = action->watchers; node; node = node->next)
g_action_observer_action_added (node->data,
G_ACTION_OBSERVABLE (muxer),
gtk_action_observer_action_added (node->data,
GTK_ACTION_OBSERVABLE (muxer),
action_name, parameter_type, enabled, state);
if (state)
@@ -273,80 +273,80 @@ g_action_muxer_action_added (GActionMuxer *muxer,
}
static void
g_action_muxer_action_added_to_group (GActionGroup *action_group,
const gchar *action_name,
gpointer user_data)
gtk_action_muxer_action_added_to_group (GActionGroup *action_group,
const gchar *action_name,
gpointer user_data)
{
Group *group = user_data;
gchar *fullname;
fullname = g_strconcat (group->prefix, ".", action_name, NULL);
g_action_muxer_action_added (group->muxer, fullname, action_group, action_name);
gtk_action_muxer_action_added (group->muxer, fullname, action_group, action_name);
g_free (fullname);
}
static void
g_action_muxer_action_added_to_parent (GActionGroup *action_group,
const gchar *action_name,
gpointer user_data)
gtk_action_muxer_action_added_to_parent (GActionGroup *action_group,
const gchar *action_name,
gpointer user_data)
{
GActionMuxer *muxer = user_data;
GtkActionMuxer *muxer = user_data;
g_action_muxer_action_added (muxer, action_name, action_group, action_name);
gtk_action_muxer_action_added (muxer, action_name, action_group, action_name);
}
static void
g_action_muxer_action_removed (GActionMuxer *muxer,
const gchar *action_name)
gtk_action_muxer_action_removed (GtkActionMuxer *muxer,
const gchar *action_name)
{
Action *action;
GSList *node;
action = g_hash_table_lookup (muxer->observed_actions, action_name);
for (node = action ? action->watchers : NULL; node; node = node->next)
g_action_observer_action_removed (node->data, G_ACTION_OBSERVABLE (muxer), action_name);
gtk_action_observer_action_removed (node->data, GTK_ACTION_OBSERVABLE (muxer), action_name);
g_action_group_action_removed (G_ACTION_GROUP (muxer), action_name);
}
static void
g_action_muxer_action_removed_from_group (GActionGroup *action_group,
const gchar *action_name,
gpointer user_data)
gtk_action_muxer_action_removed_from_group (GActionGroup *action_group,
const gchar *action_name,
gpointer user_data)
{
Group *group = user_data;
gchar *fullname;
fullname = g_strconcat (group->prefix, ".", action_name, NULL);
g_action_muxer_action_removed (group->muxer, fullname);
gtk_action_muxer_action_removed (group->muxer, fullname);
g_free (fullname);
}
static void
g_action_muxer_action_removed_from_parent (GActionGroup *action_group,
const gchar *action_name,
gpointer user_data)
gtk_action_muxer_action_removed_from_parent (GActionGroup *action_group,
const gchar *action_name,
gpointer user_data)
{
GActionMuxer *muxer = user_data;
GtkActionMuxer *muxer = user_data;
g_action_muxer_action_removed (muxer, action_name);
gtk_action_muxer_action_removed (muxer, action_name);
}
static gboolean
g_action_muxer_query_action (GActionGroup *action_group,
const gchar *action_name,
gboolean *enabled,
const GVariantType **parameter_type,
const GVariantType **state_type,
GVariant **state_hint,
GVariant **state)
gtk_action_muxer_query_action (GActionGroup *action_group,
const gchar *action_name,
gboolean *enabled,
const GVariantType **parameter_type,
const GVariantType **state_type,
GVariant **state_hint,
GVariant **state)
{
GActionMuxer *muxer = G_ACTION_MUXER (action_group);
GtkActionMuxer *muxer = GTK_ACTION_MUXER (action_group);
Group *group;
const gchar *unprefixed_name;
group = g_action_muxer_find_group (muxer, action_name, &unprefixed_name);
group = gtk_action_muxer_find_group (muxer, action_name, &unprefixed_name);
if (group)
return g_action_group_query_action (group->group, unprefixed_name, enabled,
@@ -361,15 +361,15 @@ g_action_muxer_query_action (GActionGroup *action_group,
}
static void
g_action_muxer_activate_action (GActionGroup *action_group,
const gchar *action_name,
GVariant *parameter)
gtk_action_muxer_activate_action (GActionGroup *action_group,
const gchar *action_name,
GVariant *parameter)
{
GActionMuxer *muxer = G_ACTION_MUXER (action_group);
GtkActionMuxer *muxer = GTK_ACTION_MUXER (action_group);
Group *group;
const gchar *unprefixed_name;
group = g_action_muxer_find_group (muxer, action_name, &unprefixed_name);
group = gtk_action_muxer_find_group (muxer, action_name, &unprefixed_name);
if (group)
g_action_group_activate_action (group->group, unprefixed_name, parameter);
@@ -378,15 +378,15 @@ g_action_muxer_activate_action (GActionGroup *action_group,
}
static void
g_action_muxer_change_action_state (GActionGroup *action_group,
const gchar *action_name,
GVariant *state)
gtk_action_muxer_change_action_state (GActionGroup *action_group,
const gchar *action_name,
GVariant *state)
{
GActionMuxer *muxer = G_ACTION_MUXER (action_group);
GtkActionMuxer *muxer = GTK_ACTION_MUXER (action_group);
Group *group;
const gchar *unprefixed_name;
group = g_action_muxer_find_group (muxer, action_name, &unprefixed_name);
group = gtk_action_muxer_find_group (muxer, action_name, &unprefixed_name);
if (group)
g_action_group_change_action_state (group->group, unprefixed_name, state);
@@ -395,10 +395,10 @@ g_action_muxer_change_action_state (GActionGroup *action_group,
}
static void
g_action_muxer_unregister_internal (Action *action,
gpointer observer)
gtk_action_muxer_unregister_internal (Action *action,
gpointer observer)
{
GActionMuxer *muxer = action->muxer;
GtkActionMuxer *muxer = action->muxer;
GSList **ptr;
for (ptr = &action->watchers; *ptr; ptr = &(*ptr)->next)
@@ -414,20 +414,20 @@ g_action_muxer_unregister_internal (Action *action,
}
static void
g_action_muxer_weak_notify (gpointer data,
GObject *where_the_object_was)
gtk_action_muxer_weak_notify (gpointer data,
GObject *where_the_object_was)
{
Action *action = data;
g_action_muxer_unregister_internal (action, where_the_object_was);
gtk_action_muxer_unregister_internal (action, where_the_object_was);
}
static void
g_action_muxer_register_observer (GActionObservable *observable,
const gchar *name,
GActionObserver *observer)
gtk_action_muxer_register_observer (GtkActionObservable *observable,
const gchar *name,
GtkActionObserver *observer)
{
GActionMuxer *muxer = G_ACTION_MUXER (observable);
GtkActionMuxer *muxer = GTK_ACTION_MUXER (observable);
Action *action;
action = g_hash_table_lookup (muxer->observed_actions, name);
@@ -443,24 +443,24 @@ g_action_muxer_register_observer (GActionObservable *observable,
}
action->watchers = g_slist_prepend (action->watchers, observer);
g_object_weak_ref (G_OBJECT (observer), g_action_muxer_weak_notify, action);
g_object_weak_ref (G_OBJECT (observer), gtk_action_muxer_weak_notify, action);
}
static void
g_action_muxer_unregister_observer (GActionObservable *observable,
const gchar *name,
GActionObserver *observer)
gtk_action_muxer_unregister_observer (GtkActionObservable *observable,
const gchar *name,
GtkActionObserver *observer)
{
GActionMuxer *muxer = G_ACTION_MUXER (observable);
GtkActionMuxer *muxer = GTK_ACTION_MUXER (observable);
Action *action;
action = g_hash_table_lookup (muxer->observed_actions, name);
g_object_weak_unref (G_OBJECT (observer), g_action_muxer_weak_notify, action);
g_action_muxer_unregister_internal (action, observer);
g_object_weak_unref (G_OBJECT (observer), gtk_action_muxer_weak_notify, action);
gtk_action_muxer_unregister_internal (action, observer);
}
static void
g_action_muxer_free_group (gpointer data)
gtk_action_muxer_free_group (gpointer data)
{
Group *group = data;
gint i;
@@ -476,13 +476,13 @@ g_action_muxer_free_group (gpointer data)
}
static void
g_action_muxer_free_action (gpointer data)
gtk_action_muxer_free_action (gpointer data)
{
Action *action = data;
GSList *it;
for (it = action->watchers; it; it = it->next)
g_object_weak_unref (G_OBJECT (it->data), g_action_muxer_weak_notify, action);
g_object_weak_unref (G_OBJECT (it->data), gtk_action_muxer_weak_notify, action);
g_slist_free (action->watchers);
g_free (action->fullname);
@@ -491,51 +491,51 @@ g_action_muxer_free_action (gpointer data)
}
static void
g_action_muxer_finalize (GObject *object)
gtk_action_muxer_finalize (GObject *object)
{
GActionMuxer *muxer = G_ACTION_MUXER (object);
GtkActionMuxer *muxer = GTK_ACTION_MUXER (object);
g_assert_cmpint (g_hash_table_size (muxer->observed_actions), ==, 0);
g_hash_table_unref (muxer->observed_actions);
g_hash_table_unref (muxer->groups);
G_OBJECT_CLASS (g_action_muxer_parent_class)
G_OBJECT_CLASS (gtk_action_muxer_parent_class)
->finalize (object);
}
static void
g_action_muxer_dispose (GObject *object)
gtk_action_muxer_dispose (GObject *object)
{
GActionMuxer *muxer = G_ACTION_MUXER (object);
GtkActionMuxer *muxer = GTK_ACTION_MUXER (object);
if (muxer->parent)
{
g_signal_handlers_disconnect_by_func (muxer->parent, g_action_muxer_action_added_to_parent, muxer);
g_signal_handlers_disconnect_by_func (muxer->parent, g_action_muxer_action_removed_from_parent, muxer);
g_signal_handlers_disconnect_by_func (muxer->parent, g_action_muxer_parent_action_enabled_changed, muxer);
g_signal_handlers_disconnect_by_func (muxer->parent, g_action_muxer_parent_action_state_changed, muxer);
g_signal_handlers_disconnect_by_func (muxer->parent, gtk_action_muxer_action_added_to_parent, muxer);
g_signal_handlers_disconnect_by_func (muxer->parent, gtk_action_muxer_action_removed_from_parent, muxer);
g_signal_handlers_disconnect_by_func (muxer->parent, gtk_action_muxer_parent_action_enabled_changed, muxer);
g_signal_handlers_disconnect_by_func (muxer->parent, gtk_action_muxer_parent_action_state_changed, muxer);
g_clear_object (&muxer->parent);
}
g_hash_table_remove_all (muxer->observed_actions);
G_OBJECT_CLASS (g_action_muxer_parent_class)
G_OBJECT_CLASS (gtk_action_muxer_parent_class)
->dispose (object);
}
static void
g_action_muxer_get_property (GObject *object,
guint property_id,
GValue *value,
GParamSpec *pspec)
gtk_action_muxer_get_property (GObject *object,
guint property_id,
GValue *value,
GParamSpec *pspec)
{
GActionMuxer *muxer = G_ACTION_MUXER (object);
GtkActionMuxer *muxer = GTK_ACTION_MUXER (object);
switch (property_id)
{
case PROP_PARENT:
g_value_set_object (value, g_action_muxer_get_parent (muxer));
g_value_set_object (value, gtk_action_muxer_get_parent (muxer));
break;
default:
@@ -544,17 +544,17 @@ g_action_muxer_get_property (GObject *object,
}
static void
g_action_muxer_set_property (GObject *object,
guint property_id,
const GValue *value,
GParamSpec *pspec)
gtk_action_muxer_set_property (GObject *object,
guint property_id,
const GValue *value,
GParamSpec *pspec)
{
GActionMuxer *muxer = G_ACTION_MUXER (object);
GtkActionMuxer *muxer = GTK_ACTION_MUXER (object);
switch (property_id)
{
case PROP_PARENT:
g_action_muxer_set_parent (muxer, g_value_get_object (value));
gtk_action_muxer_set_parent (muxer, g_value_get_object (value));
break;
default:
@@ -563,48 +563,48 @@ g_action_muxer_set_property (GObject *object,
}
static void
g_action_muxer_init (GActionMuxer *muxer)
gtk_action_muxer_init (GtkActionMuxer *muxer)
{
muxer->observed_actions = g_hash_table_new_full (g_str_hash, g_str_equal, NULL, g_action_muxer_free_action);
muxer->groups = g_hash_table_new_full (g_str_hash, g_str_equal, NULL, g_action_muxer_free_group);
muxer->observed_actions = g_hash_table_new_full (g_str_hash, g_str_equal, NULL, gtk_action_muxer_free_action);
muxer->groups = g_hash_table_new_full (g_str_hash, g_str_equal, NULL, gtk_action_muxer_free_group);
}
static void
g_action_muxer_observable_iface_init (GActionObservableInterface *iface)
gtk_action_muxer_observable_iface_init (GtkActionObservableInterface *iface)
{
iface->register_observer = g_action_muxer_register_observer;
iface->unregister_observer = g_action_muxer_unregister_observer;
iface->register_observer = gtk_action_muxer_register_observer;
iface->unregister_observer = gtk_action_muxer_unregister_observer;
}
static void
g_action_muxer_group_iface_init (GActionGroupInterface *iface)
gtk_action_muxer_group_iface_init (GActionGroupInterface *iface)
{
iface->list_actions = g_action_muxer_list_actions;
iface->query_action = g_action_muxer_query_action;
iface->activate_action = g_action_muxer_activate_action;
iface->change_action_state = g_action_muxer_change_action_state;
iface->list_actions = gtk_action_muxer_list_actions;
iface->query_action = gtk_action_muxer_query_action;
iface->activate_action = gtk_action_muxer_activate_action;
iface->change_action_state = gtk_action_muxer_change_action_state;
}
static void
g_action_muxer_class_init (GObjectClass *class)
gtk_action_muxer_class_init (GObjectClass *class)
{
class->get_property = g_action_muxer_get_property;
class->set_property = g_action_muxer_set_property;
class->finalize = g_action_muxer_finalize;
class->dispose = g_action_muxer_dispose;
class->get_property = gtk_action_muxer_get_property;
class->set_property = gtk_action_muxer_set_property;
class->finalize = gtk_action_muxer_finalize;
class->dispose = gtk_action_muxer_dispose;
properties[PROP_PARENT] = g_param_spec_object ("parent", "Parent",
"The parent muxer",
G_TYPE_ACTION_MUXER,
GTK_TYPE_ACTION_MUXER,
G_PARAM_READWRITE |
G_PARAM_STATIC_STRINGS);
g_object_class_install_properties (class, NUM_PROPERTIES, properties);
}
/*
* g_action_muxer_insert:
* @muxer: a #GActionMuxer
/**
* gtk_action_muxer_insert:
* @muxer: a #GtkActionMuxer
* @prefix: the prefix string for the action group
* @action_group: a #GActionGroup
*
@@ -617,22 +617,22 @@ g_action_muxer_class_init (GObjectClass *class)
* contains an action called "<literal>quit</literal>", then @muxer will
* now contain an action called "<literal>app.quit</literal>".
*
* If any #GActionObservers are registered for actions in the group,
* If any #GtkActionObservers are registered for actions in the group,
* "action_added" notifications will be emitted, as appropriate.
*
* @prefix must not contain a dot ('.').
*/
void
g_action_muxer_insert (GActionMuxer *muxer,
const gchar *prefix,
GActionGroup *action_group)
gtk_action_muxer_insert (GtkActionMuxer *muxer,
const gchar *prefix,
GActionGroup *action_group)
{
gchar **actions;
Group *group;
gint i;
/* TODO: diff instead of ripout and replace */
g_action_muxer_remove (muxer, prefix);
gtk_action_muxer_remove (muxer, prefix);
group = g_slice_new (Group);
group->muxer = muxer;
@@ -643,32 +643,32 @@ g_action_muxer_insert (GActionMuxer *muxer,
actions = g_action_group_list_actions (group->group);
for (i = 0; actions[i]; i++)
g_action_muxer_action_added_to_group (group->group, actions[i], group);
gtk_action_muxer_action_added_to_group (group->group, actions[i], group);
g_strfreev (actions);
group->handler_ids[0] = g_signal_connect (group->group, "action-added",
G_CALLBACK (g_action_muxer_action_added_to_group), group);
G_CALLBACK (gtk_action_muxer_action_added_to_group), group);
group->handler_ids[1] = g_signal_connect (group->group, "action-removed",
G_CALLBACK (g_action_muxer_action_removed_from_group), group);
G_CALLBACK (gtk_action_muxer_action_removed_from_group), group);
group->handler_ids[2] = g_signal_connect (group->group, "action-enabled-changed",
G_CALLBACK (g_action_muxer_group_action_enabled_changed), group);
G_CALLBACK (gtk_action_muxer_group_action_enabled_changed), group);
group->handler_ids[3] = g_signal_connect (group->group, "action-state-changed",
G_CALLBACK (g_action_muxer_group_action_state_changed), group);
G_CALLBACK (gtk_action_muxer_group_action_state_changed), group);
}
/*
* g_action_muxer_remove:
* @muxer: a #GActionMuxer
/**
* gtk_action_muxer_remove:
* @muxer: a #GtkActionMuxer
* @prefix: the prefix of the action group to remove
*
* Removes a #GActionGroup from the #GActionMuxer.
* Removes a #GActionGroup from the #GtkActionMuxer.
*
* If any #GActionObservers are registered for actions in the group,
* If any #GtkActionObservers are registered for actions in the group,
* "action_removed" notifications will be emitted, as appropriate.
*/
void
g_action_muxer_remove (GActionMuxer *muxer,
const gchar *prefix)
gtk_action_muxer_remove (GtkActionMuxer *muxer,
const gchar *prefix)
{
Group *group;
@@ -683,49 +683,51 @@ g_action_muxer_remove (GActionMuxer *muxer,
actions = g_action_group_list_actions (group->group);
for (i = 0; actions[i]; i++)
g_action_muxer_action_removed_from_group (group->group, actions[i], group);
gtk_action_muxer_action_removed_from_group (group->group, actions[i], group);
g_strfreev (actions);
g_action_muxer_free_group (group);
gtk_action_muxer_free_group (group);
}
}
/*
* g_action_muxer_new:
/**
* gtk_action_muxer_new:
*
* Creates a new #GActionMuxer.
* Creates a new #GtkActionMuxer.
*/
GActionMuxer *
g_action_muxer_new (void)
GtkActionMuxer *
gtk_action_muxer_new (void)
{
return g_object_new (G_TYPE_ACTION_MUXER, NULL);
return g_object_new (GTK_TYPE_ACTION_MUXER, NULL);
}
/* g_action_muxer_get_parent:
* @muxer: a #GActionMuxer
/**
* gtk_action_muxer_get_parent:
* @muxer: a #GtkActionMuxer
*
* Returns: (transfer-none): the parent of @muxer, or NULL.
* Returns: (transfer none): the parent of @muxer, or NULL.
*/
GActionMuxer *
g_action_muxer_get_parent (GActionMuxer *muxer)
GtkActionMuxer *
gtk_action_muxer_get_parent (GtkActionMuxer *muxer)
{
g_return_val_if_fail (G_IS_ACTION_MUXER (muxer), NULL);
g_return_val_if_fail (GTK_IS_ACTION_MUXER (muxer), NULL);
return muxer->parent;
}
/* g_action_muxer_set_parent:
* @muxer: a #GActionMuxer
* @parent: (allow-none): the new parent #GActionMuxer
/**
* gtk_action_muxer_set_parent:
* @muxer: a #GtkActionMuxer
* @parent: (allow-none): the new parent #GtkActionMuxer
*
* Sets the parent of @muxer to @parent.
*/
void
g_action_muxer_set_parent (GActionMuxer *muxer,
GActionMuxer *parent)
gtk_action_muxer_set_parent (GtkActionMuxer *muxer,
GtkActionMuxer *parent)
{
g_return_if_fail (G_IS_ACTION_MUXER (muxer));
g_return_if_fail (parent == NULL || G_IS_ACTION_MUXER (parent));
g_return_if_fail (GTK_IS_ACTION_MUXER (muxer));
g_return_if_fail (parent == NULL || GTK_IS_ACTION_MUXER (parent));
if (muxer->parent == parent)
return;
@@ -737,13 +739,13 @@ g_action_muxer_set_parent (GActionMuxer *muxer,
actions = g_action_group_list_actions (G_ACTION_GROUP (muxer->parent));
for (it = actions; *it; it++)
g_action_muxer_action_removed (muxer, *it);
gtk_action_muxer_action_removed (muxer, *it);
g_strfreev (actions);
g_signal_handlers_disconnect_by_func (muxer->parent, g_action_muxer_action_added_to_parent, muxer);
g_signal_handlers_disconnect_by_func (muxer->parent, g_action_muxer_action_removed_from_parent, muxer);
g_signal_handlers_disconnect_by_func (muxer->parent, g_action_muxer_parent_action_enabled_changed, muxer);
g_signal_handlers_disconnect_by_func (muxer->parent, g_action_muxer_parent_action_state_changed, muxer);
g_signal_handlers_disconnect_by_func (muxer->parent, gtk_action_muxer_action_added_to_parent, muxer);
g_signal_handlers_disconnect_by_func (muxer->parent, gtk_action_muxer_action_removed_from_parent, muxer);
g_signal_handlers_disconnect_by_func (muxer->parent, gtk_action_muxer_parent_action_enabled_changed, muxer);
g_signal_handlers_disconnect_by_func (muxer->parent, gtk_action_muxer_parent_action_state_changed, muxer);
g_object_unref (muxer->parent);
}
@@ -759,17 +761,17 @@ g_action_muxer_set_parent (GActionMuxer *muxer,
actions = g_action_group_list_actions (G_ACTION_GROUP (muxer->parent));
for (it = actions; *it; it++)
g_action_muxer_action_added (muxer, *it, G_ACTION_GROUP (muxer->parent), *it);
gtk_action_muxer_action_added (muxer, *it, G_ACTION_GROUP (muxer->parent), *it);
g_strfreev (actions);
g_signal_connect (muxer->parent, "action-added",
G_CALLBACK (g_action_muxer_action_added_to_parent), muxer);
G_CALLBACK (gtk_action_muxer_action_added_to_parent), muxer);
g_signal_connect (muxer->parent, "action-removed",
G_CALLBACK (g_action_muxer_action_removed_from_parent), muxer);
G_CALLBACK (gtk_action_muxer_action_removed_from_parent), muxer);
g_signal_connect (muxer->parent, "action-enabled-changed",
G_CALLBACK (g_action_muxer_parent_action_enabled_changed), muxer);
G_CALLBACK (gtk_action_muxer_parent_action_enabled_changed), muxer);
g_signal_connect (muxer->parent, "action-state-changed",
G_CALLBACK (g_action_muxer_parent_action_state_changed), muxer);
G_CALLBACK (gtk_action_muxer_parent_action_state_changed), muxer);
}
g_object_notify_by_pspec (G_OBJECT (muxer), properties[PROP_PARENT]);

52
gtk/gtkactionmuxer.h Normal file
View File

@@ -0,0 +1,52 @@
/*
* Copyright © 2011 Canonical Limited
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the licence, 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
*
* Author: Ryan Lortie <desrt@desrt.ca>
*/
#ifndef __GTK_ACTION_MUXER_H__
#define __GTK_ACTION_MUXER_H__
#include <gio/gio.h>
G_BEGIN_DECLS
#define GTK_TYPE_ACTION_MUXER (gtk_action_muxer_get_type ())
#define GTK_ACTION_MUXER(inst) (G_TYPE_CHECK_INSTANCE_CAST ((inst), \
GTK_TYPE_ACTION_MUXER, GtkActionMuxer))
#define GTK_IS_ACTION_MUXER(inst) (G_TYPE_CHECK_INSTANCE_TYPE ((inst), \
GTK_TYPE_ACTION_MUXER))
typedef struct _GtkActionMuxer GtkActionMuxer;
GType gtk_action_muxer_get_type (void);
GtkActionMuxer * gtk_action_muxer_new (void);
void gtk_action_muxer_insert (GtkActionMuxer *muxer,
const gchar *prefix,
GActionGroup *action_group);
void gtk_action_muxer_remove (GtkActionMuxer *muxer,
const gchar *prefix);
GtkActionMuxer * gtk_action_muxer_get_parent (GtkActionMuxer *muxer);
void gtk_action_muxer_set_parent (GtkActionMuxer *muxer,
GtkActionMuxer *parent);
G_END_DECLS
#endif /* __GTK_ACTION_MUXER_H__ */

View File

@@ -19,46 +19,46 @@
#include "config.h"
#include "gactionobservable.h"
#include "gtkactionobservable.h"
G_DEFINE_INTERFACE (GActionObservable, g_action_observable, G_TYPE_OBJECT)
G_DEFINE_INTERFACE (GtkActionObservable, gtk_action_observable, G_TYPE_OBJECT)
/*
* SECTION:gactionobserable
* SECTION:gtkactionobserable
* @short_description: an interface implemented by objects that report
* changes to actions
*/
void
g_action_observable_default_init (GActionObservableInterface *iface)
gtk_action_observable_default_init (GtkActionObservableInterface *iface)
{
}
/*
* g_action_observable_register_observer:
* @observable: a #GActionObservable
/**
* gtk_action_observable_register_observer:
* @observable: a #GtkActionObservable
* @action_name: the name of the action
* @observer: the #GActionObserver to which the events will be reported
* @observer: the #GtkActionObserver to which the events will be reported
*
* Registers @observer as being interested in changes to @action_name on
* @observable.
*/
void
g_action_observable_register_observer (GActionObservable *observable,
const gchar *action_name,
GActionObserver *observer)
gtk_action_observable_register_observer (GtkActionObservable *observable,
const gchar *action_name,
GtkActionObserver *observer)
{
g_return_if_fail (G_IS_ACTION_OBSERVABLE (observable));
g_return_if_fail (GTK_IS_ACTION_OBSERVABLE (observable));
G_ACTION_OBSERVABLE_GET_IFACE (observable)
GTK_ACTION_OBSERVABLE_GET_IFACE (observable)
->register_observer (observable, action_name, observer);
}
/*
* g_action_observable_unregister_observer:
* @observable: a #GActionObservable
/**
* gtk_action_observable_unregister_observer:
* @observable: a #GtkActionObservable
* @action_name: the name of the action
* @observer: the #GActionObserver to which the events will be reported
* @observer: the #GtkActionObserver to which the events will be reported
*
* Removes the registration of @observer as being interested in changes
* to @action_name on @observable.
@@ -67,12 +67,12 @@ g_action_observable_register_observer (GActionObservable *observable,
* unregistered an equal number of times.
*/
void
g_action_observable_unregister_observer (GActionObservable *observable,
const gchar *action_name,
GActionObserver *observer)
gtk_action_observable_unregister_observer (GtkActionObservable *observable,
const gchar *action_name,
GtkActionObserver *observer)
{
g_return_if_fail (G_IS_ACTION_OBSERVABLE (observable));
g_return_if_fail (GTK_IS_ACTION_OBSERVABLE (observable));
G_ACTION_OBSERVABLE_GET_IFACE (observable)
GTK_ACTION_OBSERVABLE_GET_IFACE (observable)
->unregister_observer (observable, action_name, observer);
}

60
gtk/gtkactionobservable.h Normal file
View File

@@ -0,0 +1,60 @@
/*
* Copyright © 2011 Canonical Limited
*
* This library is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2 of the
* licence 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
*
* Authors: Ryan Lortie <desrt@desrt.ca>
*/
#ifndef __GTK_ACTION_OBSERVABLE_H__
#define __GTK_ACTION_OBSERVABLE_H__
#include "gtkactionobserver.h"
G_BEGIN_DECLS
#define GTK_TYPE_ACTION_OBSERVABLE (gtk_action_observable_get_type ())
#define GTK_ACTION_OBSERVABLE(inst) (G_TYPE_CHECK_INSTANCE_CAST ((inst), \
GTK_TYPE_ACTION_OBSERVABLE, GtkActionObservable))
#define GTK_IS_ACTION_OBSERVABLE(inst) (G_TYPE_CHECK_INSTANCE_TYPE ((inst), \
GTK_TYPE_ACTION_OBSERVABLE))
#define GTK_ACTION_OBSERVABLE_GET_IFACE(inst) (G_TYPE_INSTANCE_GET_INTERFACE ((inst), \
GTK_TYPE_ACTION_OBSERVABLE, \
GtkActionObservableInterface))
typedef struct _GtkActionObservableInterface GtkActionObservableInterface;
struct _GtkActionObservableInterface
{
GTypeInterface g_iface;
void (* register_observer) (GtkActionObservable *observable,
const gchar *action_name,
GtkActionObserver *observer);
void (* unregister_observer) (GtkActionObservable *observable,
const gchar *action_name,
GtkActionObserver *observer);
};
GType gtk_action_observable_get_type (void);
void gtk_action_observable_register_observer (GtkActionObservable *observable,
const gchar *action_name,
GtkActionObserver *observer);
void gtk_action_observable_unregister_observer (GtkActionObservable *observable,
const gchar *action_name,
GtkActionObserver *observer);
G_END_DECLS
#endif /* __GTK_ACTION_OBSERVABLE_H__ */

View File

@@ -19,16 +19,16 @@
#include "config.h"
#include "gactionobserver.h"
#include "gtkactionobserver.h"
G_DEFINE_INTERFACE (GActionObserver, g_action_observer, G_TYPE_OBJECT)
G_DEFINE_INTERFACE (GtkActionObserver, gtk_action_observer, G_TYPE_OBJECT)
/**
* SECTION:gactionobserver
* SECTION:gtkactionobserver
* @short_description: an interface implemented by objects that are
* interested in monitoring actions for changes
*
* GActionObserver is a simple interface allowing objects that wish to
* GtkActionObserver is a simple interface allowing objects that wish to
* be notified of changes to actions to be notified of those changes.
*
* It is also possible to monitor changes to action groups using
@@ -50,13 +50,13 @@ G_DEFINE_INTERFACE (GActionObserver, g_action_observer, G_TYPE_OBJECT)
*/
void
g_action_observer_default_init (GActionObserverInterface *class)
gtk_action_observer_default_init (GtkActionObserverInterface *class)
{
}
/*
* g_action_observer_action_added:
* @observer: a #GActionObserver
/**
* gtk_action_observer_action_added:
* @observer: a #GtkActionObserver
* @observable: the source of the event
* @action_name: the name of the action
* @enabled: %TRUE if the action is now enabled
@@ -72,22 +72,22 @@ g_action_observer_default_init (GActionObserverInterface *class)
* observer has explicitly registered itself to receive events.
*/
void
g_action_observer_action_added (GActionObserver *observer,
GActionObservable *observable,
const gchar *action_name,
const GVariantType *parameter_type,
gboolean enabled,
GVariant *state)
gtk_action_observer_action_added (GtkActionObserver *observer,
GtkActionObservable *observable,
const gchar *action_name,
const GVariantType *parameter_type,
gboolean enabled,
GVariant *state)
{
g_return_if_fail (G_IS_ACTION_OBSERVER (observer));
g_return_if_fail (GTK_IS_ACTION_OBSERVER (observer));
G_ACTION_OBSERVER_GET_IFACE (observer)
GTK_ACTION_OBSERVER_GET_IFACE (observer)
->action_added (observer, observable, action_name, parameter_type, enabled, state);
}
/*
* g_action_observer_action_enabled_changed:
* @observer: a #GActionObserver
/**
* gtk_action_observer_action_enabled_changed:
* @observer: a #GtkActionObserver
* @observable: the source of the event
* @action_name: the name of the action
* @enabled: %TRUE if the action is now enabled
@@ -99,20 +99,20 @@ g_action_observer_action_added (GActionObserver *observer,
* observer has explicitly registered itself to receive events.
*/
void
g_action_observer_action_enabled_changed (GActionObserver *observer,
GActionObservable *observable,
const gchar *action_name,
gboolean enabled)
gtk_action_observer_action_enabled_changed (GtkActionObserver *observer,
GtkActionObservable *observable,
const gchar *action_name,
gboolean enabled)
{
g_return_if_fail (G_IS_ACTION_OBSERVER (observer));
g_return_if_fail (GTK_IS_ACTION_OBSERVER (observer));
G_ACTION_OBSERVER_GET_IFACE (observer)
GTK_ACTION_OBSERVER_GET_IFACE (observer)
->action_enabled_changed (observer, observable, action_name, enabled);
}
/*
* g_action_observer_action_state_changed:
* @observer: a #GActionObserver
/**
* gtk_action_observer_action_state_changed:
* @observer: a #GtkActionObserver
* @observable: the source of the event
* @action_name: the name of the action
* @state: the new state of the action
@@ -124,20 +124,20 @@ g_action_observer_action_enabled_changed (GActionObserver *observer,
* observer has explicitly registered itself to receive events.
*/
void
g_action_observer_action_state_changed (GActionObserver *observer,
GActionObservable *observable,
const gchar *action_name,
GVariant *state)
gtk_action_observer_action_state_changed (GtkActionObserver *observer,
GtkActionObservable *observable,
const gchar *action_name,
GVariant *state)
{
g_return_if_fail (G_IS_ACTION_OBSERVER (observer));
g_return_if_fail (GTK_IS_ACTION_OBSERVER (observer));
G_ACTION_OBSERVER_GET_IFACE (observer)
GTK_ACTION_OBSERVER_GET_IFACE (observer)
->action_state_changed (observer, observable, action_name, state);
}
/*
* g_action_observer_action_removed:
* @observer: a #GActionObserver
/**
* gtk_action_observer_action_removed:
* @observer: a #GtkActionObserver
* @observable: the source of the event
* @action_name: the name of the action
*
@@ -148,12 +148,12 @@ g_action_observer_action_state_changed (GActionObserver *observer,
* observer has explicitly registered itself to receive events.
*/
void
g_action_observer_action_removed (GActionObserver *observer,
GActionObservable *observable,
const gchar *action_name)
gtk_action_observer_action_removed (GtkActionObserver *observer,
GtkActionObservable *observable,
const gchar *action_name)
{
g_return_if_fail (G_IS_ACTION_OBSERVER (observer));
g_return_if_fail (GTK_IS_ACTION_OBSERVER (observer));
G_ACTION_OBSERVER_GET_IFACE (observer)
GTK_ACTION_OBSERVER_GET_IFACE (observer)
->action_removed (observer, observable, action_name);
}

83
gtk/gtkactionobserver.h Normal file
View File

@@ -0,0 +1,83 @@
/*
* Copyright © 2011 Canonical Limited
*
* This library is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2 of the
* licence 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
*
* Authors: Ryan Lortie <desrt@desrt.ca>
*/
#ifndef __GTK_ACTION_OBSERVER_H__
#define __GTK_ACTION_OBSERVER_H__
#include <gio/gio.h>
G_BEGIN_DECLS
#define GTK_TYPE_ACTION_OBSERVER (gtk_action_observer_get_type ())
#define GTK_ACTION_OBSERVER(inst) (G_TYPE_CHECK_INSTANCE_CAST ((inst), \
GTK_TYPE_ACTION_OBSERVER, GtkActionObserver))
#define GTK_IS_ACTION_OBSERVER(inst) (G_TYPE_CHECK_INSTANCE_TYPE ((inst), \
GTK_TYPE_ACTION_OBSERVER))
#define GTK_ACTION_OBSERVER_GET_IFACE(inst) (G_TYPE_INSTANCE_GET_INTERFACE ((inst), \
GTK_TYPE_ACTION_OBSERVER, GtkActionObserverInterface))
typedef struct _GtkActionObserverInterface GtkActionObserverInterface;
typedef struct _GtkActionObservable GtkActionObservable;
typedef struct _GtkActionObserver GtkActionObserver;
struct _GtkActionObserverInterface
{
GTypeInterface g_iface;
void (* action_added) (GtkActionObserver *observer,
GtkActionObservable *observable,
const gchar *action_name,
const GVariantType *parameter_type,
gboolean enabled,
GVariant *state);
void (* action_enabled_changed) (GtkActionObserver *observer,
GtkActionObservable *observable,
const gchar *action_name,
gboolean enabled);
void (* action_state_changed) (GtkActionObserver *observer,
GtkActionObservable *observable,
const gchar *action_name,
GVariant *state);
void (* action_removed) (GtkActionObserver *observer,
GtkActionObservable *observable,
const gchar *action_name);
};
GType gtk_action_observer_get_type (void);
void gtk_action_observer_action_added (GtkActionObserver *observer,
GtkActionObservable *observable,
const gchar *action_name,
const GVariantType *parameter_type,
gboolean enabled,
GVariant *state);
void gtk_action_observer_action_enabled_changed (GtkActionObserver *observer,
GtkActionObservable *observable,
const gchar *action_name,
gboolean enabled);
void gtk_action_observer_action_state_changed (GtkActionObserver *observer,
GtkActionObservable *observable,
const gchar *action_name,
GVariant *state);
void gtk_action_observer_action_removed (GtkActionObserver *observer,
GtkActionObservable *observable,
const gchar *action_name);
G_END_DECLS
#endif /* __GTK_ACTION_OBSERVER_H__ */

View File

@@ -52,6 +52,7 @@
#include "gtkintl.h"
#include "gtktypebuiltins.h"
#include "gtkmodelmenuitem.h"
#include "gtkwidgetprivate.h"
#include "deprecated/gtktearoffmenuitem.h"
@@ -2039,33 +2040,30 @@ gtk_menu_shell_get_parent_shell (GtkMenuShell *menu_shell)
}
static void
gtk_menu_shell_tracker_insert_func (gint position,
GMenuModel *model,
gint item_index,
const gchar *action_namespace,
gboolean is_separator,
gpointer user_data)
gtk_menu_shell_item_activate (GtkMenuItem *menuitem,
gpointer user_data)
{
GtkMenuShell *menu_shell = user_data;
GtkWidget *item;
GtkMenuTrackerItem *item = user_data;
if (is_separator)
{
gchar *label;
gtk_menu_tracker_item_activated (item);
}
item = gtk_separator_menu_item_new ();
static void
gtk_menu_shell_submenu_shown (GtkWidget *submenu,
gpointer user_data)
{
GtkMenuTrackerItem *item = user_data;
if (g_menu_model_get_item_attribute (model, item_index, G_MENU_ATTRIBUTE_LABEL, "s", &label))
{
gtk_menu_item_set_label (GTK_MENU_ITEM (item), label);
g_free (label);
}
}
else
item = gtk_model_menu_item_new (model, item_index, action_namespace);
gtk_menu_tracker_item_request_submenu_shown (item, TRUE);
}
gtk_menu_shell_insert (menu_shell, item, position);
gtk_widget_show (item);
static void
gtk_menu_shell_submenu_hidden (GtkWidget *submenu,
gpointer user_data)
{
GtkMenuTrackerItem *item = user_data;
gtk_menu_tracker_item_request_submenu_shown (item, FALSE);
}
static void
@@ -2083,6 +2081,84 @@ gtk_menu_shell_tracker_remove_func (gint position,
gtk_widget_destroy (child);
}
static void
gtk_menu_shell_tracker_insert_func (GtkMenuTrackerItem *item,
gint position,
gpointer user_data)
{
GtkMenuShell *menu_shell = user_data;
GtkWidget *widget;
if (gtk_menu_tracker_item_get_is_separator (item))
{
widget = gtk_separator_menu_item_new ();
/* For separators, we bind to the "label" property in case there
* is a section heading.
*/
g_object_bind_property (item, "label", widget, "label", G_BINDING_SYNC_CREATE);
}
else if (gtk_menu_tracker_item_get_has_submenu (item))
{
GtkMenuShell *submenu;
widget = gtk_model_menu_item_new ();
g_object_bind_property (item, "label", widget, "text", G_BINDING_SYNC_CREATE);
submenu = GTK_MENU_SHELL (gtk_menu_new ());
/* We recurse directly here: we could use an idle instead to
* prevent arbitrary recursion depth. We could also do it
* lazy...
*/
submenu->priv->tracker = gtk_menu_tracker_new_for_item_submenu (item,
gtk_menu_shell_tracker_insert_func,
gtk_menu_shell_tracker_remove_func,
submenu);
gtk_menu_item_set_submenu (GTK_MENU_ITEM (widget), GTK_WIDGET (submenu));
if (gtk_menu_tracker_item_get_should_request_show (item))
{
/* We don't request show in the strictest sense of the
* word: we just notify when we are showing and don't
* bother waiting for the reply.
*
* This could be fixed one day, but it would be slightly
* complicated and would have a strange interaction with
* the submenu pop-up delay.
*
* Note: 'item' is already kept alive from above.
*/
g_signal_connect (submenu, "show", G_CALLBACK (gtk_menu_shell_submenu_shown), item);
g_signal_connect (submenu, "hide", G_CALLBACK (gtk_menu_shell_submenu_hidden), item);
}
}
else
{
widget = gtk_model_menu_item_new ();
/* We bind to "text" instead of "label" because GtkModelMenuItem
* uses this property (along with "icon") to control its child
* widget. Once this is merged into GtkMenuItem we can go back to
* using "label".
*/
g_object_bind_property (item, "label", widget, "text", G_BINDING_SYNC_CREATE);
g_object_bind_property (item, "icon", widget, "icon", G_BINDING_SYNC_CREATE);
g_object_bind_property (item, "sensitive", widget, "sensitive", G_BINDING_SYNC_CREATE);
g_object_bind_property (item, "visible", widget, "visible", G_BINDING_SYNC_CREATE);
g_object_bind_property (item, "role", widget, "action-role", G_BINDING_SYNC_CREATE);
g_object_bind_property (item, "toggled", widget, "toggled", G_BINDING_SYNC_CREATE);
g_object_bind_property (item, "accel", widget, "accel", G_BINDING_SYNC_CREATE);
g_signal_connect (widget, "activate", G_CALLBACK (gtk_menu_shell_item_activate), item);
}
/* TODO: drop this when we have bindings that ref the source */
g_object_set_data_full (G_OBJECT (widget), "GtkMenuTrackerItem", g_object_ref (item), g_object_unref);
gtk_menu_shell_insert (menu_shell, widget, position);
}
/**
* gtk_menu_shell_bind_model:
* @menu_shell: a #GtkMenuShell
@@ -2134,16 +2210,21 @@ gtk_menu_shell_bind_model (GtkMenuShell *menu_shell,
const gchar *action_namespace,
gboolean with_separators)
{
GtkActionMuxer *muxer;
g_return_if_fail (GTK_IS_MENU_SHELL (menu_shell));
g_return_if_fail (model == NULL || G_IS_MENU_MODEL (model));
muxer = _gtk_widget_get_action_muxer (GTK_WIDGET (menu_shell));
g_clear_pointer (&menu_shell->priv->tracker, gtk_menu_tracker_free);
while (menu_shell->priv->children)
gtk_container_remove (GTK_CONTAINER (menu_shell), menu_shell->priv->children->data);
if (model)
menu_shell->priv->tracker = gtk_menu_tracker_new (model, with_separators, action_namespace,
menu_shell->priv->tracker = gtk_menu_tracker_new (GTK_ACTION_OBSERVABLE (muxer),
model, with_separators, action_namespace,
gtk_menu_shell_tracker_insert_func,
gtk_menu_shell_tracker_remove_func,
menu_shell);

View File

@@ -27,6 +27,7 @@ typedef struct _GtkMenuTrackerSection GtkMenuTrackerSection;
struct _GtkMenuTracker
{
GtkActionObservable *observable;
GtkMenuTrackerInsertFunc insert_func;
GtkMenuTrackerRemoveFunc remove_func;
gpointer user_data;
@@ -159,7 +160,12 @@ gtk_menu_tracker_section_sync_separators (GtkMenuTrackerSection *section,
if (should_have_separator > section->has_separator)
{
/* Add a separator */
(* tracker->insert_func) (offset, parent_model, parent_index, NULL, TRUE, tracker->user_data);
GtkMenuTrackerItem *item;
item = gtk_menu_tracker_item_new (tracker->observable, parent_model, parent_index, NULL, TRUE);
(* tracker->insert_func) (item, offset, tracker->user_data);
g_object_unref (item);
section->has_separator = TRUE;
}
else if (should_have_separator < section->has_separator)
@@ -258,8 +264,13 @@ gtk_menu_tracker_add_items (GtkMenuTracker *tracker,
}
else
{
(* tracker->insert_func) (offset, model, position + n_items,
section->action_namespace, FALSE, tracker->user_data);
GtkMenuTrackerItem *item;
item = gtk_menu_tracker_item_new (tracker->observable, model, position + n_items,
section->action_namespace, FALSE);
(* tracker->insert_func) (item, offset, tracker->user_data);
g_object_unref (item);
*change_point = g_slist_prepend (*change_point, NULL);
}
}
@@ -400,7 +411,8 @@ gtk_menu_tracker_section_new (GtkMenuTracker *tracker,
* gtk_menu_tracker_free() is called.
*/
GtkMenuTracker *
gtk_menu_tracker_new (GMenuModel *model,
gtk_menu_tracker_new (GtkActionObservable *observable,
GMenuModel *model,
gboolean with_separators,
const gchar *action_namespace,
GtkMenuTrackerInsertFunc insert_func,
@@ -410,6 +422,7 @@ gtk_menu_tracker_new (GMenuModel *model,
GtkMenuTracker *tracker;
tracker = g_slice_new (GtkMenuTracker);
tracker->observable = g_object_ref (observable);
tracker->insert_func = insert_func;
tracker->remove_func = remove_func;
tracker->user_data = user_data;
@@ -420,6 +433,19 @@ gtk_menu_tracker_new (GMenuModel *model,
return tracker;
}
GtkMenuTracker *
gtk_menu_tracker_new_for_item_submenu (GtkMenuTrackerItem *item,
GtkMenuTrackerInsertFunc insert_func,
GtkMenuTrackerRemoveFunc remove_func,
gpointer user_data)
{
return gtk_menu_tracker_new (gtk_menu_tracker_item_get_observable (item),
gtk_menu_tracker_item_get_submenu (item),
TRUE,
gtk_menu_tracker_item_get_submenu_namespace (item),
insert_func, remove_func, user_data);
}
/*< private >
* gtk_menu_tracker_free:
* @tracker: a #GtkMenuTracker
@@ -430,5 +456,6 @@ void
gtk_menu_tracker_free (GtkMenuTracker *tracker)
{
gtk_menu_tracker_section_free (tracker->toplevel);
g_object_unref (tracker->observable);
g_slice_free (GtkMenuTracker, tracker);
}

View File

@@ -22,30 +22,31 @@
#ifndef __GTK_MENU_TRACKER_H__
#define __GTK_MENU_TRACKER_H__
#include <gio/gio.h>
#include "gtkmenutrackeritem.h"
typedef struct _GtkMenuTracker GtkMenuTracker;
typedef void (* GtkMenuTrackerInsertFunc) (gint position,
GMenuModel *model,
gint item_index,
const gchar *action_namespace,
gboolean is_separator,
gpointer user_data);
typedef void (* GtkMenuTrackerInsertFunc) (GtkMenuTrackerItem *item,
gint position,
gpointer user_data);
typedef void (* GtkMenuTrackerRemoveFunc) (gint position,
gpointer user_data);
typedef void (* GtkMenuTrackerRemoveFunc) (gint position,
gpointer user_data);
G_GNUC_INTERNAL
GtkMenuTracker * gtk_menu_tracker_new (GMenuModel *model,
gboolean with_separators,
const gchar *action_namespace,
GtkMenuTrackerInsertFunc insert_func,
GtkMenuTrackerRemoveFunc remove_func,
gpointer user_data);
GtkMenuTracker * gtk_menu_tracker_new (GtkActionObservable *observer,
GMenuModel *model,
gboolean with_separators,
const gchar *action_namespace,
GtkMenuTrackerInsertFunc insert_func,
GtkMenuTrackerRemoveFunc remove_func,
gpointer user_data);
G_GNUC_INTERNAL
void gtk_menu_tracker_free (GtkMenuTracker *tracker);
GtkMenuTracker * gtk_menu_tracker_new_for_item_submenu (GtkMenuTrackerItem *item,
GtkMenuTrackerInsertFunc insert_func,
GtkMenuTrackerRemoveFunc remove_func,
gpointer user_data);
void gtk_menu_tracker_free (GtkMenuTracker *tracker);
#endif /* __GTK_MENU_TRACKER_H__ */

715
gtk/gtkmenutrackeritem.c Normal file
View File

@@ -0,0 +1,715 @@
#include "gtkmenutrackeritem.h"
typedef GObjectClass GtkMenuTrackerItemClass;
struct _GtkMenuTrackerItem
{
GObject parent_instance;
GtkActionObservable *observable;
gchar *action_namespace;
GMenuItem *item;
GtkMenuTrackerItemRole role : 4;
guint is_separator : 1;
guint can_activate : 1;
guint sensitive : 1;
guint toggled : 1;
guint submenu_shown : 1;
guint submenu_requested : 1;
};
enum {
PROP_0,
PROP_IS_SEPARATOR,
PROP_HAS_SUBMENU,
PROP_LABEL,
PROP_ICON,
PROP_SENSITIVE,
PROP_VISIBLE,
PROP_ROLE,
PROP_TOGGLED,
PROP_ACCEL,
PROP_SUBMENU,
PROP_SUBMENU_NAMESPACE,
PROP_SUBMENU_SHOWN,
N_PROPS
};
static GParamSpec *gtk_menu_tracker_item_pspecs[N_PROPS];
static void gtk_menu_tracker_item_init_observer_iface (GtkActionObserverInterface *iface);
G_DEFINE_TYPE_WITH_CODE (GtkMenuTrackerItem, gtk_menu_tracker_item, G_TYPE_OBJECT,
G_IMPLEMENT_INTERFACE (GTK_TYPE_ACTION_OBSERVER, gtk_menu_tracker_item_init_observer_iface))
GType
gtk_menu_tracker_item_role_get_type (void)
{
static gsize gtk_menu_tracker_item_role_type;
if (g_once_init_enter (&gtk_menu_tracker_item_role_type))
{
static const GEnumValue values[] = {
{ GTK_MENU_TRACKER_ITEM_ROLE_NORMAL, "GTK_MENU_TRACKER_ITEM_ROLE_NORMAL", "normal" },
{ GTK_MENU_TRACKER_ITEM_ROLE_CHECK, "GTK_MENU_TRACKER_ITEM_ROLE_CHECK", "check" },
{ GTK_MENU_TRACKER_ITEM_ROLE_RADIO, "GTK_MENU_TRACKER_ITEM_ROLE_RADIO", "radio" },
{ 0, NULL, NULL }
};
GType type;
type = g_enum_register_static ("GtkMenuTrackerItemRole", values);
g_once_init_leave (&gtk_menu_tracker_item_role_type, type);
}
return gtk_menu_tracker_item_role_type;
}
static void
gtk_menu_tracker_item_get_property (GObject *object,
guint prop_id,
GValue *value,
GParamSpec *pspec)
{
GtkMenuTrackerItem *self = GTK_MENU_TRACKER_ITEM (object);
switch (prop_id)
{
case PROP_IS_SEPARATOR:
g_value_set_boolean (value, gtk_menu_tracker_item_get_is_separator (self));
break;
case PROP_HAS_SUBMENU:
g_value_set_boolean (value, gtk_menu_tracker_item_get_has_submenu (self));
break;
case PROP_LABEL:
g_value_set_string (value, gtk_menu_tracker_item_get_label (self));
break;
case PROP_ICON:
g_value_set_object (value, gtk_menu_tracker_item_get_icon (self));
break;
case PROP_SENSITIVE:
g_value_set_boolean (value, gtk_menu_tracker_item_get_sensitive (self));
break;
case PROP_VISIBLE:
g_value_set_boolean (value, gtk_menu_tracker_item_get_visible (self));
break;
case PROP_ROLE:
g_value_set_enum (value, gtk_menu_tracker_item_get_role (self));
break;
case PROP_TOGGLED:
g_value_set_boolean (value, gtk_menu_tracker_item_get_toggled (self));
break;
case PROP_ACCEL:
g_value_set_string (value, gtk_menu_tracker_item_get_accel (self));
break;
case PROP_SUBMENU:
g_value_set_object (value, gtk_menu_tracker_item_get_submenu (self));
break;
case PROP_SUBMENU_NAMESPACE:
g_value_set_string (value, gtk_menu_tracker_item_get_submenu_namespace (self));
break;
case PROP_SUBMENU_SHOWN:
g_value_set_boolean (value, gtk_menu_tracker_item_get_submenu_shown (self));
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static void
gtk_menu_tracker_item_finalize (GObject *object)
{
GtkMenuTrackerItem *self = GTK_MENU_TRACKER_ITEM (object);
g_free (self->action_namespace);
if (self->observable)
g_object_unref (self->observable);
g_object_unref (self->item);
G_OBJECT_CLASS (gtk_menu_tracker_item_parent_class)->finalize (object);
}
static void
gtk_menu_tracker_item_init (GtkMenuTrackerItem * self)
{
}
static void
gtk_menu_tracker_item_class_init (GtkMenuTrackerItemClass *class)
{
class->get_property = gtk_menu_tracker_item_get_property;
class->finalize = gtk_menu_tracker_item_finalize;
gtk_menu_tracker_item_pspecs[PROP_IS_SEPARATOR] =
g_param_spec_boolean ("is-separator", "", "", FALSE, G_PARAM_STATIC_STRINGS | G_PARAM_READABLE);
gtk_menu_tracker_item_pspecs[PROP_HAS_SUBMENU] =
g_param_spec_boolean ("has-submenu", "", "", FALSE, G_PARAM_STATIC_STRINGS | G_PARAM_READABLE);
gtk_menu_tracker_item_pspecs[PROP_LABEL] =
g_param_spec_string ("label", "", "", NULL, G_PARAM_STATIC_STRINGS | G_PARAM_READABLE);
gtk_menu_tracker_item_pspecs[PROP_ICON] =
g_param_spec_object ("icon", "", "", G_TYPE_ICON, G_PARAM_STATIC_STRINGS | G_PARAM_READABLE);
gtk_menu_tracker_item_pspecs[PROP_SENSITIVE] =
g_param_spec_boolean ("sensitive", "", "", FALSE, G_PARAM_STATIC_STRINGS | G_PARAM_READABLE);
gtk_menu_tracker_item_pspecs[PROP_VISIBLE] =
g_param_spec_boolean ("visible", "", "", FALSE, G_PARAM_STATIC_STRINGS | G_PARAM_READABLE);
gtk_menu_tracker_item_pspecs[PROP_ROLE] =
g_param_spec_enum ("role", "", "",
GTK_TYPE_MENU_TRACKER_ITEM_ROLE, GTK_MENU_TRACKER_ITEM_ROLE_NORMAL,
G_PARAM_STATIC_STRINGS | G_PARAM_READABLE);
gtk_menu_tracker_item_pspecs[PROP_TOGGLED] =
g_param_spec_boolean ("toggled", "", "", FALSE, G_PARAM_STATIC_STRINGS | G_PARAM_READABLE);
gtk_menu_tracker_item_pspecs[PROP_ACCEL] =
g_param_spec_string ("accel", "", "", NULL, G_PARAM_STATIC_STRINGS | G_PARAM_READABLE);
gtk_menu_tracker_item_pspecs[PROP_SUBMENU] =
g_param_spec_object ("submenu", "", "", G_TYPE_MENU_MODEL, G_PARAM_STATIC_STRINGS | G_PARAM_READABLE);
gtk_menu_tracker_item_pspecs[PROP_SUBMENU_NAMESPACE] =
g_param_spec_string ("submenu-namespace", "", "", NULL, G_PARAM_STATIC_STRINGS | G_PARAM_READABLE);
gtk_menu_tracker_item_pspecs[PROP_SUBMENU_SHOWN] =
g_param_spec_boolean ("submenu-shown", "", "", FALSE, G_PARAM_STATIC_STRINGS | G_PARAM_READABLE);
g_object_class_install_properties (class, N_PROPS, gtk_menu_tracker_item_pspecs);
}
static void
gtk_menu_tracker_item_action_added (GtkActionObserver *observer,
GtkActionObservable *observable,
const gchar *action_name,
const GVariantType *parameter_type,
gboolean enabled,
GVariant *state)
{
GtkMenuTrackerItem *self = GTK_MENU_TRACKER_ITEM (observer);
GVariant *action_target;
action_target = g_menu_item_get_attribute_value (self->item, G_MENU_ATTRIBUTE_TARGET, NULL);
self->can_activate = (action_target == NULL && parameter_type == NULL) ||
(action_target != NULL && parameter_type != NULL &&
g_variant_is_of_type (action_target, parameter_type));
if (!self->can_activate)
{
if (action_target)
g_variant_unref (action_target);
return;
}
self->sensitive = enabled;
if (action_target != NULL && state != NULL)
{
self->toggled = g_variant_equal (state, action_target);
self->role = GTK_MENU_TRACKER_ITEM_ROLE_RADIO;
}
else if (state != NULL && g_variant_is_of_type (state, G_VARIANT_TYPE_BOOLEAN))
{
self->toggled = g_variant_get_boolean (state);
self->role = GTK_MENU_TRACKER_ITEM_ROLE_CHECK;
}
g_object_freeze_notify (G_OBJECT (self));
if (self->sensitive)
g_object_notify_by_pspec (G_OBJECT (self), gtk_menu_tracker_item_pspecs[PROP_SENSITIVE]);
if (self->toggled)
g_object_notify_by_pspec (G_OBJECT (self), gtk_menu_tracker_item_pspecs[PROP_TOGGLED]);
if (self->role != GTK_MENU_TRACKER_ITEM_ROLE_NORMAL)
g_object_notify_by_pspec (G_OBJECT (self), gtk_menu_tracker_item_pspecs[PROP_ROLE]);
g_object_thaw_notify (G_OBJECT (self));
if (action_target)
g_variant_unref (action_target);
}
static void
gtk_menu_tracker_item_action_enabled_changed (GtkActionObserver *observer,
GtkActionObservable *observable,
const gchar *action_name,
gboolean enabled)
{
GtkMenuTrackerItem *self = GTK_MENU_TRACKER_ITEM (observer);
if (!self->can_activate)
return;
if (self->sensitive == enabled)
return;
self->sensitive = enabled;
g_object_notify_by_pspec (G_OBJECT (self), gtk_menu_tracker_item_pspecs[PROP_SENSITIVE]);
}
static void
gtk_menu_tracker_item_action_state_changed (GtkActionObserver *observer,
GtkActionObservable *observable,
const gchar *action_name,
GVariant *state)
{
GtkMenuTrackerItem *self = GTK_MENU_TRACKER_ITEM (observer);
GVariant *action_target;
gboolean was_toggled;
if (!self->can_activate)
return;
action_target = g_menu_item_get_attribute_value (self->item, G_MENU_ATTRIBUTE_TARGET, NULL);
was_toggled = self->toggled;
if (action_target)
{
self->toggled = g_variant_equal (state, action_target);
g_variant_unref (action_target);
}
else if (g_variant_is_of_type (state, G_VARIANT_TYPE_BOOLEAN))
self->toggled = g_variant_get_boolean (state);
else
self->toggled = FALSE;
if (self->toggled != was_toggled)
g_object_notify_by_pspec (G_OBJECT (self), gtk_menu_tracker_item_pspecs[PROP_TOGGLED]);
}
static void
gtk_menu_tracker_item_action_removed (GtkActionObserver *observer,
GtkActionObservable *observable,
const gchar *action_name)
{
GtkMenuTrackerItem *self = GTK_MENU_TRACKER_ITEM (observer);
if (!self->can_activate)
return;
g_object_freeze_notify (G_OBJECT (self));
if (self->sensitive)
{
self->sensitive = FALSE;
g_object_notify_by_pspec (G_OBJECT (self), gtk_menu_tracker_item_pspecs[PROP_SENSITIVE]);
}
if (self->toggled)
{
self->toggled = FALSE;
g_object_notify_by_pspec (G_OBJECT (self), gtk_menu_tracker_item_pspecs[PROP_TOGGLED]);
}
if (self->role != GTK_MENU_TRACKER_ITEM_ROLE_NORMAL)
{
self->role = GTK_MENU_TRACKER_ITEM_ROLE_NORMAL;
g_object_notify_by_pspec (G_OBJECT (self), gtk_menu_tracker_item_pspecs[PROP_ROLE]);
}
g_object_thaw_notify (G_OBJECT (self));
}
static void
gtk_menu_tracker_item_init_observer_iface (GtkActionObserverInterface *iface)
{
iface->action_added = gtk_menu_tracker_item_action_added;
iface->action_enabled_changed = gtk_menu_tracker_item_action_enabled_changed;
iface->action_state_changed = gtk_menu_tracker_item_action_state_changed;
iface->action_removed = gtk_menu_tracker_item_action_removed;
}
GtkMenuTrackerItem *
gtk_menu_tracker_item_new (GtkActionObservable *observable,
GMenuModel *model,
gint item_index,
const gchar *action_namespace,
gboolean is_separator)
{
GtkMenuTrackerItem *self;
const gchar *action_name;
g_return_val_if_fail (GTK_IS_ACTION_OBSERVABLE (observable), NULL);
g_return_val_if_fail (G_IS_MENU_MODEL (model), NULL);
self = g_object_new (GTK_TYPE_MENU_TRACKER_ITEM, NULL);
self->item = g_menu_item_new_from_model (model, item_index);
self->action_namespace = g_strdup (action_namespace);
self->observable = g_object_ref (observable);
self->is_separator = is_separator;
if (!is_separator && g_menu_item_get_attribute (self->item, "action", "&s", &action_name))
{
GActionGroup *group = G_ACTION_GROUP (observable);
const GVariantType *parameter_type;
gboolean enabled;
GVariant *state;
gboolean found;
state = NULL;
if (action_namespace)
{
gchar *full_action;
full_action = g_strjoin (".", action_namespace, action_name, NULL);
gtk_action_observable_register_observer (self->observable, full_action, GTK_ACTION_OBSERVER (self));
found = g_action_group_query_action (group, full_action, &enabled, &parameter_type, NULL, NULL, &state);
g_free (full_action);
}
else
{
gtk_action_observable_register_observer (self->observable, action_name, GTK_ACTION_OBSERVER (self));
found = g_action_group_query_action (group, action_name, &enabled, &parameter_type, NULL, NULL, &state);
}
if (found)
gtk_menu_tracker_item_action_added (GTK_ACTION_OBSERVER (self), observable, NULL,
parameter_type, enabled, state);
else
gtk_menu_tracker_item_action_removed (GTK_ACTION_OBSERVER (self), observable, NULL);
if (state)
g_variant_unref (state);
}
else
self->sensitive = TRUE;
return self;
}
/**
* gtk_menu_tracker_item_get_observable:
*
* Returns: (transfer none):
*/
GtkActionObservable *
gtk_menu_tracker_item_get_observable (GtkMenuTrackerItem *self)
{
return self->observable;
}
gboolean
gtk_menu_tracker_item_get_is_separator (GtkMenuTrackerItem *self)
{
return self->is_separator;
}
gboolean
gtk_menu_tracker_item_get_has_submenu (GtkMenuTrackerItem *self)
{
GMenuModel *link;
link = g_menu_item_get_link (self->item, G_MENU_LINK_SUBMENU);
if (link)
{
g_object_unref (link);
return TRUE;
}
else
return FALSE;
}
const gchar *
gtk_menu_tracker_item_get_label (GtkMenuTrackerItem *self)
{
const gchar *label = NULL;
g_menu_item_get_attribute (self->item, G_MENU_ATTRIBUTE_LABEL, "&s", &label);
return label;
}
/**
* gtk_menu_tracker_item_get_icon:
*
* Returns: (transfer full):
*/
GIcon *
gtk_menu_tracker_item_get_icon (GtkMenuTrackerItem *self)
{
GVariant *icon_data;
GIcon *icon;
icon_data = g_menu_item_get_attribute_value (self->item, "icon", NULL);
if (icon_data == NULL)
return NULL;
icon = g_icon_deserialize (icon_data);
g_variant_unref (icon_data);
return icon;
}
gboolean
gtk_menu_tracker_item_get_sensitive (GtkMenuTrackerItem *self)
{
return self->sensitive;
}
gboolean
gtk_menu_tracker_item_get_visible (GtkMenuTrackerItem *self)
{
return TRUE;
}
GtkMenuTrackerItemRole
gtk_menu_tracker_item_get_role (GtkMenuTrackerItem *self)
{
return self->role;
}
gboolean
gtk_menu_tracker_item_get_toggled (GtkMenuTrackerItem *self)
{
return self->toggled;
}
const gchar *
gtk_menu_tracker_item_get_accel (GtkMenuTrackerItem *self)
{
const gchar *accel = NULL;
g_menu_item_get_attribute (self->item, "accel", "&s", &accel);
return accel;
}
/**
* gtk_menu_tracker_item_get_submenu:
*
* Returns: (transfer full):
*/
GMenuModel *
gtk_menu_tracker_item_get_submenu (GtkMenuTrackerItem *self)
{
return g_menu_item_get_link (self->item, "submenu");
}
gchar *
gtk_menu_tracker_item_get_submenu_namespace (GtkMenuTrackerItem *self)
{
const gchar *namespace;
if (g_menu_item_get_attribute (self->item, "action-namespace", "&s", &namespace))
{
if (self->action_namespace)
return g_strjoin (".", self->action_namespace, namespace, NULL);
else
return g_strdup (namespace);
}
else
return g_strdup (self->action_namespace);
}
gboolean
gtk_menu_tracker_item_get_should_request_show (GtkMenuTrackerItem *self)
{
return g_menu_item_get_attribute (self->item, "submenu-action", "&s", NULL);
}
gboolean
gtk_menu_tracker_item_get_submenu_shown (GtkMenuTrackerItem *self)
{
return self->submenu_shown;
}
/* only called from the opener, internally */
static void
gtk_menu_tracker_item_set_submenu_shown (GtkMenuTrackerItem *self,
gboolean submenu_shown)
{
if (submenu_shown == self->submenu_shown)
return;
self->submenu_shown = submenu_shown;
g_object_notify_by_pspec (G_OBJECT (self), gtk_menu_tracker_item_pspecs[PROP_SUBMENU_SHOWN]);
}
void
gtk_menu_tracker_item_activated (GtkMenuTrackerItem *self)
{
const gchar *action_name;
GVariant *action_target;
g_return_if_fail (GTK_IS_MENU_TRACKER_ITEM (self));
if (!self->can_activate)
return;
g_menu_item_get_attribute (self->item, G_MENU_ATTRIBUTE_ACTION, "&s", &action_name);
action_target = g_menu_item_get_attribute_value (self->item, G_MENU_ATTRIBUTE_TARGET, NULL);
if (self->action_namespace)
{
gchar *full_action;
full_action = g_strjoin (".", self->action_namespace, action_name, NULL);
g_action_group_activate_action (G_ACTION_GROUP (self->observable), full_action, action_target);
g_free (full_action);
}
else
g_action_group_activate_action (G_ACTION_GROUP (self->observable), action_name, action_target);
if (action_target)
g_variant_unref (action_target);
}
typedef struct
{
GtkMenuTrackerItem *item;
gchar *submenu_action;
gboolean first_time;
} GtkMenuTrackerOpener;
static void
gtk_menu_tracker_opener_update (GtkMenuTrackerOpener *opener)
{
GActionGroup *group = G_ACTION_GROUP (opener->item->observable);
gboolean is_open = TRUE;
/* We consider the menu as being "open" if the action does not exist
* or if there is another problem (no state, wrong state type, etc.).
* If the action exists, with the correct state then we consider it
* open if we have ever seen this state equal to TRUE.
*
* In the event that we see the state equal to FALSE, we force it back
* to TRUE. We do not signal that the menu was closed because this is
* likely to create UI thrashing.
*
* The only way the menu can have a true-to-false submenu-shown
* transition is if the user calls _request_submenu_shown (FALSE).
* That is handled in _free() below.
*/
if (g_action_group_has_action (group, opener->submenu_action))
{
GVariant *state = g_action_group_get_action_state (group, opener->submenu_action);
if (state)
{
if (g_variant_is_of_type (state, G_VARIANT_TYPE_BOOLEAN))
is_open = g_variant_get_boolean (state);
g_variant_unref (state);
}
}
/* If it is already open, signal that.
*
* If it is not open, ask it to open.
*/
if (is_open)
gtk_menu_tracker_item_set_submenu_shown (opener->item, TRUE);
if (!is_open || opener->first_time)
{
g_action_group_change_action_state (group, opener->submenu_action, g_variant_new_boolean (TRUE));
opener->first_time = FALSE;
}
}
static void
gtk_menu_tracker_opener_added (GActionGroup *group,
const gchar *action_name,
gpointer user_data)
{
GtkMenuTrackerOpener *opener = user_data;
if (g_str_equal (action_name, opener->submenu_action))
gtk_menu_tracker_opener_update (opener);
}
static void
gtk_menu_tracker_opener_removed (GActionGroup *action_group,
const gchar *action_name,
gpointer user_data)
{
GtkMenuTrackerOpener *opener = user_data;
if (g_str_equal (action_name, opener->submenu_action))
gtk_menu_tracker_opener_update (opener);
}
static void
gtk_menu_tracker_opener_changed (GActionGroup *action_group,
const gchar *action_name,
GVariant *new_state,
gpointer user_data)
{
GtkMenuTrackerOpener *opener = user_data;
if (g_str_equal (action_name, opener->submenu_action))
gtk_menu_tracker_opener_update (opener);
}
static void
gtk_menu_tracker_opener_free (gpointer data)
{
GtkMenuTrackerOpener *opener = data;
g_signal_handlers_disconnect_by_func (opener->item->observable, gtk_menu_tracker_opener_added, opener);
g_signal_handlers_disconnect_by_func (opener->item->observable, gtk_menu_tracker_opener_removed, opener);
g_signal_handlers_disconnect_by_func (opener->item->observable, gtk_menu_tracker_opener_changed, opener);
g_action_group_change_action_state (G_ACTION_GROUP (opener->item->observable),
opener->submenu_action,
g_variant_new_boolean (FALSE));
gtk_menu_tracker_item_set_submenu_shown (opener->item, FALSE);
g_free (opener->submenu_action);
g_slice_free (GtkMenuTrackerOpener, opener);
}
static GtkMenuTrackerOpener *
gtk_menu_tracker_opener_new (GtkMenuTrackerItem *item,
const gchar *submenu_action)
{
GtkMenuTrackerOpener *opener;
opener = g_slice_new (GtkMenuTrackerOpener);
opener->first_time = TRUE;
opener->item = item;
if (item->action_namespace)
opener->submenu_action = g_strjoin (".", item->action_namespace, submenu_action, NULL);
else
opener->submenu_action = g_strdup (submenu_action);
g_signal_connect (item->observable, "action-added", G_CALLBACK (gtk_menu_tracker_opener_added), opener);
g_signal_connect (item->observable, "action-removed", G_CALLBACK (gtk_menu_tracker_opener_removed), opener);
g_signal_connect (item->observable, "action-state-changed", G_CALLBACK (gtk_menu_tracker_opener_changed), opener);
gtk_menu_tracker_opener_update (opener);
return opener;
}
void
gtk_menu_tracker_item_request_submenu_shown (GtkMenuTrackerItem *self,
gboolean shown)
{
const gchar *submenu_action;
gboolean okay;
if (shown == self->submenu_requested)
return;
/* Should not be getting called unless we have submenu-action.
*/
okay = g_menu_item_get_attribute (self->item, "submenu-action", "&s", &submenu_action);
g_assert (okay);
self->submenu_requested = shown;
if (shown)
g_object_set_data_full (G_OBJECT (self), "submenu-opener",
gtk_menu_tracker_opener_new (self, submenu_action),
gtk_menu_tracker_opener_free);
else
g_object_set_data (G_OBJECT (self), "submenu-opener", NULL);
}

84
gtk/gtkmenutrackeritem.h Normal file
View File

@@ -0,0 +1,84 @@
/*
* Copyright © 2011, 2013 Canonical Limited
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the licence, 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
*
* Author: Ryan Lortie <desrt@desrt.ca>
*/
#ifndef __GTK_MENU_TRACKER_ITEM_H__
#define __GTK_MENU_TRACKER_ITEM_H__
#include "gtkactionobservable.h"
#define GTK_TYPE_MENU_TRACKER_ITEM (gtk_menu_tracker_item_get_type ())
#define GTK_MENU_TRACKER_ITEM(inst) (G_TYPE_CHECK_INSTANCE_CAST ((inst), \
GTK_TYPE_MENU_TRACKER_ITEM, GtkMenuTrackerItem))
#define GTK_IS_MENU_TRACKER_ITEM(inst) (G_TYPE_CHECK_INSTANCE_TYPE ((inst), \
GTK_TYPE_MENU_TRACKER_ITEM))
typedef struct _GtkMenuTrackerItem GtkMenuTrackerItem;
#define GTK_TYPE_MENU_TRACKER_ITEM_ROLE (gtk_menu_tracker_item_role_get_type ())
typedef enum {
GTK_MENU_TRACKER_ITEM_ROLE_NORMAL,
GTK_MENU_TRACKER_ITEM_ROLE_CHECK,
GTK_MENU_TRACKER_ITEM_ROLE_RADIO,
} GtkMenuTrackerItemRole;
GType gtk_menu_tracker_item_get_type (void) G_GNUC_CONST;
GType gtk_menu_tracker_item_role_get_type (void) G_GNUC_CONST;
GtkMenuTrackerItem * gtk_menu_tracker_item_new (GtkActionObservable *observable,
GMenuModel *model,
gint item_index,
const gchar *action_namespace,
gboolean is_separator);
GtkActionObservable * gtk_menu_tracker_item_get_observable (GtkMenuTrackerItem *self);
gboolean gtk_menu_tracker_item_get_is_separator (GtkMenuTrackerItem *self);
gboolean gtk_menu_tracker_item_get_has_submenu (GtkMenuTrackerItem *self);
const gchar * gtk_menu_tracker_item_get_label (GtkMenuTrackerItem *self);
GIcon * gtk_menu_tracker_item_get_icon (GtkMenuTrackerItem *self);
gboolean gtk_menu_tracker_item_get_sensitive (GtkMenuTrackerItem *self);
gboolean gtk_menu_tracker_item_get_visible (GtkMenuTrackerItem *self);
GtkMenuTrackerItemRole gtk_menu_tracker_item_get_role (GtkMenuTrackerItem *self);
gboolean gtk_menu_tracker_item_get_toggled (GtkMenuTrackerItem *self);
const gchar * gtk_menu_tracker_item_get_accel (GtkMenuTrackerItem *self);
GMenuModel * gtk_menu_tracker_item_get_submenu (GtkMenuTrackerItem *self);
gchar * gtk_menu_tracker_item_get_submenu_namespace (GtkMenuTrackerItem *self);
gboolean gtk_menu_tracker_item_get_should_request_show (GtkMenuTrackerItem *self);
void gtk_menu_tracker_item_activated (GtkMenuTrackerItem *self);
void gtk_menu_tracker_item_request_submenu_shown (GtkMenuTrackerItem *self,
gboolean shown);
gboolean gtk_menu_tracker_item_get_submenu_shown (GtkMenuTrackerItem *self);
#endif

View File

@@ -1,5 +1,5 @@
/*
* Copyright © 2011 Canonical Limited
* Copyright © 2011, 2013 Canonical Limited
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@@ -21,9 +21,6 @@
#include "gtkmodelmenuitem.h"
#include "gtkaccelmapprivate.h"
#include "gtkactionhelper.h"
#include "gtkwidgetprivate.h"
#include "gtkaccellabel.h"
#include "gtkimage.h"
#include "gtkbox.h"
@@ -31,7 +28,7 @@
struct _GtkModelMenuItem
{
GtkCheckMenuItem parent_instance;
GtkActionHelperRole role;
GtkMenuTrackerItemRole role;
gboolean has_indicator;
};
@@ -39,7 +36,15 @@ typedef GtkCheckMenuItemClass GtkModelMenuItemClass;
G_DEFINE_TYPE (GtkModelMenuItem, gtk_model_menu_item, GTK_TYPE_CHECK_MENU_ITEM)
#define PROP_ACTION_ROLE 1
enum
{
PROP_0,
PROP_ACTION_ROLE,
PROP_ICON,
PROP_TEXT,
PROP_TOGGLED,
PROP_ACCEL
};
static void
gtk_model_menu_item_toggle_size_request (GtkMenuItem *menu_item,
@@ -55,6 +60,12 @@ gtk_model_menu_item_toggle_size_request (GtkMenuItem *menu_item,
*requisition = 0;
}
static void
gtk_model_menu_item_activate (GtkMenuItem *item)
{
/* block the automatic toggle behaviour -- just do nothing */
}
static void
gtk_model_menu_item_draw_indicator (GtkCheckMenuItem *check_item,
cairo_t *cr)
@@ -66,177 +77,6 @@ gtk_model_menu_item_draw_indicator (GtkCheckMenuItem *check_item,
->draw_indicator (check_item, cr);
}
static void
gtk_actionable_set_namespaced_action_name (GtkActionable *actionable,
const gchar *namespace,
const gchar *action_name)
{
if (namespace)
{
gchar *name = g_strdup_printf ("%s.%s", namespace, action_name);
gtk_actionable_set_action_name (actionable, name);
g_free (name);
}
else
{
gtk_actionable_set_action_name (actionable, action_name);
}
}
static void
gtk_model_menu_item_submenu_shown (GtkWidget *widget,
gpointer user_data)
{
const gchar *action_name = user_data;
GActionMuxer *muxer;
muxer = _gtk_widget_get_action_muxer (widget);
g_action_group_change_action_state (G_ACTION_GROUP (muxer), action_name, g_variant_new_boolean (TRUE));
}
static void
gtk_model_menu_item_submenu_hidden (GtkWidget *widget,
gpointer user_data)
{
const gchar *action_name = user_data;
GActionMuxer *muxer;
muxer = _gtk_widget_get_action_muxer (widget);
g_action_group_change_action_state (G_ACTION_GROUP (muxer), action_name, g_variant_new_boolean (FALSE));
}
static void
gtk_model_menu_item_setup (GtkModelMenuItem *item,
GMenuModel *model,
gint item_index,
const gchar *action_namespace)
{
GMenuAttributeIter *iter;
GMenuModel *submenu;
const gchar *key;
GVariant *value;
GtkWidget *label;
label = NULL;
/* In the case that we have an icon, make an HBox and put it beside
* the label. Otherwise, we just have a label directly.
*/
if ((value = g_menu_model_get_item_attribute_value (model, item_index, "icon", NULL)))
{
GIcon *icon;
icon = g_icon_deserialize (value);
if (icon != NULL)
{
GtkWidget *image;
GtkWidget *box;
box = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0);
image = gtk_image_new_from_gicon (icon, GTK_ICON_SIZE_MENU);
gtk_box_pack_start (GTK_BOX (box), image, FALSE, FALSE, 0);
g_object_unref (icon);
label = gtk_accel_label_new ("");
gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
gtk_accel_label_set_accel_widget (GTK_ACCEL_LABEL (label), GTK_WIDGET (item));
gtk_box_pack_end (GTK_BOX (box), label, TRUE, TRUE, 0);
gtk_container_add (GTK_CONTAINER (item), box);
gtk_widget_show_all (box);
}
g_variant_unref (value);
}
if (label == NULL)
{
/* Ensure that the GtkAccelLabel has been created... */
(void) gtk_menu_item_get_label (GTK_MENU_ITEM (item));
label = gtk_bin_get_child (GTK_BIN (item));
}
g_assert (label != NULL);
if ((submenu = g_menu_model_get_item_link (model, item_index, "submenu")))
{
gchar *section_namespace = NULL;
GtkWidget *menu;
g_menu_model_get_item_attribute (model, item_index, "action-namespace", "s", &section_namespace);
menu = gtk_menu_new ();
if (action_namespace)
{
gchar *namespace = g_strjoin (".", action_namespace, section_namespace, NULL);
gtk_menu_shell_bind_model (GTK_MENU_SHELL (menu), submenu, namespace, TRUE);
g_free (namespace);
}
else
gtk_menu_shell_bind_model (GTK_MENU_SHELL (menu), submenu, section_namespace, TRUE);
gtk_menu_item_set_submenu (GTK_MENU_ITEM (item), menu);
g_free (section_namespace);
g_object_unref (submenu);
}
iter = g_menu_model_iterate_item_attributes (model, item_index);
while (g_menu_attribute_iter_get_next (iter, &key, &value))
{
if (g_str_equal (key, "label") && g_variant_is_of_type (value, G_VARIANT_TYPE_STRING))
gtk_label_set_text_with_mnemonic (GTK_LABEL (label), g_variant_get_string (value, NULL));
else if (g_str_equal (key, "accel") && g_variant_is_of_type (value, G_VARIANT_TYPE_STRING))
{
GdkModifierType modifiers;
guint key;
gtk_accelerator_parse (g_variant_get_string (value, NULL), &key, &modifiers);
if (key)
gtk_accel_label_set_accel (GTK_ACCEL_LABEL (label), key, modifiers);
}
else if (g_str_equal (key, "action") && g_variant_is_of_type (value, G_VARIANT_TYPE_STRING))
gtk_actionable_set_namespaced_action_name (GTK_ACTIONABLE (item), action_namespace,
g_variant_get_string (value, NULL));
else if (g_str_equal (key, "target"))
gtk_actionable_set_action_target_value (GTK_ACTIONABLE (item), value);
else if (g_str_equal (key, "submenu-action") && g_variant_is_of_type (value, G_VARIANT_TYPE_STRING))
{
GtkWidget *submenu;
submenu = gtk_menu_item_get_submenu (GTK_MENU_ITEM (item));
if (submenu != NULL)
{
const gchar *action = g_variant_get_string (value, NULL);
gchar *full_action;
if (action_namespace)
full_action = g_strjoin (".", action_namespace, action, NULL);
else
full_action = g_strdup (action);
g_object_set_data_full (G_OBJECT (submenu), "gtkmodelmenu-visibility-action", full_action, g_free);
g_signal_connect (submenu, "show", G_CALLBACK (gtk_model_menu_item_submenu_shown), full_action);
g_signal_connect (submenu, "hide", G_CALLBACK (gtk_model_menu_item_submenu_hidden), full_action);
}
}
g_variant_unref (value);
}
g_object_unref (iter);
gtk_menu_item_set_use_underline (GTK_MENU_ITEM (item), TRUE);
}
static void
gtk_model_menu_item_set_has_indicator (GtkModelMenuItem *item,
gboolean has_indicator)
@@ -250,36 +90,30 @@ gtk_model_menu_item_set_has_indicator (GtkModelMenuItem *item,
}
static void
gtk_model_menu_item_set_property (GObject *object, guint prop_id,
const GValue *value, GParamSpec *pspec)
gtk_model_menu_item_set_action_role (GtkModelMenuItem *item,
GtkMenuTrackerItemRole role)
{
GtkModelMenuItem *item = GTK_MODEL_MENU_ITEM (object);
GtkActionHelperRole role;
AtkObject *accessible;
AtkRole a11y_role;
g_assert (prop_id == PROP_ACTION_ROLE);
role = g_value_get_uint (value);
if (role == item->role)
return;
gtk_check_menu_item_set_draw_as_radio (GTK_CHECK_MENU_ITEM (item), role == GTK_ACTION_HELPER_ROLE_RADIO);
gtk_model_menu_item_set_has_indicator (item, role != GTK_ACTION_HELPER_ROLE_NORMAL);
gtk_check_menu_item_set_draw_as_radio (GTK_CHECK_MENU_ITEM (item), role == GTK_MENU_TRACKER_ITEM_ROLE_RADIO);
gtk_model_menu_item_set_has_indicator (item, role != GTK_MENU_TRACKER_ITEM_ROLE_NORMAL);
accessible = gtk_widget_get_accessible (GTK_WIDGET (item));
switch (role)
{
case GTK_ACTION_HELPER_ROLE_NORMAL:
case GTK_MENU_TRACKER_ITEM_ROLE_NORMAL:
a11y_role = ATK_ROLE_MENU_ITEM;
break;
case GTK_ACTION_HELPER_ROLE_TOGGLE:
case GTK_MENU_TRACKER_ITEM_ROLE_CHECK:
a11y_role = ATK_ROLE_CHECK_MENU_ITEM;
break;
case GTK_ACTION_HELPER_ROLE_RADIO:
case GTK_MENU_TRACKER_ITEM_ROLE_RADIO:
a11y_role = ATK_ROLE_RADIO_MENU_ITEM;
break;
@@ -290,6 +124,201 @@ gtk_model_menu_item_set_property (GObject *object, guint prop_id,
atk_object_set_role (accessible, a11y_role);
}
static void
gtk_model_menu_item_set_icon (GtkModelMenuItem *item,
GIcon *icon)
{
GtkWidget *child;
g_return_if_fail (GTK_IS_MODEL_MENU_ITEM (item));
g_return_if_fail (icon == NULL || G_IS_ICON (icon));
child = gtk_bin_get_child (GTK_BIN (item));
/* There are only three possibilities here:
*
* - no child
* - accel label child
* - already a box
*
* Handle the no-child case by having GtkMenuItem create the accel
* label, then we will only have two possible cases.
*/
if (child == NULL)
{
gtk_menu_item_get_label (GTK_MENU_ITEM (item));
child = gtk_bin_get_child (GTK_BIN (item));
g_assert (GTK_IS_LABEL (child));
}
/* If it is a box, make sure there are no images inside of it already.
*/
if (GTK_IS_BOX (child))
{
GList *children;
children = gtk_container_get_children (GTK_CONTAINER (child));
while (children)
{
if (GTK_IS_IMAGE (children->data))
gtk_widget_destroy (children->data);
children = g_list_delete_link (children, children);
}
}
/* If it is not a box, put it into a box, at the end */
if (!GTK_IS_BOX (child))
{
GtkWidget *box;
box = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0);
/* Reparent the child without destroying it */
g_object_ref (child);
gtk_container_remove (GTK_CONTAINER (item), child);
gtk_box_pack_end (GTK_BOX (box), child, TRUE, TRUE, 0);
g_object_unref (child);
gtk_container_add (GTK_CONTAINER (item), box);
gtk_widget_show (box);
/* Now we have a box */
child = box;
}
g_assert (GTK_IS_BOX (child));
/* child is now a box containing a label and no image. Add the icon,
* if appropriate.
*/
if (icon != NULL)
{
GtkWidget *image;
image = gtk_image_new_from_gicon (icon, GTK_ICON_SIZE_MENU);
gtk_box_pack_start (GTK_BOX (child), image, FALSE, FALSE, 0);
gtk_widget_show (image);
}
}
static void
gtk_model_menu_item_set_text (GtkModelMenuItem *item,
const gchar *text)
{
GtkWidget *child;
GList *children;
child = gtk_bin_get_child (GTK_BIN (item));
if (child == NULL)
{
gtk_menu_item_get_label (GTK_MENU_ITEM (item));
child = gtk_bin_get_child (GTK_BIN (item));
g_assert (GTK_IS_LABEL (child));
}
if (GTK_IS_LABEL (child))
{
gtk_label_set_text_with_mnemonic (GTK_LABEL (child), text);
return;
}
if (!GTK_IS_CONTAINER (child))
return;
children = gtk_container_get_children (GTK_CONTAINER (child));
while (children)
{
if (GTK_IS_LABEL (children->data))
gtk_label_set_label (GTK_LABEL (children->data), text);
children = g_list_delete_link (children, children);
}
}
static void
gtk_model_menu_item_set_accel (GtkModelMenuItem *item,
const gchar *accel)
{
GtkWidget *child;
GList *children;
GdkModifierType modifiers;
guint key;
if (accel)
{
gtk_accelerator_parse (accel, &key, &modifiers);
if (!key)
modifiers = 0;
}
else
{
key = 0;
modifiers = 0;
}
child = gtk_bin_get_child (GTK_BIN (item));
if (child == NULL)
{
gtk_menu_item_get_label (GTK_MENU_ITEM (item));
child = gtk_bin_get_child (GTK_BIN (item));
g_assert (GTK_IS_LABEL (child));
}
if (GTK_IS_LABEL (child))
{
gtk_accel_label_set_accel (GTK_ACCEL_LABEL (child), key, modifiers);
return;
}
if (!GTK_IS_CONTAINER (child))
return;
children = gtk_container_get_children (GTK_CONTAINER (child));
while (children)
{
if (GTK_IS_ACCEL_LABEL (children->data))
gtk_accel_label_set_accel (children->data, key, modifiers);
children = g_list_delete_link (children, children);
}
}
void
gtk_model_menu_item_set_property (GObject *object, guint prop_id,
const GValue *value, GParamSpec *pspec)
{
GtkModelMenuItem *item = GTK_MODEL_MENU_ITEM (object);
switch (prop_id)
{
case PROP_ACTION_ROLE:
gtk_model_menu_item_set_action_role (item, g_value_get_enum (value));
break;
case PROP_ICON:
gtk_model_menu_item_set_icon (item, g_value_get_object (value));
break;
case PROP_TEXT:
gtk_model_menu_item_set_text (item, g_value_get_string (value));
break;
case PROP_TOGGLED:
_gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (item), g_value_get_boolean (value));
break;
case PROP_ACCEL:
gtk_model_menu_item_set_accel (item, g_value_get_string (value));
break;
default:
g_assert_not_reached ();
}
}
static void
gtk_model_menu_item_init (GtkModelMenuItem *item)
{
@@ -305,24 +334,31 @@ gtk_model_menu_item_class_init (GtkModelMenuItemClass *class)
check_class->draw_indicator = gtk_model_menu_item_draw_indicator;
item_class->toggle_size_request = gtk_model_menu_item_toggle_size_request;
item_class->activate = gtk_model_menu_item_activate;
object_class->set_property = gtk_model_menu_item_set_property;
g_object_class_install_property (object_class, PROP_ACTION_ROLE,
g_param_spec_uint ("action-role", "action role", "action role",
0, 2, 0, G_PARAM_WRITABLE | G_PARAM_STATIC_STRINGS));
g_param_spec_enum ("action-role", "action role", "action role",
GTK_TYPE_MENU_TRACKER_ITEM_ROLE,
GTK_MENU_TRACKER_ITEM_ROLE_NORMAL,
G_PARAM_WRITABLE | G_PARAM_STATIC_STRINGS));
g_object_class_install_property (object_class, PROP_ICON,
g_param_spec_object ("icon", "icon", "icon", G_TYPE_ICON,
G_PARAM_WRITABLE | G_PARAM_STATIC_STRINGS));
g_object_class_install_property (object_class, PROP_TEXT,
g_param_spec_string ("text", "text", "text", NULL,
G_PARAM_WRITABLE | G_PARAM_STATIC_STRINGS));
g_object_class_install_property (object_class, PROP_TOGGLED,
g_param_spec_boolean ("toggled", "toggled", "toggled", FALSE,
G_PARAM_WRITABLE | G_PARAM_STATIC_STRINGS));
g_object_class_install_property (object_class, PROP_ACCEL,
g_param_spec_string ("accel", "accel", "accel", NULL,
G_PARAM_WRITABLE | G_PARAM_STATIC_STRINGS));
}
GtkWidget *
gtk_model_menu_item_new (GMenuModel *model,
gint item_index,
const gchar *action_namespace)
gtk_model_menu_item_new (void)
{
GtkModelMenuItem *item;
item = g_object_new (GTK_TYPE_MODEL_MENU_ITEM, NULL);
gtk_model_menu_item_setup (item, model, item_index, action_namespace);
return GTK_WIDGET (item);
return g_object_new (GTK_TYPE_MODEL_MENU_ITEM, NULL);
}

View File

@@ -21,6 +21,7 @@
#define __GTK_MODEL_MENU_ITEM_H__
#include <gtk/gtkcheckmenuitem.h>
#include <gtk/gtkmenutrackeritem.h>
#define GTK_TYPE_MODEL_MENU_ITEM (gtk_model_menu_item_get_type ())
#define GTK_MODEL_MENU_ITEM(inst) (G_TYPE_CHECK_INSTANCE_CAST ((inst), \
@@ -34,8 +35,6 @@ G_GNUC_INTERNAL
GType gtk_model_menu_item_get_type (void) G_GNUC_CONST;
G_GNUC_INTERNAL
GtkWidget * gtk_model_menu_item_new (GMenuModel *model,
gint item_index,
const gchar *action_namespace);
GtkWidget * gtk_model_menu_item_new (void);
#endif /* __GTK_MODEL_MENU_ITEM_H__ */

View File

@@ -505,7 +505,7 @@ struct _GtkWidgetPrivate
SizeRequestCache requests;
/* actions attached to this or any parent widget */
GActionMuxer *muxer;
GtkActionMuxer *muxer;
/* The widget's window or its parent window if it does
* not have a window. (Which will be indicated by the
@@ -15351,7 +15351,7 @@ void
_gtk_widget_update_parent_muxer (GtkWidget *widget)
{
GtkWidget *parent;
GActionMuxer *parent_muxer;
GtkActionMuxer *parent_muxer;
if (widget->priv->muxer == NULL)
return;
@@ -15363,15 +15363,15 @@ _gtk_widget_update_parent_muxer (GtkWidget *widget)
parent_muxer = parent ? _gtk_widget_get_action_muxer (parent) : NULL;
g_action_muxer_set_parent (widget->priv->muxer, parent_muxer);
gtk_action_muxer_set_parent (widget->priv->muxer, parent_muxer);
}
GActionMuxer *
GtkActionMuxer *
_gtk_widget_get_action_muxer (GtkWidget *widget)
{
if (widget->priv->muxer == NULL)
{
widget->priv->muxer = g_action_muxer_new ();
widget->priv->muxer = gtk_action_muxer_new ();
_gtk_widget_update_parent_muxer (widget);
}
@@ -15396,7 +15396,7 @@ gtk_widget_insert_action_group (GtkWidget *widget,
const gchar *name,
GActionGroup *group)
{
GActionMuxer *muxer;
GtkActionMuxer *muxer;
g_return_if_fail (GTK_IS_WIDGET (widget));
g_return_if_fail (name != NULL);
@@ -15404,9 +15404,9 @@ gtk_widget_insert_action_group (GtkWidget *widget,
muxer = _gtk_widget_get_action_muxer (widget);
if (group)
g_action_muxer_insert (muxer, name, group);
gtk_action_muxer_insert (muxer, name, group);
else
g_action_muxer_remove (muxer, name);
gtk_action_muxer_remove (muxer, name);
}
/****************************************************************

View File

@@ -27,7 +27,7 @@
#include "gtkcsstypesprivate.h"
#include "gtkwidget.h"
#include "gactionmuxer.h"
#include "gtkactionmuxer.h"
G_BEGIN_DECLS
@@ -147,7 +147,7 @@ void _gtk_widget_invalidate_style_context (GtkWidget *widget
void _gtk_widget_style_context_invalidated (GtkWidget *widget);
void _gtk_widget_update_parent_muxer (GtkWidget *widget);
GActionMuxer * _gtk_widget_get_action_muxer (GtkWidget *widget);
GtkActionMuxer * _gtk_widget_get_action_muxer (GtkWidget *widget);
G_END_DECLS

View File

@@ -216,6 +216,25 @@ random_menu_new (GRand *rand,
static void assert_menu_equality (GtkContainer *container, GMenuModel *model);
static const gchar *
get_label (GtkMenuItem *item)
{
GList *children = gtk_container_get_children (GTK_CONTAINER (item));
const gchar *label = NULL;
while (children)
{
if (GTK_IS_CONTAINER (children->data))
children = g_list_concat (children, gtk_container_get_children (children->data));
else if (GTK_IS_LABEL (children->data))
label = gtk_label_get_text (children->data);
children = g_list_delete_link (children, children);
}
return label;
}
/* a bit complicated with the separators...
*
* with_separators are if subsections of this GMenuModel should have
@@ -307,7 +326,7 @@ assert_section_equality (GSList **children,
our_children = g_slist_remove (our_children, item);
/* get_label() returns "" when it ought to return NULL */
g_assert_cmpstr (gtk_menu_item_get_label (item), ==, label ? label : "");
g_assert_cmpstr (get_label (item), ==, label ? label : "");
submenu_widget = gtk_menu_item_get_submenu (item);
if (submenu)