From ed406c02254fe7c15477a319c796573ca0d552f7 Mon Sep 17 00:00:00 2001 From: Juan Pablo Ugarte Date: Thu, 30 Aug 2018 20:39:35 -0300 Subject: Add org.gnome.Glade DBus interface Add initial DBus iface implementation There is a r/w property called "project" to open and create new projects A AddObject method to create toplevel objects/templates and signals to keep track of handlers added to the project (HandlerAdded, HandlerRemoved, HandlerChanged and HandlerActivated) --- src/Makefile.am | 4 +- src/glade-dbus.c | 341 ++++++++++++++++++++++++++++++++++++++ src/glade-dbus.h | 56 +++++++ src/glade-dbus.xml | 72 ++++++++ src/glade-resources.gresource.xml | 1 + src/glade-window.c | 70 +++++++- src/glade-window.h | 18 +- src/main.c | 3 + 8 files changed, 552 insertions(+), 13 deletions(-) create mode 100644 src/glade-dbus.c create mode 100644 src/glade-dbus.h create mode 100644 src/glade-dbus.xml diff --git a/src/Makefile.am b/src/Makefile.am index 428ae4eb..fafc7926 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -24,6 +24,7 @@ BUILT_SOURCES = glade-resources.c glade-resources.h glade_SOURCES = \ glade-window.c \ + glade-dbus.c \ glade-intro.c \ glade-resources.c \ glade-preferences.c \ @@ -33,6 +34,7 @@ glade_SOURCES = \ noinst_HEADERS = \ glade-window.h \ + glade-dbus.h \ glade-intro.h \ glade-resources.h \ glade-preferences.h \ @@ -67,4 +69,4 @@ UI_FILES = glade.glade \ glade-window.css \ glade-registration.css -EXTRA_DIST = glade.rc.in glade-resources.gresource.xml $(UI_FILES) +EXTRA_DIST = glade.rc.in glade-resources.gresource.xml glade-dbus.xml $(UI_FILES) diff --git a/src/glade-dbus.c b/src/glade-dbus.c new file mode 100644 index 00000000..937a8c85 --- /dev/null +++ b/src/glade-dbus.c @@ -0,0 +1,341 @@ +/* + * glade-dbus.c + * + * Copyright (C) 2018 Juan Pablo Ugarte + * + * 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.1 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 program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * Authors: + * Juan Pablo Ugarte + */ + +#include "glade-window.h" +#include "glade-dbus.h" + +typedef enum +{ + GLADE_DBUS_OK, + GLADE_DBUS_NO_PROJECT +} GladeDBusError; + +#define GLADE_DBUS_ERROR glade_dbus_error_quark() +static GQuark glade_dbus_error_quark (void); +G_DEFINE_QUARK (glade-dbus-error-quark, glade_dbus_error) + +static GDBusInterfaceInfo *iface_info = NULL; + +static void +add_object (GtkApplication *app, + const gchar *project_path, + const gchar *object_type, + const gchar *object_id, + gboolean is_template) +{ + GladeWidgetAdaptor *adaptor; + GladeProject *project; + GladeWidget *widget; + + if (!(project = glade_app_get_project_by_path (project_path))) + return; + + if (!(adaptor = glade_widget_adaptor_get_by_name (object_type))) + return; + + widget = glade_widget_adaptor_create_widget (adaptor, FALSE, NULL); + if (!widget) + return; + + glade_project_add_object (project, glade_widget_get_object (widget)); + + if (is_template) + glade_project_set_template (project, widget); + + glade_project_save (project, glade_project_get_path (project), NULL); +} + +static void +glade_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) +{ + GtkApplication *app = user_data; + + /* gdbus call --session --dest org.gnome.Glade --object-path /org/gnome/Glade --method \ + org.gnome.Glade.AddObject '/home/xjuan/test.glade' GtkWindow MyWindow true + */ + if (g_strcmp0 (method_name, "AddObject") == 0) + { + gchar *project_path, *object_type, *object_id; + gboolean is_template; + + g_variant_get (parameters, "(sssb)", + &project_path, + &object_type, + &object_id, + &is_template); + + add_object (app, project_path, object_type, object_id, is_template); + + g_free (project_path); + g_free (object_type); + g_free (object_id); + } + + g_dbus_method_invocation_return_value (invocation, NULL); +} + +static GVariant * +glade_dbus_get_property (GDBusConnection *connection, + const gchar *sender, + const gchar *object_path, + const gchar *interface_name, + const gchar *property_name, + GError **error, + gpointer user_data) +{ + GtkApplication *app = user_data; + + /* gdbus call --session --dest org.gnome.Glade --object-path /org/gnome/Glade --method \ + org.freedesktop.DBus.Properties.Set 'org.gnome.Glade' 'Project' "<'/home/xjuan/test.glade'>" + */ + if (g_strcmp0 (property_name, "Project") == 0) + { + GladeWindow *window = GLADE_WINDOW (gtk_application_get_active_window (app)); + GladeProject *project; + + if ((project = glade_window_get_active_project (window))) + return g_variant_new_string (glade_project_get_path (project)); + + *error = g_error_new_literal (GLADE_DBUS_ERROR, + GLADE_DBUS_NO_PROJECT, + "Project not found"); + } + + return NULL; +} + +static gboolean +set_project (GtkApplication *app, const gchar *path) +{ + GladeWindow *window = GLADE_WINDOW (gtk_application_get_active_window (app)); + + if (glade_app_is_project_loaded (path) || + g_file_test (path, G_FILE_TEST_EXISTS)) + glade_window_open_project (window, path); + else + { + GladeProject *project = glade_window_new_project (window); + glade_project_save (project, path, NULL); + } + + return TRUE; +} + +static gboolean +glade_dbus_set_property (GDBusConnection *connection, + const gchar *sender, + const gchar *object_path, + const gchar *interface_name, + const gchar *property_name, + GVariant *value, + GError **error, + gpointer user_data) +{ + GtkApplication *app = user_data; + + if (strcmp (property_name, "Project") == 0) + return set_project (app, g_variant_get_string (value, NULL)); + + return FALSE; +} + +#define DBUS_IFACE "org.gnome.Glade" + +void +glade_dbus_register (GApplication *app) +{ + const static GDBusInterfaceVTable vtable = { + glade_dbus_method_call, + glade_dbus_get_property, + glade_dbus_set_property + }; + GDBusNodeInfo *info; + GError *error = NULL; + GBytes *xml; + + if (!(xml = g_resources_lookup_data ("/org/gnome/glade/glade-dbus.xml", 0, NULL))) + return; + + if (!(info = g_dbus_node_info_new_for_xml (g_bytes_get_data (xml, NULL), &error))) + { + g_debug ("%s %s", __func__, error->message); + return; + } + + iface_info = g_dbus_node_info_lookup_interface (info, DBUS_IFACE); + g_assert (iface_info != NULL); + g_dbus_interface_info_ref (iface_info); + g_dbus_node_info_unref (info); + + g_dbus_connection_register_object (g_application_get_dbus_connection (app), + g_application_get_dbus_object_path (app), + iface_info, + &vtable, + app, + NULL, + &error); + if (error) + g_debug ("%s %s", __func__, error->message); +} + +static inline void +glade_dbus_emit (GApplication *app, + GError **error, + const gchar *signal, + const gchar *format, + ...) +{ + va_list params; + va_start (params, format); + g_dbus_connection_emit_signal (g_application_get_dbus_connection (app), + NULL, + g_application_get_dbus_object_path (app), + DBUS_IFACE, + signal, + g_variant_new_va (format, NULL, ¶ms), + error); + va_end (params); +} + +static const gchar * +widget_get_class (GladeWidget *widget) +{ + GObject *object = glade_widget_get_object (widget); + return object ? G_OBJECT_TYPE_NAME (object) : NULL; +} + +static inline void +glade_dbus_emit_plain (GApplication *app, + const gchar *dbus_signal, + GladeWidget *widget, + GladeSignal *signal, + GError **error) +{ + const gchar *path, *widget_class, *widget_name, *handler, *signal_name; + GladeProject *project; + + if ((project = glade_widget_get_project (widget)) && + (path = glade_project_get_path (project)) && + (widget_class = widget_get_class (widget)) && + (widget_name = glade_widget_get_name (widget)) && + (handler = glade_signal_get_handler (signal)) && + (signal_name = glade_signal_get_name (signal))) + glade_dbus_emit (app, + error, + dbus_signal, + "(sssss)", + path, + widget_class, + widget_name, + handler, + signal_name); +} + +void +glade_dbus_emit_handler_added (GApplication *app, + GladeWidget *widget, + GladeSignal *signal, + GError **error) +{ + const gchar *path, *widget_class, *widget_name, *handler, *signal_name, *userdata; + GladeProject *project; + + userdata = glade_signal_get_userdata (signal); + + if ((project = glade_widget_get_project (widget)) && + (path = glade_project_get_path (project)) && + (widget_class = widget_get_class (widget)) && + (widget_name = glade_widget_get_name (widget)) && + (handler = glade_signal_get_handler (signal)) && + (signal_name = glade_signal_get_name (signal))) + glade_dbus_emit (app, + error, + "HandlerAdded", + "(ssssssb)", + path, + widget_class, + widget_name, + handler, + signal_name, + userdata ? userdata : "", + glade_signal_get_swapped (signal)); +} + +void +glade_dbus_emit_handler_removed (GApplication *app, + GladeWidget *widget, + GladeSignal *signal, + GError **error) +{ + glade_dbus_emit_plain (app, "HandlerRemoved", widget, signal, error); +} + +void +glade_dbus_emit_handler_activated (GApplication *app, + GladeWidget *widget, + GladeSignal *signal, + GError **error) +{ + glade_dbus_emit_plain (app, "HandlerActivated", widget, signal, error); +} + +void +glade_dbus_emit_handler_changed (GApplication *app, + GladeWidget *widget, + GladeSignal *old_signal, + GladeSignal *new_signal, + GError **error) +{ + const gchar *path, *widget_class, *widget_name, *old_handler, *new_handler, *signal_name, *userdata; + GladeProject *project; + + userdata = glade_signal_get_userdata (new_signal); + + if ((project = glade_widget_get_project (widget)) && + (path = glade_project_get_path (project)) && + (widget_class = widget_get_class (widget)) && + (widget_name = glade_widget_get_name (widget)) && + (old_handler = glade_signal_get_handler (old_signal)) && + (new_handler = glade_signal_get_handler (new_signal)) && + (signal_name = glade_signal_get_name (new_signal))) + glade_dbus_emit (app, + error, + "HandlerChanged", + "(sssssssb)", + path, + widget_class, + widget_name, + old_handler, + new_handler, + signal_name, + userdata ? userdata : "", + glade_signal_get_swapped (new_signal)); +} + diff --git a/src/glade-dbus.h b/src/glade-dbus.h new file mode 100644 index 00000000..63c5e5b9 --- /dev/null +++ b/src/glade-dbus.h @@ -0,0 +1,56 @@ +/* + * glade-dbus.h + * + * Copyright (C) 2018 Juan Pablo Ugarte + * + * 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.1 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 program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * Authors: + * Juan Pablo Ugarte + */ + +#ifndef _GLADE_DBUS_H_ +#define _GLADE_DBUS_H_ + +#include + +G_BEGIN_DECLS + +void glade_dbus_register (GApplication *app); + +void glade_dbus_emit_handler_added (GApplication *app, + GladeWidget *widget, + GladeSignal *signal, + GError **error); + +void glade_dbus_emit_handler_removed (GApplication *app, + GladeWidget *widget, + GladeSignal *signal, + GError **error); + +void glade_dbus_emit_handler_changed (GApplication *app, + GladeWidget *widget, + GladeSignal *old_signal, + GladeSignal *new_signal, + GError **error); + +void glade_dbus_emit_handler_activated (GApplication *app, + GladeWidget *widget, + GladeSignal *signal, + GError **error); + +G_END_DECLS + +#endif /* _GLADE_DBUS_H_ */ diff --git a/src/glade-dbus.xml b/src/glade-dbus.xml new file mode 100644 index 00000000..f42e5401 --- /dev/null +++ b/src/glade-dbus.xml @@ -0,0 +1,72 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/glade-resources.gresource.xml b/src/glade-resources.gresource.xml index 4ada8c66..e55c1817 100644 --- a/src/glade-resources.gresource.xml +++ b/src/glade-resources.gresource.xml @@ -6,5 +6,6 @@ glade-registration.glade glade-window.css glade-registration.css + glade-dbus.xml diff --git a/src/glade-window.c b/src/glade-window.c index c290a399..869ff56c 100644 --- a/src/glade-window.c +++ b/src/glade-window.c @@ -30,6 +30,7 @@ #include "glade-resources.h" #include "glade-preferences.h" #include "glade-registration.h" +#include "glade-dbus.h" #include "glade-intro.h" #include @@ -406,6 +407,37 @@ project_targets_changed_cb (GladeProject *project, GladeWindow *window) refresh_stack_title_for_project (window, project); } +static void +project_add_signal_handler_cb (GladeProject *project, + GladeWidget *widget, + GladeSignal *signal, + GladeWindow *window) +{ + glade_dbus_emit_handler_added (G_APPLICATION (window->priv->application), + widget, signal, NULL); +} + +static void +project_remove_signal_handler_cb (GladeProject *project, + GladeWidget *widget, + GladeSignal *signal, + GladeWindow *window) +{ + glade_dbus_emit_handler_removed (G_APPLICATION (window->priv->application), + widget, signal, NULL); +} + +static void +project_change_signal_handler_cb (GladeProject *project, + GladeWidget *widget, + GladeSignal *old_signal, + GladeSignal *new_signal, + GladeWindow *window) +{ + glade_dbus_emit_handler_changed (G_APPLICATION (window->priv->application), + widget, old_signal, new_signal, NULL); +} + static inline void actions_set_enabled (GladeWindow *window, const gchar *name, gboolean enabled) { @@ -1580,6 +1612,12 @@ add_project (GladeWindow *window, GladeProject *project, gboolean for_file) G_CALLBACK (project_selection_changed_cb), window); g_signal_connect (G_OBJECT (project), "targets-changed", G_CALLBACK (project_targets_changed_cb), window); + g_signal_connect (G_OBJECT (project), "add-signal-handler", + G_CALLBACK (project_add_signal_handler_cb), window); + g_signal_connect (G_OBJECT (project), "remove-signal-handler", + G_CALLBACK (project_remove_signal_handler_cb), window); + g_signal_connect (G_OBJECT (project), "change-signal-handler", + G_CALLBACK (project_change_signal_handler_cb), window); g_signal_connect (G_OBJECT (project), "changed", G_CALLBACK (project_changed_cb), window); @@ -1648,12 +1686,12 @@ on_redo_button_button_press_event (GtkWidget *widget, return FALSE; } -void +GladeProject * glade_window_new_project (GladeWindow *window) { GladeProject *project; - g_return_if_fail (GLADE_IS_WINDOW (window)); + g_return_val_if_fail (GLADE_IS_WINDOW (window), NULL); project = glade_project_new (); if (!project) @@ -1661,9 +1699,11 @@ glade_window_new_project (GladeWindow *window) glade_util_ui_message (GTK_WIDGET (window), GLADE_UI_ERROR, NULL, _("Could not create a new project.")); - return; + return NULL; } add_project (window, project, FALSE); + + return project; } static void @@ -2142,7 +2182,6 @@ glade_window_init (GladeWindow *window) static void glade_window_action_handler (GladeWindow *window, const gchar *name) { - GladeWindowPrivate *priv = window->priv; GAction *action; if ((action = GLADE_WINDOW_GET_ACTION (window, name))) @@ -2382,11 +2421,23 @@ on_application_notify (GObject *gobject, GParamSpec *pspec) project_actions_set_enabled (GLADE_WINDOW (gobject), FALSE); } +static void +on_glade_editor_signal_activated (GladeSignalEditor *signal_editor, + GladeSignal *signal, + GladeWindow *window) +{ + glade_dbus_emit_handler_activated (G_APPLICATION (window->priv->application), + glade_signal_editor_get_widget (signal_editor), + signal, + NULL); +} + static void glade_window_constructed (GObject *object) { GladeWindow *window = GLADE_WINDOW (object); GladeWindowPrivate *priv = window->priv; + GladeSignalEditor *signal_editor; gchar *version; /* Chain up... */ @@ -2423,6 +2474,10 @@ glade_window_constructed (GObject *object) g_signal_connect (G_OBJECT (window), "key-press-event", G_CALLBACK (glade_utils_hijack_key_press), window); + g_object_get (priv->editor, "signal-editor", &signal_editor, NULL); + g_signal_connect (signal_editor, "signal-activated", + G_CALLBACK (on_glade_editor_signal_activated), window); + /* Load configuration, we need the list of extra catalog paths before creating * the GladeApp */ @@ -2516,6 +2571,12 @@ glade_window_new (void) return g_object_new (GLADE_TYPE_WINDOW, NULL); } +GladeProject * +glade_window_get_active_project (GladeWindow *window) +{ + return get_active_project (window); +} + void glade_window_check_devhelp (GladeWindow *window) { @@ -2578,3 +2639,4 @@ glade_window_registration_notify_user (GladeWindow *window) /* translators: Text to show in the statusbar if the user did not completed the survey and choose not to show the notification dialog again */ _("Go to Help -> Registration & User Survey and complete our survey!")); } + diff --git a/src/glade-window.h b/src/glade-window.h index 757ecff4..f6a1ec49 100644 --- a/src/glade-window.h +++ b/src/glade-window.h @@ -21,7 +21,7 @@ #ifndef __GLADE_WINDOW_H__ #define __GLADE_WINDOW_H__ -#include +#include G_BEGIN_DECLS @@ -47,18 +47,20 @@ struct _GladeWindowClass GtkWindowClass parent_class; }; -GType glade_window_get_type (void) G_GNUC_CONST; +GType glade_window_get_type (void) G_GNUC_CONST; -GtkWidget *glade_window_new (void); +GtkWidget *glade_window_new (void); -void glade_window_new_project (GladeWindow *window); +GladeProject *glade_window_new_project (GladeWindow *window); -gboolean glade_window_open_project (GladeWindow *window, - const gchar *path); +gboolean glade_window_open_project (GladeWindow *window, + const gchar *path); -void glade_window_check_devhelp (GladeWindow *window); +GladeProject *glade_window_get_active_project (GladeWindow *window); -void glade_window_registration_notify_user (GladeWindow *window); +void glade_window_check_devhelp (GladeWindow *window); + +void glade_window_registration_notify_user (GladeWindow *window); G_END_DECLS diff --git a/src/main.c b/src/main.c index 8a81771f..7f6f069d 100644 --- a/src/main.c +++ b/src/main.c @@ -24,6 +24,7 @@ #include #include "glade-window.h" +#include "glade-dbus.h" #include "glade-resources.h" #include @@ -100,6 +101,8 @@ activate (GApplication *application) gtk_widget_show (GTK_WIDGET (window)); + glade_dbus_register (application); + glade_window_registration_notify_user (window); } -- cgit v1.2.1