mirror of
https://gitlab.gnome.org/GNOME/glib.git
synced 2024-11-09 19:06:15 +01:00
new GApplication implementation
This commit is contained in:
parent
9d80c36141
commit
a7923a4aa3
@ -142,10 +142,11 @@ application_headers = \
|
||||
gapplication.h
|
||||
|
||||
application_sources = \
|
||||
gactiongroup.c \
|
||||
gsimpleactiongroup.c \
|
||||
gaction.c \
|
||||
gsimpleaction.c \
|
||||
gactiongroup.c \
|
||||
gsimpleactiongroup.c \
|
||||
gaction.c \
|
||||
gsimpleaction.c \
|
||||
gapplicationimpl-dbus.c \
|
||||
gapplication.c
|
||||
|
||||
local_sources = \
|
||||
|
2190
gio/gapplication.c
2190
gio/gapplication.c
File diff suppressed because it is too large
Load Diff
@ -1,6 +1,5 @@
|
||||
/* GIO - GLib Input, Output and Streaming Library
|
||||
*
|
||||
* Copyright © 2010 Red Hat, Inc
|
||||
/*
|
||||
* Copyright © 2010 Codethink Limited
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published
|
||||
@ -17,8 +16,7 @@
|
||||
* Free Software Foundation, Inc., 59 Temple Place, Suite 330,
|
||||
* Boston, MA 02111-1307, USA.
|
||||
*
|
||||
* Authors: Colin Walters <walters@verbum.org>
|
||||
* Emmanuele Bassi <ebassi@linux.intel.com>
|
||||
* Authors: Ryan Lortie <desrt@desrt.ca>
|
||||
*/
|
||||
|
||||
#if !defined (__GIO_GIO_H_INSIDE__) && !defined (GIO_COMPILATION)
|
||||
@ -28,21 +26,22 @@
|
||||
#ifndef __G_APPLICATION_H__
|
||||
#define __G_APPLICATION_H__
|
||||
|
||||
#include <glib-object.h>
|
||||
#include <gio/giotypes.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#define G_TYPE_APPLICATION (g_application_get_type ())
|
||||
#define G_APPLICATION(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), G_TYPE_APPLICATION, GApplication))
|
||||
#define G_APPLICATION_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), G_TYPE_APPLICATION, GApplicationClass))
|
||||
#define G_IS_APPLICATION(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), G_TYPE_APPLICATION))
|
||||
#define G_IS_APPLICATION_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), G_TYPE_APPLICATION))
|
||||
#define G_APPLICATION_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), G_TYPE_APPLICATION, GApplicationClass))
|
||||
#define G_TYPE_APPLICATION (g_application_get_type ())
|
||||
#define G_APPLICATION(inst) (G_TYPE_CHECK_INSTANCE_CAST ((inst), \
|
||||
G_TYPE_APPLICATION, GApplication))
|
||||
#define G_APPLICATION_CLASS(class) (G_TYPE_CHECK_CLASS_CAST ((class), \
|
||||
G_TYPE_APPLICATION, GApplicationClass))
|
||||
#define G_IS_APPLICATION(inst) (G_TYPE_CHECK_INSTANCE_TYPE ((inst), G_TYPE_APPLICATION))
|
||||
#define G_IS_APPLICATION_CLASS(class) (G_TYPE_CHECK_CLASS_TYPE ((class), G_TYPE_APPLICATION))
|
||||
#define G_APPLICATION_GET_CLASS(inst) (G_TYPE_INSTANCE_GET_CLASS ((inst), \
|
||||
G_TYPE_APPLICATION, GApplicationClass))
|
||||
|
||||
typedef struct _GApplication GApplication;
|
||||
typedef struct _GApplicationPrivate GApplicationPrivate;
|
||||
typedef struct _GApplicationClass GApplicationClass;
|
||||
typedef struct _GApplicationPrivate GApplicationPrivate;
|
||||
typedef struct _GApplicationClass GApplicationClass;
|
||||
|
||||
/**
|
||||
* GApplication:
|
||||
@ -62,13 +61,19 @@ struct _GApplication
|
||||
|
||||
/**
|
||||
* GApplicationClass:
|
||||
* @action_with_data: class handler for the #GApplication::action-with-data signal
|
||||
* @quit_with_data: class handler for the #GApplication::quit-with-data signal
|
||||
* @prepare_activation: class handler for the #GApplication::prepare-activation signal
|
||||
* @run: virtual function, called by g_application_run()
|
||||
*
|
||||
* The <structname>GApplicationClass</structname> structure contains
|
||||
* private data only
|
||||
* @startup: invoked on the primary instance immediately after registration
|
||||
* @activate: invoked on the primary instance when an activation occurs
|
||||
* @open: invoked on the primary instance when there are files to open
|
||||
* @local_command_line: invoked (locally) when the process has been invoked via commandline execution. The
|
||||
* virtual function has the chance to inspect (and possibly replace) the list of command line arguments. See
|
||||
* g_application_run() for more information.
|
||||
* @before_emit: invoked on the primary instance before 'activate', 'open' or any action invocation
|
||||
* @after_emit: invoked on the primary instance after 'activate', 'open' or any action invocation
|
||||
* @add_platform_data: invoked (locally) to add 'platform data' to be sent to the primary instance when
|
||||
* activating, opening or invoking actions
|
||||
* @quit_mainloop: invoked on the primary instance when the use count of the application drops to zero (and
|
||||
* after any inactivity timeout, if requested)
|
||||
* @run_mainloop: invoked on the primary instance from g_application_run() if the use-count is non-zero
|
||||
*
|
||||
* Since: 2.26
|
||||
*/
|
||||
@ -79,70 +84,78 @@ struct _GApplicationClass
|
||||
|
||||
/*< public >*/
|
||||
/* signals */
|
||||
void (* action_with_data) (GApplication *application,
|
||||
const gchar *action_name,
|
||||
GVariant *platform_data);
|
||||
gboolean (* quit_with_data) (GApplication *application,
|
||||
GVariant *platform_data);
|
||||
void (* prepare_activation) (GApplication *application,
|
||||
GVariant *arguments,
|
||||
GVariant *platform_data);
|
||||
void (* startup) (GApplication *application);
|
||||
|
||||
void (* activate) (GApplication *application);
|
||||
|
||||
void (* open) (GApplication *application,
|
||||
GFile **files,
|
||||
gint n_files,
|
||||
const gchar *hint);
|
||||
|
||||
gpointer _reserved_1;
|
||||
|
||||
/* vfuncs */
|
||||
void (* run) (GApplication *application);
|
||||
gboolean (* local_command_line) (GApplication *application,
|
||||
GVariant **arguments,
|
||||
int *exit_status);
|
||||
|
||||
gpointer _reserved_2;
|
||||
|
||||
void (* before_emit) (GApplication *application,
|
||||
GVariant *platform_data);
|
||||
void (* after_emit) (GApplication *application,
|
||||
GVariant *platform_data);
|
||||
void (* add_platform_data) (GApplication *application,
|
||||
GVariantBuilder *builder);
|
||||
void (* quit_mainloop) (GApplication *application);
|
||||
void (* run_mainloop) (GApplication *application);
|
||||
|
||||
/*< private >*/
|
||||
/* Padding for future expansion */
|
||||
void (*_g_reserved1) (void);
|
||||
void (*_g_reserved2) (void);
|
||||
void (*_g_reserved3) (void);
|
||||
void (*_g_reserved4) (void);
|
||||
void (*_g_reserved5) (void);
|
||||
void (*_g_reserved6) (void);
|
||||
gpointer padding[12];
|
||||
};
|
||||
GType g_application_get_type (void) G_GNUC_CONST;
|
||||
|
||||
GApplication * g_application_new (const gchar *appid,
|
||||
int argc,
|
||||
char **argv);
|
||||
GType g_application_get_type (void) G_GNUC_CONST;
|
||||
|
||||
GApplication * g_application_try_new (const gchar *appid,
|
||||
int argc,
|
||||
char **argv,
|
||||
GError **error);
|
||||
gboolean g_application_id_is_valid (const gchar *application_id);
|
||||
|
||||
GApplication * g_application_unregistered_try_new (const gchar *appid,
|
||||
int argc,
|
||||
char **argv,
|
||||
GError **error);
|
||||
GApplication * g_application_new (const gchar *application_id,
|
||||
GApplicationFlags flags);
|
||||
|
||||
gboolean g_application_register (GApplication *application);
|
||||
const gchar * g_application_get_application_id (GApplication *application);
|
||||
void g_application_set_application_id (GApplication *application,
|
||||
const gchar *application_id);
|
||||
|
||||
GApplication * g_application_get_instance (void);
|
||||
G_CONST_RETURN gchar * g_application_get_id (GApplication *application);
|
||||
guint g_application_get_inactivity_timeout (GApplication *application);
|
||||
void g_application_set_inactivity_timeout (GApplication *application,
|
||||
guint inactivity_timeout);
|
||||
|
||||
void g_application_add_action (GApplication *application,
|
||||
const gchar *name,
|
||||
const gchar *description);
|
||||
void g_application_remove_action (GApplication *application,
|
||||
const gchar *name);
|
||||
gchar ** g_application_list_actions (GApplication *application);
|
||||
void g_application_set_action_enabled (GApplication *application,
|
||||
const gchar *name,
|
||||
gboolean enabled);
|
||||
gboolean g_application_get_action_enabled (GApplication *application,
|
||||
const gchar *name);
|
||||
G_CONST_RETURN gchar * g_application_get_action_description (GApplication *application,
|
||||
const gchar *name);
|
||||
void g_application_invoke_action (GApplication *application,
|
||||
const gchar *name,
|
||||
GVariant *platform_data);
|
||||
GApplicationFlags g_application_get_flags (GApplication *application);
|
||||
void g_application_set_flags (GApplication *application,
|
||||
GApplicationFlags flags);
|
||||
|
||||
void g_application_run (GApplication *application);
|
||||
gboolean g_application_quit_with_data (GApplication *application,
|
||||
GVariant *platform_data);
|
||||
gboolean g_application_get_is_registered (GApplication *application);
|
||||
gboolean g_application_get_is_remote (GApplication *application);
|
||||
|
||||
gboolean g_application_is_remote (GApplication *application);
|
||||
gboolean g_application_register (GApplication *application,
|
||||
GCancellable *cancellable,
|
||||
GError **error);
|
||||
|
||||
void g_application_hold (GApplication *application);
|
||||
void g_application_release (GApplication *application);
|
||||
|
||||
void g_application_activate (GApplication *application);
|
||||
|
||||
void g_application_open (GApplication *application,
|
||||
GFile **file,
|
||||
gint n_files,
|
||||
const gchar *hint);
|
||||
|
||||
int g_application_run (GApplication *application,
|
||||
int argc,
|
||||
char **argv);
|
||||
int g_application_run_with_arguments (GApplication *application,
|
||||
GVariant *arguments);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
|
59
gio/gapplicationimpl-dbus-interface.c
Normal file
59
gio/gapplicationimpl-dbus-interface.c
Normal file
@ -0,0 +1,59 @@
|
||||
/*
|
||||
* Copyright © 2010 Codethink 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, write to the
|
||||
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
|
||||
* Boston, MA 02111-1307, USA.
|
||||
*
|
||||
* Author: Ryan Lortie <desrt@desrt.ca>
|
||||
*/
|
||||
|
||||
static const GDBusArgInfo platform_data_arg = { -1, (gchar *) "platform_data", (gchar *) "a{sv}" };
|
||||
|
||||
static const GDBusArgInfo open_uris_arg = { -1, (gchar *) "uris", (gchar *) "as" };
|
||||
static const GDBusArgInfo open_hint_arg = { -1, (gchar *) "hint", (gchar *) "s" };
|
||||
|
||||
static const GDBusArgInfo invoke_action_name_arg = { -1, (gchar *) "name", (gchar *) "s" };
|
||||
static const GDBusArgInfo invoke_action_args_arg = { -1, (gchar *) "args", (gchar *) "v" };
|
||||
|
||||
static const GDBusArgInfo cmdline_path_arg = { -1, (gchar *) "path", (gchar *) "o" };
|
||||
static const GDBusArgInfo cmdline_arguments_arg = { -1, (gchar *) "arguments", (gchar *) "aay" };
|
||||
static const GDBusArgInfo cmdline_exit_status_arg = { -1, (gchar *) "exit_status", (gchar *) "i" };
|
||||
|
||||
static const GDBusArgInfo *activate_in[] = { &platform_data_arg, NULL };
|
||||
static const GDBusArgInfo *activate_out[] = { NULL };
|
||||
|
||||
static const GDBusArgInfo *open_in[] = { &open_uris_arg, &open_hint_arg, &platform_data_arg, NULL };
|
||||
static const GDBusArgInfo *open_out[] = { NULL };
|
||||
|
||||
static const GDBusMethodInfo activate_method = {
|
||||
-1, (gchar *) "Activate",
|
||||
(GDBusArgInfo **) activate_in,
|
||||
(GDBusArgInfo **) activate_out
|
||||
};
|
||||
|
||||
static const GDBusMethodInfo open_method = {
|
||||
-1, (gchar *) "Open",
|
||||
(GDBusArgInfo **) open_in,
|
||||
(GDBusArgInfo **) open_out
|
||||
};
|
||||
|
||||
static const GDBusMethodInfo *application_methods[] = {
|
||||
&activate_method, &open_method, NULL
|
||||
};
|
||||
|
||||
const GDBusInterfaceInfo org_gtk_Application = {
|
||||
-1, (gchar *) "org.gtk.Application",
|
||||
(GDBusMethodInfo **) application_methods
|
||||
};
|
304
gio/gapplicationimpl-dbus.c
Normal file
304
gio/gapplicationimpl-dbus.c
Normal file
@ -0,0 +1,304 @@
|
||||
/*
|
||||
* Copyright © 2010 Codethink 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 License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* 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, write to the
|
||||
* Free Software Foundation, Inc., 59 Temple Place, Suite 330,
|
||||
* Boston, MA 02111-1307, USA.
|
||||
*
|
||||
* Authors: Ryan Lortie <desrt@desrt.ca>
|
||||
*/
|
||||
|
||||
#include "gapplicationimpl.h"
|
||||
|
||||
#include "gapplication.h"
|
||||
#include "gfile.h"
|
||||
#include "gdbusconnection.h"
|
||||
#include "gdbusintrospection.h"
|
||||
#include "gdbuserror.h"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
|
||||
#include "gapplicationimpl-dbus-interface.c"
|
||||
|
||||
struct _GApplicationImpl
|
||||
{
|
||||
GDBusConnection *session_bus;
|
||||
const gchar *bus_name;
|
||||
gchar *object_path;
|
||||
guint object_id;
|
||||
gpointer app;
|
||||
|
||||
GMainLoop *cmdline_mainloop;
|
||||
};
|
||||
|
||||
static void
|
||||
g_application_impl_method_call (GDBusConnection *connection,
|
||||
const gchar *sender,
|
||||
const gchar *object_path,
|
||||
const gchar *interface_name,
|
||||
const gchar *method_name,
|
||||
GVariant *parameters,
|
||||
GDBusMethodInvocation *invocation,
|
||||
gpointer user_data)
|
||||
{
|
||||
GApplicationImpl *impl = user_data;
|
||||
GApplicationClass *class;
|
||||
|
||||
class = G_APPLICATION_GET_CLASS (impl->app);
|
||||
|
||||
if (strcmp (method_name, "Activate") == 0)
|
||||
{
|
||||
GVariant *platform_data;
|
||||
|
||||
g_variant_get (parameters, "(@a{sv})", &platform_data);
|
||||
class->before_emit (impl->app, platform_data);
|
||||
g_signal_emit_by_name (impl->app, "activate");
|
||||
class->after_emit (impl->app, platform_data);
|
||||
g_variant_unref (platform_data);
|
||||
}
|
||||
|
||||
else if (strcmp (method_name, "Open") == 0)
|
||||
{
|
||||
GVariant *platform_data;
|
||||
const gchar *hint;
|
||||
GVariant *array;
|
||||
GFile **files;
|
||||
gint n, i;
|
||||
|
||||
g_variant_get (parameters, "(@ass@a{sv})",
|
||||
&array, &hint, &platform_data);
|
||||
|
||||
n = g_variant_n_children (array);
|
||||
files = g_new (GFile *, n + 1);
|
||||
|
||||
for (i = 0; i < n; i++)
|
||||
{
|
||||
const gchar *uri;
|
||||
|
||||
g_variant_get_child (array, i, "&s", &uri);
|
||||
files[i] = g_file_new_for_uri (uri);
|
||||
}
|
||||
g_variant_unref (array);
|
||||
files[n] = NULL;
|
||||
|
||||
class->before_emit (impl->app, platform_data);
|
||||
g_signal_emit_by_name (impl->app, "open", files, n, hint);
|
||||
class->after_emit (impl->app, platform_data);
|
||||
|
||||
g_variant_unref (platform_data);
|
||||
|
||||
for (i = 0; i < n; i++)
|
||||
g_object_unref (files[i]);
|
||||
g_free (files);
|
||||
}
|
||||
|
||||
else
|
||||
g_assert_not_reached ();
|
||||
}
|
||||
|
||||
static gchar *
|
||||
application_path_from_appid (const gchar *appid)
|
||||
{
|
||||
gchar *appid_path, *iter;
|
||||
|
||||
appid_path = g_strconcat ("/", appid, NULL);
|
||||
for (iter = appid_path; *iter; iter++)
|
||||
{
|
||||
if (*iter == '.')
|
||||
*iter = '/';
|
||||
}
|
||||
|
||||
return appid_path;
|
||||
}
|
||||
|
||||
void
|
||||
g_application_impl_destroy (GApplicationImpl *impl)
|
||||
{
|
||||
if (impl->session_bus)
|
||||
{
|
||||
if (impl->object_id)
|
||||
g_dbus_connection_unregister_object (impl->session_bus,
|
||||
impl->object_id);
|
||||
|
||||
g_object_unref (impl->session_bus);
|
||||
g_free (impl->object_path);
|
||||
}
|
||||
else
|
||||
{
|
||||
g_assert (impl->object_path == NULL);
|
||||
g_assert (impl->object_id == 0);
|
||||
}
|
||||
|
||||
g_slice_free (GApplicationImpl, impl);
|
||||
}
|
||||
|
||||
GApplicationImpl *
|
||||
g_application_impl_register (GApplication *application,
|
||||
const gchar *appid,
|
||||
GApplicationFlags flags,
|
||||
gboolean *is_remote,
|
||||
GCancellable *cancellable,
|
||||
GError **error)
|
||||
{
|
||||
const static GDBusInterfaceVTable vtable = {
|
||||
g_application_impl_method_call
|
||||
};
|
||||
GApplicationImpl *impl;
|
||||
GVariant *reply;
|
||||
guint32 rval;
|
||||
|
||||
impl = g_slice_new (GApplicationImpl);
|
||||
|
||||
impl->app = application;
|
||||
impl->bus_name = appid;
|
||||
|
||||
impl->session_bus = g_bus_get_sync (G_BUS_TYPE_SESSION,
|
||||
cancellable, error);
|
||||
|
||||
if (impl->session_bus == NULL)
|
||||
{
|
||||
g_slice_free (GApplicationImpl, impl);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
impl->object_path = application_path_from_appid (appid);
|
||||
|
||||
if (flags & G_APPLICATION_FLAGS_IS_LAUNCHER)
|
||||
{
|
||||
impl->object_id = 0;
|
||||
*is_remote = TRUE;
|
||||
|
||||
return impl;
|
||||
}
|
||||
|
||||
impl->object_id = g_dbus_connection_register_object (impl->session_bus,
|
||||
impl->object_path,
|
||||
(GDBusInterfaceInfo *)
|
||||
&org_gtk_Application,
|
||||
&vtable,
|
||||
impl, NULL,
|
||||
error);
|
||||
|
||||
if (impl->object_id == 0)
|
||||
{
|
||||
g_object_unref (impl->session_bus);
|
||||
g_free (impl->object_path);
|
||||
impl->session_bus = NULL;
|
||||
impl->object_path = NULL;
|
||||
|
||||
g_slice_free (GApplicationImpl, impl);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
reply = g_dbus_connection_call_sync (impl->session_bus,
|
||||
"org.freedesktop.DBus",
|
||||
"/org/freedesktop/DBus",
|
||||
"org.freedesktop.DBus",
|
||||
"RequestName",
|
||||
g_variant_new ("(su)",
|
||||
/* DBUS_NAME_FLAG_DO_NOT_QUEUE: 0x4 */
|
||||
impl->bus_name, 0x4),
|
||||
G_VARIANT_TYPE ("(u)"),
|
||||
0, -1, cancellable, error);
|
||||
|
||||
if (reply == NULL)
|
||||
{
|
||||
g_dbus_connection_unregister_object (impl->session_bus,
|
||||
impl->object_id);
|
||||
impl->object_id = 0;
|
||||
|
||||
g_object_unref (impl->session_bus);
|
||||
g_free (impl->object_path);
|
||||
impl->session_bus = NULL;
|
||||
impl->object_path = NULL;
|
||||
|
||||
g_slice_free (GApplicationImpl, impl);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
g_variant_get (reply, "(u)", &rval);
|
||||
g_variant_unref (reply);
|
||||
|
||||
/* DBUS_REQUEST_NAME_REPLY_EXISTS: 3 */
|
||||
if ((*is_remote = (rval == 3)))
|
||||
{
|
||||
g_dbus_connection_unregister_object (impl->session_bus,
|
||||
impl->object_id);
|
||||
impl->object_id = 0;
|
||||
|
||||
if (flags & G_APPLICATION_FLAGS_IS_SERVICE)
|
||||
{
|
||||
g_set_error (error, G_DBUS_ERROR, G_DBUS_ERROR_FAILED,
|
||||
"Unable to acquire bus name `%s'", appid);
|
||||
g_object_unref (impl->session_bus);
|
||||
g_free (impl->object_path);
|
||||
|
||||
g_slice_free (GApplicationImpl, impl);
|
||||
impl = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
return impl;
|
||||
}
|
||||
|
||||
void
|
||||
g_application_impl_activate (GApplicationImpl *impl,
|
||||
GVariant *platform_data)
|
||||
{
|
||||
g_dbus_connection_call (impl->session_bus,
|
||||
impl->bus_name,
|
||||
impl->object_path,
|
||||
"org.gtk.Application",
|
||||
"Activate",
|
||||
g_variant_new ("(@a{sv})", platform_data),
|
||||
NULL, 0, -1, NULL, NULL, NULL);
|
||||
}
|
||||
|
||||
void
|
||||
g_application_impl_open (GApplicationImpl *impl,
|
||||
GFile **files,
|
||||
gint n_files,
|
||||
const gchar *hint,
|
||||
GVariant *platform_data)
|
||||
{
|
||||
GVariantBuilder builder;
|
||||
gint i;
|
||||
|
||||
g_variant_builder_init (&builder, G_VARIANT_TYPE ("(assa{sv})"));
|
||||
g_variant_builder_open (&builder, G_VARIANT_TYPE_STRING_ARRAY);
|
||||
for (i = 0; i < n_files; i++)
|
||||
{
|
||||
gchar *uri = g_file_get_uri (files[i]);
|
||||
g_variant_builder_add (&builder, "s", uri);
|
||||
g_free (uri);
|
||||
}
|
||||
g_variant_builder_close (&builder);
|
||||
g_variant_builder_add (&builder, "s", hint);
|
||||
g_variant_builder_add_value (&builder, platform_data);
|
||||
|
||||
g_dbus_connection_call (impl->session_bus,
|
||||
impl->bus_name,
|
||||
impl->object_path,
|
||||
"org.gtk.Application",
|
||||
"Open",
|
||||
g_variant_builder_end (&builder),
|
||||
NULL, 0, -1, NULL, NULL, NULL);
|
||||
}
|
||||
|
||||
void
|
||||
g_application_impl_flush (GApplicationImpl *impl)
|
||||
{
|
||||
g_dbus_connection_flush_sync (impl->session_bus, NULL, NULL);
|
||||
}
|
28
gio/gapplicationimpl.h
Normal file
28
gio/gapplicationimpl.h
Normal file
@ -0,0 +1,28 @@
|
||||
#include "giotypes.h"
|
||||
|
||||
typedef struct _GApplicationImpl GApplicationImpl;
|
||||
|
||||
G_GNUC_INTERNAL
|
||||
void g_application_impl_destroy (GApplicationImpl *impl);
|
||||
|
||||
G_GNUC_INTERNAL
|
||||
GApplicationImpl * g_application_impl_register (GApplication *application,
|
||||
const gchar *appid,
|
||||
GApplicationFlags flags,
|
||||
gboolean *is_remote,
|
||||
GCancellable *cancellable,
|
||||
GError **error);
|
||||
|
||||
G_GNUC_INTERNAL
|
||||
void g_application_impl_activate (GApplicationImpl *impl,
|
||||
GVariant *platform_data);
|
||||
|
||||
G_GNUC_INTERNAL
|
||||
void g_application_impl_open (GApplicationImpl *impl,
|
||||
GFile **files,
|
||||
gint n_files,
|
||||
const gchar *hint,
|
||||
GVariant *platform_data);
|
||||
|
||||
G_GNUC_INTERNAL
|
||||
void g_application_impl_flush (GApplicationImpl *impl);
|
@ -1,424 +0,0 @@
|
||||
/* GIO - GLib Input, Output and Streaming Library
|
||||
*
|
||||
* Copyright © 2010 Red Hat, Inc
|
||||
*
|
||||
* 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 License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* 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, write to the
|
||||
* Free Software Foundation, Inc., 59 Temple Place, Suite 330,
|
||||
* Boston, MA 02111-1307, USA.
|
||||
*
|
||||
* Authors: Colin Walters <walters@verbum.org>
|
||||
*/
|
||||
|
||||
#define G_APPLICATION_IFACE "org.gtk.Application"
|
||||
|
||||
static void
|
||||
application_dbus_method_call (GDBusConnection *connection,
|
||||
const gchar *sender,
|
||||
const gchar *object_path,
|
||||
const gchar *interface_name,
|
||||
const gchar *method_name,
|
||||
GVariant *parameters,
|
||||
GDBusMethodInvocation *invocation,
|
||||
gpointer user_data)
|
||||
{
|
||||
GApplication *app = G_APPLICATION (user_data);
|
||||
|
||||
if (method_name == NULL && *method_name == '\0')
|
||||
return;
|
||||
|
||||
if (strcmp (method_name, "Quit") == 0)
|
||||
{
|
||||
GVariant *platform_data;
|
||||
|
||||
g_variant_get (parameters, "(@a{sv})", &platform_data);
|
||||
|
||||
g_dbus_method_invocation_return_value (invocation, NULL);
|
||||
|
||||
g_application_quit_with_data (app, platform_data);
|
||||
|
||||
g_variant_unref (platform_data);
|
||||
}
|
||||
else if (strcmp (method_name, "ListActions") == 0)
|
||||
{
|
||||
GHashTableIter iter;
|
||||
GApplicationAction *value;
|
||||
GVariantBuilder builder;
|
||||
|
||||
g_variant_builder_init (&builder, G_VARIANT_TYPE ("(a{s(sb)})"));
|
||||
g_variant_builder_open (&builder, G_VARIANT_TYPE ("a{s(sb)}"));
|
||||
g_hash_table_iter_init (&iter, app->priv->actions);
|
||||
while (g_hash_table_iter_next (&iter, NULL, (gpointer *)&value))
|
||||
g_variant_builder_add (&builder, "{s(sb)}",
|
||||
value->name,
|
||||
value->description ? value->description : "",
|
||||
value->enabled);
|
||||
g_variant_builder_close (&builder);
|
||||
|
||||
g_dbus_method_invocation_return_value (invocation,
|
||||
g_variant_builder_end (&builder));
|
||||
}
|
||||
else if (strcmp (method_name, "InvokeAction") == 0)
|
||||
{
|
||||
const char *action_name;
|
||||
GVariant *platform_data;
|
||||
GApplicationAction *action;
|
||||
|
||||
g_variant_get (parameters, "(&s@a{sv})", &action_name, &platform_data);
|
||||
|
||||
action = g_hash_table_lookup (app->priv->actions, action_name);
|
||||
|
||||
if (!action)
|
||||
{
|
||||
char *errmsg = g_strdup_printf ("Invalid action: %s", action_name);
|
||||
g_dbus_method_invocation_return_dbus_error (invocation, G_APPLICATION_IFACE ".InvalidAction", errmsg);
|
||||
g_free (errmsg);
|
||||
g_variant_unref (platform_data);
|
||||
return;
|
||||
}
|
||||
|
||||
g_signal_emit (app, application_signals[ACTION_WITH_DATA],
|
||||
g_quark_from_string (action_name), action_name, platform_data);
|
||||
|
||||
g_dbus_method_invocation_return_value (invocation, NULL);
|
||||
g_variant_unref (platform_data);
|
||||
}
|
||||
else if (strcmp (method_name, "Activate") == 0)
|
||||
{
|
||||
GVariant *args;
|
||||
GVariant *platform_data;
|
||||
|
||||
g_variant_get (parameters, "(@aay@a{sv})", &args, &platform_data);
|
||||
|
||||
g_signal_emit (app, application_signals[PREPARE_ACTIVATION], 0, args, platform_data);
|
||||
|
||||
g_variant_unref (args);
|
||||
g_variant_unref (platform_data);
|
||||
|
||||
g_dbus_method_invocation_return_value (invocation, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
static const GDBusArgInfo application_quit_in_args[] =
|
||||
{
|
||||
{
|
||||
-1,
|
||||
"platform_data",
|
||||
"a{sv}",
|
||||
NULL
|
||||
}
|
||||
};
|
||||
|
||||
static const GDBusArgInfo * const application_quit_in_args_p[] = {
|
||||
&application_quit_in_args[0],
|
||||
NULL
|
||||
};
|
||||
|
||||
static const GDBusArgInfo application_list_actions_out_args[] =
|
||||
{
|
||||
{
|
||||
-1,
|
||||
"actions",
|
||||
"a{s(sb)}",
|
||||
NULL
|
||||
}
|
||||
};
|
||||
|
||||
static const GDBusArgInfo * const application_list_actions_out_args_p[] = {
|
||||
&application_list_actions_out_args[0],
|
||||
NULL
|
||||
};
|
||||
|
||||
static const GDBusArgInfo application_invoke_action_in_args[] =
|
||||
{
|
||||
{
|
||||
-1,
|
||||
"action",
|
||||
"s",
|
||||
NULL
|
||||
},
|
||||
{
|
||||
-1,
|
||||
"platform_data",
|
||||
"a{sv}",
|
||||
NULL
|
||||
}
|
||||
};
|
||||
|
||||
static const GDBusArgInfo * const application_invoke_action_in_args_p[] = {
|
||||
&application_invoke_action_in_args[0],
|
||||
&application_invoke_action_in_args[1],
|
||||
NULL
|
||||
};
|
||||
|
||||
static const GDBusMethodInfo application_quit_method_info =
|
||||
{
|
||||
-1,
|
||||
"Quit",
|
||||
(GDBusArgInfo **) &application_quit_in_args_p,
|
||||
NULL,
|
||||
NULL
|
||||
};
|
||||
|
||||
static const GDBusMethodInfo application_list_actions_method_info =
|
||||
{
|
||||
-1,
|
||||
"ListActions",
|
||||
NULL,
|
||||
(GDBusArgInfo **) &application_list_actions_out_args_p,
|
||||
NULL
|
||||
};
|
||||
|
||||
static const GDBusMethodInfo application_invoke_action_method_info =
|
||||
{
|
||||
-1,
|
||||
"InvokeAction",
|
||||
(GDBusArgInfo **) &application_invoke_action_in_args_p,
|
||||
NULL,
|
||||
NULL
|
||||
};
|
||||
|
||||
static const GDBusArgInfo application_activate_in_args[] =
|
||||
{
|
||||
{
|
||||
-1,
|
||||
"arguments",
|
||||
"aay",
|
||||
NULL
|
||||
},
|
||||
{
|
||||
-1,
|
||||
"data",
|
||||
"a{sv}",
|
||||
NULL
|
||||
}
|
||||
};
|
||||
|
||||
static const GDBusArgInfo * const application_activate_in_args_p[] = {
|
||||
&application_activate_in_args[0],
|
||||
&application_activate_in_args[1],
|
||||
NULL
|
||||
};
|
||||
|
||||
static const GDBusMethodInfo application_activate_method_info =
|
||||
{
|
||||
-1,
|
||||
"Activate",
|
||||
(GDBusArgInfo **) &application_activate_in_args_p,
|
||||
NULL,
|
||||
NULL
|
||||
};
|
||||
|
||||
static const GDBusMethodInfo * const application_dbus_method_info_p[] =
|
||||
{
|
||||
&application_quit_method_info,
|
||||
&application_list_actions_method_info,
|
||||
&application_invoke_action_method_info,
|
||||
&application_activate_method_info,
|
||||
NULL
|
||||
};
|
||||
|
||||
static const GDBusSignalInfo application_dbus_signal_info[] =
|
||||
{
|
||||
{
|
||||
-1,
|
||||
"ActionsChanged",
|
||||
NULL,
|
||||
NULL
|
||||
}
|
||||
};
|
||||
|
||||
static const GDBusSignalInfo * const application_dbus_signal_info_p[] = {
|
||||
&application_dbus_signal_info[0],
|
||||
NULL
|
||||
};
|
||||
|
||||
static const GDBusInterfaceInfo application_dbus_interface_info =
|
||||
{
|
||||
-1,
|
||||
G_APPLICATION_IFACE,
|
||||
(GDBusMethodInfo **) application_dbus_method_info_p,
|
||||
(GDBusSignalInfo **) application_dbus_signal_info_p,
|
||||
NULL,
|
||||
};
|
||||
|
||||
static GDBusInterfaceVTable application_dbus_vtable =
|
||||
{
|
||||
application_dbus_method_call,
|
||||
NULL,
|
||||
NULL
|
||||
};
|
||||
|
||||
static gchar *
|
||||
application_path_from_appid (const gchar *appid)
|
||||
{
|
||||
gchar *appid_path, *iter;
|
||||
|
||||
|
||||
appid_path = g_strconcat ("/", appid, NULL);
|
||||
for (iter = appid_path; *iter; iter++)
|
||||
{
|
||||
if (*iter == '.')
|
||||
*iter = '/';
|
||||
}
|
||||
|
||||
return appid_path;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
_g_application_platform_init (GApplication *app,
|
||||
GCancellable *cancellable,
|
||||
GError **error)
|
||||
{
|
||||
if (app->priv->session_bus == NULL)
|
||||
app->priv->session_bus = g_bus_get_sync (G_BUS_TYPE_SESSION, cancellable, error);
|
||||
if (!app->priv->session_bus)
|
||||
return FALSE;
|
||||
|
||||
if (!app->priv->dbus_path)
|
||||
app->priv->dbus_path = application_path_from_appid (app->priv->appid);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
_g_application_platform_register (GApplication *app,
|
||||
gboolean *unique,
|
||||
GCancellable *cancellable,
|
||||
GError **error)
|
||||
{
|
||||
GVariant *request_result;
|
||||
guint32 request_status;
|
||||
gboolean result;
|
||||
guint registration_id;
|
||||
|
||||
/* Callers should have verified this */
|
||||
g_assert (app->priv->registration_tried == FALSE);
|
||||
app->priv->registration_tried = TRUE;
|
||||
|
||||
registration_id = g_dbus_connection_register_object (app->priv->session_bus,
|
||||
app->priv->dbus_path,
|
||||
(GDBusInterfaceInfo *) &application_dbus_interface_info,
|
||||
&application_dbus_vtable,
|
||||
app,
|
||||
NULL,
|
||||
error);
|
||||
if (registration_id == 0)
|
||||
return FALSE;
|
||||
|
||||
request_result = g_dbus_connection_call_sync (app->priv->session_bus,
|
||||
"org.freedesktop.DBus",
|
||||
"/org/freedesktop/DBus",
|
||||
"org.freedesktop.DBus",
|
||||
"RequestName",
|
||||
g_variant_new ("(su)", app->priv->appid, 0x4),
|
||||
NULL, 0, -1, cancellable, error);
|
||||
|
||||
if (request_result == NULL)
|
||||
{
|
||||
result = FALSE;
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (g_variant_is_of_type (request_result, G_VARIANT_TYPE ("(u)")))
|
||||
g_variant_get (request_result, "(u)", &request_status);
|
||||
else
|
||||
request_status = 0;
|
||||
|
||||
g_variant_unref (request_result);
|
||||
|
||||
*unique = (request_status == 1 || request_status == 4);
|
||||
result = TRUE;
|
||||
|
||||
if (*unique)
|
||||
{
|
||||
app->priv->is_remote = FALSE;
|
||||
}
|
||||
else
|
||||
{
|
||||
GVariantBuilder builder;
|
||||
GVariant *message;
|
||||
GVariant *result;
|
||||
|
||||
g_variant_builder_init (&builder, G_VARIANT_TYPE ("(aaya{sv})"));
|
||||
g_variant_builder_add_value (&builder, app->priv->argv);
|
||||
g_variant_builder_add_value (&builder, app->priv->platform_data);
|
||||
message = g_variant_builder_end (&builder);
|
||||
|
||||
result = g_dbus_connection_call_sync (app->priv->session_bus,
|
||||
app->priv->appid,
|
||||
app->priv->dbus_path,
|
||||
G_APPLICATION_IFACE,
|
||||
"Activate",
|
||||
message,
|
||||
NULL, 0, -1, NULL, NULL);
|
||||
|
||||
if (result)
|
||||
g_variant_unref (result);
|
||||
|
||||
if (app->priv->default_quit)
|
||||
exit (0);
|
||||
}
|
||||
|
||||
done:
|
||||
if (!result)
|
||||
g_dbus_connection_unregister_object (app->priv->session_bus, registration_id);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static void
|
||||
_g_application_platform_on_actions_changed (GApplication *app)
|
||||
{
|
||||
g_dbus_connection_emit_signal (app->priv->session_bus, NULL,
|
||||
app->priv->dbus_path,
|
||||
G_APPLICATION_IFACE,
|
||||
"ActionsChanged", NULL, NULL);
|
||||
}
|
||||
|
||||
static void
|
||||
_g_application_platform_remote_invoke_action (GApplication *app,
|
||||
const gchar *action,
|
||||
GVariant *platform_data)
|
||||
{
|
||||
GVariant *result;
|
||||
|
||||
result = g_dbus_connection_call_sync (app->priv->session_bus,
|
||||
app->priv->appid,
|
||||
app->priv->dbus_path,
|
||||
G_APPLICATION_IFACE,
|
||||
"InvokeAction",
|
||||
g_variant_new ("(s@a{sv})",
|
||||
action,
|
||||
platform_data),
|
||||
NULL, 0, -1, NULL, NULL);
|
||||
if (result)
|
||||
g_variant_unref (result);
|
||||
}
|
||||
|
||||
static void
|
||||
_g_application_platform_remote_quit (GApplication *app,
|
||||
GVariant *platform_data)
|
||||
{
|
||||
GVariant *result;
|
||||
|
||||
result = g_dbus_connection_call_sync (app->priv->session_bus,
|
||||
app->priv->appid,
|
||||
app->priv->dbus_path,
|
||||
G_APPLICATION_IFACE,
|
||||
"Quit",
|
||||
g_variant_new ("(@a{sv})",
|
||||
platform_data),
|
||||
NULL, 0, -1, NULL, NULL);
|
||||
if (result)
|
||||
g_variant_unref (result);
|
||||
}
|
@ -21,4 +21,5 @@ VOID:STRING,STRING,VARIANT
|
||||
VOID:STRING
|
||||
VOID:STRING,STRING
|
||||
VOID:STRING,BOOLEAN
|
||||
BOOL:OBJECT
|
||||
VOID:POINTER,INT,STRING
|
||||
BOOLEAN:OBJECT
|
||||
|
@ -27,22 +27,24 @@ g_vfs_get_local
|
||||
#if IN_HEADER(__G_APPLICATION_H__)
|
||||
#if IN_FILE(__G_APPLICATION_C__)
|
||||
g_application_get_type G_GNUC_CONST
|
||||
g_application_activate
|
||||
g_application_flags_get_type
|
||||
g_application_get_application_id
|
||||
g_application_get_flags
|
||||
g_application_get_inactivity_timeout
|
||||
g_application_get_is_registered
|
||||
g_application_get_is_remote
|
||||
g_application_hold
|
||||
g_application_id_is_valid
|
||||
g_application_new
|
||||
g_application_get_instance
|
||||
g_application_get_id
|
||||
g_application_set_action_enabled
|
||||
g_application_get_action_enabled
|
||||
g_application_get_action_description
|
||||
g_application_add_action
|
||||
g_application_remove_action
|
||||
g_application_invoke_action
|
||||
g_application_list_actions
|
||||
g_application_run
|
||||
g_application_open
|
||||
g_application_register
|
||||
g_application_try_new
|
||||
g_application_unregistered_try_new
|
||||
g_application_quit_with_data
|
||||
g_application_is_remote
|
||||
g_application_release
|
||||
g_application_run
|
||||
g_application_run_with_arguments
|
||||
g_application_set_application_id
|
||||
g_application_set_flags
|
||||
g_application_set_inactivity_timeout
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
@ -1216,6 +1216,24 @@ typedef enum
|
||||
G_DBUS_MESSAGE_BYTE_ORDER_LITTLE_ENDIAN = 'l'
|
||||
} GDBusMessageByteOrder;
|
||||
|
||||
/**
|
||||
* GApplicationFlags:
|
||||
* @G_APPLICATION_FLAGS_NONE: Default
|
||||
* @G_APPLICATION_FLAGS_HANDLE_OPEN: This application handles opening files.
|
||||
*
|
||||
* Flags used to define the behaviour of a #GApplication.
|
||||
*
|
||||
* Since: 2.26
|
||||
**/
|
||||
typedef enum
|
||||
{
|
||||
G_APPLICATION_FLAGS_NONE,
|
||||
G_APPLICATION_FLAGS_IS_SERVICE = (1 << 0),
|
||||
G_APPLICATION_FLAGS_IS_LAUNCHER = (1 << 1),
|
||||
|
||||
G_APPLICATION_FLAGS_HANDLES_OPEN = (1 << 2)
|
||||
} GApplicationFlags;
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __GIO_ENUMS_H__ */
|
||||
|
@ -51,6 +51,8 @@ typedef struct _GSimpleActionGroup GSimpleActionGroup;
|
||||
typedef struct _GActionGroup GActionGroup;
|
||||
typedef struct _GSimpleAction GSimpleAction;
|
||||
typedef struct _GAction GAction;
|
||||
typedef struct _GApplication GApplication;
|
||||
typedef struct _GApplicationCommandLine GApplicationCommandLine;
|
||||
typedef struct _GSettingsBackend GSettingsBackend;
|
||||
typedef struct _GSettings GSettings;
|
||||
typedef struct _GPermission GPermission;
|
||||
|
3
gio/tests/.gitignore
vendored
3
gio/tests/.gitignore
vendored
@ -1,7 +1,6 @@
|
||||
actions
|
||||
appinfo
|
||||
appinfo-test
|
||||
application
|
||||
async-close-output-stream
|
||||
buffered-input-stream
|
||||
buffered-output-stream
|
||||
@ -65,8 +64,6 @@ sleepy-stream
|
||||
socket-client
|
||||
socket-server
|
||||
srvtarget
|
||||
testapp
|
||||
testapps
|
||||
test.mo
|
||||
unix-fd
|
||||
unix-streams
|
||||
|
@ -59,8 +59,6 @@ TEST_PROGS += \
|
||||
gdbus-exit-on-close \
|
||||
gdbus-non-socket \
|
||||
gdbus-bz627724 \
|
||||
application \
|
||||
testapps \
|
||||
appinfo \
|
||||
contenttype \
|
||||
file \
|
||||
@ -84,7 +82,6 @@ SAMPLE_PROGS = \
|
||||
gdbus-example-peer \
|
||||
gdbus-example-proxy-subclass \
|
||||
gdbus-connection-flush-helper \
|
||||
testapp \
|
||||
appinfo-test \
|
||||
proxy \
|
||||
$(NULL)
|
||||
@ -291,21 +288,12 @@ gdbus_example_export_LDADD = $(progs_ldadd)
|
||||
gdbus_connection_flush_helper_SOURCES = gdbus-connection-flush-helper.c
|
||||
gdbus_connection_flush_helper_LDADD = $(progs_ldadd)
|
||||
|
||||
application_SOURCES = application.c gdbus-sessionbus.c gdbus-sessionbus.h
|
||||
application_LDADD = $(progs_ldadd)
|
||||
|
||||
appinfo_SOURCES = appinfo.c
|
||||
appinfo_LDADD = $(progs_ldadd)
|
||||
|
||||
appinfo_test_SOURCES = appinfo-test.c
|
||||
appinfo_test_LDADD = $(progs_ldadd)
|
||||
|
||||
testapp_SOURCES = testapp.c
|
||||
testapp_LDADD = $(progs_ldadd)
|
||||
|
||||
testapps_SOURCES = testapps.c gdbus-sessionbus.c gdbus-sessionbus.h
|
||||
testapps_LDADD = $(progs_ldadd)
|
||||
|
||||
contenttype_SOURCES = contenttype.c
|
||||
contenttype_LDADD = $(progs_ldadd)
|
||||
|
||||
|
@ -1,222 +0,0 @@
|
||||
#include <stdlib.h>
|
||||
#include <gio/gio.h>
|
||||
#include <gstdio.h>
|
||||
|
||||
#include "gdbus-sessionbus.h"
|
||||
|
||||
enum
|
||||
{
|
||||
INVOKE_ACTION,
|
||||
CHECK_ACTION,
|
||||
DISABLE_ACTION,
|
||||
INVOKE_DISABLED_ACTION,
|
||||
CHECK_DISABLED_ACTION,
|
||||
END
|
||||
};
|
||||
|
||||
static guint timestamp = 0;
|
||||
static gint state = -1;
|
||||
static gboolean action_invoked = FALSE;
|
||||
|
||||
static void
|
||||
on_app_action (GApplication *application,
|
||||
const gchar *action_name,
|
||||
GVariant *platform_data)
|
||||
{
|
||||
gboolean found_timestamp;
|
||||
GVariantIter *iter;
|
||||
const char *key;
|
||||
guint action_timestamp;
|
||||
GVariant *value;
|
||||
|
||||
if (g_test_verbose ())
|
||||
{
|
||||
char *str = g_variant_print (platform_data, FALSE);
|
||||
g_print ("Action '%s' invoked (data: %s, expected: %u)\n",
|
||||
action_name,
|
||||
str,
|
||||
timestamp);
|
||||
g_free (str);
|
||||
}
|
||||
|
||||
g_assert_cmpstr (action_name, ==, "About");
|
||||
|
||||
g_variant_get (platform_data, "a{sv}", &iter);
|
||||
found_timestamp = FALSE;
|
||||
while (g_variant_iter_next (iter, "{&sv}",
|
||||
&key, &value))
|
||||
{
|
||||
if (g_strcmp0 ("timestamp", key) == 0)
|
||||
{
|
||||
found_timestamp = TRUE;
|
||||
g_variant_get (value, "u", &action_timestamp);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
g_variant_iter_free (iter);
|
||||
|
||||
g_assert_cmpuint (timestamp, ==, action_timestamp);
|
||||
|
||||
action_invoked = TRUE;
|
||||
}
|
||||
|
||||
static GVariant *
|
||||
create_timestamp_data ()
|
||||
{
|
||||
GVariantBuilder builder;
|
||||
|
||||
timestamp = 42 + timestamp;
|
||||
|
||||
g_variant_builder_init (&builder, G_VARIANT_TYPE ("a{sv}"));
|
||||
g_variant_builder_add (&builder, "{sv}",
|
||||
"timestamp", g_variant_new ("u", timestamp));
|
||||
|
||||
return g_variant_builder_end (&builder);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
check_invoke_action (gpointer data)
|
||||
{
|
||||
GApplication *application = data;
|
||||
|
||||
if (state == INVOKE_ACTION)
|
||||
{
|
||||
if (g_test_verbose ())
|
||||
g_print ("Invoking About...\n");
|
||||
|
||||
g_application_invoke_action (application, "About", create_timestamp_data ());
|
||||
|
||||
state = CHECK_ACTION;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
if (state == CHECK_ACTION)
|
||||
{
|
||||
if (g_test_verbose ())
|
||||
g_print ("Verifying About invocation...\n");
|
||||
|
||||
g_assert (action_invoked);
|
||||
state = DISABLE_ACTION;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
if (state == DISABLE_ACTION)
|
||||
{
|
||||
if (g_test_verbose ())
|
||||
g_print ("Disabling About...\n");
|
||||
|
||||
g_application_set_action_enabled (application, "About", FALSE);
|
||||
action_invoked = FALSE;
|
||||
state = INVOKE_DISABLED_ACTION;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
if (state == INVOKE_DISABLED_ACTION)
|
||||
{
|
||||
if (g_test_verbose ())
|
||||
g_print ("Invoking disabled About action...\n");
|
||||
|
||||
g_application_invoke_action (application, "About", create_timestamp_data ());
|
||||
state = CHECK_DISABLED_ACTION;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
if (state == CHECK_DISABLED_ACTION)
|
||||
{
|
||||
if (g_test_verbose ())
|
||||
g_print ("Verifying lack of About invocation...\n");
|
||||
|
||||
g_assert (!action_invoked);
|
||||
state = END;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
if (state == END)
|
||||
{
|
||||
if (g_test_verbose ())
|
||||
g_print ("Test complete\n");
|
||||
|
||||
g_application_quit_with_data (application, create_timestamp_data ());
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
g_assert_not_reached ();
|
||||
}
|
||||
|
||||
static void
|
||||
test_basic (void)
|
||||
{
|
||||
GApplication *app;
|
||||
const gchar *appid;
|
||||
gboolean quit;
|
||||
gboolean remote;
|
||||
gboolean reg;
|
||||
gchar **actions;
|
||||
|
||||
app = g_application_new ("org.gtk.TestApplication", 0, NULL);
|
||||
|
||||
g_assert (g_application_get_instance () == app);
|
||||
g_assert_cmpstr (g_application_get_id (app), ==, "org.gtk.TestApplication");
|
||||
g_object_get (app,
|
||||
"application-id", &appid,
|
||||
"default-quit", &quit,
|
||||
"is-remote", &remote,
|
||||
"register", ®,
|
||||
NULL);
|
||||
g_assert_cmpstr (appid, ==, "org.gtk.TestApplication");
|
||||
g_assert (quit);
|
||||
g_assert (!remote);
|
||||
g_assert (reg);
|
||||
|
||||
g_application_add_action (app, "About", "Print an about message");
|
||||
|
||||
g_assert (g_application_get_action_enabled (app, "About"));
|
||||
g_assert_cmpstr (g_application_get_action_description (app, "About"), ==, "Print an about message");
|
||||
|
||||
actions = g_application_list_actions (app);
|
||||
g_assert_cmpint (g_strv_length (actions), ==, 1);
|
||||
g_assert_cmpstr (actions[0], ==, "About");
|
||||
g_strfreev (actions);
|
||||
|
||||
g_application_add_action (app, "Action2", "Another action");
|
||||
actions = g_application_list_actions (app);
|
||||
g_assert_cmpint (g_strv_length (actions), ==, 2);
|
||||
g_strfreev (actions);
|
||||
g_application_remove_action (app, "Action2");
|
||||
actions = g_application_list_actions (app);
|
||||
g_assert_cmpint (g_strv_length (actions), ==, 1);
|
||||
g_strfreev (actions);
|
||||
|
||||
g_signal_connect (app, "action-with-data::About", G_CALLBACK (on_app_action), NULL);
|
||||
|
||||
state = INVOKE_ACTION;
|
||||
g_timeout_add (100, check_invoke_action, app);
|
||||
|
||||
g_application_run (app);
|
||||
|
||||
g_assert (state == END);
|
||||
g_object_unref (app);
|
||||
}
|
||||
|
||||
int
|
||||
main (int argc, char *argv[])
|
||||
{
|
||||
gint ret;
|
||||
|
||||
g_type_init ();
|
||||
g_test_init (&argc, &argv, NULL);
|
||||
|
||||
g_unsetenv ("DISPLAY");
|
||||
g_setenv ("DBUS_SESSION_BUS_ADDRESS", session_bus_get_temporary_address (), TRUE);
|
||||
|
||||
session_bus_up ();
|
||||
|
||||
g_test_add_func ("/application/basic", test_basic);
|
||||
|
||||
ret = g_test_run ();
|
||||
|
||||
session_bus_down ();
|
||||
|
||||
return ret;
|
||||
}
|
@ -1,107 +0,0 @@
|
||||
#include <gio/gio.h>
|
||||
#include <gstdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#ifdef G_OS_UNIX
|
||||
#include <stdlib.h>
|
||||
#include <fcntl.h>
|
||||
#endif
|
||||
|
||||
static gboolean action3_added = FALSE;
|
||||
|
||||
static void
|
||||
on_app_action (GApplication *application,
|
||||
const gchar *action_name,
|
||||
GVariant *platform_data)
|
||||
{
|
||||
if (strcmp (action_name, "action1") == 0)
|
||||
exit (1);
|
||||
else if (strcmp (action_name, "action2") == 0)
|
||||
{
|
||||
if (action3_added)
|
||||
g_application_remove_action (application, "action3");
|
||||
else
|
||||
g_application_add_action (application, "action3", "An extra action");
|
||||
action3_added = !action3_added;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
on_app_activated (GApplication *application,
|
||||
GVariant *args,
|
||||
GVariant *platform_data)
|
||||
{
|
||||
GVariantIter iter;
|
||||
const char *key;
|
||||
GVariant *value;
|
||||
char *cwd;
|
||||
|
||||
cwd = g_get_current_dir ();
|
||||
g_variant_iter_init (&iter, platform_data);
|
||||
while (g_variant_iter_next (&iter, "{&sv}", &key, &value))
|
||||
{
|
||||
const char *activate_cwd;
|
||||
|
||||
if (strcmp (key, "cwd") != 0)
|
||||
continue;
|
||||
|
||||
activate_cwd = g_variant_get_bytestring (value);
|
||||
g_assert_cmpstr (cwd, ==, activate_cwd);
|
||||
g_variant_unref (value);
|
||||
}
|
||||
|
||||
g_free (cwd);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
on_monitor_fd_io (GIOChannel *source,
|
||||
GIOCondition condition,
|
||||
gpointer data)
|
||||
{
|
||||
exit (0);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
int
|
||||
main (int argc, char *argv[])
|
||||
{
|
||||
GApplication *app;
|
||||
|
||||
#ifdef G_OS_UNIX
|
||||
{
|
||||
const char *slave_fd_env = g_getenv ("_G_TEST_SLAVE_FD");
|
||||
if (slave_fd_env)
|
||||
{
|
||||
int slave_fd = atoi (slave_fd_env);
|
||||
fcntl (slave_fd, F_SETFD, FD_CLOEXEC);
|
||||
g_io_add_watch (g_io_channel_unix_new (slave_fd), G_IO_HUP | G_IO_ERR,
|
||||
on_monitor_fd_io, NULL);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
app = g_application_unregistered_try_new ("org.gtk.test.app",
|
||||
argc, argv, NULL);
|
||||
if (!(argc > 1 && strcmp (argv[1], "--non-unique") == 0))
|
||||
{
|
||||
if (!g_application_register (app))
|
||||
exit (0);
|
||||
}
|
||||
|
||||
if (g_application_is_remote (app))
|
||||
{
|
||||
g_application_invoke_action (app, "action1", 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
g_application_add_action (app, "action1", "Action1");
|
||||
g_application_add_action (app, "action2", "Action2");
|
||||
g_signal_connect (app, "action-with-data",
|
||||
G_CALLBACK (on_app_action), NULL);
|
||||
g_signal_connect (app, "prepare-activation",
|
||||
G_CALLBACK (on_app_activated), NULL);
|
||||
g_application_run (app);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
@ -1,604 +0,0 @@
|
||||
#include <gio/gio.h>
|
||||
#ifdef G_OS_UNIX
|
||||
#include <fcntl.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/wait.h>
|
||||
#include <signal.h>
|
||||
#endif
|
||||
|
||||
#include "gdbus-sessionbus.h"
|
||||
|
||||
static gint appeared;
|
||||
static gint disappeared;
|
||||
static gint changed;
|
||||
|
||||
static void
|
||||
name_appeared (GDBusConnection *connection,
|
||||
const gchar *name,
|
||||
const gchar *name_owner,
|
||||
gpointer user_data)
|
||||
{
|
||||
GMainLoop *loop = user_data;
|
||||
|
||||
appeared++;
|
||||
|
||||
if (loop)
|
||||
g_main_loop_quit (loop);
|
||||
}
|
||||
|
||||
static void
|
||||
name_disappeared (GDBusConnection *connection,
|
||||
const gchar *name,
|
||||
gpointer user_data)
|
||||
{
|
||||
GMainLoop *loop = user_data;
|
||||
|
||||
disappeared++;
|
||||
|
||||
if (loop)
|
||||
g_main_loop_quit (loop);
|
||||
}
|
||||
|
||||
#ifdef G_OS_UNIX
|
||||
void
|
||||
child_setup_pipe (gpointer user_data)
|
||||
{
|
||||
int *fds = user_data;
|
||||
|
||||
close (fds[0]);
|
||||
dup2 (fds[1], 3);
|
||||
g_setenv ("_G_TEST_SLAVE_FD", "3", TRUE);
|
||||
close (fds[1]);
|
||||
}
|
||||
#endif
|
||||
|
||||
static gboolean
|
||||
spawn_async_with_monitor_pipe (const gchar *argv[], GPid *pid, int *fd)
|
||||
{
|
||||
#ifdef G_OS_UNIX
|
||||
int fds[2];
|
||||
gboolean result;
|
||||
|
||||
pipe (fds);
|
||||
|
||||
result = g_spawn_async (NULL, (char**)argv, NULL, G_SPAWN_DO_NOT_REAP_CHILD, child_setup_pipe, &fds, pid, NULL);
|
||||
close (fds[1]);
|
||||
*fd = fds[0];
|
||||
return result;
|
||||
#else
|
||||
*fd = -1;
|
||||
return g_spawn_async (NULL, argv, 0, NULL, NULL, pid, NULL);
|
||||
#endif
|
||||
}
|
||||
|
||||
static gboolean
|
||||
start_application (GPid *pid, int *fd)
|
||||
{
|
||||
const gchar *argv[] = { "./testapp", NULL };
|
||||
|
||||
g_assert (spawn_async_with_monitor_pipe (argv, pid, fd));
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
typedef struct {
|
||||
GMainContext *context;
|
||||
GSource *child_watch;
|
||||
GSource *timeout;
|
||||
GPid pid;
|
||||
int fd;
|
||||
|
||||
gboolean child_exited;
|
||||
GMainLoop *loop;
|
||||
} AwaitChildTerminationData;
|
||||
|
||||
static void
|
||||
on_child_termination_exited (GPid pid,
|
||||
gint status,
|
||||
gpointer user_data)
|
||||
{
|
||||
AwaitChildTerminationData *data = user_data;
|
||||
data->child_exited = TRUE;
|
||||
g_spawn_close_pid (data->pid);
|
||||
g_main_loop_quit (data->loop);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
on_child_termination_timeout (gpointer user_data)
|
||||
{
|
||||
AwaitChildTerminationData *data = user_data;
|
||||
g_main_loop_quit (data->loop);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static void
|
||||
await_child_termination_init (AwaitChildTerminationData *data,
|
||||
GPid pid,
|
||||
int fd)
|
||||
{
|
||||
data->context = g_main_context_get_thread_default ();
|
||||
data->child_exited = FALSE;
|
||||
data->pid = pid;
|
||||
data->fd = fd;
|
||||
}
|
||||
|
||||
static void
|
||||
await_child_termination_terminate (AwaitChildTerminationData *data)
|
||||
{
|
||||
#ifdef G_OS_UNIX
|
||||
kill (data->pid, SIGTERM);
|
||||
close (data->fd);
|
||||
#endif
|
||||
}
|
||||
|
||||
static gboolean
|
||||
await_child_termination_run (AwaitChildTerminationData *data)
|
||||
{
|
||||
GSource *timeout_source;
|
||||
GSource *child_watch_source;
|
||||
|
||||
data->loop = g_main_loop_new (data->context, FALSE);
|
||||
|
||||
child_watch_source = g_child_watch_source_new (data->pid);
|
||||
g_source_set_callback (child_watch_source, (GSourceFunc) on_child_termination_exited, data, NULL);
|
||||
g_source_attach (child_watch_source, data->context);
|
||||
|
||||
timeout_source = g_timeout_source_new_seconds (5);
|
||||
g_source_set_callback (timeout_source, on_child_termination_timeout, data, NULL);
|
||||
g_source_attach (timeout_source, data->context);
|
||||
|
||||
g_main_loop_run (data->loop);
|
||||
|
||||
g_source_destroy (child_watch_source);
|
||||
g_source_unref (child_watch_source);
|
||||
g_source_destroy (timeout_source);
|
||||
g_source_unref (timeout_source);
|
||||
|
||||
g_main_loop_unref (data->loop);
|
||||
|
||||
return data->child_exited;
|
||||
}
|
||||
|
||||
static void
|
||||
terminate_child_sync (GPid pid, int fd)
|
||||
{
|
||||
AwaitChildTerminationData data;
|
||||
|
||||
await_child_termination_init (&data, pid, fd);
|
||||
await_child_termination_terminate (&data);
|
||||
await_child_termination_run (&data);
|
||||
}
|
||||
|
||||
typedef void (*RunWithApplicationFunc) (void);
|
||||
|
||||
typedef struct {
|
||||
GMainLoop *loop;
|
||||
RunWithApplicationFunc func;
|
||||
guint timeout_id;
|
||||
} RunWithAppNameAppearedData;
|
||||
|
||||
static void
|
||||
on_run_with_application_name_appeared (GDBusConnection *connection,
|
||||
const gchar *name,
|
||||
const gchar *name_owner,
|
||||
gpointer user_data)
|
||||
{
|
||||
RunWithAppNameAppearedData *data = user_data;
|
||||
|
||||
data->func ();
|
||||
|
||||
g_main_loop_quit (data->loop);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
on_run_with_application_timeout (gpointer user_data)
|
||||
{
|
||||
RunWithAppNameAppearedData *data = user_data;
|
||||
data->timeout_id = 0;
|
||||
g_error ("Timed out starting testapp");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static void
|
||||
run_with_application (RunWithApplicationFunc test_func)
|
||||
{
|
||||
GMainLoop *loop;
|
||||
RunWithAppNameAppearedData data;
|
||||
gint watch;
|
||||
GPid main_pid;
|
||||
gint main_fd;
|
||||
|
||||
loop = g_main_loop_new (NULL, FALSE);
|
||||
|
||||
data.timeout_id = 0;
|
||||
data.func = test_func;
|
||||
data.loop = loop;
|
||||
|
||||
watch = g_bus_watch_name (G_BUS_TYPE_SESSION,
|
||||
"org.gtk.test.app",
|
||||
0,
|
||||
on_run_with_application_name_appeared,
|
||||
NULL,
|
||||
&data,
|
||||
NULL);
|
||||
|
||||
data.timeout_id = g_timeout_add_seconds (5, on_run_with_application_timeout, &data);
|
||||
|
||||
start_application (&main_pid, &main_fd);
|
||||
|
||||
g_main_loop_run (loop);
|
||||
|
||||
if (data.timeout_id)
|
||||
{
|
||||
g_source_remove (data.timeout_id);
|
||||
data.timeout_id = 0;
|
||||
}
|
||||
|
||||
g_main_loop_unref (loop);
|
||||
|
||||
g_bus_unwatch_name (watch);
|
||||
|
||||
terminate_child_sync (main_pid, main_fd);
|
||||
}
|
||||
|
||||
/* This test starts an application, checks that its name appears
|
||||
* on the bus, then starts it again and checks that the second
|
||||
* instance exits right away.
|
||||
*/
|
||||
static void
|
||||
test_unique_on_app_appeared (void)
|
||||
{
|
||||
GPid sub_pid;
|
||||
int sub_fd;
|
||||
int watch;
|
||||
AwaitChildTerminationData data;
|
||||
|
||||
appeared = 0;
|
||||
disappeared = 0;
|
||||
|
||||
watch = g_bus_watch_name (G_BUS_TYPE_SESSION,
|
||||
"org.gtk.test.app",
|
||||
0,
|
||||
name_appeared,
|
||||
name_disappeared,
|
||||
NULL,
|
||||
NULL);
|
||||
|
||||
start_application (&sub_pid, &sub_fd);
|
||||
await_child_termination_init (&data, sub_pid, sub_fd);
|
||||
await_child_termination_run (&data);
|
||||
|
||||
g_bus_unwatch_name (watch);
|
||||
|
||||
g_assert_cmpint (appeared, ==, 1);
|
||||
g_assert_cmpint (disappeared, ==, 0);
|
||||
}
|
||||
|
||||
static void
|
||||
test_unique (void)
|
||||
{
|
||||
run_with_application (test_unique_on_app_appeared);
|
||||
}
|
||||
|
||||
static void
|
||||
on_name_disappeared_quit (GDBusConnection *connection,
|
||||
const gchar *name,
|
||||
gpointer user_data)
|
||||
{
|
||||
GMainLoop *loop = user_data;
|
||||
|
||||
g_main_loop_quit (loop);
|
||||
}
|
||||
|
||||
static GVariant *
|
||||
create_empty_vardict ()
|
||||
{
|
||||
GVariantBuilder builder;
|
||||
|
||||
g_variant_builder_init (&builder, G_VARIANT_TYPE ("a{sv}"));
|
||||
return g_variant_builder_end (&builder);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
call_quit (gpointer data)
|
||||
{
|
||||
GDBusConnection *connection;
|
||||
GError *error = NULL;
|
||||
GVariant *res;
|
||||
|
||||
connection = g_bus_get_sync (G_BUS_TYPE_SESSION, NULL, NULL);
|
||||
res = g_dbus_connection_call_sync (connection,
|
||||
"org.gtk.test.app",
|
||||
"/org/gtk/test/app",
|
||||
"org.gtk.Application",
|
||||
"Quit",
|
||||
g_variant_new ("(@a{sv})", create_empty_vardict ()),
|
||||
NULL,
|
||||
G_DBUS_CALL_FLAGS_NONE,
|
||||
-1,
|
||||
NULL,
|
||||
&error);
|
||||
if (error)
|
||||
{
|
||||
g_assert_error (error, G_DBUS_ERROR, G_DBUS_ERROR_NO_REPLY);
|
||||
g_error_free (error);
|
||||
}
|
||||
|
||||
if (res)
|
||||
g_variant_unref (res);
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* This test starts an application, checks that its name appears on
|
||||
* the bus, then calls Quit, and verifies that the name disappears and
|
||||
* the application exits.
|
||||
*/
|
||||
static void
|
||||
test_quit_on_app_appeared (void)
|
||||
{
|
||||
GMainLoop *loop;
|
||||
int quit_disappeared_watch;
|
||||
|
||||
loop = g_main_loop_new (NULL, FALSE);
|
||||
quit_disappeared_watch = g_bus_watch_name (G_BUS_TYPE_SESSION,
|
||||
"org.gtk.test.app",
|
||||
0,
|
||||
NULL,
|
||||
on_name_disappeared_quit,
|
||||
loop,
|
||||
NULL);
|
||||
call_quit (NULL);
|
||||
|
||||
g_main_loop_run (loop);
|
||||
|
||||
g_bus_unwatch_name (quit_disappeared_watch);
|
||||
|
||||
g_main_loop_unref (loop);
|
||||
}
|
||||
|
||||
static void
|
||||
test_quit (void)
|
||||
{
|
||||
run_with_application (test_quit_on_app_appeared);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
_g_strv_has_string (const gchar* const * haystack,
|
||||
const gchar *needle)
|
||||
{
|
||||
guint n;
|
||||
|
||||
for (n = 0; haystack != NULL && haystack[n] != NULL; n++)
|
||||
{
|
||||
if (g_strcmp0 (haystack[n], needle) == 0)
|
||||
return TRUE;
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static gchar **
|
||||
list_actions (void)
|
||||
{
|
||||
GDBusConnection *connection;
|
||||
GVariant *res;
|
||||
gchar **strv;
|
||||
gchar *str;
|
||||
GVariantIter *iter;
|
||||
gint i;
|
||||
|
||||
connection = g_bus_get_sync (G_BUS_TYPE_SESSION, NULL, NULL);
|
||||
res = g_dbus_connection_call_sync (connection,
|
||||
"org.gtk.test.app",
|
||||
"/org/gtk/test/app",
|
||||
"org.gtk.Application",
|
||||
"ListActions",
|
||||
NULL,
|
||||
NULL,
|
||||
G_DBUS_CALL_FLAGS_NONE,
|
||||
-1,
|
||||
NULL,
|
||||
NULL);
|
||||
|
||||
strv = g_new0 (gchar *, 32);
|
||||
g_variant_get (res, "(a{s(sb)})", &iter);
|
||||
i = 0;
|
||||
while (g_variant_iter_loop (iter, "{s(sb)}", &str, NULL, NULL))
|
||||
{
|
||||
strv[i] = g_strdup (str);
|
||||
i++;
|
||||
g_assert (i < 32);
|
||||
}
|
||||
g_variant_iter_free (iter);
|
||||
|
||||
strv[i] = NULL;
|
||||
|
||||
g_variant_unref (res);
|
||||
g_object_unref (connection);
|
||||
|
||||
return strv;
|
||||
}
|
||||
|
||||
static void
|
||||
test_list_actions_on_app_appeared (void)
|
||||
{
|
||||
gchar **actions;
|
||||
|
||||
actions = list_actions ();
|
||||
|
||||
g_assert (g_strv_length (actions) == 2);
|
||||
g_assert (_g_strv_has_string ((const char *const *)actions, "action1"));
|
||||
g_assert (_g_strv_has_string ((const char *const *)actions, "action2"));
|
||||
|
||||
g_strfreev (actions);
|
||||
}
|
||||
|
||||
/* This test start an application, waits for its name to appear on
|
||||
* the bus, then calls ListActions, and verifies that it gets the expected
|
||||
* actions back.
|
||||
*/
|
||||
static void
|
||||
test_list_actions (void)
|
||||
{
|
||||
run_with_application (test_list_actions_on_app_appeared);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
invoke_action (gpointer user_data)
|
||||
{
|
||||
const gchar *action = user_data;
|
||||
GDBusConnection *connection;
|
||||
GVariant *res;
|
||||
|
||||
connection = g_bus_get_sync (G_BUS_TYPE_SESSION, NULL, NULL);
|
||||
res = g_dbus_connection_call_sync (connection,
|
||||
"org.gtk.test.app",
|
||||
"/org/gtk/test/app",
|
||||
"org.gtk.Application",
|
||||
"InvokeAction",
|
||||
g_variant_new ("(s@a{sv})",
|
||||
action,
|
||||
create_empty_vardict ()),
|
||||
NULL,
|
||||
G_DBUS_CALL_FLAGS_NONE,
|
||||
-1,
|
||||
NULL,
|
||||
NULL);
|
||||
if (res)
|
||||
g_variant_unref (res);
|
||||
g_object_unref (connection);
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* This test starts an application, waits for it to appear,
|
||||
* then invokes 'action1' and checks that it causes the application
|
||||
* to exit with an exit code of 1.
|
||||
*/
|
||||
static void
|
||||
test_invoke (void)
|
||||
{
|
||||
GMainLoop *loop;
|
||||
int quit_disappeared_watch;
|
||||
|
||||
loop = g_main_loop_new (NULL, FALSE);
|
||||
|
||||
quit_disappeared_watch = g_bus_watch_name (G_BUS_TYPE_SESSION,
|
||||
"org.gtk.test.app",
|
||||
0,
|
||||
NULL,
|
||||
on_name_disappeared_quit,
|
||||
loop,
|
||||
NULL);
|
||||
|
||||
g_timeout_add (0, invoke_action, "action1");
|
||||
|
||||
g_main_loop_run (loop);
|
||||
|
||||
g_bus_unwatch_name (quit_disappeared_watch);
|
||||
}
|
||||
|
||||
static void
|
||||
test_remote_on_application_appeared (void)
|
||||
{
|
||||
GPid sub_pid;
|
||||
int sub_fd;
|
||||
AwaitChildTerminationData data;
|
||||
gchar *argv[] = { "./testapp", "--non-unique", NULL };
|
||||
|
||||
spawn_async_with_monitor_pipe ((const char **) argv, &sub_pid, &sub_fd);
|
||||
|
||||
await_child_termination_init (&data, sub_pid, sub_fd);
|
||||
await_child_termination_run (&data);
|
||||
}
|
||||
|
||||
static void
|
||||
test_remote (void)
|
||||
{
|
||||
run_with_application (test_remote_on_application_appeared);
|
||||
}
|
||||
|
||||
static void
|
||||
actions_changed (GDBusConnection *connection,
|
||||
const gchar *sender_name,
|
||||
const gchar *object_path,
|
||||
const gchar *interface_name,
|
||||
const gchar *signal_name,
|
||||
GVariant *parameters,
|
||||
gpointer user_data)
|
||||
{
|
||||
GMainLoop *loop = user_data;
|
||||
|
||||
g_assert_cmpstr (interface_name, ==, "org.gtk.Application");
|
||||
g_assert_cmpstr (signal_name, ==, "ActionsChanged");
|
||||
|
||||
changed++;
|
||||
|
||||
g_main_loop_quit (loop);
|
||||
}
|
||||
|
||||
static void
|
||||
test_change_action_on_application_appeared (void)
|
||||
{
|
||||
GMainLoop *loop;
|
||||
guint id;
|
||||
GDBusConnection *connection;
|
||||
|
||||
loop = g_main_loop_new (NULL, FALSE);
|
||||
|
||||
connection = g_bus_get_sync (G_BUS_TYPE_SESSION, NULL, NULL);
|
||||
id = g_dbus_connection_signal_subscribe (connection,
|
||||
NULL,
|
||||
"org.gtk.Application",
|
||||
"ActionsChanged",
|
||||
"/org/gtk/test/app",
|
||||
NULL,
|
||||
G_DBUS_SIGNAL_FLAGS_NONE,
|
||||
actions_changed,
|
||||
loop,
|
||||
NULL);
|
||||
|
||||
g_timeout_add (0, invoke_action, "action2");
|
||||
|
||||
g_main_loop_run (loop);
|
||||
|
||||
g_assert_cmpint (changed, >, 0);
|
||||
|
||||
g_dbus_connection_signal_unsubscribe (connection, id);
|
||||
g_object_unref (connection);
|
||||
g_main_loop_unref (loop);
|
||||
}
|
||||
|
||||
static void
|
||||
test_change_action (void)
|
||||
{
|
||||
run_with_application (test_change_action_on_application_appeared);
|
||||
}
|
||||
|
||||
int
|
||||
main (int argc, char *argv[])
|
||||
{
|
||||
gint ret;
|
||||
|
||||
g_type_init ();
|
||||
g_test_init (&argc, &argv, NULL);
|
||||
|
||||
g_unsetenv ("DISPLAY");
|
||||
g_setenv ("DBUS_SESSION_BUS_ADDRESS", session_bus_get_temporary_address (), TRUE);
|
||||
|
||||
session_bus_up ();
|
||||
|
||||
g_test_add_func ("/application/unique", test_unique);
|
||||
g_test_add_func ("/application/quit", test_quit);
|
||||
g_test_add_func ("/application/list-actions", test_list_actions);
|
||||
g_test_add_func ("/application/invoke", test_invoke);
|
||||
g_test_add_func ("/application/remote", test_remote);
|
||||
g_test_add_func ("/application/change-action", test_change_action);
|
||||
|
||||
ret = g_test_run ();
|
||||
|
||||
session_bus_down ();
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user