mirror of
https://gitlab.gnome.org/GNOME/glib.git
synced 2025-10-05 05:09:21 +02:00
new GApplication implementation
This commit is contained in:
@@ -146,6 +146,7 @@ application_sources = \
|
|||||||
gsimpleactiongroup.c \
|
gsimpleactiongroup.c \
|
||||||
gaction.c \
|
gaction.c \
|
||||||
gsimpleaction.c \
|
gsimpleaction.c \
|
||||||
|
gapplicationimpl-dbus.c \
|
||||||
gapplication.c
|
gapplication.c
|
||||||
|
|
||||||
local_sources = \
|
local_sources = \
|
||||||
|
2186
gio/gapplication.c
2186
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 Codethink Limited
|
||||||
* Copyright © 2010 Red Hat, Inc
|
|
||||||
*
|
*
|
||||||
* This program is free software: you can redistribute it and/or modify
|
* 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
|
* 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,
|
* Free Software Foundation, Inc., 59 Temple Place, Suite 330,
|
||||||
* Boston, MA 02111-1307, USA.
|
* Boston, MA 02111-1307, USA.
|
||||||
*
|
*
|
||||||
* Authors: Colin Walters <walters@verbum.org>
|
* Authors: Ryan Lortie <desrt@desrt.ca>
|
||||||
* Emmanuele Bassi <ebassi@linux.intel.com>
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#if !defined (__GIO_GIO_H_INSIDE__) && !defined (GIO_COMPILATION)
|
#if !defined (__GIO_GIO_H_INSIDE__) && !defined (GIO_COMPILATION)
|
||||||
@@ -28,19 +26,20 @@
|
|||||||
#ifndef __G_APPLICATION_H__
|
#ifndef __G_APPLICATION_H__
|
||||||
#define __G_APPLICATION_H__
|
#define __G_APPLICATION_H__
|
||||||
|
|
||||||
#include <glib-object.h>
|
|
||||||
#include <gio/giotypes.h>
|
#include <gio/giotypes.h>
|
||||||
|
|
||||||
G_BEGIN_DECLS
|
G_BEGIN_DECLS
|
||||||
|
|
||||||
#define G_TYPE_APPLICATION (g_application_get_type ())
|
#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(inst) (G_TYPE_CHECK_INSTANCE_CAST ((inst), \
|
||||||
#define G_APPLICATION_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), G_TYPE_APPLICATION, GApplicationClass))
|
G_TYPE_APPLICATION, GApplication))
|
||||||
#define G_IS_APPLICATION(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), G_TYPE_APPLICATION))
|
#define G_APPLICATION_CLASS(class) (G_TYPE_CHECK_CLASS_CAST ((class), \
|
||||||
#define G_IS_APPLICATION_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), G_TYPE_APPLICATION))
|
G_TYPE_APPLICATION, GApplicationClass))
|
||||||
#define G_APPLICATION_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), 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 _GApplicationPrivate GApplicationPrivate;
|
||||||
typedef struct _GApplicationClass GApplicationClass;
|
typedef struct _GApplicationClass GApplicationClass;
|
||||||
|
|
||||||
@@ -62,13 +61,19 @@ struct _GApplication
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* GApplicationClass:
|
* GApplicationClass:
|
||||||
* @action_with_data: class handler for the #GApplication::action-with-data signal
|
* @startup: invoked on the primary instance immediately after registration
|
||||||
* @quit_with_data: class handler for the #GApplication::quit-with-data signal
|
* @activate: invoked on the primary instance when an activation occurs
|
||||||
* @prepare_activation: class handler for the #GApplication::prepare-activation signal
|
* @open: invoked on the primary instance when there are files to open
|
||||||
* @run: virtual function, called by g_application_run()
|
* @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
|
||||||
* The <structname>GApplicationClass</structname> structure contains
|
* g_application_run() for more information.
|
||||||
* private data only
|
* @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
|
* Since: 2.26
|
||||||
*/
|
*/
|
||||||
@@ -79,70 +84,78 @@ struct _GApplicationClass
|
|||||||
|
|
||||||
/*< public >*/
|
/*< public >*/
|
||||||
/* signals */
|
/* signals */
|
||||||
void (* action_with_data) (GApplication *application,
|
void (* startup) (GApplication *application);
|
||||||
const gchar *action_name,
|
|
||||||
GVariant *platform_data);
|
void (* activate) (GApplication *application);
|
||||||
gboolean (* quit_with_data) (GApplication *application,
|
|
||||||
GVariant *platform_data);
|
void (* open) (GApplication *application,
|
||||||
void (* prepare_activation) (GApplication *application,
|
GFile **files,
|
||||||
GVariant *arguments,
|
gint n_files,
|
||||||
GVariant *platform_data);
|
const gchar *hint);
|
||||||
|
|
||||||
|
gpointer _reserved_1;
|
||||||
|
|
||||||
/* vfuncs */
|
/* 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 >*/
|
/*< private >*/
|
||||||
/* Padding for future expansion */
|
gpointer padding[12];
|
||||||
void (*_g_reserved1) (void);
|
|
||||||
void (*_g_reserved2) (void);
|
|
||||||
void (*_g_reserved3) (void);
|
|
||||||
void (*_g_reserved4) (void);
|
|
||||||
void (*_g_reserved5) (void);
|
|
||||||
void (*_g_reserved6) (void);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
GType g_application_get_type (void) G_GNUC_CONST;
|
GType g_application_get_type (void) G_GNUC_CONST;
|
||||||
|
|
||||||
GApplication * g_application_new (const gchar *appid,
|
gboolean g_application_id_is_valid (const gchar *application_id);
|
||||||
|
|
||||||
|
GApplication * g_application_new (const gchar *application_id,
|
||||||
|
GApplicationFlags flags);
|
||||||
|
|
||||||
|
const gchar * g_application_get_application_id (GApplication *application);
|
||||||
|
void g_application_set_application_id (GApplication *application,
|
||||||
|
const gchar *application_id);
|
||||||
|
|
||||||
|
guint g_application_get_inactivity_timeout (GApplication *application);
|
||||||
|
void g_application_set_inactivity_timeout (GApplication *application,
|
||||||
|
guint inactivity_timeout);
|
||||||
|
|
||||||
|
GApplicationFlags g_application_get_flags (GApplication *application);
|
||||||
|
void g_application_set_flags (GApplication *application,
|
||||||
|
GApplicationFlags flags);
|
||||||
|
|
||||||
|
gboolean g_application_get_is_registered (GApplication *application);
|
||||||
|
gboolean g_application_get_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,
|
int argc,
|
||||||
char **argv);
|
char **argv);
|
||||||
|
int g_application_run_with_arguments (GApplication *application,
|
||||||
GApplication * g_application_try_new (const gchar *appid,
|
GVariant *arguments);
|
||||||
int argc,
|
|
||||||
char **argv,
|
|
||||||
GError **error);
|
|
||||||
|
|
||||||
GApplication * g_application_unregistered_try_new (const gchar *appid,
|
|
||||||
int argc,
|
|
||||||
char **argv,
|
|
||||||
GError **error);
|
|
||||||
|
|
||||||
gboolean g_application_register (GApplication *application);
|
|
||||||
|
|
||||||
GApplication * g_application_get_instance (void);
|
|
||||||
G_CONST_RETURN gchar * g_application_get_id (GApplication *application);
|
|
||||||
|
|
||||||
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);
|
|
||||||
|
|
||||||
void g_application_run (GApplication *application);
|
|
||||||
gboolean g_application_quit_with_data (GApplication *application,
|
|
||||||
GVariant *platform_data);
|
|
||||||
|
|
||||||
gboolean g_application_is_remote (GApplication *application);
|
|
||||||
|
|
||||||
G_END_DECLS
|
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
|
||||||
VOID:STRING,STRING
|
VOID:STRING,STRING
|
||||||
VOID:STRING,BOOLEAN
|
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_HEADER(__G_APPLICATION_H__)
|
||||||
#if IN_FILE(__G_APPLICATION_C__)
|
#if IN_FILE(__G_APPLICATION_C__)
|
||||||
g_application_get_type G_GNUC_CONST
|
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_new
|
||||||
g_application_get_instance
|
g_application_open
|
||||||
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_register
|
g_application_register
|
||||||
g_application_try_new
|
g_application_release
|
||||||
g_application_unregistered_try_new
|
g_application_run
|
||||||
g_application_quit_with_data
|
g_application_run_with_arguments
|
||||||
g_application_is_remote
|
g_application_set_application_id
|
||||||
|
g_application_set_flags
|
||||||
|
g_application_set_inactivity_timeout
|
||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@@ -1216,6 +1216,24 @@ typedef enum
|
|||||||
G_DBUS_MESSAGE_BYTE_ORDER_LITTLE_ENDIAN = 'l'
|
G_DBUS_MESSAGE_BYTE_ORDER_LITTLE_ENDIAN = 'l'
|
||||||
} GDBusMessageByteOrder;
|
} 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
|
G_END_DECLS
|
||||||
|
|
||||||
#endif /* __GIO_ENUMS_H__ */
|
#endif /* __GIO_ENUMS_H__ */
|
||||||
|
@@ -51,6 +51,8 @@ typedef struct _GSimpleActionGroup GSimpleActionGroup;
|
|||||||
typedef struct _GActionGroup GActionGroup;
|
typedef struct _GActionGroup GActionGroup;
|
||||||
typedef struct _GSimpleAction GSimpleAction;
|
typedef struct _GSimpleAction GSimpleAction;
|
||||||
typedef struct _GAction GAction;
|
typedef struct _GAction GAction;
|
||||||
|
typedef struct _GApplication GApplication;
|
||||||
|
typedef struct _GApplicationCommandLine GApplicationCommandLine;
|
||||||
typedef struct _GSettingsBackend GSettingsBackend;
|
typedef struct _GSettingsBackend GSettingsBackend;
|
||||||
typedef struct _GSettings GSettings;
|
typedef struct _GSettings GSettings;
|
||||||
typedef struct _GPermission GPermission;
|
typedef struct _GPermission GPermission;
|
||||||
|
3
gio/tests/.gitignore
vendored
3
gio/tests/.gitignore
vendored
@@ -1,7 +1,6 @@
|
|||||||
actions
|
actions
|
||||||
appinfo
|
appinfo
|
||||||
appinfo-test
|
appinfo-test
|
||||||
application
|
|
||||||
async-close-output-stream
|
async-close-output-stream
|
||||||
buffered-input-stream
|
buffered-input-stream
|
||||||
buffered-output-stream
|
buffered-output-stream
|
||||||
@@ -65,8 +64,6 @@ sleepy-stream
|
|||||||
socket-client
|
socket-client
|
||||||
socket-server
|
socket-server
|
||||||
srvtarget
|
srvtarget
|
||||||
testapp
|
|
||||||
testapps
|
|
||||||
test.mo
|
test.mo
|
||||||
unix-fd
|
unix-fd
|
||||||
unix-streams
|
unix-streams
|
||||||
|
@@ -59,8 +59,6 @@ TEST_PROGS += \
|
|||||||
gdbus-exit-on-close \
|
gdbus-exit-on-close \
|
||||||
gdbus-non-socket \
|
gdbus-non-socket \
|
||||||
gdbus-bz627724 \
|
gdbus-bz627724 \
|
||||||
application \
|
|
||||||
testapps \
|
|
||||||
appinfo \
|
appinfo \
|
||||||
contenttype \
|
contenttype \
|
||||||
file \
|
file \
|
||||||
@@ -84,7 +82,6 @@ SAMPLE_PROGS = \
|
|||||||
gdbus-example-peer \
|
gdbus-example-peer \
|
||||||
gdbus-example-proxy-subclass \
|
gdbus-example-proxy-subclass \
|
||||||
gdbus-connection-flush-helper \
|
gdbus-connection-flush-helper \
|
||||||
testapp \
|
|
||||||
appinfo-test \
|
appinfo-test \
|
||||||
proxy \
|
proxy \
|
||||||
$(NULL)
|
$(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_SOURCES = gdbus-connection-flush-helper.c
|
||||||
gdbus_connection_flush_helper_LDADD = $(progs_ldadd)
|
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_SOURCES = appinfo.c
|
||||||
appinfo_LDADD = $(progs_ldadd)
|
appinfo_LDADD = $(progs_ldadd)
|
||||||
|
|
||||||
appinfo_test_SOURCES = appinfo-test.c
|
appinfo_test_SOURCES = appinfo-test.c
|
||||||
appinfo_test_LDADD = $(progs_ldadd)
|
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_SOURCES = contenttype.c
|
||||||
contenttype_LDADD = $(progs_ldadd)
|
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;
|
|
||||||
}
|
|
||||||
|
|
Reference in New Issue
Block a user