GApplication: add remote commandline support

This commit is contained in:
Ryan Lortie 2010-10-09 17:24:09 -04:00
parent 2854c373e1
commit 3e6eee806c
11 changed files with 748 additions and 24 deletions

View File

@ -139,6 +139,7 @@ application_headers = \
gsimpleactiongroup.h \ gsimpleactiongroup.h \
gaction.h \ gaction.h \
gsimpleaction.h \ gsimpleaction.h \
gapplicationcommandline.h \
gapplication.h gapplication.h
application_sources = \ application_sources = \
@ -146,6 +147,7 @@ application_sources = \
gsimpleactiongroup.c \ gsimpleactiongroup.c \
gaction.c \ gaction.c \
gsimpleaction.c \ gsimpleaction.c \
gapplicationcommandline.c \
gapplicationimpl-dbus.c \ gapplicationimpl-dbus.c \
gapplication.c gapplication.c

View File

@ -22,6 +22,7 @@
/* Prologue {{{1 */ /* Prologue {{{1 */
#include "gapplication.h" #include "gapplication.h"
#include "gapplicationcommandline.h"
#include "gapplicationimpl.h" #include "gapplicationimpl.h"
#include "gioenumtypes.h" #include "gioenumtypes.h"
@ -132,12 +133,30 @@ g_application_real_open (GApplication *application,
} }
} }
static int
g_application_real_command_line (GApplication *application,
GApplicationCommandLine *cmdline)
{
static gboolean warned;
if (warned)
return 1;
g_warning ("Your application claims to support custom command line "
"handling but does not implement g_application_command_line() "
"and has no handlers connected to the 'command-line' signal.");
warned = TRUE;
return 1;
}
static gboolean static gboolean
g_application_real_local_command_line (GApplication *application, g_application_real_local_command_line (GApplication *application,
GVariant **arguments, GVariant **arguments,
int *exit_status) int *exit_status)
{ {
if (0) if (application->priv->flags & G_APPLICATION_HANDLES_COMMAND_LINE)
return FALSE; return FALSE;
else else
@ -155,12 +174,12 @@ g_application_real_local_command_line (GApplication *application,
n_args = g_variant_n_children (*arguments); n_args = g_variant_n_children (*arguments);
if (application->priv->flags & G_APPLICATION_FLAGS_IS_SERVICE) if (application->priv->flags & G_APPLICATION_IS_SERVICE)
{ {
if (n_args > 1) if (n_args > 1)
{ {
g_printerr ("GApplication service mode takes no arguments.\n"); g_printerr ("GApplication service mode takes no arguments.\n");
application->priv->flags &= ~G_APPLICATION_FLAGS_IS_SERVICE; application->priv->flags &= ~G_APPLICATION_IS_SERVICE;
} }
return TRUE; return TRUE;
@ -174,7 +193,7 @@ g_application_real_local_command_line (GApplication *application,
else else
{ {
if (~application->priv->flags & G_APPLICATION_FLAGS_HANDLES_OPEN) if (~application->priv->flags & G_APPLICATION_HANDLES_OPEN)
{ {
g_critical ("This application can not open files."); g_critical ("This application can not open files.");
*exit_status = 1; *exit_status = 1;
@ -330,6 +349,17 @@ g_application_init (GApplication *application)
GApplicationPrivate); GApplicationPrivate);
} }
static gboolean
first_wins_accumulator (GSignalInvocationHint *ihint,
GValue *return_accu,
const GValue *handler_return,
gpointer data)
{
g_value_copy (handler_return, return_accu);
return FALSE;
}
static void static void
g_application_class_init (GApplicationClass *class) g_application_class_init (GApplicationClass *class)
{ {
@ -345,6 +375,7 @@ g_application_class_init (GApplicationClass *class)
class->startup = g_application_real_startup; class->startup = g_application_real_startup;
class->activate = g_application_real_activate; class->activate = g_application_real_activate;
class->open = g_application_real_open; class->open = g_application_real_open;
class->command_line = g_application_real_command_line;
class->local_command_line = g_application_real_local_command_line; class->local_command_line = g_application_real_local_command_line;
class->add_platform_data = g_application_real_add_platform_data; class->add_platform_data = g_application_real_add_platform_data;
class->quit_mainloop = g_application_real_quit_mainloop; class->quit_mainloop = g_application_real_quit_mainloop;
@ -394,6 +425,12 @@ g_application_class_init (GApplicationClass *class)
NULL, NULL, _gio_marshal_VOID__POINTER_INT_STRING, NULL, NULL, _gio_marshal_VOID__POINTER_INT_STRING,
G_TYPE_NONE, 3, G_TYPE_POINTER, G_TYPE_INT, G_TYPE_STRING); G_TYPE_NONE, 3, G_TYPE_POINTER, G_TYPE_INT, G_TYPE_STRING);
g_application_signals[SIGNAL_COMMAND_LINE] =
g_signal_new ("command-line", G_TYPE_APPLICATION, G_SIGNAL_RUN_LAST,
G_STRUCT_OFFSET (GApplicationClass, command_line),
first_wins_accumulator, NULL, _gio_marshal_INT__OBJECT,
G_TYPE_INT, 1, G_TYPE_APPLICATION_COMMAND_LINE);
g_type_class_add_private (class, sizeof (GApplicationPrivate)); g_type_class_add_private (class, sizeof (GApplicationPrivate));
} }
@ -729,9 +766,9 @@ g_application_register (GApplication *application,
gboolean try; gboolean try;
/* don't try to be the primary instance if /* don't try to be the primary instance if
* G_APPLICATION_FLAGS_IS_LAUNCHER was specified. * G_APPLICATION_IS_LAUNCHER was specified.
*/ */
try = !(application->priv->flags & G_APPLICATION_FLAGS_IS_LAUNCHER); try = !(application->priv->flags & G_APPLICATION_IS_LAUNCHER);
application->priv->impl = application->priv->impl =
g_application_impl_register (application, application->priv->id, g_application_impl_register (application, application->priv->id,
@ -867,7 +904,7 @@ g_application_activate (GApplication *application)
* for this functionality, you should use "". * for this functionality, you should use "".
* *
* The application must be registered before calling this function and * The application must be registered before calling this function and
* it must have the %G_APPLICATION_FLAGS_CAN_OPEN flag set. The open() * it must have the %G_APPLICATION_CAN_OPEN flag set. The open()
* virtual function should also be implemented in order for anything * virtual function should also be implemented in order for anything
* meaningful to happen. * meaningful to happen.
* *
@ -881,7 +918,7 @@ g_application_open (GApplication *application,
{ {
g_return_if_fail (G_IS_APPLICATION (application)); g_return_if_fail (G_IS_APPLICATION (application));
g_return_if_fail (application->priv->flags & g_return_if_fail (application->priv->flags &
G_APPLICATION_FLAGS_HANDLES_OPEN); G_APPLICATION_HANDLES_OPEN);
g_return_if_fail (application->priv->is_registered); g_return_if_fail (application->priv->is_registered);
if (application->priv->is_remote) if (application->priv->is_remote)
@ -913,7 +950,7 @@ g_application_open (GApplication *application,
* virtual function is invoked in the primary instance (which may or may * virtual function is invoked in the primary instance (which may or may
* not be this instance). * not be this instance).
* *
* If the application has the %G_APPLICATION_FLAGS_REMOTE_COMMAND_LINE * If the application has the %G_APPLICATION_REMOTE_COMMAND_LINE
* flag set then the default implementation of handle_command_line() * flag set then the default implementation of handle_command_line()
* always returns %FALSE immediately, resulting in the commandline * always returns %FALSE immediately, resulting in the commandline
* always being handled in the primary instance. * always being handled in the primary instance.
@ -924,7 +961,7 @@ g_application_open (GApplication *application,
* to register the application. If that works, then the command line * to register the application. If that works, then the command line
* arguments are inspected. If no commandline arguments are given, then * arguments are inspected. If no commandline arguments are given, then
* g_application_activate() is called. If commandline arguments are * g_application_activate() is called. If commandline arguments are
* given and the %G_APPLICATION_FLAGS_CAN_OPEN flags is set then they * given and the %G_APPLICATION_CAN_OPEN flags is set then they
* are assumed to be filenames and g_application_open() is called. * are assumed to be filenames and g_application_open() is called.
* *
* If you are interested in doing more complicated local handling of the * If you are interested in doing more complicated local handling of the
@ -984,12 +1021,39 @@ g_application_run_with_arguments (GApplication *application,
if (!G_APPLICATION_GET_CLASS (application) if (!G_APPLICATION_GET_CLASS (application)
->local_command_line (application, &arguments, &status)) ->local_command_line (application, &arguments, &status))
{ {
g_assert_not_reached (); GError *error = NULL;
if (!g_application_register (application, NULL, &error))
{
g_printerr ("%s", error->message);
g_error_free (error);
return 1;
}
if (application->priv->is_remote)
{
GVariant *platform_data;
platform_data = get_platform_data (application);
status = g_application_impl_command_line (application->priv->impl,
arguments, platform_data);
}
else
{
GApplicationCommandLine *cmdline;
cmdline = g_object_new (G_TYPE_APPLICATION_COMMAND_LINE,
"arguments", arguments, NULL);
g_signal_emit (application,
g_application_signals[SIGNAL_COMMAND_LINE],
0, cmdline, &status);
g_object_unref (cmdline);
}
} }
g_variant_unref (arguments); g_variant_unref (arguments);
if (application->priv->flags & G_APPLICATION_FLAGS_IS_SERVICE && if (application->priv->flags & G_APPLICATION_IS_SERVICE &&
!application->priv->use_count && !application->priv->use_count &&
!application->priv->inactivity_timeout_id) !application->priv->inactivity_timeout_id)
{ {

View File

@ -93,15 +93,14 @@ struct _GApplicationClass
gint n_files, gint n_files,
const gchar *hint); const gchar *hint);
gpointer _reserved_1; int (* command_line) (GApplication *application,
GApplicationCommandLine *command_line);
/* vfuncs */ /* vfuncs */
gboolean (* local_command_line) (GApplication *application, gboolean (* local_command_line) (GApplication *application,
GVariant **arguments, GVariant **arguments,
int *exit_status); int *exit_status);
gpointer _reserved_2;
void (* before_emit) (GApplication *application, void (* before_emit) (GApplication *application,
GVariant *platform_data); GVariant *platform_data);
void (* after_emit) (GApplication *application, void (* after_emit) (GApplication *application,

View File

@ -0,0 +1,273 @@
#include "gapplicationcommandline.h"
#include <string.h>
#include <stdio.h>
G_DEFINE_TYPE (GApplicationCommandLine, g_application_command_line, G_TYPE_OBJECT)
enum
{
PROP_NONE,
PROP_ARGUMENTS,
PROP_PLATFORM_DATA,
PROP_IS_REMOTE
};
struct _GApplicationCommandLinePrivate
{
GVariant *platform_data;
GVariant *arguments;
GVariant *cwd;
gint exit_status;
};
#define IS_REMOTE(cmdline) ((cmdline)->priv->platform_data != NULL)
void
g_application_command_line_get_argc_argv (GApplicationCommandLine *cmdline,
int *argc,
char ***argv)
{
gsize len;
g_return_if_fail (G_IS_APPLICATION_COMMAND_LINE (cmdline));
g_return_if_fail (argc != NULL && argv != NULL);
*argv = g_variant_dup_bytestring_array (cmdline->priv->arguments, &len);
*argc = len;
}
GVariant *
g_application_command_line_get_arguments (GApplicationCommandLine *cmdline)
{
return g_variant_ref (cmdline->priv->arguments);
}
const gchar *
g_application_command_line_get_cwd (GApplicationCommandLine *cmdline)
{
if (cmdline->priv->cwd)
return g_variant_get_bytestring (cmdline->priv->cwd);
else
return NULL;
}
GVariant *
g_application_command_line_get_cwd_variant (GApplicationCommandLine *cmdline)
{
if (cmdline->priv->cwd)
return g_variant_ref (cmdline->priv->cwd);
else
return NULL;
}
gboolean
g_application_command_line_get_is_remote (GApplicationCommandLine *cmdline)
{
return IS_REMOTE (cmdline);
}
static void
g_application_command_line_real_print_literal (GApplicationCommandLine *cmdline,
const gchar *message)
{
g_print ("%s\n", message);
}
static void
g_application_command_line_real_printerr_literal (GApplicationCommandLine *cmdline,
const gchar *message)
{
g_printerr ("%s\n", message);
}
void
g_application_command_line_print (GApplicationCommandLine *cmdline,
const gchar *format,
...)
{
gchar *message;
va_list ap;
g_return_if_fail (G_IS_APPLICATION_COMMAND_LINE (cmdline));
g_return_if_fail (format != NULL);
va_start (ap, format);
message = g_strdup_vprintf (format, ap);
va_end (ap);
G_APPLICATION_COMMAND_LINE_GET_CLASS (cmdline)
->print_literal (cmdline, message);
g_free (message);
}
void
g_application_command_line_printerr (GApplicationCommandLine *cmdline,
const gchar *format,
...)
{
gchar *message;
va_list ap;
g_return_if_fail (G_IS_APPLICATION_COMMAND_LINE (cmdline));
g_return_if_fail (format != NULL);
va_start (ap, format);
message = g_strdup_vprintf (format, ap);
va_end (ap);
G_APPLICATION_COMMAND_LINE_GET_CLASS (cmdline)
->printerr_literal (cmdline, message);
g_free (message);
}
void
g_application_command_line_set_exit_status (GApplicationCommandLine *cmdline,
int exit_status)
{
g_return_if_fail (G_IS_APPLICATION_COMMAND_LINE (cmdline));
cmdline->priv->exit_status = exit_status;
}
int
g_application_command_line_get_exit_status (GApplicationCommandLine *cmdline)
{
g_return_val_if_fail (G_IS_APPLICATION_COMMAND_LINE (cmdline), -1);
return cmdline->priv->exit_status;
}
static void
grok_platform_data (GApplicationCommandLine *cmdline)
{
GVariantIter iter;
const gchar *key;
GVariant *value;
g_variant_iter_init (&iter, cmdline->priv->platform_data);
while (g_variant_iter_loop (&iter, "{&sv}", &key, &value))
if (strcmp (key, "cwd") == 0)
{
if (!cmdline->priv->cwd)
cmdline->priv->cwd = g_variant_ref (value);
}
}
static void
g_application_command_line_get_property (GObject *object, guint prop_id,
GValue *value, GParamSpec *pspec)
{
GApplicationCommandLine *cmdline = G_APPLICATION_COMMAND_LINE (object);
switch (prop_id)
{
case PROP_ARGUMENTS:
g_value_set_variant (value, cmdline->priv->arguments);
break;
case PROP_PLATFORM_DATA:
g_value_set_variant (value, cmdline->priv->platform_data);
break;
case PROP_IS_REMOTE:
g_value_set_boolean (value, IS_REMOTE (cmdline));
break;
default:
g_assert_not_reached ();
}
}
static void
g_application_command_line_set_property (GObject *object, guint prop_id,
const GValue *value, GParamSpec *pspec)
{
GApplicationCommandLine *cmdline = G_APPLICATION_COMMAND_LINE (object);
switch (prop_id)
{
case PROP_ARGUMENTS:
g_assert (cmdline->priv->arguments == NULL);
cmdline->priv->arguments = g_value_dup_variant (value);
break;
case PROP_PLATFORM_DATA:
g_assert (cmdline->priv->platform_data == NULL);
cmdline->priv->platform_data = g_value_dup_variant (value);
if (cmdline->priv->platform_data != NULL)
grok_platform_data (cmdline);
break;
default:
g_assert_not_reached ();
}
}
static void
g_application_command_line_finalize (GObject *object)
{
GApplicationCommandLine *cmdline = G_APPLICATION_COMMAND_LINE (object);
if (cmdline->priv->platform_data)
g_variant_unref (cmdline->priv->platform_data);
if (cmdline->priv->arguments)
g_variant_unref (cmdline->priv->arguments);
if (cmdline->priv->cwd)
g_variant_unref (cmdline->priv->cwd);
G_OBJECT_CLASS (g_application_command_line_parent_class)
->finalize (object);
}
static void
g_application_command_line_init (GApplicationCommandLine *cmdline)
{
cmdline->priv =
G_TYPE_INSTANCE_GET_PRIVATE (cmdline,
G_TYPE_APPLICATION_COMMAND_LINE,
GApplicationCommandLinePrivate);
}
static void
g_application_command_line_class_init (GApplicationCommandLineClass *class)
{
GObjectClass *object_class = G_OBJECT_CLASS (class);
object_class->get_property = g_application_command_line_get_property;
object_class->set_property = g_application_command_line_set_property;
object_class->finalize = g_application_command_line_finalize;
class->printerr_literal = g_application_command_line_real_printerr_literal;
class->print_literal = g_application_command_line_real_print_literal;
g_object_class_install_property (object_class, PROP_ARGUMENTS,
g_param_spec_variant ("arguments", "commandline arguments",
"the commandline that caused this cmdline",
G_VARIANT_TYPE_BYTESTRING_ARRAY, NULL,
G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY |
G_PARAM_STATIC_STRINGS));
g_object_class_install_property (object_class, PROP_PLATFORM_DATA,
g_param_spec_variant ("platform-data", "platform data",
"platform-specific data for the cmdline",
G_VARIANT_TYPE ("a{sv}"), NULL,
G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY |
G_PARAM_STATIC_STRINGS));
g_object_class_install_property (object_class, PROP_IS_REMOTE,
g_param_spec_boolean ("is-remote", "is remote",
"TRUE if this is a remote cmdline", FALSE,
G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
g_type_class_add_private (class, sizeof (GApplicationCommandLinePrivate));
}
GVariant *
g_application_command_line_get_platform_data (GApplicationCommandLine *cmdline)
{
g_return_val_if_fail (G_IS_APPLICATION_COMMAND_LINE (cmdline), NULL);
g_return_val_if_fail (IS_REMOTE (cmdline), NULL);
return g_variant_ref (cmdline->priv->platform_data);
}

View File

@ -0,0 +1,120 @@
/* GIO - GLib Input, Output and Streaming Library
*
* Copyright © 2010 Codethink Limited
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published
* 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: Ryan Lortie <desrt@desrt.ca>
*/
#if !defined (__GIO_GIO_H_INSIDE__) && !defined (GIO_COMPILATION)
#error "Only <gio/gio.h> can be included directly."
#endif
#ifndef __G_APPLICATION_COMMAND_LINE_H__
#define __G_APPLICATION_COMMAND_LINE_H__
#include <gio/giotypes.h>
G_BEGIN_DECLS
#define G_TYPE_APPLICATION_COMMAND_LINE (g_application_command_line_get_type ())
#define G_APPLICATION_COMMAND_LINE(inst) (G_TYPE_CHECK_INSTANCE_CAST ((inst), \
G_TYPE_APPLICATION_COMMAND_LINE, \
GApplicationCommandLine))
#define G_APPLICATION_COMMAND_LINE_CLASS(class) (G_TYPE_CHECK_CLASS_CAST ((class), \
G_TYPE_APPLICATION_COMMAND_LINE, \
GApplicationCommandLineClass))
#define G_IS_APPLICATION_COMMAND_LINE(inst) (G_TYPE_CHECK_INSTANCE_TYPE ((inst), \
G_TYPE_APPLICATION_COMMAND_LINE))
#define G_IS_APPLICATION_COMMAND_LINE_CLASS(class) (G_TYPE_CHECK_CLASS_TYPE ((class), \
G_TYPE_APPLICATION_COMMAND_LINE))
#define G_APPLICATION_COMMAND_LINE_GET_CLASS(inst) (G_TYPE_INSTANCE_GET_CLASS ((inst), \
G_TYPE_APPLICATION_COMMAND_LINE, \
GApplicationCommandLineClass))
typedef struct _GApplicationCommandLinePrivate GApplicationCommandLinePrivate;
typedef struct _GApplicationCommandLineClass GApplicationCommandLineClass;
/**
* GApplicationCommandLine:
*
* The <structname>GApplicationCommandLine</structname> structure contains private
* data and should only be accessed using the provided API
*
* Since: 2.26
*/
struct _GApplicationCommandLine
{
/*< private >*/
GObject parent_instance;
GApplicationCommandLinePrivate *priv;
};
/**
* GApplicationCommandLineClass:
*
* The <structname>GApplicationCommandLineClass</structname> structure contains
* private data only
*
* Since: 2.26
*/
struct _GApplicationCommandLineClass
{
/*< private >*/
GObjectClass parent_class;
void (* print_literal) (GApplicationCommandLine *command_line,
const gchar *message);
void (* printerr_literal) (GApplicationCommandLine *command_line,
const gchar *message);
gpointer padding[12];
};
GType g_application_command_line_get_type (void) G_GNUC_CONST;
void g_application_command_line_get_argc_argv (GApplicationCommandLine *command_line,
int *argc,
char ***argv);
GVariant * g_application_command_line_get_arguments (GApplicationCommandLine *command_line);
const gchar * g_application_command_line_get_cwd (GApplicationCommandLine *command_line);
GVariant * g_application_command_line_get_cwd_variant (GApplicationCommandLine *command_line);
gboolean g_application_command_line_get_is_remote (GApplicationCommandLine *command_line);
void g_application_command_line_output (GApplicationCommandLine *command_line,
gint fd,
gconstpointer buffer,
gssize length);
void g_application_command_line_print (GApplicationCommandLine *command_line,
const gchar *format,
...);
void g_application_command_line_printerr (GApplicationCommandLine *command_line,
const gchar *format,
...);
int g_application_command_line_get_exit_status (GApplicationCommandLine *command_line);
void g_application_command_line_set_exit_status (GApplicationCommandLine *command_line,
int exit_status);
GVariant * g_application_command_line_get_platform_data (GApplicationCommandLine *command_line);
G_END_DECLS
#endif /* __G_APPLICATION_COMMAND_LINE_H__ */

View File

@ -37,6 +37,9 @@ 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_in[] = { &open_uris_arg, &open_hint_arg, &platform_data_arg, NULL };
static const GDBusArgInfo *open_out[] = { NULL }; static const GDBusArgInfo *open_out[] = { NULL };
static const GDBusArgInfo *cmdline_in[] = { &cmdline_path_arg, &cmdline_arguments_arg, &platform_data_arg, NULL };
static const GDBusArgInfo *cmdline_out[] = { &cmdline_exit_status_arg, NULL };
static const GDBusMethodInfo activate_method = { static const GDBusMethodInfo activate_method = {
-1, (gchar *) "Activate", -1, (gchar *) "Activate",
(GDBusArgInfo **) activate_in, (GDBusArgInfo **) activate_in,
@ -49,11 +52,42 @@ static const GDBusMethodInfo open_method = {
(GDBusArgInfo **) open_out (GDBusArgInfo **) open_out
}; };
static const GDBusMethodInfo command_line_method = {
-1, (gchar *) "CommandLine",
(GDBusArgInfo **) cmdline_in,
(GDBusArgInfo **) cmdline_out
};
static const GDBusMethodInfo *application_methods[] = { static const GDBusMethodInfo *application_methods[] = {
&activate_method, &open_method, NULL &activate_method, &open_method, &command_line_method, NULL
}; };
const GDBusInterfaceInfo org_gtk_Application = { const GDBusInterfaceInfo org_gtk_Application = {
-1, (gchar *) "org.gtk.Application", -1, (gchar *) "org.gtk.Application",
(GDBusMethodInfo **) application_methods (GDBusMethodInfo **) application_methods
}; };
static const GDBusArgInfo message_arg = { -1, (gchar *) "message", (gchar *) "s" };
static const GDBusArgInfo *print_in[] = { &message_arg, NULL };
static const GDBusArgInfo *print_out[] = { NULL };
static const GDBusMethodInfo stdout_method = {
-1, (gchar *) "Print",
(GDBusArgInfo **) print_in,
(GDBusArgInfo **) print_out
};
static const GDBusMethodInfo stderr_method = {
-1, (gchar *) "PrintError",
(GDBusArgInfo **) print_in,
(GDBusArgInfo **) print_out
};
static const GDBusMethodInfo *cmdline_methods[] = {
&stdout_method, &stderr_method, NULL
};
const GDBusInterfaceInfo org_gtk_private_Cmdline = {
-1, (gchar *) "org.gtk.private.CommandLine",
(GDBusMethodInfo **) cmdline_methods
};

View File

@ -28,9 +28,11 @@
#include "gdbuserror.h" #include "gdbuserror.h"
#include <string.h> #include <string.h>
#include <stdio.h>
#include "gapplicationimpl-dbus-interface.c" #include "gapplicationimpl-dbus-interface.c"
#include "gapplicationcommandline.h"
#include "gdbusmethodinvocation.h"
struct _GApplicationImpl struct _GApplicationImpl
{ {
@ -39,10 +41,13 @@ struct _GApplicationImpl
gchar *object_path; gchar *object_path;
guint object_id; guint object_id;
gpointer app; gpointer app;
GMainLoop *cmdline_mainloop;
}; };
static GApplicationCommandLine *
g_dbus_command_line_new (GDBusMethodInvocation *invocation);
static void static void
g_application_impl_method_call (GDBusConnection *connection, g_application_impl_method_call (GDBusConnection *connection,
const gchar *sender, const gchar *sender,
@ -104,6 +109,22 @@ g_application_impl_method_call (GDBusConnection *connection,
g_free (files); g_free (files);
} }
else if (strcmp (method_name, "CommandLine") == 0)
{
GApplicationCommandLine *cmdline;
GVariant *platform_data;
int status;
cmdline = g_dbus_command_line_new (invocation);
platform_data = g_variant_get_child_value (parameters, 2);
class->before_emit (impl->app, platform_data);
g_signal_emit_by_name (impl->app, "command-line", cmdline, &status);
g_application_command_line_set_exit_status (cmdline, status);
class->after_emit (impl->app, platform_data);
g_variant_unref (platform_data);
g_object_unref (cmdline);
}
else else
g_assert_not_reached (); g_assert_not_reached ();
} }
@ -175,7 +196,7 @@ g_application_impl_register (GApplication *application,
impl->object_path = application_path_from_appid (appid); impl->object_path = application_path_from_appid (appid);
if (flags & G_APPLICATION_FLAGS_IS_LAUNCHER) if (flags & G_APPLICATION_IS_LAUNCHER)
{ {
impl->object_id = 0; impl->object_id = 0;
*is_remote = TRUE; *is_remote = TRUE;
@ -238,7 +259,7 @@ g_application_impl_register (GApplication *application,
impl->object_id); impl->object_id);
impl->object_id = 0; impl->object_id = 0;
if (flags & G_APPLICATION_FLAGS_IS_SERVICE) if (flags & G_APPLICATION_IS_SERVICE)
{ {
g_set_error (error, G_DBUS_ERROR, G_DBUS_ERROR_FAILED, g_set_error (error, G_DBUS_ERROR, G_DBUS_ERROR_FAILED,
"Unable to acquire bus name `%s'", appid); "Unable to acquire bus name `%s'", appid);
@ -297,8 +318,211 @@ g_application_impl_open (GApplicationImpl *impl,
NULL, 0, -1, NULL, NULL, NULL); NULL, 0, -1, NULL, NULL, NULL);
} }
static void
g_application_impl_cmdline_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)
{
const gchar *message;
g_variant_get_child (parameters, 0, "&s", &message);
if (strcmp (method_name, "Print") == 0)
g_print ("%s", message);
else if (strcmp (method_name, "PrintError") == 0)
g_printerr ("%s", message);
else
g_assert_not_reached ();
g_dbus_method_invocation_return_value (invocation, NULL);
}
typedef struct
{
GMainLoop *loop;
int status;
} CommandLineData;
static void
g_application_impl_cmdline_done (GObject *source,
GAsyncResult *result,
gpointer user_data)
{
CommandLineData *data = user_data;
GError *error = NULL;
GVariant *reply;
reply = g_dbus_connection_call_finish (G_DBUS_CONNECTION (source),
result, &error);
if (reply != NULL)
{
g_variant_get (reply, "(i)", &data->status);
g_variant_unref (reply);
}
else
{
g_printerr ("%s\n", error->message);
g_error_free (error);
data->status = 1;
}
g_main_loop_quit (data->loop);
}
int
g_application_impl_command_line (GApplicationImpl *impl,
GVariant *arguments,
GVariant *platform_data)
{
const static GDBusInterfaceVTable vtable = {
g_application_impl_cmdline_method_call
};
const gchar *object_path = "/org/gtk/Application/CommandLine";
GMainContext *context;
CommandLineData data;
guint object_id;
context = g_main_context_new ();
data.loop = g_main_loop_new (context, FALSE);
g_main_context_push_thread_default (context);
object_id = g_dbus_connection_register_object (impl->session_bus,
object_path,
(GDBusInterfaceInfo *)
&org_gtk_private_Cmdline,
&vtable, &data, NULL, NULL);
/* In theory we should try other paths... */
g_assert (object_id != 0);
g_dbus_connection_call (impl->session_bus,
impl->bus_name,
impl->object_path,
"org.gtk.Application",
"CommandLine",
g_variant_new ("(o@aay@a{sv})", object_path,
arguments, platform_data),
G_VARIANT_TYPE ("(i)"), 0, -1, NULL,
g_application_impl_cmdline_done, &data);
g_main_loop_run (data.loop);
g_main_context_pop_thread_default (context);
g_main_context_unref (context);
g_main_loop_unref (data.loop);
return data.status;
}
void void
g_application_impl_flush (GApplicationImpl *impl) g_application_impl_flush (GApplicationImpl *impl)
{ {
g_dbus_connection_flush_sync (impl->session_bus, NULL, NULL); g_dbus_connection_flush_sync (impl->session_bus, NULL, NULL);
} }
typedef GApplicationCommandLineClass GDBusCommandLineClass;
static GType g_dbus_command_line_get_type (void);
typedef struct
{
GApplicationCommandLine parent_instance;
GDBusMethodInvocation *invocation;
GDBusConnection *connection;
const gchar *bus_name;
const gchar *object_path;
} GDBusCommandLine;
G_DEFINE_TYPE (GDBusCommandLine,
g_dbus_command_line,
G_TYPE_APPLICATION_COMMAND_LINE)
static void
g_dbus_command_line_print_literal (GApplicationCommandLine *cmdline,
const gchar *message)
{
GDBusCommandLine *gdbcl = (GDBusCommandLine *) cmdline;
g_dbus_connection_call (gdbcl->connection,
gdbcl->bus_name,
gdbcl->object_path,
"org.gtk.private.CommandLine", "Print",
g_variant_new ("(s)", message),
NULL, 0, -1, NULL, NULL, NULL);
}
static void
g_dbus_command_line_printerr_literal (GApplicationCommandLine *cmdline,
const gchar *message)
{
GDBusCommandLine *gdbcl = (GDBusCommandLine *) cmdline;
g_dbus_connection_call (gdbcl->connection,
gdbcl->bus_name,
gdbcl->object_path,
"org.gtk.private.CommandLine", "PrintError",
g_variant_new ("(s)", message),
NULL, 0, -1, NULL, NULL, NULL);
}
static void
g_dbus_command_line_finalize (GObject *object)
{
GApplicationCommandLine *cmdline = G_APPLICATION_COMMAND_LINE (object);
GDBusCommandLine *gdbcl = (GDBusCommandLine *) object;
gint status;
status = g_application_command_line_get_exit_status (cmdline);
g_dbus_method_invocation_return_value (gdbcl->invocation,
g_variant_new ("(i)", status));
g_object_unref (gdbcl->invocation);
G_OBJECT_CLASS (g_dbus_command_line_parent_class)
->finalize (object);
}
static void
g_dbus_command_line_init (GDBusCommandLine *gdbcl)
{
}
static void
g_dbus_command_line_class_init (GApplicationCommandLineClass *class)
{
GObjectClass *object_class = G_OBJECT_CLASS (class);
object_class->finalize = g_dbus_command_line_finalize;
class->printerr_literal = g_dbus_command_line_printerr_literal;
class->print_literal = g_dbus_command_line_print_literal;
}
static GApplicationCommandLine *
g_dbus_command_line_new (GDBusMethodInvocation *invocation)
{
GDBusCommandLine *gdbcl;
GVariant *args;
args = g_dbus_method_invocation_get_parameters (invocation);
gdbcl = g_object_new (g_dbus_command_line_get_type (),
"arguments", g_variant_get_child_value (args, 1),
"platform-data", g_variant_get_child_value (args, 2),
NULL);
gdbcl->connection = g_dbus_method_invocation_get_connection (invocation);
gdbcl->bus_name = g_dbus_method_invocation_get_sender (invocation);
g_variant_get_child (args, 0, "&o", &gdbcl->object_path);
gdbcl->invocation = g_object_ref (invocation);
return G_APPLICATION_COMMAND_LINE (gdbcl);
}

View File

@ -24,5 +24,10 @@ void g_application_impl_open (GApplic
const gchar *hint, const gchar *hint,
GVariant *platform_data); GVariant *platform_data);
G_GNUC_INTERNAL
int g_application_impl_command_line (GApplicationImpl *impl,
GVariant *arguments,
GVariant *platform_data);
G_GNUC_INTERNAL G_GNUC_INTERNAL
void g_application_impl_flush (GApplicationImpl *impl); void g_application_impl_flush (GApplicationImpl *impl);

View File

@ -23,3 +23,4 @@ VOID:STRING,STRING
VOID:STRING,BOOLEAN VOID:STRING,BOOLEAN
VOID:POINTER,INT,STRING VOID:POINTER,INT,STRING
BOOLEAN:OBJECT BOOLEAN:OBJECT
INT:OBJECT

View File

@ -33,6 +33,7 @@
#include <gio/gactiongroup.h> #include <gio/gactiongroup.h>
#include <gio/gsimpleactiongroup.h> #include <gio/gsimpleactiongroup.h>
#include <gio/gapplication.h> #include <gio/gapplication.h>
#include <gio/gapplicationcommandline.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>

View File

@ -1228,10 +1228,11 @@ typedef enum
typedef enum typedef enum
{ {
G_APPLICATION_FLAGS_NONE, G_APPLICATION_FLAGS_NONE,
G_APPLICATION_FLAGS_IS_SERVICE = (1 << 0), G_APPLICATION_IS_SERVICE = (1 << 0),
G_APPLICATION_FLAGS_IS_LAUNCHER = (1 << 1), G_APPLICATION_IS_LAUNCHER = (1 << 1),
G_APPLICATION_FLAGS_HANDLES_OPEN = (1 << 2) G_APPLICATION_HANDLES_OPEN = (1 << 2),
G_APPLICATION_HANDLES_COMMAND_LINE = (1 << 3)
} GApplicationFlags; } GApplicationFlags;
G_END_DECLS G_END_DECLS