mirror of
https://gitlab.gnome.org/GNOME/glib.git
synced 2025-02-13 06:00:36 +01:00
Merge the wip/gapplication branch
This adds a GApplication object to GIO, which is the core of an application support class, supporting - uniqueness - exporting actions (simple scripting) - standard actions (quit, activate) The implementation for Linux uses D-Bus, takes a name on the session bus, and exports a org.gtk.Application interface. Implementations for Win32 and OS X are still missing.
This commit is contained in:
parent
af78f6d418
commit
6427e93757
@ -160,6 +160,10 @@
|
|||||||
<xi:include href="xml/gpermission.xml"/>
|
<xi:include href="xml/gpermission.xml"/>
|
||||||
<xi:include href="xml/gsimplepermission.xml"/>
|
<xi:include href="xml/gsimplepermission.xml"/>
|
||||||
</chapter>
|
</chapter>
|
||||||
|
<chapter id="application">
|
||||||
|
<title>Application support</title>
|
||||||
|
<xi:include href="xml/gapplication.xml"/>
|
||||||
|
</chapter>
|
||||||
<chapter id="extending">
|
<chapter id="extending">
|
||||||
<title>Extending GIO</title>
|
<title>Extending GIO</title>
|
||||||
<xi:include href="xml/gvfs.xml"/>
|
<xi:include href="xml/gvfs.xml"/>
|
||||||
|
@ -2619,3 +2619,35 @@ g_simple_permission_new
|
|||||||
<SUBSECTION Standard>
|
<SUBSECTION Standard>
|
||||||
g_simple_permission_get_type
|
g_simple_permission_get_type
|
||||||
</SECTION>
|
</SECTION>
|
||||||
|
|
||||||
|
<FILE>gapplication</FILE>
|
||||||
|
GApplication
|
||||||
|
GApplicationClass
|
||||||
|
|
||||||
|
g_application_new
|
||||||
|
g_application_new_and_register
|
||||||
|
g_application_register_with_data
|
||||||
|
g_application_format_activation_data
|
||||||
|
g_application_get_instance
|
||||||
|
g_application_get_id
|
||||||
|
g_application_add_action
|
||||||
|
g_application_remove_action
|
||||||
|
g_application_list_actions
|
||||||
|
g_application_set_action_enabled
|
||||||
|
g_application_get_action_enabled
|
||||||
|
g_application_get_action_description
|
||||||
|
g_application_invoke_action
|
||||||
|
g_application_run
|
||||||
|
g_application_quit
|
||||||
|
g_application_is_remote
|
||||||
|
<SUBSECTION Standard>
|
||||||
|
G_TYPE_APPLICATION
|
||||||
|
G_APPLICATION
|
||||||
|
G_APPLICATION_CLASS
|
||||||
|
G_IS_APPLICATION
|
||||||
|
G_IS_APPLICATION_CLASS
|
||||||
|
G_APPLICATION_GET_CLASS
|
||||||
|
<SUBSECTION Private>
|
||||||
|
GApplicationPrivate
|
||||||
|
g_application_get_type
|
||||||
|
</SECTION>
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
g_app_info_create_flags_get_type
|
g_app_info_create_flags_get_type
|
||||||
g_app_info_get_type
|
g_app_info_get_type
|
||||||
g_app_launch_context_get_type
|
g_app_launch_context_get_type
|
||||||
|
g_application_get_type
|
||||||
g_ask_password_flags_get_type
|
g_ask_password_flags_get_type
|
||||||
g_async_initable_get_type
|
g_async_initable_get_type
|
||||||
g_async_result_get_type
|
g_async_result_get_type
|
||||||
|
@ -268,6 +268,8 @@ SUBDIRS += tests
|
|||||||
|
|
||||||
libgio_2_0_la_SOURCES = \
|
libgio_2_0_la_SOURCES = \
|
||||||
gappinfo.c \
|
gappinfo.c \
|
||||||
|
gapplication.c \
|
||||||
|
gapplication.h \
|
||||||
gasynchelper.c \
|
gasynchelper.c \
|
||||||
gasynchelper.h \
|
gasynchelper.h \
|
||||||
gasyncinitable.c \
|
gasyncinitable.c \
|
||||||
@ -374,6 +376,8 @@ libgio_2_0_la_SOURCES = \
|
|||||||
$(marshal_sources) \
|
$(marshal_sources) \
|
||||||
$(NULL)
|
$(NULL)
|
||||||
|
|
||||||
|
EXTRA_DIST += gnullapplication.c gdbusapplication.c
|
||||||
|
|
||||||
$(libgio_2_0_la_OBJECTS): $(marshal_sources)
|
$(libgio_2_0_la_OBJECTS): $(marshal_sources)
|
||||||
|
|
||||||
libgio_2_0_la_LIBADD = \
|
libgio_2_0_la_LIBADD = \
|
||||||
@ -427,6 +431,7 @@ gio-win32-res.o: gio.rc
|
|||||||
|
|
||||||
gio_headers = \
|
gio_headers = \
|
||||||
gappinfo.h \
|
gappinfo.h \
|
||||||
|
gapplication.h \
|
||||||
gasyncinitable.h \
|
gasyncinitable.h \
|
||||||
gasyncresult.h \
|
gasyncresult.h \
|
||||||
gbufferedinputstream.h \
|
gbufferedinputstream.h \
|
||||||
|
@ -477,6 +477,15 @@ g_app_info_get_icon (GAppInfo *appinfo)
|
|||||||
* a textual uri you want to pass in as argument, consider using
|
* a textual uri you want to pass in as argument, consider using
|
||||||
* g_app_info_launch_uris() instead.
|
* g_app_info_launch_uris() instead.
|
||||||
*
|
*
|
||||||
|
* On UNIX, this function sets the <envvar>GIO_LAUNCHED_DESKTOP_FILE</envvar>
|
||||||
|
* environment variable with the path of the launched desktop file and
|
||||||
|
* <envvar>GIO_LAUNCHED_DESKTOP_FILE_PID</envvar> to the process
|
||||||
|
* id of the launched process. This can be used to ignore
|
||||||
|
* <envvar>GIO_LAUNCHED_DESKTOP_FILE</envvar>, should it be inherited
|
||||||
|
* by further processes. The <envvar>DISPLAY</envvar> and
|
||||||
|
* <envvar>DESKTOP_STARTUP_ID</envvar> environment variables are also
|
||||||
|
* set, based on information provided in @launch_context.
|
||||||
|
*
|
||||||
* Returns: %TRUE on successful launch, %FALSE otherwise.
|
* Returns: %TRUE on successful launch, %FALSE otherwise.
|
||||||
**/
|
**/
|
||||||
gboolean
|
gboolean
|
||||||
@ -726,9 +735,9 @@ g_app_launch_context_init (GAppLaunchContext *launch_context)
|
|||||||
* @info: a #GAppInfo
|
* @info: a #GAppInfo
|
||||||
* @files: a #GList of #GFile objects
|
* @files: a #GList of #GFile objects
|
||||||
*
|
*
|
||||||
* Gets the display string for the display. This is used to ensure new
|
* Gets the display string for the @context. This is used to ensure new
|
||||||
* applications are started on the same display as the launching
|
* applications are started on the same display as the launching
|
||||||
* application.
|
* application, by setting the <envvar>DISPLAY</envvar> environment variable.
|
||||||
*
|
*
|
||||||
* Returns: a display string for the display.
|
* Returns: a display string for the display.
|
||||||
**/
|
**/
|
||||||
@ -757,7 +766,8 @@ g_app_launch_context_get_display (GAppLaunchContext *context,
|
|||||||
* @files: a #GList of of #GFile objects
|
* @files: a #GList of of #GFile objects
|
||||||
*
|
*
|
||||||
* Initiates startup notification for the application and returns the
|
* Initiates startup notification for the application and returns the
|
||||||
* DESKTOP_STARTUP_ID for the launched operation, if supported.
|
* <envvar>DESKTOP_STARTUP_ID</envvar> for the launched operation,
|
||||||
|
* if supported.
|
||||||
*
|
*
|
||||||
* Startup notification IDs are defined in the <ulink
|
* Startup notification IDs are defined in the <ulink
|
||||||
* url="http://standards.freedesktop.org/startup-notification-spec/startup-notification-latest.txt">
|
* url="http://standards.freedesktop.org/startup-notification-spec/startup-notification-latest.txt">
|
||||||
|
1058
gio/gapplication.c
Normal file
1058
gio/gapplication.c
Normal file
File diff suppressed because it is too large
Load Diff
151
gio/gapplication.h
Normal file
151
gio/gapplication.h
Normal file
@ -0,0 +1,151 @@
|
|||||||
|
/* GIO - GLib Input, Output and Streaming Library
|
||||||
|
*
|
||||||
|
* Copyright © 2010 Red Hat, Inc
|
||||||
|
*
|
||||||
|
* 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
|
||||||
|
* 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.
|
||||||
|
*
|
||||||
|
* Authors: Colin Walters <walters@verbum.org>
|
||||||
|
* Emmanuele Bassi <ebassi@linux.intel.com>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#if !defined (__GIO_GIO_H_INSIDE__) && !defined (GIO_COMPILATION)
|
||||||
|
#error "Only <gio/gio.h> can be included directly."
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#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))
|
||||||
|
|
||||||
|
typedef struct _GApplication GApplication;
|
||||||
|
typedef struct _GApplicationPrivate GApplicationPrivate;
|
||||||
|
typedef struct _GApplicationClass GApplicationClass;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* GApplication:
|
||||||
|
*
|
||||||
|
* The <structname>GApplication</structname> structure contains private
|
||||||
|
* data and should only be accessed using the provided API
|
||||||
|
*
|
||||||
|
* Since: 2.26
|
||||||
|
*/
|
||||||
|
struct _GApplication
|
||||||
|
{
|
||||||
|
/*< private >*/
|
||||||
|
GObject parent_instance;
|
||||||
|
|
||||||
|
GApplicationPrivate *priv;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* GApplicationClass:
|
||||||
|
* @action: class handler for the #GApplication::action signal
|
||||||
|
* @quit: class handler for the #GApplication::quit signal
|
||||||
|
* @prepare_activation: class handler for the #GApplication::prepare-activation signal
|
||||||
|
* @run: virtual function, called by g_application_run()
|
||||||
|
* @format_activation_data: virtual function, called by g_application_format_activation_data()
|
||||||
|
*
|
||||||
|
* The <structname>GApplicationClass</structname> structure contains
|
||||||
|
* private data only
|
||||||
|
*
|
||||||
|
* Since: 2.26
|
||||||
|
*/
|
||||||
|
struct _GApplicationClass
|
||||||
|
{
|
||||||
|
/*< private >*/
|
||||||
|
GObjectClass parent_class;
|
||||||
|
|
||||||
|
/*< public >*/
|
||||||
|
/* signals */
|
||||||
|
void (* action) (GApplication *application,
|
||||||
|
const gchar *action_name,
|
||||||
|
guint timestamp);
|
||||||
|
gboolean (* quit) (GApplication *application,
|
||||||
|
guint timestamp);
|
||||||
|
void (* prepare_activation) (GApplication *application,
|
||||||
|
GVariant *arguments,
|
||||||
|
GVariant *platform_data);
|
||||||
|
|
||||||
|
/* vfuncs */
|
||||||
|
void (* run) (GApplication *application);
|
||||||
|
void (*format_activation_data) (GApplication *application,
|
||||||
|
GVariantBuilder *builder);
|
||||||
|
|
||||||
|
/*< 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);
|
||||||
|
};
|
||||||
|
GType g_application_get_type (void) G_GNUC_CONST;
|
||||||
|
|
||||||
|
GApplication * g_application_new (const char *appid);
|
||||||
|
|
||||||
|
void g_application_register_with_data (GApplication *application,
|
||||||
|
int argc,
|
||||||
|
char **argv,
|
||||||
|
GVariant *platform_data);
|
||||||
|
|
||||||
|
GApplication * g_application_new_and_register (const char *appid,
|
||||||
|
int argc,
|
||||||
|
char **argv);
|
||||||
|
|
||||||
|
GApplication * g_application_get_instance (void);
|
||||||
|
G_CONST_RETURN gchar * g_application_get_id (GApplication *application);
|
||||||
|
|
||||||
|
void g_application_add_action (GApplication *application,
|
||||||
|
const char *name,
|
||||||
|
const char *description);
|
||||||
|
void g_application_remove_action (GApplication *application,
|
||||||
|
const char *name);
|
||||||
|
gchar ** g_application_list_actions (GApplication *application);
|
||||||
|
void g_application_set_action_enabled (GApplication *application,
|
||||||
|
const char *name,
|
||||||
|
gboolean enabled);
|
||||||
|
gboolean g_application_get_action_enabled (GApplication *application,
|
||||||
|
const char *name);
|
||||||
|
G_CONST_RETURN gchar * g_application_get_action_description (GApplication *application,
|
||||||
|
const char *name);
|
||||||
|
void g_application_invoke_action (GApplication *application,
|
||||||
|
const char *name,
|
||||||
|
guint timestamp);
|
||||||
|
|
||||||
|
void g_application_run (GApplication *application);
|
||||||
|
gboolean g_application_quit (GApplication *app,
|
||||||
|
guint timestamp);
|
||||||
|
|
||||||
|
gboolean g_application_is_remote (GApplication *application);
|
||||||
|
|
||||||
|
void g_application_format_activation_data (GApplication *app,
|
||||||
|
GVariantBuilder *builder);
|
||||||
|
|
||||||
|
|
||||||
|
G_END_DECLS
|
||||||
|
|
||||||
|
#endif /* __G_APPLICATION_H__ */
|
426
gio/gdbusapplication.c
Normal file
426
gio/gdbusapplication.c
Normal file
@ -0,0 +1,426 @@
|
|||||||
|
/* 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)
|
||||||
|
{
|
||||||
|
guint32 timestamp;
|
||||||
|
g_variant_get (parameters, "(u)", ×tamp);
|
||||||
|
|
||||||
|
g_dbus_method_invocation_return_value (invocation, NULL);
|
||||||
|
|
||||||
|
g_application_quit (app, timestamp);
|
||||||
|
}
|
||||||
|
else if (strcmp (method_name, "ListActions") == 0)
|
||||||
|
{
|
||||||
|
GHashTableIter iter;
|
||||||
|
GApplicationAction *value;
|
||||||
|
GVariantBuilder builder;
|
||||||
|
GVariant *return_args;
|
||||||
|
GVariant *result;
|
||||||
|
|
||||||
|
g_variant_builder_init (&builder, G_VARIANT_TYPE_ARRAY);
|
||||||
|
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);
|
||||||
|
|
||||||
|
result = g_variant_builder_end (&builder);
|
||||||
|
return_args = g_variant_new_tuple (&result, 1);
|
||||||
|
g_dbus_method_invocation_return_value (invocation, return_args);
|
||||||
|
g_variant_unref (return_args);
|
||||||
|
g_variant_unref (result);
|
||||||
|
}
|
||||||
|
else if (strcmp (method_name, "InvokeAction") == 0)
|
||||||
|
{
|
||||||
|
const char *action_name;
|
||||||
|
guint32 timestamp;
|
||||||
|
GApplicationAction *action;
|
||||||
|
|
||||||
|
g_variant_get (parameters, "(su)", &action_name, ×tamp);
|
||||||
|
|
||||||
|
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);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
g_signal_emit (app, application_signals[ACTION], g_quark_from_string (action_name), action_name, (guint)timestamp);
|
||||||
|
|
||||||
|
g_dbus_method_invocation_return_value (invocation, NULL);
|
||||||
|
}
|
||||||
|
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,
|
||||||
|
"timestamp",
|
||||||
|
"u",
|
||||||
|
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,
|
||||||
|
"timestamp",
|
||||||
|
"u",
|
||||||
|
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 char *
|
||||||
|
application_path_from_appid (const char *appid)
|
||||||
|
{
|
||||||
|
char *appid_path, *iter;
|
||||||
|
|
||||||
|
|
||||||
|
appid_path = g_strconcat ("/", appid, NULL);
|
||||||
|
for (iter = appid_path; *iter; iter++)
|
||||||
|
{
|
||||||
|
if (*iter == '.')
|
||||||
|
*iter = '/';
|
||||||
|
}
|
||||||
|
|
||||||
|
return appid_path;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
ensure_bus (GApplication *app)
|
||||||
|
{
|
||||||
|
GError *error = NULL;
|
||||||
|
|
||||||
|
if (app->priv->session_bus == NULL)
|
||||||
|
app->priv->session_bus = g_bus_get_sync (G_BUS_TYPE_SESSION, NULL, &error);
|
||||||
|
if (app->priv->session_bus == NULL)
|
||||||
|
{
|
||||||
|
g_error ("%s", error->message);
|
||||||
|
g_error_free (error);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (app->priv->dbus_path == NULL)
|
||||||
|
app->priv->dbus_path = application_path_from_appid (app->priv->appid);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
_g_application_platform_init (GApplication *app)
|
||||||
|
{
|
||||||
|
GError *error = NULL;
|
||||||
|
guint registration_id;
|
||||||
|
|
||||||
|
ensure_bus (app);
|
||||||
|
|
||||||
|
registration_id = g_dbus_connection_register_object (app->priv->session_bus,
|
||||||
|
app->priv->dbus_path,
|
||||||
|
&application_dbus_interface_info,
|
||||||
|
&application_dbus_vtable,
|
||||||
|
app, NULL,
|
||||||
|
&error);
|
||||||
|
if (registration_id == 0)
|
||||||
|
{
|
||||||
|
g_error ("%s", error->message);
|
||||||
|
g_error_free (error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
_g_application_platform_acquire_single_instance (GApplication *app,
|
||||||
|
GError **error)
|
||||||
|
{
|
||||||
|
GVariant *request_result;
|
||||||
|
guint32 request_status;
|
||||||
|
|
||||||
|
ensure_bus (app);
|
||||||
|
if (app->priv->session_bus == NULL)
|
||||||
|
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, NULL, error);
|
||||||
|
|
||||||
|
if (request_result == NULL)
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
|
if (strcmp (g_variant_get_type_string (request_result), "(u)") == 0)
|
||||||
|
g_variant_get (request_result, "(u)", &request_status);
|
||||||
|
else
|
||||||
|
request_status = 0;
|
||||||
|
|
||||||
|
g_variant_unref (request_result);
|
||||||
|
|
||||||
|
if (request_status != 1 && request_status != 4)
|
||||||
|
{
|
||||||
|
if (request_status == 3)
|
||||||
|
g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, "Another process has name \"%s\"", app->priv->appid);
|
||||||
|
else
|
||||||
|
g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_FAILED, "Unknown error");
|
||||||
|
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
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 char *action,
|
||||||
|
guint timestamp)
|
||||||
|
{
|
||||||
|
GVariant *result;
|
||||||
|
|
||||||
|
ensure_bus (app);
|
||||||
|
|
||||||
|
result = g_dbus_connection_call_sync (app->priv->session_bus,
|
||||||
|
app->priv->appid,
|
||||||
|
app->priv->dbus_path,
|
||||||
|
G_APPLICATION_IFACE,
|
||||||
|
"InvokeAction",
|
||||||
|
g_variant_new ("(su)",
|
||||||
|
action,
|
||||||
|
timestamp),
|
||||||
|
NULL, 0, -1, NULL, NULL);
|
||||||
|
if (result)
|
||||||
|
g_variant_unref (result);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
_g_application_platform_remote_quit (GApplication *app,
|
||||||
|
guint timestamp)
|
||||||
|
{
|
||||||
|
GVariant *result;
|
||||||
|
|
||||||
|
ensure_bus (app);
|
||||||
|
|
||||||
|
result = g_dbus_connection_call_sync (app->priv->session_bus,
|
||||||
|
app->priv->appid,
|
||||||
|
app->priv->dbus_path,
|
||||||
|
G_APPLICATION_IFACE,
|
||||||
|
"Quit",
|
||||||
|
g_variant_new ("(u)",
|
||||||
|
timestamp),
|
||||||
|
NULL, 0, -1, NULL, NULL);
|
||||||
|
if (result)
|
||||||
|
g_variant_unref (result);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
_g_application_platform_activate (GApplication *app,
|
||||||
|
GVariant *data)
|
||||||
|
{
|
||||||
|
GVariant *result;
|
||||||
|
|
||||||
|
ensure_bus (app);
|
||||||
|
|
||||||
|
result = g_dbus_connection_call_sync (app->priv->session_bus,
|
||||||
|
app->priv->appid,
|
||||||
|
app->priv->dbus_path,
|
||||||
|
G_APPLICATION_IFACE,
|
||||||
|
"Activate",
|
||||||
|
data,
|
||||||
|
NULL, 0, -1, NULL, NULL);
|
||||||
|
|
||||||
|
if (result)
|
||||||
|
g_variant_unref (result);
|
||||||
|
|
||||||
|
exit (0);
|
||||||
|
}
|
@ -434,7 +434,7 @@ gboolean g_dbus_connection_unregister_subtree (GDBusConnection
|
|||||||
* @connection: A #GDBusConnection.
|
* @connection: A #GDBusConnection.
|
||||||
* @sender_name: The unique bus name of the sender of the signal.
|
* @sender_name: The unique bus name of the sender of the signal.
|
||||||
* @object_path: The object path that the signal was emitted on.
|
* @object_path: The object path that the signal was emitted on.
|
||||||
* @interface_name: The name of the signal.
|
* @interface_name: The name of the interface.
|
||||||
* @signal_name: The name of the signal.
|
* @signal_name: The name of the signal.
|
||||||
* @parameters: A #GVariant tuple with parameters for the signal.
|
* @parameters: A #GVariant tuple with parameters for the signal.
|
||||||
* @user_data: User data passed when subscribing to the signal.
|
* @user_data: User data passed when subscribing to the signal.
|
||||||
|
@ -879,6 +879,7 @@ typedef struct
|
|||||||
{
|
{
|
||||||
char *display;
|
char *display;
|
||||||
char *sn_id;
|
char *sn_id;
|
||||||
|
char *desktop_file;
|
||||||
} ChildSetupData;
|
} ChildSetupData;
|
||||||
|
|
||||||
static void
|
static void
|
||||||
@ -891,6 +892,16 @@ child_setup (gpointer user_data)
|
|||||||
|
|
||||||
if (data->sn_id)
|
if (data->sn_id)
|
||||||
g_setenv ("DESKTOP_STARTUP_ID", data->sn_id, TRUE);
|
g_setenv ("DESKTOP_STARTUP_ID", data->sn_id, TRUE);
|
||||||
|
|
||||||
|
if (data->desktop_file)
|
||||||
|
{
|
||||||
|
gchar pid[20];
|
||||||
|
|
||||||
|
g_setenv ("GIO_LAUNCHED_DESKTOP_FILE", data->desktop_file, TRUE);
|
||||||
|
|
||||||
|
g_snprintf (pid, 20, "%d", getpid ());
|
||||||
|
g_setenv ("GIO_LAUNCHED_DESKTOP_FILE_PID", pid, TRUE);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static gboolean
|
static gboolean
|
||||||
@ -927,6 +938,7 @@ g_desktop_app_info_launch_uris (GAppInfo *appinfo,
|
|||||||
|
|
||||||
data.display = NULL;
|
data.display = NULL;
|
||||||
data.sn_id = NULL;
|
data.sn_id = NULL;
|
||||||
|
data.desktop_file = info->filename;
|
||||||
|
|
||||||
if (launch_context)
|
if (launch_context)
|
||||||
{
|
{
|
||||||
|
@ -9,3 +9,6 @@ BOOL:UINT
|
|||||||
VOID:STRING,STRING,BOXED
|
VOID:STRING,STRING,BOXED
|
||||||
VOID:BOOL,BOXED
|
VOID:BOOL,BOXED
|
||||||
VOID:BOXED,BOXED
|
VOID:BOXED,BOXED
|
||||||
|
VOID:INT
|
||||||
|
VOID:STRING,INT
|
||||||
|
VOID:BOXED,BOXED
|
||||||
|
@ -28,6 +28,7 @@
|
|||||||
#include <gio/giotypes.h>
|
#include <gio/giotypes.h>
|
||||||
|
|
||||||
#include <gio/gappinfo.h>
|
#include <gio/gappinfo.h>
|
||||||
|
#include <gio/gapplication.h>
|
||||||
#include <gio/gasyncinitable.h>
|
#include <gio/gasyncinitable.h>
|
||||||
#include <gio/gasyncresult.h>
|
#include <gio/gasyncresult.h>
|
||||||
#include <gio/gbufferedinputstream.h>
|
#include <gio/gbufferedinputstream.h>
|
||||||
|
@ -26,6 +26,27 @@ g_vfs_get_local
|
|||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if IN_HEADER(__G_APPLICATION_H__)
|
||||||
|
#if IN_FILE(__G_APPLICATION_C__)
|
||||||
|
g_application_get_type G_GNUC_CONST
|
||||||
|
g_application_new
|
||||||
|
g_application_new_and_register
|
||||||
|
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_register_with_data
|
||||||
|
g_application_invoke_action
|
||||||
|
g_application_list_actions
|
||||||
|
g_application_run
|
||||||
|
g_application_quit
|
||||||
|
g_application_is_remote
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
#if IN_HEADER(__G_APP_INFO_H__)
|
#if IN_HEADER(__G_APP_INFO_H__)
|
||||||
#if IN_FILE(__G_APP_INFO_C__)
|
#if IN_FILE(__G_APP_INFO_C__)
|
||||||
g_app_info_get_type G_GNUC_CONST
|
g_app_info_get_type G_GNUC_CONST
|
||||||
|
70
gio/gnullapplication.c
Normal file
70
gio/gnullapplication.c
Normal file
@ -0,0 +1,70 @@
|
|||||||
|
/* 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>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
#include "gioerror.h"
|
||||||
|
|
||||||
|
static void
|
||||||
|
_g_application_platform_init (GApplication *app)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
_g_application_platform_acquire_single_instance (GApplication *app,
|
||||||
|
GError **error)
|
||||||
|
{
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
_g_application_platform_on_actions_changed (GApplication *app)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
_g_application_platform_remote_invoke_action (GApplication *app,
|
||||||
|
const char *action,
|
||||||
|
guint timestamp)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
_g_application_platform_remote_quit (GApplication *app,
|
||||||
|
guint timestamp)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
_g_application_platform_default_quit (void)
|
||||||
|
{
|
||||||
|
exit (0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
_g_application_platform_activate (GApplication *app,
|
||||||
|
GVariant *data)
|
||||||
|
{
|
||||||
|
exit (0);
|
||||||
|
}
|
||||||
|
|
@ -54,6 +54,9 @@ TEST_PROGS += \
|
|||||||
gdbus-error \
|
gdbus-error \
|
||||||
gdbus-peer \
|
gdbus-peer \
|
||||||
gdbus-exit-on-close \
|
gdbus-exit-on-close \
|
||||||
|
application \
|
||||||
|
testapps \
|
||||||
|
appinfo \
|
||||||
$(NULL)
|
$(NULL)
|
||||||
endif
|
endif
|
||||||
|
|
||||||
@ -73,6 +76,8 @@ SAMPLE_PROGS = \
|
|||||||
gdbus-example-subtree \
|
gdbus-example-subtree \
|
||||||
gdbus-example-peer \
|
gdbus-example-peer \
|
||||||
gdbus-example-proxy-subclass \
|
gdbus-example-proxy-subclass \
|
||||||
|
testapp \
|
||||||
|
appinfo-test \
|
||||||
$(NULL)
|
$(NULL)
|
||||||
|
|
||||||
|
|
||||||
@ -248,6 +253,21 @@ gdbus_example_proxy_subclass_LDADD = $(progs_ldadd)
|
|||||||
gdbus_example_export_SOURCES = gdbus-example-export.c
|
gdbus_example_export_SOURCES = gdbus-example-export.c
|
||||||
gdbus_example_export_LDADD = $(progs_ldadd)
|
gdbus_example_export_LDADD = $(progs_ldadd)
|
||||||
|
|
||||||
|
application_SOURCES = application.c
|
||||||
|
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
|
||||||
|
testapps_LDADD = $(progs_ldadd)
|
||||||
|
|
||||||
EXTRA_DIST += \
|
EXTRA_DIST += \
|
||||||
socket-common.c \
|
socket-common.c \
|
||||||
org.gtk.test.gschema \
|
org.gtk.test.gschema \
|
||||||
|
20
gio/tests/appinfo-test.c
Normal file
20
gio/tests/appinfo-test.c
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
#include <stdlib.h>
|
||||||
|
#include <gio/gio.h>
|
||||||
|
|
||||||
|
int
|
||||||
|
main (int argc, char *argv[])
|
||||||
|
{
|
||||||
|
const gchar *envvar;
|
||||||
|
gint pid_from_env;
|
||||||
|
|
||||||
|
envvar = g_getenv ("GIO_LAUNCHED_DESKTOP_FILE_PID");
|
||||||
|
g_assert (envvar != NULL);
|
||||||
|
pid_from_env = atoi (envvar);
|
||||||
|
g_assert_cmpint (pid_from_env, ==, getpid ());
|
||||||
|
|
||||||
|
envvar = g_getenv ("GIO_LAUNCHED_DESKTOP_FILE");
|
||||||
|
g_assert_cmpstr (envvar, ==, SRCDIR "/appinfo-test.desktop");
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
4
gio/tests/appinfo-test.desktop
Normal file
4
gio/tests/appinfo-test.desktop
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
[Desktop Entry]
|
||||||
|
Type=Application
|
||||||
|
Name=appinfo-test
|
||||||
|
Exec=./appinfo-test
|
25
gio/tests/appinfo.c
Normal file
25
gio/tests/appinfo.c
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
#include <gio/gio.h>
|
||||||
|
#include <gio/gdesktopappinfo.h>
|
||||||
|
|
||||||
|
static void
|
||||||
|
test_launch (void)
|
||||||
|
{
|
||||||
|
GAppInfo *appinfo;
|
||||||
|
|
||||||
|
appinfo = (GAppInfo*)g_desktop_app_info_new_from_filename (SRCDIR "/appinfo-test.desktop");
|
||||||
|
g_assert (appinfo != NULL);
|
||||||
|
|
||||||
|
g_assert (g_app_info_launch (appinfo, NULL, NULL, NULL));
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
main (int argc, char *argv[])
|
||||||
|
{
|
||||||
|
g_type_init ();
|
||||||
|
g_test_init (&argc, &argv, NULL);
|
||||||
|
|
||||||
|
g_test_add_func ("/appinfo/launch", test_launch);
|
||||||
|
|
||||||
|
return g_test_run ();
|
||||||
|
}
|
||||||
|
|
134
gio/tests/application.c
Normal file
134
gio/tests/application.c
Normal file
@ -0,0 +1,134 @@
|
|||||||
|
#include <stdlib.h>
|
||||||
|
#include <gio.h>
|
||||||
|
#include <gstdio.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,
|
||||||
|
guint action_timestamp)
|
||||||
|
{
|
||||||
|
if (g_test_verbose ())
|
||||||
|
g_print ("Action '%s' invoked (timestamp: %u, expected: %u)\n",
|
||||||
|
action_name,
|
||||||
|
action_timestamp,
|
||||||
|
timestamp);
|
||||||
|
|
||||||
|
g_assert_cmpstr (action_name, ==, "About");
|
||||||
|
g_assert_cmpint (action_timestamp, ==, timestamp);
|
||||||
|
|
||||||
|
action_invoked = TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
check_invoke_action (gpointer data)
|
||||||
|
{
|
||||||
|
GApplication *application = data;
|
||||||
|
|
||||||
|
if (state == INVOKE_ACTION)
|
||||||
|
{
|
||||||
|
timestamp = (guint) time (NULL);
|
||||||
|
|
||||||
|
if (g_test_verbose ())
|
||||||
|
g_print ("Invoking About...\n");
|
||||||
|
|
||||||
|
g_application_invoke_action (application, "About", timestamp);
|
||||||
|
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", (guint) time (NULL));
|
||||||
|
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 (application, (guint) time (NULL));
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
g_assert_not_reached ();
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
test_basic (void)
|
||||||
|
{
|
||||||
|
GApplication *app;
|
||||||
|
|
||||||
|
app = g_application_new_and_register ("org.gtk.TestApplication", 0, NULL);
|
||||||
|
g_application_add_action (app, "About", "Print an about message");
|
||||||
|
|
||||||
|
g_signal_connect (app, "action::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[])
|
||||||
|
{
|
||||||
|
g_type_init ();
|
||||||
|
g_test_init (&argc, &argv, NULL);
|
||||||
|
|
||||||
|
g_test_add_func ("/application/basic", test_basic);
|
||||||
|
|
||||||
|
return g_test_run ();
|
||||||
|
}
|
79
gio/tests/testapp.c
Normal file
79
gio/tests/testapp.c
Normal file
@ -0,0 +1,79 @@
|
|||||||
|
#include <stdlib.h>
|
||||||
|
#include <gio.h>
|
||||||
|
#include <gstdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
static gboolean action3_added = FALSE;
|
||||||
|
|
||||||
|
static void
|
||||||
|
on_app_action (GApplication *application,
|
||||||
|
const gchar *action_name,
|
||||||
|
guint action_timestamp)
|
||||||
|
{
|
||||||
|
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 gboolean
|
||||||
|
invoke_action1 (gpointer data)
|
||||||
|
{
|
||||||
|
GApplication *app = data;
|
||||||
|
|
||||||
|
g_application_invoke_action (app, "action1", 0);
|
||||||
|
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
on_app_activated (GApplication *application,
|
||||||
|
GVariant *args,
|
||||||
|
GVariant *platform_data)
|
||||||
|
{
|
||||||
|
char *str;
|
||||||
|
|
||||||
|
g_print ("got args: ");
|
||||||
|
str = g_variant_print (args, TRUE);
|
||||||
|
g_print ("%s ", str);
|
||||||
|
g_free (str);
|
||||||
|
str = g_variant_print (platform_data, TRUE);
|
||||||
|
g_print ("%s\n", str);
|
||||||
|
g_free (str);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
main (int argc, char *argv[])
|
||||||
|
{
|
||||||
|
GApplication *app;
|
||||||
|
GMainLoop *loop;
|
||||||
|
|
||||||
|
app = g_application_new ("org.gtk.test.app");
|
||||||
|
if (!(argc > 1 && strcmp (argv[1], "--non-unique") == 0))
|
||||||
|
g_application_register_with_data (app, argc, argv, NULL);
|
||||||
|
|
||||||
|
if (g_application_is_remote (app))
|
||||||
|
{
|
||||||
|
g_timeout_add (1000, invoke_action1, app);
|
||||||
|
loop = g_main_loop_new (NULL, FALSE);
|
||||||
|
g_main_loop_run (loop);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
g_application_add_action (app, "action1", "Action1");
|
||||||
|
g_application_add_action (app, "action2", "Action2");
|
||||||
|
g_signal_connect (app, "action",
|
||||||
|
G_CALLBACK (on_app_action), NULL);
|
||||||
|
g_signal_connect (app, "prepare-activation",
|
||||||
|
G_CALLBACK (on_app_activated), NULL);
|
||||||
|
g_application_run (app);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
533
gio/tests/testapps.c
Normal file
533
gio/tests/testapps.c
Normal file
@ -0,0 +1,533 @@
|
|||||||
|
#include <gio/gio.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <sys/wait.h>
|
||||||
|
#include <signal.h>
|
||||||
|
|
||||||
|
static gint appeared;
|
||||||
|
static gint disappeared;
|
||||||
|
static gint changed;
|
||||||
|
static gboolean died;
|
||||||
|
static gboolean timed_out;
|
||||||
|
GPid pid;
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
start_application (gpointer data)
|
||||||
|
{
|
||||||
|
gchar *argv[] = { "./testapp", NULL };
|
||||||
|
|
||||||
|
g_assert (g_spawn_async (NULL, argv, NULL, 0, NULL, NULL, &pid, NULL));
|
||||||
|
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
run_application_sync (gpointer data)
|
||||||
|
{
|
||||||
|
GMainLoop *loop = data;
|
||||||
|
|
||||||
|
g_assert (g_spawn_command_line_sync ("./testapp", NULL, NULL, NULL, NULL));
|
||||||
|
|
||||||
|
if (loop)
|
||||||
|
g_main_loop_quit (loop);
|
||||||
|
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
timeout (gpointer data)
|
||||||
|
{
|
||||||
|
GMainLoop *loop = data;
|
||||||
|
|
||||||
|
timed_out = TRUE;
|
||||||
|
|
||||||
|
g_main_loop_quit (loop);
|
||||||
|
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 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 (void)
|
||||||
|
{
|
||||||
|
GMainLoop *loop;
|
||||||
|
gint watch;
|
||||||
|
guint id1, id2, id3;
|
||||||
|
|
||||||
|
appeared = 0;
|
||||||
|
timed_out = FALSE;
|
||||||
|
|
||||||
|
loop = g_main_loop_new (NULL, FALSE);
|
||||||
|
id1 = g_timeout_add (5000, timeout, loop);
|
||||||
|
|
||||||
|
watch = g_bus_watch_name (G_BUS_TYPE_SESSION,
|
||||||
|
"org.gtk.test.app",
|
||||||
|
0,
|
||||||
|
name_appeared,
|
||||||
|
NULL,
|
||||||
|
loop,
|
||||||
|
NULL);
|
||||||
|
|
||||||
|
id2 = g_timeout_add (0, start_application, loop);
|
||||||
|
|
||||||
|
g_main_loop_run (loop);
|
||||||
|
|
||||||
|
g_assert_cmpint (appeared, ==, 1);
|
||||||
|
|
||||||
|
id3 = g_timeout_add (0, run_application_sync, loop);
|
||||||
|
|
||||||
|
g_main_loop_run (loop);
|
||||||
|
|
||||||
|
g_assert_cmpint (appeared, ==, 1);
|
||||||
|
g_assert_cmpint (timed_out, ==, FALSE);
|
||||||
|
|
||||||
|
g_bus_unwatch_name (watch);
|
||||||
|
|
||||||
|
kill (pid, SIGTERM);
|
||||||
|
|
||||||
|
g_main_loop_unref (loop);
|
||||||
|
g_source_remove (id1);
|
||||||
|
g_source_remove (id2);
|
||||||
|
g_source_remove (id3);
|
||||||
|
}
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
quit_app (gpointer 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",
|
||||||
|
"Quit",
|
||||||
|
g_variant_new ("(u)", 0),
|
||||||
|
NULL,
|
||||||
|
G_DBUS_CALL_FLAGS_NONE,
|
||||||
|
-1,
|
||||||
|
NULL,
|
||||||
|
NULL);
|
||||||
|
if (res)
|
||||||
|
g_variant_unref (res);
|
||||||
|
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
child_is_dead (GPid pid,
|
||||||
|
gint status,
|
||||||
|
gpointer data)
|
||||||
|
{
|
||||||
|
GMainLoop *loop = data;
|
||||||
|
|
||||||
|
died++;
|
||||||
|
|
||||||
|
g_assert (WIFEXITED (status) && WEXITSTATUS(status) == 0);
|
||||||
|
|
||||||
|
if (loop)
|
||||||
|
g_main_loop_quit (loop);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* This test start 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 (void)
|
||||||
|
{
|
||||||
|
GMainLoop *loop;
|
||||||
|
gint watch;
|
||||||
|
guint id1, id2, id3;
|
||||||
|
gchar *argv[] = { "./testapp", NULL };
|
||||||
|
|
||||||
|
appeared = 0;
|
||||||
|
disappeared = 0;
|
||||||
|
died = FALSE;
|
||||||
|
timed_out = FALSE;
|
||||||
|
|
||||||
|
loop = g_main_loop_new (NULL, FALSE);
|
||||||
|
watch = g_bus_watch_name (G_BUS_TYPE_SESSION,
|
||||||
|
"org.gtk.test.app",
|
||||||
|
0,
|
||||||
|
name_appeared,
|
||||||
|
name_disappeared,
|
||||||
|
NULL,
|
||||||
|
NULL);
|
||||||
|
|
||||||
|
g_assert (g_spawn_async (NULL, argv, NULL, G_SPAWN_DO_NOT_REAP_CHILD, NULL, NULL, &pid, NULL));
|
||||||
|
|
||||||
|
id1 = g_child_watch_add (pid, child_is_dead, loop);
|
||||||
|
|
||||||
|
id2 = g_timeout_add (500, quit_app, NULL);
|
||||||
|
|
||||||
|
id3 = g_timeout_add (5000, timeout, loop);
|
||||||
|
|
||||||
|
g_main_loop_run (loop);
|
||||||
|
g_assert_cmpint (timed_out, ==, FALSE);
|
||||||
|
g_assert_cmpint (appeared, ==, 1);
|
||||||
|
g_assert_cmpint (disappeared, >=, 1);
|
||||||
|
g_assert_cmpint (died, ==, TRUE);
|
||||||
|
|
||||||
|
g_bus_unwatch_name (watch);
|
||||||
|
|
||||||
|
g_main_loop_unref (loop);
|
||||||
|
g_source_remove (id1);
|
||||||
|
g_source_remove (id2);
|
||||||
|
g_source_remove (id3);
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 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)
|
||||||
|
{
|
||||||
|
GMainLoop *loop;
|
||||||
|
gchar *argv[] = { "./testapp", NULL };
|
||||||
|
gchar **actions;
|
||||||
|
gint watch;
|
||||||
|
|
||||||
|
appeared = 0;
|
||||||
|
|
||||||
|
loop = g_main_loop_new (NULL, FALSE);
|
||||||
|
watch = g_bus_watch_name (G_BUS_TYPE_SESSION,
|
||||||
|
"org.gtk.test.app",
|
||||||
|
0,
|
||||||
|
name_appeared,
|
||||||
|
NULL,
|
||||||
|
loop,
|
||||||
|
NULL);
|
||||||
|
|
||||||
|
g_assert (g_spawn_async (NULL, argv, NULL, 0, NULL, NULL, &pid, NULL));
|
||||||
|
if (!appeared)
|
||||||
|
g_main_loop_run (loop);
|
||||||
|
g_main_loop_unref (loop);
|
||||||
|
|
||||||
|
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);
|
||||||
|
|
||||||
|
kill (pid, SIGTERM);
|
||||||
|
|
||||||
|
g_bus_unwatch_name (watch);
|
||||||
|
}
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
invoke_action (gpointer data)
|
||||||
|
{
|
||||||
|
const gchar *action = 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 ("(su)",
|
||||||
|
action,
|
||||||
|
0),
|
||||||
|
NULL,
|
||||||
|
G_DBUS_CALL_FLAGS_NONE,
|
||||||
|
-1,
|
||||||
|
NULL,
|
||||||
|
NULL);
|
||||||
|
if (res)
|
||||||
|
g_variant_unref (res);
|
||||||
|
g_object_unref (connection);
|
||||||
|
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
exit_with_code_1 (GPid pid,
|
||||||
|
gint status,
|
||||||
|
gpointer data)
|
||||||
|
{
|
||||||
|
GMainLoop *loop = data;
|
||||||
|
|
||||||
|
died++;
|
||||||
|
|
||||||
|
g_assert (WIFEXITED (status) && WEXITSTATUS(status) == 1);
|
||||||
|
|
||||||
|
if (loop)
|
||||||
|
g_main_loop_quit (loop);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 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;
|
||||||
|
gint watch;
|
||||||
|
gchar *argv[] = { "./testapp", NULL };
|
||||||
|
guint id1, id2, id3;
|
||||||
|
|
||||||
|
appeared = 0;
|
||||||
|
disappeared = 0;
|
||||||
|
died = FALSE;
|
||||||
|
timed_out = FALSE;
|
||||||
|
|
||||||
|
loop = g_main_loop_new (NULL, FALSE);
|
||||||
|
watch = g_bus_watch_name (G_BUS_TYPE_SESSION,
|
||||||
|
"org.gtk.test.app",
|
||||||
|
0,
|
||||||
|
name_appeared,
|
||||||
|
name_disappeared,
|
||||||
|
NULL,
|
||||||
|
NULL);
|
||||||
|
|
||||||
|
g_assert (g_spawn_async (NULL, argv, NULL, G_SPAWN_DO_NOT_REAP_CHILD, NULL, NULL, &pid, NULL));
|
||||||
|
|
||||||
|
id1 = g_child_watch_add (pid, exit_with_code_1, loop);
|
||||||
|
|
||||||
|
id2 = g_timeout_add (500, invoke_action, "action1");
|
||||||
|
|
||||||
|
id3 = g_timeout_add (5000, timeout, loop);
|
||||||
|
|
||||||
|
g_main_loop_run (loop);
|
||||||
|
g_assert_cmpint (timed_out, ==, FALSE);
|
||||||
|
g_assert_cmpint (appeared, >=, 1);
|
||||||
|
g_assert_cmpint (disappeared, >=, 1);
|
||||||
|
g_assert_cmpint (died, ==, TRUE);
|
||||||
|
|
||||||
|
g_bus_unwatch_name (watch);
|
||||||
|
g_main_loop_unref (loop);
|
||||||
|
g_source_remove (id1);
|
||||||
|
g_source_remove (id2);
|
||||||
|
g_source_remove (id3);
|
||||||
|
|
||||||
|
kill (pid, SIGTERM);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
test_remote (void)
|
||||||
|
{
|
||||||
|
GMainLoop *loop;
|
||||||
|
gint watch;
|
||||||
|
GPid pid1, pid2;
|
||||||
|
gchar *argv[] = { "./testapp", NULL, NULL };
|
||||||
|
|
||||||
|
appeared = 0;
|
||||||
|
timed_out = FALSE;
|
||||||
|
|
||||||
|
loop = g_main_loop_new (NULL, FALSE);
|
||||||
|
g_timeout_add (5000, timeout, loop);
|
||||||
|
|
||||||
|
watch = g_bus_watch_name (G_BUS_TYPE_SESSION,
|
||||||
|
"org.gtk.test.app",
|
||||||
|
0,
|
||||||
|
name_appeared,
|
||||||
|
NULL,
|
||||||
|
loop,
|
||||||
|
NULL);
|
||||||
|
|
||||||
|
g_assert (g_spawn_async (NULL, argv, NULL, G_SPAWN_DO_NOT_REAP_CHILD, NULL, NULL, &pid1, NULL));
|
||||||
|
g_child_watch_add (pid1, exit_with_code_1, loop);
|
||||||
|
|
||||||
|
g_main_loop_run (loop);
|
||||||
|
|
||||||
|
g_assert_cmpint (appeared, ==, 1);
|
||||||
|
|
||||||
|
argv[1] = "--non-unique";
|
||||||
|
g_assert (g_spawn_async (NULL, argv, NULL, G_SPAWN_DO_NOT_REAP_CHILD, NULL, NULL, &pid2, NULL));
|
||||||
|
|
||||||
|
g_main_loop_run (loop);
|
||||||
|
|
||||||
|
g_assert_cmpint (appeared, ==, 1);
|
||||||
|
g_assert_cmpint (timed_out, ==, FALSE);
|
||||||
|
|
||||||
|
g_main_loop_unref (loop);
|
||||||
|
g_bus_unwatch_name (watch);
|
||||||
|
|
||||||
|
kill (pid1, SIGTERM);
|
||||||
|
kill (pid2, SIGTERM);
|
||||||
|
}
|
||||||
|
|
||||||
|
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 (void)
|
||||||
|
{
|
||||||
|
GMainLoop *loop;
|
||||||
|
gint watch;
|
||||||
|
guint id;
|
||||||
|
GPid pid1;
|
||||||
|
gchar *argv[] = { "./testapp", NULL, NULL };
|
||||||
|
GDBusConnection *connection;
|
||||||
|
|
||||||
|
appeared = 0;
|
||||||
|
changed = 0;
|
||||||
|
timed_out = FALSE;
|
||||||
|
|
||||||
|
loop = g_main_loop_new (NULL, FALSE);
|
||||||
|
g_timeout_add (5000, timeout, loop);
|
||||||
|
|
||||||
|
watch = g_bus_watch_name (G_BUS_TYPE_SESSION,
|
||||||
|
"org.gtk.test.app",
|
||||||
|
0,
|
||||||
|
name_appeared,
|
||||||
|
NULL,
|
||||||
|
loop,
|
||||||
|
NULL);
|
||||||
|
|
||||||
|
g_assert (g_spawn_async (NULL, argv, NULL, G_SPAWN_DO_NOT_REAP_CHILD, NULL, NULL, &pid1, NULL));
|
||||||
|
g_main_loop_run (loop);
|
||||||
|
|
||||||
|
g_assert_cmpint (appeared, ==, 1);
|
||||||
|
|
||||||
|
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,
|
||||||
|
actions_changed,
|
||||||
|
loop,
|
||||||
|
NULL);
|
||||||
|
|
||||||
|
g_timeout_add (1000, invoke_action, "action2");
|
||||||
|
|
||||||
|
g_main_loop_run (loop);
|
||||||
|
|
||||||
|
g_assert_cmpint (changed, >, 0);
|
||||||
|
g_assert_cmpint (timed_out, ==, FALSE);
|
||||||
|
|
||||||
|
g_dbus_connection_signal_unsubscribe (connection, id);
|
||||||
|
g_object_unref (connection);
|
||||||
|
g_main_loop_unref (loop);
|
||||||
|
g_bus_unwatch_name (watch);
|
||||||
|
|
||||||
|
kill (pid1, SIGTERM);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
main (int argc, char *argv[])
|
||||||
|
{
|
||||||
|
g_type_init ();
|
||||||
|
g_test_init (&argc, &argv, NULL);
|
||||||
|
|
||||||
|
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);
|
||||||
|
|
||||||
|
return g_test_run ();
|
||||||
|
}
|
||||||
|
|
Loading…
x
Reference in New Issue
Block a user