Application Menu: update for latest GMenu changes
GMenuProxy has been replaced by GDBusMenuModel, and the object path has been moved (now needs to be retrieved from the AppMenu GApplication property). Update the test to prefix each action with "app." as documented, and use a GtkApplicationWindow instead of a plain GtkWindow.
This commit is contained in:
parent
75e9fa9cfb
commit
757fb5796e
104
src/shell-app.c
104
src/shell-app.c
@ -39,10 +39,11 @@ typedef struct {
|
|||||||
gboolean window_sort_stale : 1;
|
gboolean window_sort_stale : 1;
|
||||||
|
|
||||||
/* See GApplication documentation */
|
/* See GApplication documentation */
|
||||||
guint name_watcher_id;
|
gint name_watcher_id;
|
||||||
gchar *dbus_name;
|
gchar *dbus_name;
|
||||||
|
GDBusProxy *app_proxy;
|
||||||
GDBusActionGroup *remote_actions;
|
GDBusActionGroup *remote_actions;
|
||||||
GMenuProxy *remote_menu;
|
GMenuModel *remote_menu;
|
||||||
GCancellable *dbus_cancellable;
|
GCancellable *dbus_cancellable;
|
||||||
} ShellAppRunningState;
|
} ShellAppRunningState;
|
||||||
|
|
||||||
@ -1029,7 +1030,7 @@ on_action_group_acquired (GObject *object,
|
|||||||
ShellApp *self = SHELL_APP (user_data);
|
ShellApp *self = SHELL_APP (user_data);
|
||||||
ShellAppRunningState *state = self->running_state;
|
ShellAppRunningState *state = self->running_state;
|
||||||
GError *error = NULL;
|
GError *error = NULL;
|
||||||
char *object_path;
|
GVariant *menu_property;
|
||||||
|
|
||||||
state->remote_actions = g_dbus_action_group_new_finish (result,
|
state->remote_actions = g_dbus_action_group_new_finish (result,
|
||||||
&error);
|
&error);
|
||||||
@ -1042,6 +1043,65 @@ on_action_group_acquired (GObject *object,
|
|||||||
g_warning ("Unexpected error while reading application actions: %s", error->message);
|
g_warning ("Unexpected error while reading application actions: %s", error->message);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
g_clear_error (&error);
|
||||||
|
g_clear_object (&state->dbus_cancellable);
|
||||||
|
g_clear_object (&state->app_proxy);
|
||||||
|
|
||||||
|
if (state->name_watcher_id)
|
||||||
|
{
|
||||||
|
g_bus_unwatch_name (state->name_watcher_id);
|
||||||
|
state->name_watcher_id = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
g_free (state->dbus_name);
|
||||||
|
state->dbus_name = NULL;
|
||||||
|
|
||||||
|
g_object_unref (self);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
g_object_notify (G_OBJECT (self), "action-group");
|
||||||
|
|
||||||
|
/* third step: the application menu */
|
||||||
|
|
||||||
|
menu_property = g_dbus_proxy_get_cached_property (state->app_proxy, "AppMenu");
|
||||||
|
|
||||||
|
if (menu_property && g_variant_n_children (menu_property) > 0)
|
||||||
|
{
|
||||||
|
const gchar *object_path;
|
||||||
|
|
||||||
|
g_variant_get_child (menu_property, 0, "&o", &object_path);
|
||||||
|
|
||||||
|
state->remote_menu = G_MENU_MODEL (g_dbus_menu_model_get (g_bus_get_sync (G_BUS_TYPE_SESSION, NULL, NULL),
|
||||||
|
state->dbus_name,
|
||||||
|
object_path));
|
||||||
|
|
||||||
|
g_object_notify (G_OBJECT (self), "menu");
|
||||||
|
}
|
||||||
|
|
||||||
|
g_object_unref (self);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
on_dbus_proxy_gotten (GObject *initable,
|
||||||
|
GAsyncResult *result,
|
||||||
|
gpointer user_data)
|
||||||
|
{
|
||||||
|
ShellApp *self = SHELL_APP (user_data);
|
||||||
|
ShellAppRunningState *state = self->running_state;
|
||||||
|
GError *error = NULL;
|
||||||
|
|
||||||
|
state->app_proxy = g_dbus_proxy_new_finish (result,
|
||||||
|
&error);
|
||||||
|
|
||||||
|
if (error)
|
||||||
|
{
|
||||||
|
if (!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED) &&
|
||||||
|
!g_error_matches (error, G_DBUS_ERROR, G_DBUS_ERROR_UNKNOWN_METHOD))
|
||||||
|
{
|
||||||
|
g_warning ("Unexpected error while creating application proxy: %s", error->message);
|
||||||
|
}
|
||||||
|
|
||||||
g_clear_error (&error);
|
g_clear_error (&error);
|
||||||
g_clear_object (&state->dbus_cancellable);
|
g_clear_object (&state->dbus_cancellable);
|
||||||
|
|
||||||
@ -1058,19 +1118,15 @@ on_action_group_acquired (GObject *object,
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
object_path = g_strconcat ("/", state->dbus_name, NULL);
|
/* on to the second step, the primary action group */
|
||||||
g_strdelimit (object_path, ".", '/');
|
|
||||||
|
|
||||||
state->remote_menu = g_menu_proxy_get (g_bus_get_sync (G_BUS_TYPE_SESSION, NULL, NULL),
|
g_dbus_action_group_new (g_dbus_proxy_get_connection (state->app_proxy),
|
||||||
state->dbus_name,
|
g_dbus_proxy_get_name (state->app_proxy),
|
||||||
object_path);
|
g_dbus_proxy_get_object_path (state->app_proxy),
|
||||||
|
G_DBUS_ACTION_GROUP_FLAGS_NONE,
|
||||||
g_object_notify (G_OBJECT (self), "dbus-id");
|
state->dbus_cancellable,
|
||||||
g_object_notify (G_OBJECT (self), "action-group");
|
on_action_group_acquired,
|
||||||
g_object_notify (G_OBJECT (self), "menu");
|
self);
|
||||||
|
|
||||||
g_object_unref (self);
|
|
||||||
g_free (object_path);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
@ -1091,14 +1147,20 @@ on_dbus_name_appeared (GDBusConnection *bus,
|
|||||||
if (!state->dbus_cancellable)
|
if (!state->dbus_cancellable)
|
||||||
state->dbus_cancellable = g_cancellable_new ();
|
state->dbus_cancellable = g_cancellable_new ();
|
||||||
|
|
||||||
g_dbus_action_group_new (bus,
|
/* first step: the application proxy */
|
||||||
name,
|
|
||||||
|
g_dbus_proxy_new (bus,
|
||||||
|
G_DBUS_PROXY_FLAGS_NONE,
|
||||||
|
NULL, /* interface info */
|
||||||
|
name_owner,
|
||||||
object_path,
|
object_path,
|
||||||
G_DBUS_ACTION_GROUP_FLAGS_NONE,
|
"org.gtk.Application",
|
||||||
state->dbus_cancellable,
|
state->dbus_cancellable,
|
||||||
on_action_group_acquired,
|
on_dbus_proxy_gotten,
|
||||||
g_object_ref (self));
|
g_object_ref (self));
|
||||||
|
|
||||||
|
g_object_notify (G_OBJECT (self), "dbus-id");
|
||||||
|
|
||||||
g_free (object_path);
|
g_free (object_path);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1118,6 +1180,7 @@ on_dbus_name_disappeared (GDBusConnection *bus,
|
|||||||
g_clear_object (&state->dbus_cancellable);
|
g_clear_object (&state->dbus_cancellable);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
g_clear_object (&state->app_proxy);
|
||||||
g_clear_object (&state->remote_actions);
|
g_clear_object (&state->remote_actions);
|
||||||
g_clear_object (&state->remote_menu);
|
g_clear_object (&state->remote_menu);
|
||||||
|
|
||||||
@ -1362,6 +1425,7 @@ unref_running_state (ShellAppRunningState *state)
|
|||||||
g_object_unref (state->dbus_cancellable);
|
g_object_unref (state->dbus_cancellable);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
g_clear_object (&state->app_proxy);
|
||||||
g_clear_object (&state->remote_actions);
|
g_clear_object (&state->remote_actions);
|
||||||
g_clear_object (&state->remote_menu);
|
g_clear_object (&state->remote_menu);
|
||||||
g_free (state->dbus_name);
|
g_free (state->dbus_name);
|
||||||
@ -1650,7 +1714,7 @@ shell_app_class_init(ShellAppClass *klass)
|
|||||||
g_param_spec_object ("menu",
|
g_param_spec_object ("menu",
|
||||||
"Application Menu",
|
"Application Menu",
|
||||||
"The primary menu exported by the remote application",
|
"The primary menu exported by the remote application",
|
||||||
G_TYPE_MENU_PROXY,
|
G_TYPE_MENU_MODEL,
|
||||||
G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
|
G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -19,7 +19,7 @@ function do_action_toggle(action) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function do_action_state_change(action) {
|
function do_action_state_change(action) {
|
||||||
print ("Action '" + action.name + "' has now state '" + action.state.deep_unpack() + "'");
|
print ("Action '" + action.name + "' has now state " + action.state.print(true));
|
||||||
}
|
}
|
||||||
|
|
||||||
function main() {
|
function main() {
|
||||||
@ -57,17 +57,17 @@ function main() {
|
|||||||
app.add_action(action);
|
app.add_action(action);
|
||||||
|
|
||||||
let menu = new Gio.Menu();
|
let menu = new Gio.Menu();
|
||||||
menu.append('An action', 'one');
|
menu.append('An action', 'app.one');
|
||||||
|
|
||||||
let section = new Gio.Menu();
|
let section = new Gio.Menu();
|
||||||
section.append('Another action', 'two');
|
section.append('Another action', 'app.two');
|
||||||
section.append('Same as above', 'two');
|
section.append('Same as above', 'app.two');
|
||||||
menu.append_section(null, section);
|
menu.append_section(null, section);
|
||||||
|
|
||||||
// another section, to check separators
|
// another section, to check separators
|
||||||
section = new Gio.Menu();
|
section = new Gio.Menu();
|
||||||
section.append('Checkbox', 'toggle');
|
section.append('Checkbox', 'app.toggle');
|
||||||
section.append('Disabled', 'disable');
|
section.append('Disabled', 'app.disable');
|
||||||
menu.append_section(null, section);
|
menu.append_section(null, section);
|
||||||
|
|
||||||
// empty sections or submenus should be invisible
|
// empty sections or submenus should be invisible
|
||||||
@ -75,25 +75,26 @@ function main() {
|
|||||||
menu.append_submenu('Empty submenu', new Gio.Menu());
|
menu.append_submenu('Empty submenu', new Gio.Menu());
|
||||||
|
|
||||||
let submenu = new Gio.Menu();
|
let submenu = new Gio.Menu();
|
||||||
submenu.append('Open c:\\', 'parameter-string::c:\\');
|
submenu.append('Open c:\\', 'app.parameter-string::c:\\');
|
||||||
submenu.append('Open /home', 'parameter-string::/home');
|
submenu.append('Open /home', 'app.parameter-string::/home');
|
||||||
menu.append_submenu('Recent files', submenu);
|
menu.append_submenu('Recent files', submenu);
|
||||||
|
|
||||||
let item = Gio.MenuItem.new('Say 42', null);
|
let item = Gio.MenuItem.new('Say 42', null);
|
||||||
item.set_action_and_target_value('parameter-int', GLib.Variant.new('u', 42));
|
item.set_action_and_target_value('app.parameter-int', GLib.Variant.new('u', 42));
|
||||||
menu.append_item(item);
|
menu.append_item(item);
|
||||||
|
|
||||||
let item = Gio.MenuItem.new('Say 43', null);
|
let item = Gio.MenuItem.new('Say 43', null);
|
||||||
item.set_action_and_target_value('parameter-int', GLib.Variant.new('u', 43));
|
item.set_action_and_target_value('app.parameter-int', GLib.Variant.new('u', 43));
|
||||||
menu.append_item(item);
|
menu.append_item(item);
|
||||||
|
|
||||||
app.set_app_menu(menu);
|
app.set_app_menu(menu);
|
||||||
|
|
||||||
let window = null;
|
let window = null;
|
||||||
|
|
||||||
|
app.connect_after('startup', function(app) {
|
||||||
|
window = new Gtk.ApplicationWindow({ title: "Test Application", application: app });
|
||||||
|
});
|
||||||
app.connect('activate', function(app) {
|
app.connect('activate', function(app) {
|
||||||
if (!window)
|
|
||||||
window = new Gtk.Window({ title: "Test Application", application: app });
|
|
||||||
window.present();
|
window.present();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user