gedit r6755 - in trunk: . docs/reference docs/reference/tmpl gedit plugin-loaders/python/bindings plugins/filebrowser
- From: jessevdk svn gnome org
- To: svn-commits-list gnome org
- Subject: gedit r6755 - in trunk: . docs/reference docs/reference/tmpl gedit plugin-loaders/python/bindings plugins/filebrowser
- Date: Mon, 29 Dec 2008 18:52:22 +0000 (UTC)
Author: jessevdk
Date: Mon Dec 29 18:52:22 2008
New Revision: 6755
URL: http://svn.gnome.org/viewvc/gedit?rev=6755&view=rev
Log:
* gedit/gedit-message-type.h:
* gedit/gedit-message-type.c:
* gedit/gedit-message.h:
* gedit/gedit-message.c:
* gedit/gedit-message-bus.h:
* gedit/gedit-message-bus.c:
* gedit/gedit-window.h:
* gedit/gedit-window.c:
* gedit/gedit-window-private.h:
* gedit/Makefile.am:
Merged message communication bus from message_system branch providing
a framework to allow (amongst others) plugins to cooperate in similar
way as DBus (but for in-process communication)
* docs/reference/gedit-sections.txt:
* docs/reference/gedit.types:
* docs/reference/gedit-docs.sgml:
* docs/reference/tmpl/gedit-message.sgml:
* docs/reference/tmpl/gedit-message-type.sgml:
* docs/reference/tmpl/gedit-message-bus.sgml:
Added API documentation for message bus
* plugin-loaders/python/bindings/geditmessage.override:
* plugin-loaders/python/bindings/Makefile.am:
* plugin-loaders/python/bindings/gedit.override:
* plugin-loaders/python/bindings/gedit.defs:
Implemented python bindings for message bus
* plugins/filebrowser/gedit-file-browser-messages.c:
* plugins/filebrowser/gedit-file-browser-messages.h:
* plugins/filebrowser/gedit-file-browser-widget.c:
* plugins/filebrowser/gedit-file-browser-widget.h:
* plugins/filebrowser/gedit-file-browser-plugin.c:
* plugins/filebrowser/Makefile.am:
Added message bus support for the file browser plugin
* plugins/filebrowser/gedit-file-browser-view.c:
Added sanity checks for destruction of state restore table
Added:
trunk/docs/reference/tmpl/gedit-message-bus.sgml
trunk/docs/reference/tmpl/gedit-message-type.sgml
trunk/docs/reference/tmpl/gedit-message.sgml
trunk/gedit/gedit-message-bus.c
trunk/gedit/gedit-message-bus.h
trunk/gedit/gedit-message-type.c
trunk/gedit/gedit-message-type.h
trunk/gedit/gedit-message.c
trunk/gedit/gedit-message.h
trunk/plugin-loaders/python/bindings/geditmessage.override
trunk/plugins/filebrowser/gedit-file-browser-messages.c
trunk/plugins/filebrowser/gedit-file-browser-messages.h
Modified:
trunk/ChangeLog
trunk/docs/reference/gedit-docs.sgml
trunk/docs/reference/gedit-sections.txt
trunk/docs/reference/gedit.types
trunk/gedit/Makefile.am
trunk/gedit/gedit-window-private.h
trunk/gedit/gedit-window.c
trunk/gedit/gedit-window.h
trunk/plugin-loaders/python/bindings/Makefile.am
trunk/plugin-loaders/python/bindings/gedit.defs
trunk/plugin-loaders/python/bindings/gedit.override
trunk/plugins/filebrowser/Makefile.am
trunk/plugins/filebrowser/gedit-file-browser-plugin.c
trunk/plugins/filebrowser/gedit-file-browser-view.c
trunk/plugins/filebrowser/gedit-file-browser-widget.c
trunk/plugins/filebrowser/gedit-file-browser-widget.h
Modified: trunk/docs/reference/gedit-docs.sgml
==============================================================================
--- trunk/docs/reference/gedit-docs.sgml (original)
+++ trunk/docs/reference/gedit-docs.sgml Mon Dec 29 18:52:22 2008
@@ -13,6 +13,9 @@
<xi:include href="xml/gedit-encodings-option-menu.xml"/>
<xi:include href="xml/gedit-file-chooser-dialog.xml"/>
<xi:include href="xml/gedit-message-area.xml"/>
+ <xi:include href="xml/gedit-message-bus.xml"/>
+ <xi:include href="xml/gedit-message-type.xml"/>
+ <xi:include href="xml/gedit-message.xml"/>
<xi:include href="xml/gedit-notebook.xml"/>
<xi:include href="xml/gedit-panel.xml"/>
<xi:include href="xml/gedit-plugin.xml"/>
Modified: trunk/docs/reference/gedit-sections.txt
==============================================================================
--- trunk/docs/reference/gedit-sections.txt (original)
+++ trunk/docs/reference/gedit-sections.txt Mon Dec 29 18:52:22 2008
@@ -131,6 +131,88 @@
</SECTION>
<SECTION>
+<FILE>gedit-message-bus</FILE>
+<TITLE>GeditMessageBus</TITLE>
+GeditMessageBus
+GeditMessageCallback
+gedit_message_bus_get_default
+gedit_message_bus_new
+gedit_message_bus_lookup
+gedit_message_bus_register
+gedit_message_bus_unregister
+gedit_message_bus_unregister_all
+gedit_message_bus_is_registered
+gedit_message_bus_connect
+gedit_message_bus_disconnect
+gedit_message_bus_disconnect_by_func
+gedit_message_bus_block
+gedit_message_bus_block_by_func
+gedit_message_bus_unblock
+gedit_message_bus_unblock_by_func
+gedit_message_bus_send_message
+gedit_message_bus_send_message_sync
+gedit_message_bus_send
+gedit_message_bus_send_sync
+<SUBSECTION Standard>
+GEDIT_MESSAGE_BUS
+GEDIT_IS_MESSAGE_BUS
+GEDIT_TYPE_MESSAGE_BUS
+gedit_message_bus_get_type
+GEDIT_MESSAGE_BUS_CLASS
+GEDIT_IS_MESSAGE_BUS_CLASS
+GEDIT_MESSAGE_BUS_GET_CLASS
+</SECTION>
+
+<SECTION>
+<FILE>gedit-message-type</FILE>
+<TITLE>GeditMessageType</TITLE>
+GeditMessageType
+gedit_message_type_get_type
+gedit_message_type_is_supported
+gedit_message_type_identifier
+gedit_message_type_new
+gedit_message_type_new_valist
+gedit_message_type_ref
+gedit_message_type_unref
+gedit_message_type_set
+gedit_message_type_set_valist
+gedit_message_type_instantiate
+gedit_message_type_instantiate_valist
+gedit_message_type_get_object_path
+gedit_message_type_get_method
+gedit_message_type_lookup
+gedit_message_type_foreach
+<SUBSECTION Standard>
+GEDIT_TYPE_MESSAGE_TYPE
+</SECTION>
+
+<SECTION>
+<FILE>gedit-message</FILE>
+<TITLE>GeditMessage</TITLE>
+GeditMessage
+gedit_message_get
+gedit_message_get_valist
+gedit_message_get_value
+gedit_message_set
+gedit_message_set_valist
+gedit_message_set_value
+gedit_message_set_valuesv
+gedit_message_get_object_path
+gedit_message_get_method
+gedit_message_has_key
+gedit_message_get_key_type
+gedit_message_validate
+<SUBSECTION Standard>
+GEDIT_MESSAGE
+GEDIT_IS_MESSAGE
+GEDIT_TYPE_MESSAGE
+gedit_message_get_type
+GEDIT_MESSAGE_CLASS
+GEDIT_IS_MESSAGE_CLASS
+GEDIT_MESSAGE_GET_CLASS
+</SECTION>
+
+<SECTION>
<FILE>gedit-notebook</FILE>
GeditNotebookPrivate
<TITLE>GeditNotebook</TITLE>
@@ -353,6 +435,7 @@
gedit_window_get_state
gedit_window_get_tab_from_location
gedit_window_get_tab_from_uri
+gedit_window_get_message_bus
<SUBSECTION Standard>
GEDIT_WINDOW
GEDIT_IS_WINDOW
Modified: trunk/docs/reference/gedit.types
==============================================================================
--- trunk/docs/reference/gedit.types (original)
+++ trunk/docs/reference/gedit.types Mon Dec 29 18:52:22 2008
@@ -4,6 +4,9 @@
#include "gedit-encodings-option-menu.h"
#include "gedit-file-chooser-dialog.h"
#include "gedit-message-area.h"
+#include "gedit-message.h"
+#include "gedit-message-bus.h"
+#include "gedit-message-type.h"
#include "gedit-notebook.h"
#include "gedit-panel.h"
#include "gedit-plugin.h"
@@ -18,6 +21,9 @@
gedit_encodings_option_menu_get_type
gedit_file_chooser_dialog_get_type
gedit_message_area_get_type
+gedit_message_get_type
+gedit_message_bus_get_type
+gedit_message_type_get_type
gedit_notebook_get_type
gedit_panel_get_type
gedit_plugin_get_type
Added: trunk/docs/reference/tmpl/gedit-message-bus.sgml
==============================================================================
--- (empty file)
+++ trunk/docs/reference/tmpl/gedit-message-bus.sgml Mon Dec 29 18:52:22 2008
@@ -0,0 +1,246 @@
+<!-- ##### SECTION Title ##### -->
+GeditMessageBus
+
+<!-- ##### SECTION Short_Description ##### -->
+
+
+<!-- ##### SECTION Long_Description ##### -->
+<para>
+
+</para>
+
+<!-- ##### SECTION See_Also ##### -->
+<para>
+
+</para>
+
+<!-- ##### SECTION Stability_Level ##### -->
+
+
+<!-- ##### STRUCT GeditMessageBus ##### -->
+<para>
+
+</para>
+
+
+<!-- ##### SIGNAL GeditMessageBus::dispatch ##### -->
+<para>
+
+</para>
+
+ geditmessagebus: the object which received the signal.
+ arg1:
+
+<!-- ##### SIGNAL GeditMessageBus::registered ##### -->
+<para>
+
+</para>
+
+ geditmessagebus: the object which received the signal.
+ arg1:
+
+<!-- ##### SIGNAL GeditMessageBus::unregistered ##### -->
+<para>
+
+</para>
+
+ geditmessagebus: the object which received the signal.
+ arg1:
+
+<!-- ##### USER_FUNCTION GeditMessageCallback ##### -->
+<para>
+
+</para>
+
+ bus:
+ message:
+ userdata:
+
+
+<!-- ##### FUNCTION gedit_message_bus_get_default ##### -->
+<para>
+
+</para>
+
+ Returns:
+
+
+<!-- ##### FUNCTION gedit_message_bus_new ##### -->
+<para>
+
+</para>
+
+ Returns:
+
+
+<!-- ##### FUNCTION gedit_message_bus_lookup ##### -->
+<para>
+
+</para>
+
+ bus:
+ object_path:
+ method:
+ Returns:
+
+
+<!-- ##### FUNCTION gedit_message_bus_register ##### -->
+<para>
+
+</para>
+
+ bus:
+ object_path:
+ method:
+ num_optional:
+ Varargs:
+ Returns:
+
+
+<!-- ##### FUNCTION gedit_message_bus_unregister ##### -->
+<para>
+
+</para>
+
+ bus:
+ message_type:
+
+
+<!-- ##### FUNCTION gedit_message_bus_unregister_all ##### -->
+<para>
+
+</para>
+
+ bus:
+ object_path:
+
+
+<!-- ##### FUNCTION gedit_message_bus_is_registered ##### -->
+<para>
+
+</para>
+
+ bus:
+ object_path:
+ method:
+ Returns:
+
+
+<!-- ##### FUNCTION gedit_message_bus_connect ##### -->
+<para>
+
+</para>
+
+ bus:
+ object_path:
+ method:
+ callback:
+ userdata:
+ destroy_data:
+ Returns:
+
+
+<!-- ##### FUNCTION gedit_message_bus_disconnect ##### -->
+<para>
+
+</para>
+
+ bus:
+ id:
+
+
+<!-- ##### FUNCTION gedit_message_bus_disconnect_by_func ##### -->
+<para>
+
+</para>
+
+ bus:
+ object_path:
+ method:
+ callback:
+ userdata:
+
+
+<!-- ##### FUNCTION gedit_message_bus_block ##### -->
+<para>
+
+</para>
+
+ bus:
+ id:
+
+
+<!-- ##### FUNCTION gedit_message_bus_block_by_func ##### -->
+<para>
+
+</para>
+
+ bus:
+ object_path:
+ method:
+ callback:
+ userdata:
+
+
+<!-- ##### FUNCTION gedit_message_bus_unblock ##### -->
+<para>
+
+</para>
+
+ bus:
+ id:
+
+
+<!-- ##### FUNCTION gedit_message_bus_unblock_by_func ##### -->
+<para>
+
+</para>
+
+ bus:
+ object_path:
+ method:
+ callback:
+ userdata:
+
+
+<!-- ##### FUNCTION gedit_message_bus_send_message ##### -->
+<para>
+
+</para>
+
+ bus:
+ message:
+
+
+<!-- ##### FUNCTION gedit_message_bus_send_message_sync ##### -->
+<para>
+
+</para>
+
+ bus:
+ message:
+
+
+<!-- ##### FUNCTION gedit_message_bus_send ##### -->
+<para>
+
+</para>
+
+ bus:
+ object_path:
+ method:
+ Varargs:
+
+
+<!-- ##### FUNCTION gedit_message_bus_send_sync ##### -->
+<para>
+
+</para>
+
+ bus:
+ object_path:
+ method:
+ Varargs:
+ Returns:
+
+
Added: trunk/docs/reference/tmpl/gedit-message-type.sgml
==============================================================================
--- (empty file)
+++ trunk/docs/reference/tmpl/gedit-message-type.sgml Mon Dec 29 18:52:22 2008
@@ -0,0 +1,171 @@
+<!-- ##### SECTION Title ##### -->
+GeditMessageType
+
+<!-- ##### SECTION Short_Description ##### -->
+
+
+<!-- ##### SECTION Long_Description ##### -->
+<para>
+
+</para>
+
+<!-- ##### SECTION See_Also ##### -->
+<para>
+
+</para>
+
+<!-- ##### SECTION Stability_Level ##### -->
+
+
+<!-- ##### STRUCT GeditMessageType ##### -->
+<para>
+
+</para>
+
+
+<!-- ##### FUNCTION gedit_message_type_get_type ##### -->
+<para>
+
+</para>
+
+ Returns:
+
+
+<!-- ##### FUNCTION gedit_message_type_is_supported ##### -->
+<para>
+
+</para>
+
+ type:
+ Returns:
+
+
+<!-- ##### FUNCTION gedit_message_type_identifier ##### -->
+<para>
+
+</para>
+
+ object_path:
+ method:
+ Returns:
+
+
+<!-- ##### FUNCTION gedit_message_type_new ##### -->
+<para>
+
+</para>
+
+ object_path:
+ method:
+ num_optional:
+ Varargs:
+ Returns:
+
+
+<!-- ##### FUNCTION gedit_message_type_new_valist ##### -->
+<para>
+
+</para>
+
+ object_path:
+ method:
+ num_optional:
+ va_args:
+ Returns:
+
+
+<!-- ##### FUNCTION gedit_message_type_ref ##### -->
+<para>
+
+</para>
+
+ message_type:
+ Returns:
+
+
+<!-- ##### FUNCTION gedit_message_type_unref ##### -->
+<para>
+
+</para>
+
+ message_type:
+
+
+<!-- ##### FUNCTION gedit_message_type_set ##### -->
+<para>
+
+</para>
+
+ message_type:
+ num_optional:
+ Varargs:
+
+
+<!-- ##### FUNCTION gedit_message_type_set_valist ##### -->
+<para>
+
+</para>
+
+ message_type:
+ num_optional:
+ va_args:
+
+
+<!-- ##### FUNCTION gedit_message_type_instantiate ##### -->
+<para>
+
+</para>
+
+ message_type:
+ Varargs:
+ Returns:
+
+
+<!-- ##### FUNCTION gedit_message_type_instantiate_valist ##### -->
+<para>
+
+</para>
+
+ message_type:
+ va_args:
+ Returns:
+
+
+<!-- ##### FUNCTION gedit_message_type_get_object_path ##### -->
+<para>
+
+</para>
+
+ message_type:
+ Returns:
+
+
+<!-- ##### FUNCTION gedit_message_type_get_method ##### -->
+<para>
+
+</para>
+
+ message_type:
+ Returns:
+
+
+<!-- ##### FUNCTION gedit_message_type_lookup ##### -->
+<para>
+
+</para>
+
+ message_type:
+ key:
+ Returns:
+
+
+<!-- ##### FUNCTION gedit_message_type_foreach ##### -->
+<para>
+
+</para>
+
+ message_type:
+ func:
+ user_data:
+
+
Added: trunk/docs/reference/tmpl/gedit-message.sgml
==============================================================================
--- (empty file)
+++ trunk/docs/reference/tmpl/gedit-message.sgml Mon Dec 29 18:52:22 2008
@@ -0,0 +1,144 @@
+<!-- ##### SECTION Title ##### -->
+GeditMessage
+
+<!-- ##### SECTION Short_Description ##### -->
+
+
+<!-- ##### SECTION Long_Description ##### -->
+<para>
+
+</para>
+
+<!-- ##### SECTION See_Also ##### -->
+<para>
+
+</para>
+
+<!-- ##### SECTION Stability_Level ##### -->
+
+
+<!-- ##### STRUCT GeditMessage ##### -->
+<para>
+
+</para>
+
+
+<!-- ##### ARG GeditMessage:method ##### -->
+<para>
+
+</para>
+
+<!-- ##### ARG GeditMessage:object-path ##### -->
+<para>
+
+</para>
+
+<!-- ##### ARG GeditMessage:type ##### -->
+<para>
+
+</para>
+
+<!-- ##### FUNCTION gedit_message_get ##### -->
+<para>
+
+</para>
+
+ message:
+ Varargs:
+
+
+<!-- ##### FUNCTION gedit_message_get_valist ##### -->
+<para>
+
+</para>
+
+ message:
+ var_args:
+
+
+<!-- ##### FUNCTION gedit_message_get_value ##### -->
+<para>
+
+</para>
+
+ message:
+ key:
+ value:
+
+
+<!-- ##### FUNCTION gedit_message_set ##### -->
+<para>
+
+</para>
+
+ message:
+ Varargs:
+
+
+<!-- ##### FUNCTION gedit_message_set_valist ##### -->
+<para>
+
+</para>
+
+ message:
+ var_args:
+
+
+<!-- ##### FUNCTION gedit_message_set_value ##### -->
+<para>
+
+</para>
+
+ message:
+ key:
+ value:
+
+
+<!-- ##### FUNCTION gedit_message_set_valuesv ##### -->
+<para>
+
+</para>
+
+ message:
+ keys:
+ values:
+ n_values:
+
+
+<!-- ##### FUNCTION gedit_message_get_object_path ##### -->
+<para>
+
+</para>
+
+ message:
+ Returns:
+
+
+<!-- ##### FUNCTION gedit_message_get_method ##### -->
+<para>
+
+</para>
+
+ message:
+ Returns:
+
+
+<!-- ##### FUNCTION gedit_message_has_key ##### -->
+<para>
+
+</para>
+
+ message:
+ key:
+ Returns:
+
+
+<!-- ##### FUNCTION gedit_message_validate ##### -->
+<para>
+
+</para>
+
+ message:
+ Returns:
+
+
Modified: trunk/gedit/Makefile.am
==============================================================================
--- trunk/gedit/Makefile.am (original)
+++ trunk/gedit/Makefile.am Mon Dec 29 18:52:22 2008
@@ -84,6 +84,9 @@
gedit-file-chooser-dialog.h \
gedit-help.h \
gedit-message-area.h \
+ gedit-message-bus.h \
+ gedit-message-type.h \
+ gedit-message.h \
gedit-metadata-manager.h \
gedit-notebook.h \
gedit-panel.h \
@@ -141,6 +144,9 @@
gedit-io-error-message-area.c \
gedit-language-manager.c \
gedit-message-area.c \
+ gedit-message-bus.c \
+ gedit-message-type.c \
+ gedit-message.c \
gedit-metadata-manager.c \
gedit-object-module.c \
gedit-notebook.c \
Added: trunk/gedit/gedit-message-bus.c
==============================================================================
--- (empty file)
+++ trunk/gedit/gedit-message-bus.c Mon Dec 29 18:52:22 2008
@@ -0,0 +1,1100 @@
+#include "gedit-message-bus.h"
+
+#include <string.h>
+#include <stdarg.h>
+#include <gobject/gvaluecollector.h>
+
+/**
+ * GeditMessageCallback:
+ * @bus: the #GeditMessageBus on which the message was sent
+ * @message: the #GeditMessage which was sent
+ * @userdata: the supplied user data when connecting the callback
+ *
+ * Callback signature used for connecting callback functions to be called
+ * when a message is received (see gedit_message_bus_connect()).
+ *
+ */
+
+/**
+ * SECTION:gedit-message-bus
+ * @short_description: internal message communication bus
+ * @include: gedit/gedit-message-bus.h
+ *
+ * gedit has a communication bus very similar to DBus. Its primary use is to
+ * allow easy communication between plugins, but it can also be used to expose
+ * gedit functionality to external applications by providing DBus bindings for
+ * the internal gedit message bus.
+ *
+ * There are two different communication busses available. The default bus
+ * (see gedit_message_bus_get_default()) is an application wide communication
+ * bus. In addition, each #GeditWindow has a separate, private bus
+ * (see gedit_window_get_message_bus()). This makes it easier for plugins to
+ * communicate to other plugins in the same window.
+ *
+ * The concept of the message bus is very simple. You can register a message
+ * type on the bus, specified as a Method at a specific Object Path with a
+ * certain set of Method Arguments. You can then connect callback functions
+ * for this message type on the bus. Whenever a message with the Object Path
+ * and Method for which callbacks are connected is sent over the bus, the
+ * callbacks are called. There is no distinction between Methods and Signals
+ * (signals are simply messages where sender and receiver have switched places).
+ *
+ * <example>
+ * <title>Registering a message type</title>
+ * <programlisting>
+ * GeditMessageBus *bus = gedit_message_bus_get_default ();
+ *
+ * // Register 'method' at '/plugins/example' with one required
+ * // string argument 'arg1'
+ * GeditMessageType *message_type = gedit_message_bus_register ("/plugins/example", "method",
+ * 0,
+ * "arg1", G_TYPE_STRING,
+ * NULL);
+ * </programlisting>
+ * </example>
+ * <example>
+ * <title>Connecting a callback</title>
+ * <programlisting>
+ * static void
+ * example_method_cb (GeditMessageBus *bus,
+ * GeditMessage *message,
+ * gpointer userdata)
+ * {
+ * gchar *arg1 = NULL;
+ *
+ * gedit_message_get (message, "arg1", &arg1, NULL);
+ * g_message ("Evoked /plugins/example.method with: %s", arg1);
+ * g_free (arg1);
+ * }
+ *
+ * GeditMessageBus *bus = gedit_message_bus_get_default ();
+ *
+ * guint id = gedit_message_bus_connect (bus,
+ * "/plugins/example", "method",
+ * example_method_cb,
+ * NULL,
+ * NULL);
+ *
+ * </programlisting>
+ * </example>
+ * <example>
+ * <title>Sending a message</title>
+ * <programlisting>
+ * GeditMessageBus *bus = gedit_message_bus_get_default ();
+ *
+ * gedit_message_bus_send (bus,
+ * "/plugins/example", "method",
+ * "arg1", "Hello World",
+ * NULL);
+ * </programlisting>
+ * </example>
+ */
+
+#define GEDIT_MESSAGE_BUS_GET_PRIVATE(object)(G_TYPE_INSTANCE_GET_PRIVATE((object), GEDIT_TYPE_MESSAGE_BUS, GeditMessageBusPrivate))
+
+typedef struct
+{
+ gchar *object_path;
+ gchar *method;
+
+ GList *listeners;
+} Message;
+
+typedef struct
+{
+ guint id;
+ gboolean blocked;
+
+ GDestroyNotify destroy_data;
+ GeditMessageCallback callback;
+ gpointer userdata;
+} Listener;
+
+typedef struct
+{
+ Message *message;
+ GList *listener;
+} IdMap;
+
+struct _GeditMessageBusPrivate
+{
+ GHashTable *messages;
+ GHashTable *idmap;
+
+ GList *message_queue;
+ guint idle_id;
+
+ guint next_id;
+
+ GHashTable *types; /* mapping from identifier to GeditMessageType */
+};
+
+/* signals */
+enum
+{
+ DISPATCH,
+ REGISTERED,
+ UNREGISTERED,
+ LAST_SIGNAL
+};
+
+static guint message_bus_signals[LAST_SIGNAL];
+
+static void gedit_message_bus_dispatch_real (GeditMessageBus *bus,
+ GeditMessage *message);
+
+G_DEFINE_TYPE(GeditMessageBus, gedit_message_bus, G_TYPE_OBJECT)
+
+static void
+listener_free (Listener *listener)
+{
+ if (listener->destroy_data)
+ listener->destroy_data (listener->userdata);
+
+ g_free (listener);
+}
+
+static void
+message_free (Message *message)
+{
+ g_free (message->method);
+ g_free (message->object_path);
+
+ g_list_foreach (message->listeners, (GFunc)listener_free, NULL);
+ g_list_free (message->listeners);
+
+ g_free (message);
+}
+
+static void
+message_queue_free (GList *queue)
+{
+ g_list_foreach (queue, (GFunc)g_object_unref, NULL);
+ g_list_free (queue);
+}
+
+static void
+gedit_message_bus_finalize (GObject *object)
+{
+ GeditMessageBus *bus = GEDIT_MESSAGE_BUS (object);
+
+ if (bus->priv->idle_id != 0)
+ g_source_remove (bus->priv->idle_id);
+
+ message_queue_free (bus->priv->message_queue);
+
+ g_hash_table_destroy (bus->priv->messages);
+ g_hash_table_destroy (bus->priv->idmap);
+ g_hash_table_destroy (bus->priv->types);
+
+ G_OBJECT_CLASS (gedit_message_bus_parent_class)->finalize (object);
+}
+
+static void
+gedit_message_bus_class_init (GeditMessageBusClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+ object_class->finalize = gedit_message_bus_finalize;
+
+ klass->dispatch = gedit_message_bus_dispatch_real;
+
+ /**
+ * GeditMessageBus::dispatch:
+ * @bus: a #GeditMessageBus
+ * @message: the #GeditMessage to dispatch
+ *
+ * The "dispatch" signal is emitted when a message is to be dispatched.
+ * The message is dispatched in the default handler of this signal.
+ * Primary use of this signal is to customize the dispatch of a message
+ * (for instance to automatically dispatch all messages over DBus).
+ *2
+ */
+ message_bus_signals[DISPATCH] =
+ g_signal_new ("dispatch",
+ G_OBJECT_CLASS_TYPE (object_class),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (GeditMessageBusClass, dispatch),
+ NULL, NULL,
+ g_cclosure_marshal_VOID__OBJECT,
+ G_TYPE_NONE,
+ 1,
+ GEDIT_TYPE_MESSAGE);
+
+ /**
+ * GeditMessageBus::registered:
+ * @bus: a #GeditMessageBus
+ * @message_type: the registered #GeditMessageType
+ *
+ * The "registered" signal is emitted when a message has been registered
+ * on the bus.
+ *
+ */
+ message_bus_signals[REGISTERED] =
+ g_signal_new ("registered",
+ G_OBJECT_CLASS_TYPE (object_class),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (GeditMessageBusClass, registered),
+ NULL, NULL,
+ g_cclosure_marshal_VOID__BOXED,
+ G_TYPE_NONE,
+ 1,
+ GEDIT_TYPE_MESSAGE_TYPE);
+
+ /**
+ * GeditMessageBus::unregistered:
+ * @bus: a #GeditMessageBus
+ * @message_type: the unregistered #GeditMessageType
+ *
+ * The "unregistered" signal is emitted when a message has been
+ * unregistered from the bus.
+ *
+ */
+ message_bus_signals[UNREGISTERED] =
+ g_signal_new ("unregistered",
+ G_OBJECT_CLASS_TYPE (object_class),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (GeditMessageBusClass, unregistered),
+ NULL, NULL,
+ g_cclosure_marshal_VOID__BOXED,
+ G_TYPE_NONE,
+ 1,
+ GEDIT_TYPE_MESSAGE_TYPE);
+
+ g_type_class_add_private (object_class, sizeof(GeditMessageBusPrivate));
+}
+
+static Message *
+message_new (GeditMessageBus *bus,
+ const gchar *object_path,
+ const gchar *method)
+{
+ Message *message = g_new (Message, 1);
+
+ message->object_path = g_strdup (object_path);
+ message->method = g_strdup (method);
+ message->listeners = NULL;
+
+ g_hash_table_insert (bus->priv->messages,
+ gedit_message_type_identifier (object_path, method),
+ message);
+ return message;
+}
+
+static Message *
+lookup_message (GeditMessageBus *bus,
+ const gchar *object_path,
+ const gchar *method,
+ gboolean create)
+{
+ gchar *identifier;
+ Message *message;
+
+ identifier = gedit_message_type_identifier (object_path, method);
+ message = (Message *)g_hash_table_lookup (bus->priv->messages, identifier);
+ g_free (identifier);
+
+ if (!message && !create)
+ return NULL;
+
+ if (!message)
+ message = message_new (bus, object_path, method);
+
+ return message;
+}
+
+static guint
+add_listener (GeditMessageBus *bus,
+ Message *message,
+ GeditMessageCallback callback,
+ gpointer userdata,
+ GDestroyNotify destroy_data)
+{
+ Listener *listener;
+ IdMap *idmap;
+
+ listener = g_new (Listener, 1);
+ listener->id = ++bus->priv->next_id;
+ listener->callback = callback;
+ listener->userdata = userdata;
+ listener->blocked = FALSE;
+ listener->destroy_data = destroy_data;
+
+ message->listeners = g_list_append (message->listeners, listener);
+
+ idmap = g_new (IdMap, 1);
+ idmap->message = message;
+ idmap->listener = g_list_last (message->listeners);
+
+ g_hash_table_insert (bus->priv->idmap, GINT_TO_POINTER (listener->id), idmap);
+ return listener->id;
+}
+
+static void
+remove_listener (GeditMessageBus *bus,
+ Message *message,
+ GList *listener)
+{
+ Listener *lst;
+
+ lst = (Listener *)listener->data;
+
+ /* remove from idmap */
+ g_hash_table_remove (bus->priv->idmap, GINT_TO_POINTER (lst->id));
+ listener_free (lst);
+
+ /* remove from list of listeners */
+ message->listeners = g_list_delete_link (message->listeners, listener);
+
+ if (!message->listeners)
+ {
+ /* remove message because it does not have any listeners */
+ g_hash_table_remove (bus->priv->messages, message);
+ }
+}
+
+static void
+block_listener (GeditMessageBus *bus,
+ Message *message,
+ GList *listener)
+{
+ Listener *lst;
+
+ lst = (Listener *)listener->data;
+ lst->blocked = TRUE;
+}
+
+static void
+unblock_listener (GeditMessageBus *bus,
+ Message *message,
+ GList *listener)
+{
+ Listener *lst;
+
+ lst = (Listener *)listener->data;
+ lst->blocked = FALSE;
+}
+
+static void
+dispatch_message_real (GeditMessageBus *bus,
+ Message *msg,
+ GeditMessage *message)
+{
+ GList *item;
+
+ for (item = msg->listeners; item; item = item->next)
+ {
+ Listener *listener = (Listener *)item->data;
+
+ if (!listener->blocked)
+ listener->callback (bus, message, listener->userdata);
+ }
+}
+
+static void
+gedit_message_bus_dispatch_real (GeditMessageBus *bus,
+ GeditMessage *message)
+{
+ const gchar *object_path;
+ const gchar *method;
+ Message *msg;
+
+ object_path = gedit_message_get_object_path (message);
+ method = gedit_message_get_method (message);
+
+ msg = lookup_message (bus, object_path, method, FALSE);
+
+ if (msg)
+ dispatch_message_real (bus, msg, message);
+}
+
+static void
+dispatch_message (GeditMessageBus *bus,
+ GeditMessage *message)
+{
+ g_signal_emit (bus, message_bus_signals[DISPATCH], 0, message);
+}
+
+static gboolean
+idle_dispatch (GeditMessageBus *bus)
+{
+ GList *list;
+ GList *item;
+
+ /* make sure to set idle_id to 0 first so that any new async messages
+ will be queued properly */
+ bus->priv->idle_id = 0;
+
+ /* reverse queue to get correct delivery order */
+ list = g_list_reverse (bus->priv->message_queue);
+ bus->priv->message_queue = NULL;
+
+ for (item = list; item; item = item->next)
+ {
+ GeditMessage *msg = GEDIT_MESSAGE (item->data);
+
+ dispatch_message (bus, msg);
+ }
+
+ message_queue_free (list);
+ return FALSE;
+}
+
+typedef void (*MatchCallback) (GeditMessageBus *, Message *, GList *);
+
+static void
+process_by_id (GeditMessageBus *bus,
+ guint id,
+ MatchCallback processor)
+{
+ IdMap *idmap;
+
+ idmap = (IdMap *)g_hash_table_lookup (bus->priv->idmap, GINT_TO_POINTER (id));
+
+ if (idmap == NULL)
+ {
+ g_warning ("No handler registered with id `%d'", id);
+ return;
+ }
+
+ processor (bus, idmap->message, idmap->listener);
+}
+
+static void
+process_by_match (GeditMessageBus *bus,
+ const gchar *object_path,
+ const gchar *method,
+ GeditMessageCallback callback,
+ gpointer userdata,
+ MatchCallback processor)
+{
+ Message *message;
+ GList *item;
+
+ message = lookup_message (bus, object_path, method, FALSE);
+
+ if (!message)
+ {
+ g_warning ("No such handler registered for %s.%s", object_path, method);
+ return;
+ }
+
+ for (item = message->listeners; item; item = item->next)
+ {
+ Listener *listener = (Listener *)item->data;
+
+ if (listener->callback == callback &&
+ listener->userdata == userdata)
+ {
+ processor (bus, message, item);
+ return;
+ }
+ }
+
+ g_warning ("No such handler registered for %s.%s", object_path, method);
+}
+
+static void
+gedit_message_bus_init (GeditMessageBus *self)
+{
+ self->priv = GEDIT_MESSAGE_BUS_GET_PRIVATE (self);
+
+ self->priv->messages = g_hash_table_new_full (g_str_hash,
+ g_str_equal,
+ (GDestroyNotify)g_free,
+ (GDestroyNotify)message_free);
+
+ self->priv->idmap = g_hash_table_new_full (g_direct_hash,
+ g_direct_equal,
+ NULL,
+ (GDestroyNotify)g_free);
+
+ self->priv->types = g_hash_table_new_full (g_str_hash,
+ g_str_equal,
+ (GDestroyNotify)g_free,
+ (GDestroyNotify)gedit_message_type_unref);
+}
+
+/**
+ * gedit_message_bus_get_default:
+ *
+ * Get the default application #GeditMessageBus.
+ *
+ * Return value: the default #GeditMessageBus
+ *
+ */
+GeditMessageBus *
+gedit_message_bus_get_default (void)
+{
+ static GeditMessageBus *default_bus = NULL;
+
+ if (G_UNLIKELY (default_bus == NULL))
+ {
+ default_bus = g_object_new (GEDIT_TYPE_MESSAGE_BUS, NULL);
+ g_object_add_weak_pointer (G_OBJECT (default_bus),
+ (gpointer) &default_bus);
+ }
+
+ return default_bus;
+}
+
+/**
+ * gedit_message_bus_new:
+ *
+ * Create a new message bus. Use gedit_message_bus_get_default() to get the
+ * default, application wide, message bus. Creating a new bus is useful for
+ * associating a specific bus with for instance a #GeditWindow.
+ *
+ * Return value: a new #GeditMessageBus
+ *
+ */
+GeditMessageBus *
+gedit_message_bus_new (void)
+{
+ return GEDIT_MESSAGE_BUS (g_object_new (GEDIT_TYPE_MESSAGE_BUS, NULL));
+}
+
+/**
+ * gedit_message_bus_lookup:
+ * @bus: a #GeditMessageBus
+ * @object_path: the object path
+ * @method: the method
+ *
+ * Get the registered #GeditMessageType for @method at @object_path. The
+ * returned #GeditMessageType is owned by the bus and should not be unreffed.
+ *
+ * Return value: the registered #GeditMessageType or %NULL if no message type
+ * is registered for @method at @object_path
+ *
+ */
+GeditMessageType *
+gedit_message_bus_lookup (GeditMessageBus *bus,
+ const gchar *object_path,
+ const gchar *method)
+{
+ gchar *identifier;
+ GeditMessageType *message_type;
+
+ g_return_val_if_fail (GEDIT_IS_MESSAGE_BUS (bus), NULL);
+ g_return_val_if_fail (object_path != NULL, NULL);
+ g_return_val_if_fail (method != NULL, NULL);
+
+ identifier = gedit_message_type_identifier (object_path, method);
+ message_type = GEDIT_MESSAGE_TYPE (g_hash_table_lookup (bus->priv->types, identifier));
+
+ g_free (identifier);
+ return message_type;
+}
+
+/**
+ * gedit_message_bus_register:
+ * @bus: a #GeditMessageBus
+ * @object_path: the object path
+ * @method: the method to register
+ * @num_optional: the number of optional arguments
+ * @...: NULL terminated list of key/gtype method argument pairs
+ *
+ * Register a message on the bus. A message must be registered on the bus before
+ * it can be send. This function registers the type arguments for @method at
+ * @object_path. The arguments are specified with the variable arguments which
+ * should contain pairs of const gchar *key and GType terminated by %NULL. The
+ * last @num_optional arguments are registered as optional (and are thus not
+ * required when sending a message).
+ *
+ * This function emits a #GeditMessageBus::registered signal.
+ *
+ * Return value: the registered #GeditMessageType. The returned reference is
+ * owned by the bus. If you want to keep it alive after
+ * unregistering, use gedit_message_type_ref().
+ *
+ */
+GeditMessageType *
+gedit_message_bus_register (GeditMessageBus *bus,
+ const gchar *object_path,
+ const gchar *method,
+ guint num_optional,
+ ...)
+{
+ gchar *identifier;
+ gpointer data;
+ va_list var_args;
+ GeditMessageType *message_type;
+
+ g_return_val_if_fail (GEDIT_IS_MESSAGE_BUS (bus), NULL);
+
+ if (gedit_message_bus_is_registered (bus, object_path, method))
+ {
+ g_warning ("Message type for '%s.%s' is already registered", object_path, method);
+ return NULL;
+ }
+
+ identifier = gedit_message_type_identifier (object_path, method);
+ data = g_hash_table_lookup (bus->priv->types, identifier);
+
+ va_start (var_args, num_optional);
+ message_type = gedit_message_type_new_valist (object_path,
+ method,
+ num_optional,
+ var_args);
+ va_end (var_args);
+
+ if (message_type)
+ g_hash_table_insert (bus->priv->types, identifier, message_type);
+ else
+ g_free (identifier);
+
+ g_signal_emit (bus, message_bus_signals[REGISTERED], 0, message_type);
+ return message_type;
+}
+
+/**
+ * gedit_message_bus_unregister:
+ * @bus: a #GeditMessageBus
+ * @message_type: the #GeditMessageType to unregister
+ *
+ * Unregisters a previously registered message type. This is especially useful
+ * for plugins which should unregister message types when they are deactivated.
+ *
+ * This function emits the #GeditMessageBus::unregistered signal.
+ *
+ */
+void
+gedit_message_bus_unregister (GeditMessageBus *bus,
+ GeditMessageType *message_type)
+{
+ gchar *identifier;
+
+ g_return_if_fail (GEDIT_IS_MESSAGE_BUS (bus));
+
+ identifier = gedit_message_type_identifier (gedit_message_type_get_object_path (message_type),
+ gedit_message_type_get_method (message_type));
+
+ // Keep message type alive for signal emission
+ gedit_message_type_ref (message_type);
+
+ if (g_hash_table_remove (bus->priv->types, identifier))
+ g_signal_emit (bus, message_bus_signals[UNREGISTERED], 0, message_type);
+
+ gedit_message_type_unref (message_type);
+ g_free (identifier);
+}
+
+typedef struct
+{
+ GeditMessageBus *bus;
+ const gchar *object_path;
+} UnregisterInfo;
+
+static void
+unregister_each (const gchar *identifier,
+ GeditMessageType *message_type,
+ UnregisterInfo *info)
+{
+ if (strcmp (gedit_message_type_get_object_path (message_type),
+ info->object_path) == 0)
+ {
+ gedit_message_bus_unregister (info->bus, message_type);
+ }
+}
+
+/**
+ * gedit_message_bus_unregister_all:
+ * @bus: a #GeditMessageBus
+ * @object_path: the object path
+ *
+ * Unregisters all message types for @object_path. This is especially useful for
+ * plugins which should unregister message types when they are deactivated.
+ *
+ * This function emits the #GeditMessageBus::unregistered signal for all
+ * unregistered message types.
+ *
+ */
+void
+gedit_message_bus_unregister_all (GeditMessageBus *bus,
+ const gchar *object_path)
+{
+ UnregisterInfo info = {bus, object_path};
+
+ g_return_if_fail (GEDIT_IS_MESSAGE_BUS (bus));
+ g_return_if_fail (object_path != NULL);
+
+ g_hash_table_foreach (bus->priv->types,
+ (GHFunc)unregister_each,
+ &info);
+}
+
+/**
+ * gedit_message_bus_is_registered:
+ * @bus: a #GeditMessageBus
+ * @object_path: the object path
+ * @method: the method
+ *
+ * Check whether a message type @method at @object_path is registered on the
+ * bus.
+ *
+ * Return value: %TRUE if the @method at @object_path is a registered message
+ * type on the bus
+ *
+ */
+gboolean
+gedit_message_bus_is_registered (GeditMessageBus *bus,
+ const gchar *object_path,
+ const gchar *method)
+{
+ gchar *identifier;
+ gboolean ret;
+
+ g_return_val_if_fail (GEDIT_IS_MESSAGE_BUS (bus), FALSE);
+ g_return_val_if_fail (object_path != NULL, FALSE);
+ g_return_val_if_fail (method != NULL, FALSE);
+
+ identifier = gedit_message_type_identifier (object_path, method);
+ ret = g_hash_table_lookup (bus->priv->types, identifier) != NULL;
+
+ g_free(identifier);
+ return ret;
+}
+
+/**
+ * gedit_message_bus_connect:
+ * @bus: a #GeditMessageBus
+ * @object_path: the object path
+ * @method: the method
+ * @callback: function to be called when message @method at @object_path is sent
+ * @userdata: userdata to use for the callback
+ * @destroy_data: function to evoke with @userdata as argument when @userdata
+ * needs to be freed
+ *
+ * Connect a callback handler to be evoked when message @method at @object_path
+ * is sent over the bus.
+ *
+ * Return value: the callback identifier
+ *
+ */
+guint
+gedit_message_bus_connect (GeditMessageBus *bus,
+ const gchar *object_path,
+ const gchar *method,
+ GeditMessageCallback callback,
+ gpointer userdata,
+ GDestroyNotify destroy_data)
+{
+ Message *message;
+
+ g_return_val_if_fail (GEDIT_IS_MESSAGE_BUS (bus), 0);
+ g_return_val_if_fail (object_path != NULL, 0);
+ g_return_val_if_fail (method != NULL, 0);
+ g_return_val_if_fail (callback != NULL, 0);
+
+ /* lookup the message and create if it does not exist yet */
+ message = lookup_message (bus, object_path, method, TRUE);
+
+ return add_listener (bus, message, callback, userdata, destroy_data);
+}
+
+/**
+ * gedit_message_bus_disconnect:
+ * @bus: a #GeditMessageBus
+ * @id: the callback id as returned by gedit_message_bus_connect()
+ *
+ * Disconnects a previously connected message callback.
+ *
+ */
+void
+gedit_message_bus_disconnect (GeditMessageBus *bus,
+ guint id)
+{
+ g_return_if_fail (GEDIT_IS_MESSAGE_BUS (bus));
+
+ process_by_id (bus, id, remove_listener);
+}
+
+/**
+ * gedit_message_bus_disconnect_by_func:
+ * @bus: a #GeditMessageBus
+ * @object_path: the object path
+ * @method: the method
+ * @callback: the connected callback
+ * @userdata: the userdata with which the callback was connected
+ *
+ * Disconnects a previously connected message callback by matching the
+ * provided callback function and userdata. See also
+ * gedit_message_bus_disconnect().
+ *
+ */
+void
+gedit_message_bus_disconnect_by_func (GeditMessageBus *bus,
+ const gchar *object_path,
+ const gchar *method,
+ GeditMessageCallback callback,
+ gpointer userdata)
+{
+ g_return_if_fail (GEDIT_IS_MESSAGE_BUS (bus));
+
+ process_by_match (bus, object_path, method, callback, userdata, remove_listener);
+}
+
+/**
+ * gedit_message_bus_block:
+ * @bus: a #GeditMessageBus
+ * @id: the callback id
+ *
+ * Blocks evoking the callback specified by @id. Unblock the callback by
+ * using gedit_message_bus_unblock().
+ *
+ */
+void
+gedit_message_bus_block (GeditMessageBus *bus,
+ guint id)
+{
+ g_return_if_fail (GEDIT_IS_MESSAGE_BUS (bus));
+
+ process_by_id (bus, id, block_listener);
+}
+
+/**
+ * gedit_message_bus_block_by_func:
+ * @bus: a #GeditMessageBus
+ * @object_path: the object path
+ * @method: the method
+ * @callback: the callback to block
+ * @userdata: the userdata with which the callback was connected
+ *
+ * Blocks evoking the callback that matches provided @callback and @userdata.
+ * Unblock the callback using gedit_message_unblock_by_func().
+ *
+ */
+void
+gedit_message_bus_block_by_func (GeditMessageBus *bus,
+ const gchar *object_path,
+ const gchar *method,
+ GeditMessageCallback callback,
+ gpointer userdata)
+{
+ g_return_if_fail (GEDIT_IS_MESSAGE_BUS (bus));
+
+ process_by_match (bus, object_path, method, callback, userdata, block_listener);
+}
+
+/**
+ * gedit_message_bus_unblock:
+ * @bus: a #GeditMessageBus
+ * @id: the callback id
+ *
+ * Unblocks the callback specified by @id.
+ *
+ */
+void
+gedit_message_bus_unblock (GeditMessageBus *bus,
+ guint id)
+{
+ g_return_if_fail (GEDIT_IS_MESSAGE_BUS (bus));
+
+ process_by_id (bus, id, unblock_listener);
+}
+
+/**
+ * gedit_message_bus_unblock_by_func:
+ * @bus: a #GeditMessageBus
+ * @object_path: the object path
+ * @method: the method
+ * @callback: the callback to block
+ * @userdata: the userdata with which the callback was connected
+ *
+ * Unblocks the callback that matches provided @callback and @userdata.
+ *
+ */
+void
+gedit_message_bus_unblock_by_func (GeditMessageBus *bus,
+ const gchar *object_path,
+ const gchar *method,
+ GeditMessageCallback callback,
+ gpointer userdata)
+{
+ g_return_if_fail (GEDIT_IS_MESSAGE_BUS (bus));
+
+ process_by_match (bus, object_path, method, callback, userdata, unblock_listener);
+}
+
+static gboolean
+validate_message (GeditMessage *message)
+{
+ if (!gedit_message_validate (message))
+ {
+ g_warning ("Message '%s.%s' is invalid", gedit_message_get_object_path (message),
+ gedit_message_get_method (message));
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+static void
+send_message_real (GeditMessageBus *bus,
+ GeditMessage *message)
+{
+ if (!validate_message (message))
+ {
+ return;
+ }
+
+ bus->priv->message_queue = g_list_prepend (bus->priv->message_queue,
+ g_object_ref (message));
+
+ if (bus->priv->idle_id == 0)
+ bus->priv->idle_id = g_idle_add_full (G_PRIORITY_HIGH,
+ (GSourceFunc)idle_dispatch,
+ bus,
+ NULL);
+}
+
+/**
+ * gedit_message_bus_send_message:
+ * @bus: a #GeditMessageBus
+ * @message: the message to send
+ *
+ * This sends the provided @message asynchronously over the bus. To send
+ * a message synchronously, use gedit_message_bus_send_message_sync(). The
+ * convenience function gedit_message_bus_send() can be used to easily send
+ * a message without constructing the message object explicitly first.
+ *
+ */
+void
+gedit_message_bus_send_message (GeditMessageBus *bus,
+ GeditMessage *message)
+{
+ g_return_if_fail (GEDIT_IS_MESSAGE_BUS (bus));
+ g_return_if_fail (GEDIT_IS_MESSAGE (message));
+
+ send_message_real (bus, message);
+}
+
+static void
+send_message_sync_real (GeditMessageBus *bus,
+ GeditMessage *message)
+{
+ if (!validate_message (message))
+ {
+ return;
+ }
+
+ dispatch_message (bus, message);
+}
+
+/**
+ * gedit_message_bus_send_message_sync:
+ * @bus: a #GeditMessageBus
+ * @message: the message to send
+ *
+ * This sends the provided @message synchronously over the bus. To send
+ * a message asynchronously, use gedit_message_bus_send_message(). The
+ * convenience function gedit_message_bus_send_sync() can be used to easily send
+ * a message without constructing the message object explicitly first.
+ *
+ */
+void
+gedit_message_bus_send_message_sync (GeditMessageBus *bus,
+ GeditMessage *message)
+{
+ g_return_if_fail (GEDIT_IS_MESSAGE_BUS (bus));
+ g_return_if_fail (GEDIT_IS_MESSAGE (message));
+
+ send_message_sync_real (bus, message);
+}
+
+static GeditMessage *
+create_message (GeditMessageBus *bus,
+ const gchar *object_path,
+ const gchar *method,
+ va_list var_args)
+{
+ GeditMessageType *message_type;
+
+ message_type = gedit_message_bus_lookup (bus, object_path, method);
+
+ if (!message_type)
+ {
+ g_warning ("Could not find message type for '%s.%s'", object_path, method);
+ return NULL;
+ }
+
+ return gedit_message_type_instantiate_valist (message_type,
+ var_args);
+}
+
+/**
+ * gedit_message_bus_send:
+ * @bus: a #GeditMessageBus
+ * @object_path: the object path
+ * @method: the method
+ * @...: NULL terminated list of key/value pairs
+ *
+ * This provides a convenient way to quickly send a message @method at
+ * @object_path asynchronously over the bus. The variable argument list
+ * specifies key (string) value pairs used to construct the message arguments.
+ * To send a message synchronously use gedit_message_bus_send_sync().
+ *
+ */
+void
+gedit_message_bus_send (GeditMessageBus *bus,
+ const gchar *object_path,
+ const gchar *method,
+ ...)
+{
+ va_list var_args;
+ GeditMessage *message;
+
+ va_start (var_args, method);
+
+ message = create_message (bus, object_path, method, var_args);
+
+ if (message)
+ {
+ send_message_real (bus, message);
+ g_object_unref (message);
+ }
+ else
+ {
+ g_warning ("Could not instantiate message");
+ }
+
+ va_end (var_args);
+}
+
+/**
+ * gedit_message_bus_send_sync:
+ * @bus: a #GeditMessageBus
+ * @object_path: the object path
+ * @method: the method
+ * @...: NULL terminated list of key/value pairs
+ *
+ * This provides a convenient way to quickly send a message @method at
+ * @object_path synchronously over the bus. The variable argument list
+ * specifies key (string) value pairs used to construct the message
+ * arguments. To send a message asynchronously use gedit_message_bus_send().
+ *
+ * Return value: the constructed #GeditMessage. The caller owns a reference
+ * to the #GeditMessage and should call g_object_unref() when
+ * it is no longer needed
+ */
+GeditMessage *
+gedit_message_bus_send_sync (GeditMessageBus *bus,
+ const gchar *object_path,
+ const gchar *method,
+ ...)
+{
+ va_list var_args;
+ GeditMessage *message;
+
+ va_start (var_args, method);
+ message = create_message (bus, object_path, method, var_args);
+
+ if (message)
+ send_message_sync_real (bus, message);
+
+ va_end (var_args);
+
+ return message;
+}
+
+// ex:ts=8:noet:
Added: trunk/gedit/gedit-message-bus.h
==============================================================================
--- (empty file)
+++ trunk/gedit/gedit-message-bus.h Mon Dec 29 18:52:22 2008
@@ -0,0 +1,123 @@
+#ifndef __GEDIT_MESSAGE_BUS_H__
+#define __GEDIT_MESSAGE_BUS_H__
+
+#include <glib-object.h>
+#include <gedit/gedit-message.h>
+#include <gedit/gedit-message-type.h>
+
+G_BEGIN_DECLS
+
+#define GEDIT_TYPE_MESSAGE_BUS (gedit_message_bus_get_type ())
+#define GEDIT_MESSAGE_BUS(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GEDIT_TYPE_MESSAGE_BUS, GeditMessageBus))
+#define GEDIT_MESSAGE_BUS_CONST(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GEDIT_TYPE_MESSAGE_BUS, GeditMessageBus const))
+#define GEDIT_MESSAGE_BUS_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GEDIT_TYPE_MESSAGE_BUS, GeditMessageBusClass))
+#define GEDIT_IS_MESSAGE_BUS(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GEDIT_TYPE_MESSAGE_BUS))
+#define GEDIT_IS_MESSAGE_BUS_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GEDIT_TYPE_MESSAGE_BUS))
+#define GEDIT_MESSAGE_BUS_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GEDIT_TYPE_MESSAGE_BUS, GeditMessageBusClass))
+
+typedef struct _GeditMessageBus GeditMessageBus;
+typedef struct _GeditMessageBusClass GeditMessageBusClass;
+typedef struct _GeditMessageBusPrivate GeditMessageBusPrivate;
+
+struct _GeditMessageBus {
+ GObject parent;
+
+ GeditMessageBusPrivate *priv;
+};
+
+struct _GeditMessageBusClass {
+ GObjectClass parent_class;
+
+ void (*dispatch) (GeditMessageBus *bus,
+ GeditMessage *message);
+ void (*registered) (GeditMessageBus *bus,
+ GeditMessageType *message_type);
+ void (*unregistered) (GeditMessageBus *bus,
+ GeditMessageType *message_type);
+};
+
+typedef void (* GeditMessageCallback) (GeditMessageBus *bus,
+ GeditMessage *message,
+ gpointer userdata);
+
+GType gedit_message_bus_get_type (void) G_GNUC_CONST;
+
+GeditMessageBus *gedit_message_bus_get_default (void);
+GeditMessageBus *gedit_message_bus_new (void);
+
+/* registering messages */
+GeditMessageType *gedit_message_bus_lookup (GeditMessageBus *bus,
+ const gchar *object_path,
+ const gchar *method);
+GeditMessageType *gedit_message_bus_register (GeditMessageBus *bus,
+ const gchar *object_path,
+ const gchar *method,
+ guint num_optional,
+ ...) G_GNUC_NULL_TERMINATED;
+
+void gedit_message_bus_unregister (GeditMessageBus *bus,
+ GeditMessageType *message_type);
+
+void gedit_message_bus_unregister_all (GeditMessageBus *bus,
+ const gchar *object_path);
+
+gboolean gedit_message_bus_is_registered (GeditMessageBus *bus,
+ const gchar *object_path,
+ const gchar *method);
+
+
+
+/* connecting to message events */
+guint gedit_message_bus_connect (GeditMessageBus *bus,
+ const gchar *object_path,
+ const gchar *method,
+ GeditMessageCallback callback,
+ gpointer userdata,
+ GDestroyNotify destroy_data);
+
+void gedit_message_bus_disconnect (GeditMessageBus *bus,
+ guint id);
+
+void gedit_message_bus_disconnect_by_func (GeditMessageBus *bus,
+ const gchar *object_path,
+ const gchar *method,
+ GeditMessageCallback callback,
+ gpointer userdata);
+
+/* blocking message event callbacks */
+void gedit_message_bus_block (GeditMessageBus *bus,
+ guint id);
+void gedit_message_bus_block_by_func (GeditMessageBus *bus,
+ const gchar *object_path,
+ const gchar *method,
+ GeditMessageCallback callback,
+ gpointer userdata);
+
+void gedit_message_bus_unblock (GeditMessageBus *bus,
+ guint id);
+void gedit_message_bus_unblock_by_func (GeditMessageBus *bus,
+ const gchar *object_path,
+ const gchar *method,
+ GeditMessageCallback callback,
+ gpointer userdata);
+
+/* sending messages */
+void gedit_message_bus_send_message (GeditMessageBus *bus,
+ GeditMessage *message);
+void gedit_message_bus_send_message_sync (GeditMessageBus *bus,
+ GeditMessage *message);
+
+void gedit_message_bus_send (GeditMessageBus *bus,
+ const gchar *object_path,
+ const gchar *method,
+ ...) G_GNUC_NULL_TERMINATED;
+GeditMessage *gedit_message_bus_send_sync (GeditMessageBus *bus,
+ const gchar *object_path,
+ const gchar *method,
+ ...) G_GNUC_NULL_TERMINATED;
+
+G_END_DECLS
+
+#endif /* __GEDIT_MESSAGE_BUS_H__ */
+
+// ex:ts=8:noet:
Added: trunk/gedit/gedit-message-type.c
==============================================================================
--- (empty file)
+++ trunk/gedit/gedit-message-type.c Mon Dec 29 18:52:22 2008
@@ -0,0 +1,486 @@
+#include "gedit-message-type.h"
+
+/**
+ * SECTION:gedit-message-type
+ * @short_description: message type description
+ * @include: gedit/gedit-message-type.h
+ *
+ * A message type is a prototype description for a #GeditMessage used to
+ * transmit messages on a #GeditMessageBus. The message type describes
+ * the Object Path, Method and Arguments of the message.
+ *
+ * A message type can contain any number of required and optional arguments.
+ * To instantiate a #GeditMessage from a #GeditMessageType, use
+ * gedit_message_type_instantiate().
+ *
+ * Registering a new message type on a #GeditMessageBus with
+ * gedit_message_bus_register() internally creates a new #GeditMessageType. When
+ * then using gedit_message_bus_send(), an actual instantiation of the
+ * registered type is internally created and send over the bus.
+ *
+ * <example>
+ * <programlisting>
+ * // Defining a new message type
+ * GeditMessageType *message_type = gedit_message_type_new ("/plugins/example",
+ * "method",
+ * 0,
+ * "arg1", G_TYPE_STRING,
+ * NULL);
+ *
+ * // Instantiating an actual message from the type
+ * GeditMessage *message = gedit_message_type_instantiate (message_type,
+ * "arg1", "Hello World",
+ * NULL);
+ * </programlisting>
+ * </example>
+ *
+ */
+typedef struct
+{
+ GType type;
+ gboolean required;
+} ArgumentInfo;
+
+struct _GeditMessageType
+{
+ gint ref_count;
+
+ gchar *object_path;
+ gchar *method;
+
+ guint num_arguments;
+ guint num_required;
+
+ GHashTable *arguments; // mapping of key -> ArgumentInfo
+};
+
+/**
+ * gedit_message_type_ref:
+ * @message_type: the #GeditMessageType
+ *
+ * Increases the reference count on @message_type.
+ *
+ * Return value: @message_type
+ *
+ */
+GeditMessageType *
+gedit_message_type_ref (GeditMessageType *message_type)
+{
+ g_return_val_if_fail (message_type != NULL, NULL);
+ g_atomic_int_inc (&message_type->ref_count);
+
+ return message_type;
+}
+
+/**
+ * gedit_message_type_unref:
+ * @message_type: the #GeditMessageType
+ *
+ * Decreases the reference count on @message_type. When the reference count
+ * drops to 0, @message_type is destroyed.
+ *
+ */
+void
+gedit_message_type_unref (GeditMessageType *message_type)
+{
+ g_return_if_fail (message_type != NULL);
+
+ if (!g_atomic_int_dec_and_test (&message_type->ref_count))
+ return;
+
+ g_free (message_type->object_path);
+ g_free (message_type->method);
+
+ g_hash_table_destroy (message_type->arguments);
+ g_free (message_type);
+}
+
+/**
+ * gedit_message_type_get_type:
+ *
+ * Retrieves the GType object which is associated with the
+ * #GeditMessageType class.
+ *
+ * Return value: the GType associated with #GeditMessageType.
+ **/
+GType
+gedit_message_type_get_type (void)
+{
+ static GType our_type = 0;
+
+ if (!our_type)
+ our_type = g_boxed_type_register_static (
+ "GeditMessageType",
+ (GBoxedCopyFunc) gedit_message_type_ref,
+ (GBoxedFreeFunc) gedit_message_type_unref);
+
+ return our_type;
+}
+
+/**
+ * gedit_message_type_identifier:
+ * @object_path: the object path
+ * @method: the method
+ *
+ * Get the string identifier for @method at @object_path.
+ *
+ * Return value: the identifier for @method at @object_path
+ *
+ */
+gchar *
+gedit_message_type_identifier (const gchar *object_path,
+ const gchar *method)
+{
+ return g_strconcat (object_path, ".", method, NULL);
+}
+
+/**
+ * gedit_message_type_is_supported:
+ * @type: the #GType
+ *
+ * Returns if @type is #GType supported by the message system.
+ *
+ * Return value: %TRUE if @type is a supported #GType
+ *
+ */
+gboolean
+gedit_message_type_is_supported (GType type)
+{
+ gint i = 0;
+
+ static const GType type_list[] =
+ {
+ G_TYPE_BOOLEAN,
+ G_TYPE_CHAR,
+ G_TYPE_UCHAR,
+ G_TYPE_INT,
+ G_TYPE_UINT,
+ G_TYPE_LONG,
+ G_TYPE_ULONG,
+ G_TYPE_INT64,
+ G_TYPE_UINT64,
+ G_TYPE_ENUM,
+ G_TYPE_FLAGS,
+ G_TYPE_FLOAT,
+ G_TYPE_DOUBLE,
+ G_TYPE_STRING,
+ G_TYPE_POINTER,
+ G_TYPE_BOXED,
+ G_TYPE_OBJECT,
+ G_TYPE_INVALID
+ };
+
+ if (!G_TYPE_IS_VALUE_TYPE (type))
+ return FALSE;
+
+ while (type_list[i] != G_TYPE_INVALID)
+ {
+ if (g_type_is_a (type, type_list[i]))
+ return TRUE;
+ i++;
+ }
+
+ return FALSE;
+}
+
+/**
+ * gedit_message_type_new_valist:
+ * @object_path: the object path
+ * @method: the method
+ * @num_optional: number of optional arguments
+ * @var_args: key/gtype pair variable argument list
+ *
+ * Create a new #GeditMessageType for @method at @object_path. Argument names
+ * and values are supplied by the NULL terminated variable argument list.
+ * The last @num_optional provided arguments are considered optional.
+ *
+ * Return value: the newly constructed #GeditMessageType
+ *
+ */
+GeditMessageType *
+gedit_message_type_new_valist (const gchar *object_path,
+ const gchar *method,
+ guint num_optional,
+ va_list var_args)
+{
+ GeditMessageType *message_type;
+
+ g_return_val_if_fail (object_path != NULL, NULL);
+ g_return_val_if_fail (method != NULL, NULL);
+
+ message_type = g_new0(GeditMessageType, 1);
+
+ message_type->ref_count = 1;
+ message_type->object_path = g_strdup(object_path);
+ message_type->method = g_strdup(method);
+ message_type->num_arguments = 0;
+ message_type->arguments = g_hash_table_new_full (g_str_hash,
+ g_str_equal,
+ (GDestroyNotify)g_free,
+ (GDestroyNotify)g_free);
+
+ gedit_message_type_set_valist (message_type, num_optional, var_args);
+ return message_type;
+}
+
+/**
+ * gedit_message_type_new:
+ * @object_path: the object path
+ * @method: the method
+ * @num_optional: number of optional arguments
+ * @...: key/gtype pair variable argument list
+ *
+ * Create a new #GeditMessageType for @method at @object_path. Argument names
+ * and values are supplied by the NULL terminated variable argument list.
+ * The last @num_optional provided arguments are considered optional.
+ *
+ * Return value: the newly constructed #GeditMessageType
+ *
+ */
+GeditMessageType *
+gedit_message_type_new (const gchar *object_path,
+ const gchar *method,
+ guint num_optional,
+ ...)
+{
+ GeditMessageType *message_type;
+ va_list var_args;
+
+ va_start(var_args, num_optional);
+ message_type = gedit_message_type_new_valist (object_path, method, num_optional, var_args);
+ va_end(var_args);
+
+ return message_type;
+}
+
+/**
+ * gedit_message_type_set:
+ * @message_type: the #GeditMessageType
+ * @num_optional: number of optional arguments
+ * @...: key/gtype pair variable argument list
+ *
+ * Sets argument names/types supplied by the NULL terminated variable
+ * argument list. The last @num_optional provided arguments are considered
+ * optional.
+ *
+ */
+void
+gedit_message_type_set (GeditMessageType *message_type,
+ guint num_optional,
+ ...)
+{
+ va_list va_args;
+
+ va_start (va_args, num_optional);
+ gedit_message_type_set_valist (message_type, num_optional, va_args);
+ va_end (va_args);
+}
+
+/**
+ * gedit_message_type_set_valist:
+ * @message_type: the #GeditMessageType
+ * @num_optional: number of optional arguments
+ * @var_args: key/gtype pair variable argument list
+ *
+ * Sets argument names/types supplied by the NULL terminated variable
+ * argument list @var_args. The last @num_optional provided arguments are
+ * considered optional.
+ *
+ */
+void
+gedit_message_type_set_valist (GeditMessageType *message_type,
+ guint num_optional,
+ va_list var_args)
+{
+ const gchar *key;
+ ArgumentInfo **optional = g_new0(ArgumentInfo *, num_optional);
+ guint i;
+ guint added = 0;
+
+ // parse key -> gtype pair arguments
+ while ((key = va_arg (var_args, const gchar *)) != NULL)
+ {
+ // get corresponding GType
+ GType gtype = va_arg (var_args, GType);
+ ArgumentInfo *info;
+
+ if (!gedit_message_type_is_supported (gtype))
+ {
+ g_error ("Message type '%s' is not supported", g_type_name (gtype));
+
+ gedit_message_type_unref (message_type);
+ g_free (optional);
+
+ return;
+ }
+
+ info = g_new(ArgumentInfo, 1);
+ info->type = gtype;
+ info->required = TRUE;
+
+ g_hash_table_insert (message_type->arguments, g_strdup (key), info);
+
+ ++message_type->num_arguments;
+ ++added;
+
+ if (num_optional > 0)
+ {
+ for (i = 0; i < num_optional - 1; ++i)
+ {
+ optional[i + 1] = optional[i];
+ }
+
+ *optional = info;
+ }
+ }
+
+ message_type->num_required += added;
+
+ // set required for last num_optional arguments
+ for (i = 0; i < num_optional; ++i)
+ {
+ if (optional[i])
+ {
+ optional[i]->required = FALSE;
+ --message_type->num_required;
+ }
+ }
+
+ g_free (optional);
+}
+
+/**
+ * gedit_message_type_instantiate_valist:
+ * @message_type: the #GeditMessageType
+ * @va_args: NULL terminated variable list of key/value pairs
+ *
+ * Instantiate a new message from the message type with specific values
+ * for the message arguments.
+ *
+ * Return value: the newly created message
+ *
+ */
+GeditMessage *
+gedit_message_type_instantiate_valist (GeditMessageType *message_type,
+ va_list va_args)
+{
+ GeditMessage *message;
+
+ g_return_val_if_fail (message_type != NULL, NULL);
+
+ message = GEDIT_MESSAGE (g_object_new (GEDIT_TYPE_MESSAGE, "type", message_type, NULL));
+ gedit_message_set_valist (message, va_args);
+
+ return message;
+}
+
+/**
+ * gedit_message_type_instantiate:
+ * @message_type: the #GeditMessageType
+ * @...: NULL terminated variable list of key/value pairs
+ *
+ * Instantiate a new message from the message type with specific values
+ * for the message arguments.
+ *
+ * Return value: the newly created message
+ *
+ */
+GeditMessage *
+gedit_message_type_instantiate (GeditMessageType *message_type,
+ ...)
+{
+ GeditMessage *message;
+ va_list va_args;
+
+ va_start (va_args, message_type);
+ message = gedit_message_type_instantiate_valist (message_type, va_args);
+ va_end (va_args);
+
+ return message;
+}
+
+/**
+ * gedit_message_type_get_object_path:
+ * @message_type: the #GeditMessageType
+ *
+ * Get the message type object path.
+ *
+ * Return value: the message type object path
+ *
+ */
+const gchar *
+gedit_message_type_get_object_path (GeditMessageType *message_type)
+{
+ return message_type->object_path;
+}
+
+/**
+ * gedit_message_type_get_method:
+ * @message_type: the #GeditMessageType
+ *
+ * Get the message type method.
+ *
+ * Return value: the message type method
+ *
+ */
+const gchar *
+gedit_message_type_get_method (GeditMessageType *message_type)
+{
+ return message_type->method;
+}
+
+/**
+ * gedit_message_type_lookup:
+ * @message_type: the #GeditMessageType
+ * @key: the argument key
+ *
+ * Get the argument key #GType.
+ *
+ * Return value: the #GType of @key
+ *
+ */
+GType
+gedit_message_type_lookup (GeditMessageType *message_type,
+ const gchar *key)
+{
+ ArgumentInfo *info = g_hash_table_lookup (message_type->arguments, key);
+
+ if (!info)
+ return G_TYPE_INVALID;
+
+ return info->type;
+}
+
+typedef struct
+{
+ GeditMessageTypeForeach func;
+ gpointer user_data;
+} ForeachInfo;
+
+static void
+foreach_gtype (const gchar *key,
+ ArgumentInfo *info,
+ ForeachInfo *finfo)
+{
+ finfo->func (key, info->type, info->required, finfo->user_data);
+}
+
+/**
+ * gedit_message_type_foreach:
+ * @message_type: the #GeditMessageType
+ * @func: the callback function
+ * @user_data: user data supplied to the callback function
+ *
+ * Calls @func for each argument in the message type.
+ *
+ */
+void
+gedit_message_type_foreach (GeditMessageType *message_type,
+ GeditMessageTypeForeach func,
+ gpointer user_data)
+{
+ ForeachInfo info = {func, user_data};
+ g_hash_table_foreach (message_type->arguments, (GHFunc)foreach_gtype, &info);
+}
+
+// ex:ts=8:noet:
Added: trunk/gedit/gedit-message-type.h
==============================================================================
--- (empty file)
+++ trunk/gedit/gedit-message-type.h Mon Dec 29 18:52:22 2008
@@ -0,0 +1,66 @@
+#ifndef __GEDIT_MESSAGE_TYPE_H__
+#define __GEDIT_MESSAGE_TYPE_H__
+
+#include <glib-object.h>
+#include <stdarg.h>
+
+#include "gedit-message.h"
+
+G_BEGIN_DECLS
+
+#define GEDIT_TYPE_MESSAGE_TYPE (gedit_message_type_get_type ())
+#define GEDIT_MESSAGE_TYPE(x) ((GeditMessageType *)(x))
+
+typedef void (*GeditMessageTypeForeach) (const gchar *key,
+ GType type,
+ gboolean required,
+ gpointer user_data);
+
+typedef struct _GeditMessageType GeditMessageType;
+
+GType gedit_message_type_get_type (void) G_GNUC_CONST;
+
+gboolean gedit_message_type_is_supported (GType type);
+gchar *gedit_message_type_identifier (const gchar *object_path,
+ const gchar *method);
+
+GeditMessageType *gedit_message_type_new (const gchar *object_path,
+ const gchar *method,
+ guint num_optional,
+ ...) G_GNUC_NULL_TERMINATED;
+GeditMessageType *gedit_message_type_new_valist (const gchar *object_path,
+ const gchar *method,
+ guint num_optional,
+ va_list va_args);
+
+void gedit_message_type_set (GeditMessageType *message_type,
+ guint num_optional,
+ ...) G_GNUC_NULL_TERMINATED;
+void gedit_message_type_set_valist (GeditMessageType *message_type,
+ guint num_optional,
+ va_list va_args);
+
+GeditMessageType *gedit_message_type_ref (GeditMessageType *message_type);
+void gedit_message_type_unref (GeditMessageType *message_type);
+
+
+GeditMessage *gedit_message_type_instantiate_valist (GeditMessageType *message_type,
+ va_list va_args);
+GeditMessage *gedit_message_type_instantiate (GeditMessageType *message_type,
+ ...) G_GNUC_NULL_TERMINATED;
+
+const gchar *gedit_message_type_get_object_path (GeditMessageType *message_type);
+const gchar *gedit_message_type_get_method (GeditMessageType *message_type);
+
+GType gedit_message_type_lookup (GeditMessageType *message_type,
+ const gchar *key);
+
+void gedit_message_type_foreach (GeditMessageType *message_type,
+ GeditMessageTypeForeach func,
+ gpointer user_data);
+
+G_END_DECLS
+
+#endif /* __GEDIT_MESSAGE_TYPE_H__ */
+
+// ex:ts=8:noet:
Added: trunk/gedit/gedit-message.c
==============================================================================
--- (empty file)
+++ trunk/gedit/gedit-message.c Mon Dec 29 18:52:22 2008
@@ -0,0 +1,591 @@
+#include "gedit-message.h"
+#include "gedit-message-type.h"
+
+#include <string.h>
+#include <gobject/gvaluecollector.h>
+
+/**
+ * SECTION:gedit-message
+ * @short_description: message bus message object
+ * @include: gedit/gedit-message.h
+ *
+ * Communication on a #GeditMessageBus is done through messages. Messages are
+ * sent over the bus and received by connecting callbacks on the message bus.
+ * A #GeditMessage is an instantiation of a #GeditMessageType, containing
+ * values for the arguments as specified in the message type.
+ *
+ * A message can be seen as a method call, or signal emission depending on
+ * who is the sender and who is the receiver. There is no explicit distinction
+ * between methods and signals.
+ *
+ */
+#define GEDIT_MESSAGE_GET_PRIVATE(object)(G_TYPE_INSTANCE_GET_PRIVATE((object), GEDIT_TYPE_MESSAGE, GeditMessagePrivate))
+
+enum {
+ PROP_0,
+
+ PROP_OBJECT_PATH,
+ PROP_METHOD,
+ PROP_TYPE
+};
+
+struct _GeditMessagePrivate
+{
+ GeditMessageType *type;
+ gboolean valid;
+
+ GHashTable *values;
+};
+
+G_DEFINE_TYPE (GeditMessage, gedit_message, G_TYPE_OBJECT)
+
+static void
+gedit_message_finalize (GObject *object)
+{
+ GeditMessage *message = GEDIT_MESSAGE (object);
+
+ gedit_message_type_unref (message->priv->type);
+ g_hash_table_destroy (message->priv->values);
+
+ G_OBJECT_CLASS (gedit_message_parent_class)->finalize (object);
+}
+
+static void
+gedit_message_get_property (GObject *object,
+ guint prop_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ GeditMessage *msg = GEDIT_MESSAGE (object);
+
+ switch (prop_id)
+ {
+ case PROP_OBJECT_PATH:
+ g_value_set_string (value, gedit_message_type_get_object_path (msg->priv->type));
+ break;
+ case PROP_METHOD:
+ g_value_set_string (value, gedit_message_type_get_method (msg->priv->type));
+ break;
+ case PROP_TYPE:
+ g_value_set_boxed (value, msg->priv->type);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+gedit_message_set_property (GObject *object,
+ guint prop_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ GeditMessage *msg = GEDIT_MESSAGE (object);
+
+ switch (prop_id)
+ {
+ case PROP_TYPE:
+ msg->priv->type = GEDIT_MESSAGE_TYPE (g_value_dup_boxed (value));
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+static GValue *
+add_value (GeditMessage *message,
+ const gchar *key)
+{
+ GValue *value;
+ GType type = gedit_message_type_lookup (message->priv->type, key);
+
+ if (type == G_TYPE_INVALID)
+ return NULL;
+
+ value = g_new0 (GValue, 1);
+ g_value_init (value, type);
+ g_value_reset (value);
+
+ g_hash_table_insert (message->priv->values, g_strdup (key), value);
+
+ return value;
+}
+
+static void
+gedit_message_class_init (GeditMessageClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS(klass);
+
+ object_class->finalize = gedit_message_finalize;
+ object_class->get_property = gedit_message_get_property;
+ object_class->set_property = gedit_message_set_property;
+
+ /**
+ * GeditMessage:object_path:
+ *
+ * The messages object path (e.g. /gedit/object/path).
+ *
+ */
+ g_object_class_install_property (object_class, PROP_OBJECT_PATH,
+ g_param_spec_string ("object-path",
+ "OBJECT_PATH",
+ "The message object path",
+ NULL,
+ G_PARAM_READABLE |
+ G_PARAM_STATIC_STRINGS));
+
+ /**
+ * GeditMessage:method:
+ *
+ * The messages method.
+ *
+ */
+ g_object_class_install_property (object_class, PROP_METHOD,
+ g_param_spec_string ("method",
+ "METHOD",
+ "The message method",
+ NULL,
+ G_PARAM_READABLE |
+ G_PARAM_STATIC_STRINGS));
+
+ /**
+ * GeditMEssage:type:
+ *
+ * The message type.
+ *
+ */
+ g_object_class_install_property (object_class, PROP_TYPE,
+ g_param_spec_boxed ("type",
+ "TYPE",
+ "The message type",
+ GEDIT_TYPE_MESSAGE_TYPE,
+ G_PARAM_READWRITE |
+ G_PARAM_CONSTRUCT_ONLY |
+ G_PARAM_STATIC_STRINGS));
+
+ g_type_class_add_private (object_class, sizeof(GeditMessagePrivate));
+}
+
+static void
+destroy_value (GValue *value)
+{
+ g_value_unset (value);
+ g_free (value);
+}
+
+static void
+gedit_message_init (GeditMessage *self)
+{
+ self->priv = GEDIT_MESSAGE_GET_PRIVATE (self);
+
+ self->priv->values = g_hash_table_new_full (g_str_hash,
+ g_str_equal,
+ (GDestroyNotify)g_free,
+ (GDestroyNotify)destroy_value);
+}
+
+static gboolean
+set_value_real (GValue *to,
+ const GValue *from)
+{
+ GType from_type;
+ GType to_type;
+
+ from_type = G_VALUE_TYPE (from);
+ to_type = G_VALUE_TYPE (to);
+
+ if (!g_type_is_a (from_type, to_type))
+ {
+ if (!g_value_transform (from, to))
+ {
+ g_warning ("%s: Unable to make conversion from %s to %s",
+ G_STRLOC,
+ g_type_name (from_type),
+ g_type_name (to_type));
+ return FALSE;
+ }
+
+ return TRUE;
+ }
+
+ g_value_copy (from, to);
+ return TRUE;
+}
+
+inline static GValue *
+value_lookup (GeditMessage *message,
+ const gchar *key,
+ gboolean create)
+{
+ GValue *ret = (GValue *)g_hash_table_lookup (message->priv->values, key);
+
+ if (!ret && create)
+ ret = add_value (message, key);
+
+ return ret;
+}
+
+/**
+ * gedit_message_get_method:
+ * @message: the #GeditMessage
+ *
+ * Get the message method.
+ *
+ * Return value: the message method
+ *
+ */
+const gchar *
+gedit_message_get_method (GeditMessage *message)
+{
+ g_return_val_if_fail (GEDIT_IS_MESSAGE (message), NULL);
+
+ return gedit_message_type_get_method (message->priv->type);
+}
+
+/**
+ * gedit_message_get_object_path:
+ * @message: the #GeditMessage
+ *
+ * Get the message object path.
+ *
+ * Return value: the message object path
+ *
+ */
+const gchar *
+gedit_message_get_object_path (GeditMessage *message)
+{
+ g_return_val_if_fail (GEDIT_IS_MESSAGE (message), NULL);
+
+ return gedit_message_type_get_object_path (message->priv->type);
+}
+
+/**
+ * gedit_message_set:
+ * @message: the #GeditMessage
+ * @...: a NULL terminated variable list of key/value pairs
+ *
+ * Set values of message arguments. The supplied @var_args should contain
+ * pairs of keys and argument values.
+ *
+ */
+void
+gedit_message_set (GeditMessage *message,
+ ...)
+{
+ va_list ap;
+
+ g_return_if_fail (GEDIT_IS_MESSAGE (message));
+
+ va_start (ap, message);
+ gedit_message_set_valist (message, ap);
+ va_end (ap);
+}
+
+/**
+ * gedit_message_set_valist:
+ * @message: the #GeditMessage
+ * @var_args: a NULL terminated variable list of key/value pairs
+ *
+ * Set values of message arguments. The supplied @var_args should contain
+ * pairs of keys and argument values.
+ *
+ */
+void
+gedit_message_set_valist (GeditMessage *message,
+ va_list var_args)
+{
+ const gchar *key;
+
+ g_return_if_fail (GEDIT_IS_MESSAGE (message));
+
+ while ((key = va_arg (var_args, const gchar *)) != NULL)
+ {
+ /* lookup the key */
+ GValue *container = value_lookup (message, key, TRUE);
+ GValue value = {0,};
+ gchar *error = NULL;
+
+ if (!container)
+ {
+ g_warning ("%s: Cannot set value for %s, does not exist",
+ G_STRLOC,
+ key);
+
+ /* skip value */
+ va_arg (var_args, gpointer);
+ continue;
+ }
+
+ g_value_init (&value, G_VALUE_TYPE (container));
+ G_VALUE_COLLECT (&value, var_args, 0, &error);
+
+ if (error)
+ {
+ g_warning ("%s: %s", G_STRLOC, error);
+ continue;
+ }
+
+ set_value_real (container, &value);
+ g_value_unset (&value);
+ }
+}
+
+/**
+ * gedit_message_set_value:
+ * @message: the #GeditMessage
+ * @key: the argument key
+ * @value: the argument value
+ *
+ * Set value of message argument @key to @value.
+ *
+ */
+void
+gedit_message_set_value (GeditMessage *message,
+ const gchar *key,
+ GValue *value)
+{
+ GValue *container;
+ g_return_if_fail (GEDIT_IS_MESSAGE (message));
+
+ container = value_lookup (message, key, TRUE);
+
+ if (!container)
+ {
+ g_warning ("%s: Cannot set value for %s, does not exist",
+ G_STRLOC,
+ key);
+ return;
+ }
+
+ set_value_real (container, value);
+}
+
+/**
+ * gedit_message_set_valuesv:
+ * @message: the #GeditMessage
+ * @keys: keys to set values for
+ * @values: values to set
+ * @n_values: number of arguments to set values for
+ *
+ * Set message argument values.
+ *
+ */
+void
+gedit_message_set_valuesv (GeditMessage *message,
+ const gchar **keys,
+ GValue *values,
+ gint n_values)
+{
+ gint i;
+
+ g_return_if_fail (GEDIT_IS_MESSAGE (message));
+
+ for (i = 0; i < n_values; i++)
+ {
+ gedit_message_set_value (message, keys[i], &values[i]);
+ }
+}
+
+/**
+ * gedit_message_get:
+ * @message: the #GeditMessage
+ * @...: a NULL variable argument list of key/value container pairs
+ *
+ * Get values of message arguments. The supplied @var_args should contain
+ * pairs of keys and pointers to variables which are set to the argument
+ * value for the specified key.
+ *
+ */
+void
+gedit_message_get (GeditMessage *message,
+ ...)
+{
+ va_list ap;
+
+ g_return_if_fail (GEDIT_IS_MESSAGE (message));
+
+ va_start (ap, message);
+ gedit_message_get_valist (message, ap);
+ va_end (ap);
+}
+
+/**
+ * gedit_message_get_valist:
+ * @message: the #GeditMessage
+ * @var_args: a NULL variable argument list of key/value container pairs
+ *
+ * Get values of message arguments. The supplied @var_args should contain
+ * pairs of keys and pointers to variables which are set to the argument
+ * value for the specified key.
+ *
+ */
+void
+gedit_message_get_valist (GeditMessage *message,
+ va_list var_args)
+{
+ const gchar *key;
+
+ g_return_if_fail (GEDIT_IS_MESSAGE (message));
+
+ while ((key = va_arg (var_args, const gchar *)) != NULL)
+ {
+ GValue *container;
+ GValue copy = {0,};
+ gchar *error = NULL;
+
+ container = value_lookup (message, key, FALSE);
+
+ if (!container)
+ {
+ /* skip value */
+ va_arg (var_args, gpointer);
+ continue;
+ }
+
+ /* copy the value here, to be sure it isn't tainted */
+ g_value_init (©, G_VALUE_TYPE (container));
+ g_value_copy (container, ©);
+
+ G_VALUE_LCOPY (©, var_args, 0, &error);
+
+ if (error)
+ {
+ g_warning ("%s: %s", G_STRLOC, error);
+ g_free (error);
+
+ /* purposely leak the value here, because it might
+ be in a bad state */
+ continue;
+ }
+
+ g_value_unset (©);
+ }
+}
+
+/**
+ * gedit_message_get_value:
+ * @message: the #GeditMessage
+ * @key: the argument key
+ * @value: value return container
+ *
+ * Get the value of a specific message argument. @value will be initialized
+ * with the correct type.
+ *
+ */
+void
+gedit_message_get_value (GeditMessage *message,
+ const gchar *key,
+ GValue *value)
+{
+ GValue *container;
+
+ g_return_if_fail (GEDIT_IS_MESSAGE (message));
+
+ container = value_lookup (message, key, FALSE);
+
+ if (!container)
+ {
+ g_warning ("%s: Invalid key `%s'",
+ G_STRLOC,
+ key);
+ return;
+ }
+
+ g_value_init (value, G_VALUE_TYPE (container));
+ set_value_real (value, container);
+}
+
+/**
+ * gedit_message_get_key_type:
+ * @message: the #GeditMessage
+ * @key: the argument key
+ *
+ * Get the type of a message argument.
+ *
+ * Return value: the type of @key
+ *
+ */
+GType
+gedit_message_get_key_type (GeditMessage *message,
+ const gchar *key)
+{
+ g_return_val_if_fail (GEDIT_IS_MESSAGE (message), G_TYPE_INVALID);
+ g_return_val_if_fail (message->priv->type != NULL, G_TYPE_INVALID);
+
+ return gedit_message_type_lookup (message->priv->type, key);
+}
+
+/**
+ * gedit_message_has_key:
+ * @message: the #GeditMessage
+ * @key: the argument key
+ *
+ * Check whether the message has a specific key.
+ *
+ * Return value: %TRUE if @message has argument @key
+ *
+ */
+gboolean
+gedit_message_has_key (GeditMessage *message,
+ const gchar *key)
+{
+ g_return_val_if_fail (GEDIT_IS_MESSAGE (message), FALSE);
+
+ return value_lookup (message, key, FALSE) != NULL;
+}
+
+typedef struct
+{
+ GeditMessage *message;
+ gboolean valid;
+} ValidateInfo;
+
+static void
+validate_key (const gchar *key,
+ GType type,
+ gboolean required,
+ ValidateInfo *info)
+{
+ GValue *value;
+
+ if (!info->valid || !required)
+ return;
+
+ value = value_lookup (info->message, key, FALSE);
+
+ if (!value)
+ info->valid = FALSE;
+}
+
+/**
+ * gedit_message_validate:
+ * @message: the #GeditMessage
+ *
+ * Validates the message arguments according to the message type.
+ *
+ * Return value: %TRUE if the message is valid
+ *
+ */
+gboolean
+gedit_message_validate (GeditMessage *message)
+{
+ ValidateInfo info = {message, TRUE};
+
+ g_return_val_if_fail (GEDIT_IS_MESSAGE (message), FALSE);
+ g_return_val_if_fail (message->priv->type != NULL, FALSE);
+
+ if (!message->priv->valid)
+ {
+ gedit_message_type_foreach (message->priv->type,
+ (GeditMessageTypeForeach)validate_key,
+ &info);
+
+ message->priv->valid = info.valid;
+ }
+
+ return message->priv->valid;
+}
+
+// ex:ts=8:noet:
Added: trunk/gedit/gedit-message.h
==============================================================================
--- (empty file)
+++ trunk/gedit/gedit-message.h Mon Dec 29 18:52:22 2008
@@ -0,0 +1,71 @@
+#ifndef __GEDIT_MESSAGE_H__
+#define __GEDIT_MESSAGE_H__
+
+#include <glib-object.h>
+#include <stdarg.h>
+
+G_BEGIN_DECLS
+
+#define GEDIT_TYPE_MESSAGE (gedit_message_get_type ())
+#define GEDIT_MESSAGE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GEDIT_TYPE_MESSAGE, GeditMessage))
+#define GEDIT_MESSAGE_CONST(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GEDIT_TYPE_MESSAGE, GeditMessage const))
+#define GEDIT_MESSAGE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GEDIT_TYPE_MESSAGE, GeditMessageClass))
+#define GEDIT_IS_MESSAGE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GEDIT_TYPE_MESSAGE))
+#define GEDIT_IS_MESSAGE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GEDIT_TYPE_MESSAGE))
+#define GEDIT_MESSAGE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GEDIT_TYPE_MESSAGE, GeditMessageClass))
+
+typedef struct _GeditMessage GeditMessage;
+typedef struct _GeditMessageClass GeditMessageClass;
+typedef struct _GeditMessagePrivate GeditMessagePrivate;
+
+struct _GeditMessage {
+ GObject parent;
+
+ GeditMessagePrivate *priv;
+};
+
+struct _GeditMessageClass {
+ GObjectClass parent_class;
+};
+
+GType gedit_message_get_type (void) G_GNUC_CONST;
+
+struct _GeditMessageType gedit_message_get_message_type (GeditMessage *message);
+
+void gedit_message_get (GeditMessage *message,
+ ...) G_GNUC_NULL_TERMINATED;
+void gedit_message_get_valist (GeditMessage *message,
+ va_list var_args);
+void gedit_message_get_value (GeditMessage *message,
+ const gchar *key,
+ GValue *value);
+
+void gedit_message_set (GeditMessage *message,
+ ...) G_GNUC_NULL_TERMINATED;
+void gedit_message_set_valist (GeditMessage *message,
+ va_list var_args);
+void gedit_message_set_value (GeditMessage *message,
+ const gchar *key,
+ GValue *value);
+void gedit_message_set_valuesv (GeditMessage *message,
+ const gchar **keys,
+ GValue *values,
+ gint n_values);
+
+const gchar *gedit_message_get_object_path (GeditMessage *message);
+const gchar *gedit_message_get_method (GeditMessage *message);
+
+gboolean gedit_message_has_key (GeditMessage *message,
+ const gchar *key);
+
+GType gedit_message_get_key_type (GeditMessage *message,
+ const gchar *key);
+
+gboolean gedit_message_validate (GeditMessage *message);
+
+
+G_END_DECLS
+
+#endif /* __GEDIT_MESSAGE_H__ */
+
+// ex:ts=8:noet:
Modified: trunk/gedit/gedit-window-private.h
==============================================================================
--- trunk/gedit/gedit-window-private.h (original)
+++ trunk/gedit/gedit-window-private.h Mon Dec 29 18:52:22 2008
@@ -33,6 +33,7 @@
#include "gedit/gedit-window.h"
#include "gedit-prefs-manager.h"
+#include "gedit-message-bus.h"
G_BEGIN_DECLS
@@ -46,7 +47,9 @@
GtkWidget *bottom_panel;
GtkWidget *hpaned;
- GtkWidget *vpaned;
+ GtkWidget *vpaned;
+
+ GeditMessageBus *message_bus;
/* statusbar and context ids for statusbar messages */
GtkWidget *statusbar;
Modified: trunk/gedit/gedit-window.c
==============================================================================
--- trunk/gedit/gedit-window.c (original)
+++ trunk/gedit/gedit-window.c Mon Dec 29 18:52:22 2008
@@ -186,6 +186,12 @@
window->priv->manager = NULL;
}
+ if (window->priv->message_bus != NULL)
+ {
+ g_object_unref (window->priv->message_bus);
+ window->priv->message_bus = NULL;
+ }
+
if (window->priv->window_group != NULL)
{
g_object_unref (window->priv->window_group);
@@ -3066,6 +3072,8 @@
window->priv->state = GEDIT_WINDOW_STATE_NORMAL;
window->priv->dispose_has_run = FALSE;
+ window->priv->message_bus = gedit_message_bus_new ();
+
window->priv->window_group = gtk_window_group_new ();
gtk_window_group_add_window (window->priv->window_group, GTK_WINDOW (window));
@@ -3810,6 +3818,23 @@
}
/**
+ * gedit_window_get_message_bus:
+ * @window: a #GeditWindow
+ *
+ * Gets the #GeditMessageBus associated with @window. The returned reference
+ * is owned by the window and should not be unreffed.
+ *
+ * Return value: the #GeditMessageBus associated with @window
+ */
+GeditMessageBus *
+gedit_window_get_message_bus (GeditWindow *window)
+{
+ g_return_val_if_fail (GEDIT_IS_WINDOW (window), NULL);
+
+ return window->priv->message_bus;
+}
+
+/**
* gedit_window_get_tab_from_uri:
* @window: a #GeditWindow
* @uri: the uri to get the #GeditTab
Modified: trunk/gedit/gedit-window.h
==============================================================================
--- trunk/gedit/gedit-window.h (original)
+++ trunk/gedit/gedit-window.h Mon Dec 29 18:52:22 2008
@@ -36,6 +36,7 @@
#include <gedit/gedit-tab.h>
#include <gedit/gedit-panel.h>
+#include <gedit/gedit-message-bus.h>
G_BEGIN_DECLS
@@ -155,6 +156,10 @@
GeditTab *gedit_window_get_tab_from_uri (GeditWindow *window,
const gchar *uri);
+
+/* Message bus */
+GeditMessageBus *gedit_window_get_message_bus (GeditWindow *window);
+
/*
* Non exported functions
*/
Modified: trunk/plugin-loaders/python/bindings/Makefile.am
==============================================================================
--- trunk/plugin-loaders/python/bindings/Makefile.am (original)
+++ trunk/plugin-loaders/python/bindings/Makefile.am Mon Dec 29 18:52:22 2008
@@ -3,9 +3,9 @@
noinst_LTLIBRARIES = \
gedit.la
-nodist_gedit_la_SOURCES = \
+nodist_gedit_la_SOURCES = \
gedit.c \
- geditutils.c \
+ geditutils.c \
geditcommands.c
gedit_la_LDFLAGS = \
@@ -33,7 +33,7 @@
$(top_builddir)/gedit/gedit-enum-types.h:
cd $(top_builddir)/gedit && $(MAKE) gedit-enum-types.h
-gedit.c: gedit.defs gedit.override geditplugin.override $(top_builddir)/gedit/gedit-enum-types.h
+gedit.c: gedit.defs gedit.override geditplugin.override geditmessage.override $(top_builddir)/gedit/gedit-enum-types.h
( cd $(srcdir) && $(PYGTK_CODEGEN) \
--register $(PYGTK_DEFSDIR)/pango-types.defs \
--register $(PYGTK_DEFSDIR)/gdk-types.defs \
@@ -59,7 +59,7 @@
gedit/gedit-document.h \
gedit/gedit-encodings.h \
gedit/gedit-plugin.h \
- $(srcdir)/../gedit-plugin-python.h \
+ plugin-loaders/python/gedit-plugin-python.h \
gedit/gedit-view.h \
gedit/gedit-statusbar.h \
gedit/gedit-tab.h \
@@ -67,6 +67,9 @@
gedit/gedit-window.h \
gedit/gedit-help.h \
gedit/gedit-debug.h \
+ gedit/gedit-message-type.h \
+ gedit/gedit-message.h \
+ gedit/gedit-message-bus.h \
gedit/gedit-language-manager.h
BINDING_UTILS_HEADERS_SRCDIR_IN = \
@@ -100,6 +103,7 @@
geditutils.defs \
geditcommands.override \
geditcommands.defs \
+ geditmessage.override \
geditplugin.override
CLEANFILES = $(BUILT_SOURCES)
Modified: trunk/plugin-loaders/python/bindings/gedit.defs
==============================================================================
--- trunk/plugin-loaders/python/bindings/gedit.defs (original)
+++ trunk/plugin-loaders/python/bindings/gedit.defs Mon Dec 29 18:52:22 2008
@@ -14,6 +14,20 @@
(gtype-id "GEDIT_TYPE_DOCUMENT")
)
+(define-object Message
+ (in-module "Gedit")
+ (parent "GObject")
+ (c-name "GeditMessage")
+ (gtype-id "GEDIT_TYPE_MESSAGE")
+)
+
+(define-object MessageBus
+ (in-module "Gedit")
+ (parent "GObject")
+ (c-name "GeditMessageBus")
+ (gtype-id "GEDIT_TYPE_MESSAGE_BUS")
+)
+
(define-object Panel
(in-module "Gedit")
(parent "GtkVBox")
@@ -149,6 +163,14 @@
;; )
)
+(define-boxed MessageType
+ (in-module "Gedit")
+ (c-name "GeditMessageType")
+ (gtype-id "GEDIT_TYPE_MESSAGE_TYPE")
+ (copy-func "gedit_message_type_ref")
+ (release-func "gedit_message_type_unref")
+)
+
;; From ../../gedit/gedit-app.h
@@ -975,6 +997,12 @@
(return-type "GeditWindowState")
)
+(define-method get_message_bus
+ (of-object "GeditWindow")
+ (c-name "gedit_window_get_message_bus")
+ (return-type "GeditMessageBus*")
+)
+
(define-method get_tab_from_uri
(of-object "GeditWindow")
(c-name "gedit_window_get_tab_from_uri")
@@ -1000,6 +1028,412 @@
)
)
+
+;; From gedit-message-bus.h
+
+(define-function gedit_message_bus_get_type
+ (c-name "gedit_message_bus_get_type")
+ (return-type "GType")
+)
+
+(define-function message_bus_get_default
+ (c-name "gedit_message_bus_get_default")
+ (return-type "GeditMessageBus*")
+)
+
+(define-function gedit_message_bus_new
+ (c-name "gedit_message_bus_new")
+ (is-constructor-of "GeditMessageBus")
+ (return-type "GeditMessageBus*")
+)
+
+(define-method lookup
+ (of-object "GeditMessageBus")
+ (c-name "gedit_message_bus_lookup")
+ (return-type "GeditMessageType*")
+ (parameters
+ '("const-gchar*" "object_path")
+ '("const-gchar*" "method")
+ )
+)
+
+(define-method register
+ (of-object "GeditMessageBus")
+ (c-name "gedit_message_bus_register")
+ (return-type "GeditMessageType*")
+ (parameters
+ '("const-gchar*" "object_path")
+ '("const-gchar*" "method")
+ '("guint" "num_optional")
+ )
+ (varargs #t)
+)
+
+(define-method unregister
+ (of-object "GeditMessageBus")
+ (c-name "gedit_message_bus_unregister")
+ (return-type "none")
+ (parameters
+ '("GeditMessageType*" "message_type")
+ )
+)
+
+(define-method unregister_all
+ (of-object "GeditMessageBus")
+ (c-name "gedit_message_bus_unregister_all")
+ (return-type "none")
+ (parameters
+ '("const-gchar*" "object_path")
+ )
+)
+
+(define-method is_registered
+ (of-object "GeditMessageBus")
+ (c-name "gedit_message_bus_is_registered")
+ (return-type "gboolean")
+ (parameters
+ '("const-gchar*" "object_path")
+ '("const-gchar*" "method")
+ )
+)
+
+(define-method connect
+ (of-object "GeditMessageBus")
+ (c-name "gedit_message_bus_connect")
+ (return-type "guint")
+ (parameters
+ '("const-gchar*" "object_path")
+ '("const-gchar*" "method")
+ '("GeditMessageCallback" "callback")
+ '("gpointer" "userdata")
+ '("GDestroyNotify" "destroy_data")
+ )
+)
+
+(define-method disconnect
+ (of-object "GeditMessageBus")
+ (c-name "gedit_message_bus_disconnect")
+ (return-type "none")
+ (parameters
+ '("guint" "id")
+ )
+)
+
+(define-method disconnect_by_func
+ (of-object "GeditMessageBus")
+ (c-name "gedit_message_bus_disconnect_by_func")
+ (return-type "none")
+ (parameters
+ '("const-gchar*" "object_path")
+ '("const-gchar*" "method")
+ '("GeditMessageCallback" "callback")
+ '("gpointer" "userdata")
+ )
+)
+
+(define-method block
+ (of-object "GeditMessageBus")
+ (c-name "gedit_message_bus_block")
+ (return-type "none")
+ (parameters
+ '("guint" "id")
+ )
+)
+
+(define-method block_by_func
+ (of-object "GeditMessageBus")
+ (c-name "gedit_message_bus_block_by_func")
+ (return-type "none")
+ (parameters
+ '("const-gchar*" "object_path")
+ '("const-gchar*" "method")
+ '("GeditMessageCallback" "callback")
+ '("gpointer" "userdata")
+ )
+)
+
+(define-method unblock
+ (of-object "GeditMessageBus")
+ (c-name "gedit_message_bus_unblock")
+ (return-type "none")
+ (parameters
+ '("guint" "id")
+ )
+)
+
+(define-method unblock_by_func
+ (of-object "GeditMessageBus")
+ (c-name "gedit_message_bus_unblock_by_func")
+ (return-type "none")
+ (parameters
+ '("const-gchar*" "object_path")
+ '("const-gchar*" "method")
+ '("GeditMessageCallback" "callback")
+ '("gpointer" "userdata")
+ )
+)
+
+(define-method send_message
+ (of-object "GeditMessageBus")
+ (c-name "gedit_message_bus_send_message")
+ (return-type "none")
+ (parameters
+ '("GeditMessage*" "message")
+ )
+)
+
+(define-method send_message_sync
+ (of-object "GeditMessageBus")
+ (c-name "gedit_message_bus_send_message_sync")
+ (return-type "none")
+ (parameters
+ '("GeditMessage*" "message")
+ )
+)
+
+(define-method send
+ (of-object "GeditMessageBus")
+ (c-name "gedit_message_bus_send")
+ (return-type "none")
+ (parameters
+ '("const-gchar*" "object_path")
+ '("const-gchar*" "method")
+ )
+ (varargs #t)
+)
+
+(define-method send_sync
+ (of-object "GeditMessageBus")
+ (c-name "gedit_message_bus_send_sync")
+ (return-type "GeditMessage*")
+ (parameters
+ '("const-gchar*" "object_path")
+ '("const-gchar*" "method")
+ )
+ (varargs #t)
+)
+
+
+;; From gedit-message-type.h
+
+(define-function gedit_message_type_get_type
+ (c-name "gedit_message_type_get_type")
+ (return-type "GType")
+)
+
+(define-function gedit_message_type_is_supported
+ (c-name "gedit_message_type_is_supported")
+ (return-type "gboolean")
+ (parameters
+ '("GType" "type")
+ )
+)
+
+(define-function gedit_message_type_identifier
+ (c-name "gedit_message_type_identifier")
+ (return-type "gchar*")
+ (parameters
+ '("const-gchar*" "object_path")
+ '("const-gchar*" "method")
+ )
+)
+
+(define-function gedit_message_type_new
+ (c-name "gedit_message_type_new")
+ (is-constructor-of "GeditMessageType")
+ (return-type "GeditMessageType*")
+ (parameters
+ '("const-gchar*" "object_path")
+ '("const-gchar*" "method")
+ '("guint" "num_optional")
+ )
+ (varargs #t)
+)
+
+(define-function gedit_message_type_new_valist
+ (c-name "gedit_message_type_new_valist")
+ (return-type "GeditMessageType*")
+ (parameters
+ '("const-gchar*" "object_path")
+ '("const-gchar*" "method")
+ '("guint" "num_optional")
+ '("va_list" "va_args")
+ )
+)
+
+(define-method ref
+ (of-object "GeditMessageType")
+ (c-name "gedit_message_type_ref")
+ (return-type "GeditMessageType*")
+)
+
+(define-method unref
+ (of-object "GeditMessageType")
+ (c-name "gedit_message_type_unref")
+ (return-type "none")
+)
+
+(define-method instantiate_valist
+ (of-object "GeditMessageType")
+ (c-name "gedit_message_type_instantiate_valist")
+ (return-type "GeditMessage*")
+ (parameters
+ '("va_list" "va_args")
+ )
+)
+
+(define-method instantiate
+ (of-object "GeditMessageType")
+ (c-name "gedit_message_type_instantiate")
+ (return-type "GeditMessage*")
+ (parameters
+ )
+ (varargs #t)
+)
+
+(define-method get_object_path
+ (of-object "GeditMessageType")
+ (c-name "gedit_message_type_get_object_path")
+ (return-type "const-gchar*")
+)
+
+(define-method get_method
+ (of-object "GeditMessageType")
+ (c-name "gedit_message_type_get_method")
+ (return-type "const-gchar*")
+)
+
+(define-method lookup
+ (of-object "GeditMessageType")
+ (c-name "gedit_message_type_lookup")
+ (return-type "GType")
+ (parameters
+ '("const-gchar*" "key")
+ )
+)
+
+(define-method foreach
+ (of-object "GeditMessageType")
+ (c-name "gedit_message_type_foreach")
+ (return-type "none")
+ (parameters
+ '("GeditMessageTypeForeach" "func")
+ '("gpointer" "user_data")
+ )
+)
+
+
+;; From gedit-message.h
+
+(define-function gedit_message_get_type
+ (c-name "gedit_message_get_type")
+ (return-type "GType")
+)
+
+(define-method get
+ (of-object "GeditMessage")
+ (c-name "gedit_message_get")
+ (return-type "none")
+ (parameters
+ )
+ (varargs #t)
+)
+
+(define-method get_valist
+ (of-object "GeditMessage")
+ (c-name "gedit_message_get_valist")
+ (return-type "none")
+ (parameters
+ '("va_list" "var_args")
+ )
+)
+
+(define-method get_value
+ (of-object "GeditMessage")
+ (c-name "gedit_message_get_value")
+ (return-type "none")
+ (parameters
+ '("const-gchar*" "key")
+ '("GValue*" "value")
+ )
+)
+
+(define-method set
+ (of-object "GeditMessage")
+ (c-name "gedit_message_set")
+ (return-type "none")
+ (parameters
+ )
+ (varargs #t)
+)
+
+(define-method set_valist
+ (of-object "GeditMessage")
+ (c-name "gedit_message_set_valist")
+ (return-type "none")
+ (parameters
+ '("va_list" "var_args")
+ )
+)
+
+(define-method set_value
+ (of-object "GeditMessage")
+ (c-name "gedit_message_set_value")
+ (return-type "none")
+ (parameters
+ '("const-gchar*" "key")
+ '("GValue*" "value")
+ )
+)
+
+(define-method set_valuesv
+ (of-object "GeditMessage")
+ (c-name "gedit_message_set_valuesv")
+ (return-type "none")
+ (parameters
+ '("const-gchar**" "keys")
+ '("GValue*" "values")
+ '("gint" "n_values")
+ )
+)
+
+(define-method get_object_path
+ (of-object "GeditMessage")
+ (c-name "gedit_message_get_object_path")
+ (return-type "const-gchar*")
+)
+
+(define-method get_method
+ (of-object "GeditMessage")
+ (c-name "gedit_message_get_method")
+ (return-type "const-gchar*")
+)
+
+(define-method has_key
+ (of-object "GeditMessage")
+ (c-name "gedit_message_has_key")
+ (return-type "gboolean")
+ (parameters
+ '("const-gchar*" "key")
+ )
+)
+
+(define-method get_key_type
+ (of-object "GeditMessage")
+ (c-name "gedit_message_get_key_type")
+ (return-type "GType")
+ (parameters
+ '("const-gchar*" "key")
+ )
+)
+
+(define-method validate
+ (of-object "GeditMessage")
+ (c-name "gedit_message_validate")
+ (return-type "gboolean")
+)
+
+
;; From ../../gedit/gedit-debug.h
(define-function debug
Modified: trunk/plugin-loaders/python/bindings/gedit.override
==============================================================================
--- trunk/plugin-loaders/python/bindings/gedit.override (original)
+++ trunk/plugin-loaders/python/bindings/gedit.override Mon Dec 29 18:52:22 2008
@@ -62,6 +62,7 @@
%%
include
geditplugin.override
+ geditmessage.override
%%
modulename gedit
%%
Added: trunk/plugin-loaders/python/bindings/geditmessage.override
==============================================================================
--- (empty file)
+++ trunk/plugin-loaders/python/bindings/geditmessage.override Mon Dec 29 18:52:22 2008
@@ -0,0 +1,499 @@
+%%
+headers
+
+#include <gedit/gedit-message-bus.h>
+#include <gedit/gedit-message.h>
+
+static GType
+_helper_wrap_get_gtype_from_pytype (PyObject *pytype)
+{
+ PyTypeObject *type = (PyTypeObject *)pytype;
+
+ if (type == &PyList_Type || type == &PyTuple_Type)
+ return G_TYPE_STRV;
+
+ return pyg_type_from_object (pytype);
+}
+
+static gchar *
+_helper_wrap_get_string (PyObject *obj)
+{
+ PyObject *str;
+ gchar *result;
+
+ str = PyObject_Str (obj);
+
+ if (!str)
+ return NULL;
+
+ result = g_strdup (PyString_AsString (str));
+ Py_DECREF (str);
+
+ return result;
+}
+
+static int
+_helper_wrap_list_to_gvalue (GValue *gvalue, PyObject *pyvalue)
+{
+ int num;
+ gchar **lst;
+ gint i;
+
+ num = PySequence_Size (pyvalue);
+ lst = g_new0 (gchar *, num + 1);
+
+ for (i = 0; i < num; i++)
+ {
+ lst[i] = _helper_wrap_get_string (PySequence_GetItem (pyvalue, i));
+
+ if (lst[i] == NULL)
+ {
+ g_strfreev (lst);
+ return 1;
+ }
+ }
+
+ g_value_set_boxed (gvalue, lst);
+ g_strfreev (lst);
+
+ return 0;
+}
+
+static int
+_helper_wrap_get_gvalue_from_pyobject (GValue *gvalue, PyObject *pyvalue)
+{
+ if (pyvalue->ob_type == &PyList_Type || pyvalue->ob_type == &PyTuple_Type)
+ return _helper_wrap_list_to_gvalue (gvalue, pyvalue);
+
+ return pyg_value_from_pyobject(gvalue, pyvalue);
+}
+
+static int
+_helper_wrap_message_set_value(GeditMessage *message, PyObject *pykey, PyObject *pyvalue)
+{
+ gchar *key;
+ GType gtype;
+ GValue value = {0,};
+
+ key = _helper_wrap_get_string(pykey);
+
+ if (key == NULL)
+ return 0;
+
+ gtype = gedit_message_get_key_type(message, key);
+
+ if (gtype == 0) {
+ PyErr_SetString(PyExc_TypeError, "invalid key");
+ g_free (key);
+ return 0;
+ }
+
+ g_value_init(&value, gtype);
+
+ if (_helper_wrap_get_gvalue_from_pyobject (&value, pyvalue)) {
+ PyErr_SetString(PyExc_TypeError,
+ "value is of the wrong type for this key");
+ g_free (key);
+ return 0;
+ }
+
+ gedit_message_set_value(message, key, &value);
+ g_value_unset(&value);
+ g_free (key);
+
+ return 1;
+}
+
+typedef void (*ParsePairFunc)(PyObject *key, PyObject *value, gpointer user_data);
+
+static void
+_helper_parse_pairs_dict (PyObject *dict, ParsePairFunc func, gpointer user_data)
+{
+ if (!dict)
+ return;
+
+ PyObject *key, *value;
+ Py_ssize_t i = 0;
+
+ while (PyDict_Next(dict, &i, &key, &value))
+ {
+ func(key, value, user_data);
+ }
+}
+
+static void
+_helper_parse_pairs(PyObject *args, PyObject *kwargs, ParsePairFunc func, gpointer user_data)
+{
+ guint len;
+ guint i;
+
+ len = PyTuple_Size(args);
+
+ for (i = 0; i < len; ++i)
+ {
+ PyObject *d = PyTuple_GetItem(args, i);
+
+ if (PyDict_Check(d))
+ _helper_parse_pairs_dict(d, func, user_data);
+ }
+
+ _helper_parse_pairs_dict(kwargs, func, user_data);
+}
+
+static void
+_helper_message_set(PyObject *key, PyObject *value, GeditMessage *message)
+{
+ _helper_wrap_message_set_value(message, key, value);
+}
+
+static void
+_helper_message_set_values(GeditMessage *message, PyObject *args, PyObject *kwargs)
+{
+ _helper_parse_pairs(args, kwargs, (ParsePairFunc)_helper_message_set, message);
+}
+
+static GeditMessage *
+_helper_wrap_create_message(GeditMessageBus *bus, PyObject *args, PyObject *kwargs)
+{
+ PyObject *pypath, *pymethod, *pydict;
+
+ if (!PyArg_ParseTuple(args, "OO|O:GeditMessage.create", &pypath, &pymethod, &pydict))
+ return NULL;
+
+ gchar *object_path = _helper_wrap_get_string(pypath);
+ gchar *method = _helper_wrap_get_string(pymethod);
+
+ GeditMessageType *message_type = gedit_message_bus_lookup (bus, object_path, method);
+ GeditMessage *message;
+
+ if (message_type)
+ {
+ message = gedit_message_type_instantiate(message_type, NULL);
+ _helper_message_set_values(message, args, kwargs);
+ }
+ else
+ {
+ PyErr_SetString(PyExc_StandardError, "Message type does not exist");
+ message = NULL;
+ }
+
+ g_free(object_path);
+ g_free(method);
+
+ return message;
+}
+
+typedef struct {
+ PyObject *func;
+ PyObject *data;
+} PyGeditCustomNotify;
+
+static void
+pygedit_custom_destroy_notify(gpointer user_data)
+{
+ PyGeditCustomNotify *cunote = user_data;
+ PyGILState_STATE state;
+
+ g_return_if_fail(user_data);
+ state = pyg_gil_state_ensure();
+ Py_XDECREF(cunote->func);
+ Py_XDECREF(cunote->data);
+ pyg_gil_state_release(state);
+
+ g_free(cunote);
+}
+%%
+ignore-glob
+ *_get_type
+ gedit_message_type_foreach
+ gedit_message_type_instantiate_valist
+ gedit_message_type_new_valist
+ gedit_message_get_valist
+ gedit_message_set_valist
+ gedit_message_set_valuesv
+ gedit_message_bus_disconnect_by_func
+ gedit_message_bus_block_by_func
+ gedit_message_bus_unblock_by_func
+%%
+override gedit_message_type_new kwargs
+
+typedef struct
+{
+ GeditMessageType *message_type;
+ PyObject *optional;
+} MessageTypeSetInfo;
+
+static void
+_message_type_set(PyObject *key, PyObject *value, MessageTypeSetInfo *info)
+{
+ GType gtype;
+
+ gchar *k = _helper_wrap_get_string(key);
+
+ if (!k)
+ return;
+
+ gtype = _helper_wrap_get_gtype_from_pytype(value);
+
+ gboolean optional = info->optional && PySequence_Contains(info->optional, key);
+
+ gedit_message_type_set(info->message_type, optional, k, gtype, NULL);
+ g_free(k);
+}
+
+static int
+_wrap_gedit_message_type_new(PyGObject *self, PyObject *args, PyObject *kwargs)
+{
+ PyObject *pypath, *pymethod, *optional = NULL, *pydict;
+ guint len;
+
+ if (!PyArg_ParseTuple(args, "OO|OO:GeditMessageType.new", &pypath, &pymethod, &optional, &pydict))
+ return -1;
+
+ GeditMessageType *message_type = GEDIT_MESSAGE_TYPE(g_object_new(pyg_type_from_object((PyObject *) self), NULL));
+
+ MessageTypeSetInfo info = {message_type, optional && PySequence_Check(optional) ? optional : NULL};
+ _helper_parse_pairs (args, kwargs, (ParsePairFunc)_message_type_set, &info);
+
+ self->obj = (GObject *)message_type;
+ pygobject_register_wrapper((PyObject *) self);
+}
+%%
+override gedit_message_type_instantiate kwargs
+static PyObject *
+_wrap_gedit_message_type_instantiate(PyGObject *self, PyObject *args, PyObject *kwargs)
+{
+ GeditMessageType *message_type = GEDIT_MESSAGE_TYPE (self->obj);
+ GeditMessage *message = gedit_message_type_instantiate(message_type, NULL);
+
+ _wrap_helper_message_set_value(message, args, kwargs);
+
+ return pygobject_new((GObject *)message);
+}
+%%
+override gedit_message_get args
+static PyObject *
+_wrap_gedit_message_get(PyGObject *self, PyObject *args)
+{
+ guint len, i;
+ PyObject *ret;
+
+ len = PyTuple_Size(args);
+
+ ret = PyTuple_New(len);
+
+ for (i = 0; i < len; i++) {
+ GValue value = { 0, };
+ PyObject *py_key = PyTuple_GetItem(args, i);
+ gchar *key = _helper_wrap_get_string(py_key);
+
+ if (!key) {
+ PyErr_SetString(PyExc_TypeError, "keys must be strings");
+ Py_DECREF(ret);
+ return NULL;
+ }
+
+ gedit_message_get_value (GEDIT_MESSAGE (self->obj), key, &value);
+ g_free (key);
+
+ PyTuple_SetItem(ret, i, pyg_value_as_pyobject(&value, TRUE));
+ g_value_unset(&value);
+ }
+
+ return ret;
+}
+%%
+override gedit_message_get_value kwargs
+static PyObject *
+_wrap_gedit_message_get_value(PyGObject *self, PyObject *args, PyObject *kwargs)
+{
+ static char *kwlist[] = { "key", NULL };
+ const gchar *key;
+ PyObject *ret;
+ GValue value = { 0, };
+
+ if (!PyArg_ParseTupleAndKeywords(args, kwargs, "s:GeditMessage.get_value", kwlist, &key))
+ return NULL;
+
+ gedit_message_get_value(GEDIT_MESSAGE(self->obj), key, &value);
+ ret = pyg_value_as_pyobject(&value, TRUE);
+ g_value_unset(&value);
+
+ return ret;
+}
+%%
+override gedit_message_set_value kwargs
+static PyObject *
+_wrap_gedit_message_set_value(PyGObject *self, PyObject *args, PyObject *kwargs)
+{
+ static char *kwlist[] = { "key", "value", NULL };
+ PyObject *ret, *pykey, *pyvalue;
+ GValue value = { 0, };
+ GType gtype;
+
+ if (!PyArg_ParseTupleAndKeywords(args, kwargs, "OO:GeditMessage.set_value", kwlist, &pykey, &pyvalue))
+ return NULL;
+
+ if (!_helper_wrap_message_set_value(GEDIT_MESSAGE(self->obj), pykey, pyvalue))
+ return NULL;
+
+ Py_INCREF(Py_None);
+ return Py_None;
+}
+%%
+override gedit_message_set kwargs
+static PyObject *
+_wrap_gedit_message_set (PyGObject *self, PyObject *args, PyObject *kwargs) {
+ _helper_wrap_message_set_values(GEDIT_MESSAGE(self->obj), args, kwargs);
+
+ Py_INCREF(Py_None);
+ return Py_None;
+}
+%%
+override gedit_message_bus_new
+static int
+_wrap_gedit_message_bus_new(PyGObject *self)
+{
+ pygobject_construct (self, NULL);
+
+ if (!self->obj) {
+ PyErr_SetString (PyExc_RuntimeError, "could not create gedit.MessageBus object");
+ return -1;
+ }
+
+ return 0;
+}
+%%
+new-constructor GEDIT_TYPE_MESSAGE_BUS
+%%
+override gedit_message_bus_register kwargs
+static PyObject *
+_wrap_gedit_message_bus_register(PyGObject *self, PyObject *args, PyObject *kwargs)
+{
+ PyObject *pypath, *pymethod, *optional = NULL, *pydict;
+ guint len;
+ GeditMessageBus *bus = GEDIT_MESSAGE_BUS(self->obj);
+
+ if (!PyArg_ParseTuple(args, "OO|OO:GeditMessageBus.register", &pypath, &pymethod, &optional, &pydict))
+ return NULL;
+
+ gchar *object_path = _helper_wrap_get_string(pypath);
+ gchar *method = _helper_wrap_get_string(pymethod);
+
+ GeditMessageType *message_type = gedit_message_bus_register(bus, object_path, method, 0, NULL);
+
+ g_free(object_path);
+ g_free(method);
+
+ if (!message_type)
+ {
+ PyErr_SetString(PyExc_StandardError, "Message type already exists");
+ return NULL;
+ }
+
+ MessageTypeSetInfo info = {message_type, optional && PySequence_Check(optional) ? optional : NULL};
+ _helper_parse_pairs (args, kwargs, (ParsePairFunc)_message_type_set, &info);
+
+ return pyg_boxed_new(GEDIT_TYPE_MESSAGE_TYPE, message_type, TRUE, TRUE);
+}
+%%
+override gedit_message_bus_connect kwargs
+static void
+pygedit_message_bus_connect_cb(GeditMessageBus *bus, GeditMessage *message, gpointer data)
+{
+ PyGILState_STATE state;
+ PyGeditCustomNotify *cunote = data;
+ PyObject *pybus, *pymessage, *retobj;
+ gboolean ret = FALSE;
+
+ g_assert(cunote->func);
+
+ state = pyg_gil_state_ensure();
+
+ pybus = pygobject_new((GObject *)bus);
+ pymessage = pygobject_new((GObject *)message);
+
+ if (cunote->data) {
+ retobj = PyEval_CallFunction(cunote->func, "(NNO)", pybus, pymessage, cunote->data);
+ } else {
+ retobj = PyEval_CallFunction(cunote->func, "(NN)", pybus, pymessage);
+ }
+
+ if (PyErr_Occurred()) {
+ PyErr_Print();
+ }
+
+ Py_XDECREF(retobj);
+
+ pyg_gil_state_release(state);
+}
+
+static PyObject *
+_wrap_gedit_message_bus_connect(PyGObject *self, PyObject *args, PyObject *kwargs)
+{
+ static char *kwlist[] = { "domain", "name", "func", "data", NULL };
+ PyObject *pyfunc, *pyarg = NULL;
+ const gchar *domain;
+ const gchar *name;
+ PyGeditCustomNotify *cunote;
+
+ if (!PyArg_ParseTupleAndKeywords(args, kwargs,
+ "ssO|O:GeditMessageBus.connect",
+ kwlist, &domain, &name, &pyfunc, &pyarg))
+ return NULL;
+
+ if (!PyCallable_Check(pyfunc)) {
+ PyErr_SetString(PyExc_TypeError, "func must be a callable object");
+ return NULL;
+ }
+ cunote = g_new(PyGeditCustomNotify, 1);
+ Py_INCREF(pyfunc);
+ cunote->func = pyfunc;
+ Py_XINCREF(pyarg);
+ cunote->data = pyarg;
+
+ guint id = gedit_message_bus_connect(GEDIT_MESSAGE_BUS(self->obj),
+ domain,
+ name,
+ pygedit_message_bus_connect_cb,
+ (gpointer)cunote,
+ pygedit_custom_destroy_notify);
+ return PyLong_FromUnsignedLong(id);
+}
+%%
+override gedit_message_bus_send kwargs
+static PyObject *
+_wrap_gedit_message_bus_send(PyGObject *self, PyObject *args, PyObject *kwargs)
+{
+ /* create a new message object */
+ GeditMessage *message;
+ GeditMessageBus *bus = GEDIT_MESSAGE_BUS(self->obj);
+ message = _helper_wrap_create_message(bus, args, kwargs);
+
+ if (!message)
+ return NULL;
+
+ gedit_message_bus_send_message(bus, message);
+ g_object_unref (message);
+
+ Py_INCREF(Py_None);
+ return Py_None;
+}
+%%
+override gedit_message_bus_send_sync args
+static PyObject *
+_wrap_gedit_message_bus_send_sync(PyGObject *self, PyObject *args, PyObject *kwargs)
+{
+ /* create a new message object */
+ GeditMessage *message;
+ GeditMessageBus *bus = GEDIT_MESSAGE_BUS(self->obj);
+
+ message = _helper_wrap_create_message(bus, args, kwargs);
+
+ if (!message)
+ return NULL;
+
+ gedit_message_bus_send_message_sync(bus, message);
+ return pygobject_new((GObject *)message);
+}
+%%
Modified: trunk/plugins/filebrowser/Makefile.am
==============================================================================
--- trunk/plugins/filebrowser/Makefile.am (original)
+++ trunk/plugins/filebrowser/Makefile.am Mon Dec 29 18:52:22 2008
@@ -24,7 +24,8 @@
gedit-file-browser-widget.h \
gedit-file-browser-error.h \
gedit-file-browser-utils.h \
- gedit-file-browser-plugin.h
+ gedit-file-browser-plugin.h \
+ gedit-file-browser-messages.h
libfilebrowser_la_SOURCES = \
$(BUILT_SOURCES) \
@@ -34,6 +35,7 @@
gedit-file-browser-widget.c \
gedit-file-browser-utils.c \
gedit-file-browser-plugin.c \
+ gedit-file-browser-messages.c \
$(NOINST_H_FILES)
libfilebrowser_la_LDFLAGS = $(PLUGIN_LIBTOOL_FLAGS)
Added: trunk/plugins/filebrowser/gedit-file-browser-messages.c
==============================================================================
--- (empty file)
+++ trunk/plugins/filebrowser/gedit-file-browser-messages.c Mon Dec 29 18:52:22 2008
@@ -0,0 +1,878 @@
+#include "gedit-file-browser-messages.h"
+#include "gedit-file-browser-store.h"
+#include <gedit/gedit-message.h>
+
+#define MESSAGE_OBJECT_PATH "/plugins/filebrowser"
+#define WINDOW_DATA_KEY "GeditFileBrowserMessagesWindowData"
+
+#define BUS_CONNECT(bus, name, data) gedit_message_bus_connect(bus, MESSAGE_OBJECT_PATH, #name, (GeditMessageCallback) message_##name##_cb, data, NULL)
+
+typedef struct
+{
+ GeditWindow *window;
+ GeditMessage *message;
+} MessageCacheData;
+
+typedef struct
+{
+ guint row_inserted_id;
+ guint row_deleted_id;
+ guint root_changed_id;
+ guint begin_loading_id;
+ guint end_loading_id;
+
+ GeditMessageBus *bus;
+ GeditFileBrowserWidget *widget;
+ GHashTable *row_tracking;
+
+ GHashTable *filters;
+} WindowData;
+
+typedef struct
+{
+ gulong id;
+
+ GeditWindow *window;
+ GeditMessage *message;
+} FilterData;
+
+static WindowData *
+window_data_new (GeditWindow *window,
+ GeditFileBrowserWidget *widget)
+{
+ WindowData *data = g_slice_new (WindowData);
+
+ data->bus = gedit_window_get_message_bus (window);
+ data->widget = widget;
+ data->row_tracking = g_hash_table_new_full (g_str_hash,
+ g_str_equal,
+ (GDestroyNotify)g_free,
+ (GDestroyNotify)gtk_tree_row_reference_free);
+ data->filters = g_hash_table_new_full (g_str_hash,
+ g_str_equal,
+ (GDestroyNotify)g_free,
+ NULL);
+
+ g_object_set_data (G_OBJECT (window), WINDOW_DATA_KEY, data);
+
+ return data;
+}
+
+static WindowData *
+get_window_data (GeditWindow * window)
+{
+ return (WindowData *) (g_object_get_data (G_OBJECT (window), WINDOW_DATA_KEY));
+}
+
+static void
+window_data_free (GeditWindow *window)
+{
+ WindowData *data = get_window_data (window);
+
+ g_hash_table_destroy (data->row_tracking);
+ g_hash_table_destroy (data->filters);
+
+ g_slice_free (WindowData, data);
+
+ g_object_set_data (G_OBJECT (window), WINDOW_DATA_KEY, NULL);
+}
+
+static FilterData *
+filter_data_new (GeditWindow *window,
+ GeditMessage *message)
+{
+ FilterData *data = g_slice_new (FilterData);
+ WindowData *wdata;
+
+ data->window = window;
+ data->id = 0;
+ data->message = message;
+
+ wdata = get_window_data (window);
+
+ g_hash_table_insert (wdata->filters,
+ gedit_message_type_identifier (gedit_message_get_object_path (message),
+ gedit_message_get_method (message)),
+ data);
+
+ return data;
+}
+
+static void
+filter_data_free (FilterData *data)
+{
+ WindowData *wdata = get_window_data (data->window);
+ gchar *identifier;
+
+ identifier = gedit_message_type_identifier (gedit_message_get_object_path (data->message),
+ gedit_message_get_method (data->message));
+
+ g_hash_table_remove (wdata->filters, identifier);
+ g_free (identifier);
+
+ g_object_unref (data->message);
+ g_slice_free (FilterData, data);
+}
+
+static GtkTreePath *
+track_row_lookup (WindowData *data,
+ const gchar *id)
+{
+ GtkTreeRowReference *ref;
+
+ ref = (GtkTreeRowReference *)g_hash_table_lookup (data->row_tracking, id);
+
+ if (!ref)
+ return NULL;
+
+ return gtk_tree_row_reference_get_path (ref);
+}
+
+static void
+message_cache_data_free (MessageCacheData *data)
+{
+ g_object_unref (data->message);
+ g_slice_free (MessageCacheData, data);
+}
+
+static MessageCacheData *
+message_cache_data_new (GeditWindow *window,
+ GeditMessage *message)
+{
+ MessageCacheData *data = g_slice_new (MessageCacheData);
+
+ data->window = window;
+ data->message = message;
+
+ return data;
+}
+
+static void
+message_set_root_cb (GeditMessageBus *bus,
+ GeditMessage *message,
+ WindowData *data)
+{
+ gchar *root = NULL;
+ gchar *virtual = NULL;
+
+ gedit_message_get (message, "uri", &root, NULL);
+
+ if (!root)
+ return;
+
+ if (gedit_message_has_key (message, "virtual"))
+ gedit_message_get (message, "virtual", &virtual, NULL);
+
+ if (virtual)
+ gedit_file_browser_widget_set_root_and_virtual_root (data->widget, root, virtual);
+ else
+ gedit_file_browser_widget_set_root (data->widget, root, TRUE);
+
+ g_free (root);
+ g_free (virtual);
+}
+
+static void
+message_set_emblem_cb (GeditMessageBus *bus,
+ GeditMessage *message,
+ WindowData *data)
+{
+ gchar *id = NULL;
+ gchar *emblem = NULL;
+ GtkTreePath *path;
+ GeditFileBrowserStore *store;
+
+ gedit_message_get (message, "id", &id, "emblem", &emblem, NULL);
+
+ if (!id || !emblem)
+ {
+ g_free (id);
+ g_free (emblem);
+
+ return;
+ }
+
+ path = track_row_lookup (data, id);
+
+ if (path != NULL)
+ {
+ GError *error = NULL;
+ GdkPixbuf *pixbuf;
+
+ pixbuf = gtk_icon_theme_load_icon (gtk_icon_theme_get_default (),
+ emblem,
+ 10,
+ 0,
+ &error);
+
+ if (pixbuf)
+ {
+ GValue value = { 0, };
+ GtkTreeIter iter;
+
+ store = gedit_file_browser_widget_get_browser_store (data->widget);
+
+ if (gtk_tree_model_get_iter (GTK_TREE_MODEL (store), &iter, path))
+ {
+ g_value_init (&value, GDK_TYPE_PIXBUF);
+ g_value_set_object (&value, pixbuf);
+
+ gedit_file_browser_store_set_value (store,
+ &iter,
+ GEDIT_FILE_BROWSER_STORE_COLUMN_EMBLEM,
+ &value);
+
+ g_value_unset (&value);
+ }
+
+ g_object_unref (pixbuf);
+ }
+
+ if (error)
+ g_error_free (error);
+ }
+
+ g_free (id);
+ g_free (emblem);
+}
+
+static gchar *
+item_id (const gchar *path,
+ const gchar *uri)
+{
+ return g_strconcat (path, "::", uri, NULL);
+}
+
+static gchar *
+track_row (WindowData *data,
+ GeditFileBrowserStore *store,
+ GtkTreePath *path,
+ const gchar *uri)
+{
+ GtkTreeRowReference *ref;
+ gchar *id;
+ gchar *pathstr;
+
+ pathstr = gtk_tree_path_to_string (path);
+ id = item_id (pathstr, uri);
+
+ ref = gtk_tree_row_reference_new (GTK_TREE_MODEL (store), path);
+ g_hash_table_insert (data->row_tracking, g_strdup (id), ref);
+
+ g_free (pathstr);
+
+ return id;
+}
+
+static void
+set_item_message (WindowData *data,
+ GtkTreeIter *iter,
+ GtkTreePath *path,
+ GeditMessage *message)
+{
+ GeditFileBrowserStore *store;
+ gchar *uri = NULL;
+ guint flags = 0;
+ gchar *track_id;
+
+ store = gedit_file_browser_widget_get_browser_store (data->widget);
+
+ gtk_tree_model_get (GTK_TREE_MODEL (store), iter,
+ GEDIT_FILE_BROWSER_STORE_COLUMN_URI, &uri,
+ GEDIT_FILE_BROWSER_STORE_COLUMN_FLAGS, &flags,
+ -1);
+
+ if (!uri)
+ return;
+
+ if (path && gtk_tree_path_get_depth (path) != 0)
+ track_id = track_row (data, store, path, uri);
+ else
+ track_id = NULL;
+
+ gedit_message_set (message,
+ "id", track_id,
+ "uri", uri,
+ NULL);
+
+ if (gedit_message_has_key (message, "is_directory"))
+ {
+ gedit_message_set (message,
+ "is_directory", FILE_IS_DIR (flags),
+ NULL);
+ }
+
+ g_free (uri);
+ g_free (track_id);
+}
+
+static gboolean
+custom_message_filter_func (GeditFileBrowserWidget *widget,
+ GeditFileBrowserStore *store,
+ GtkTreeIter *iter,
+ FilterData *data)
+{
+ WindowData *wdata = get_window_data (data->window);
+ gchar *uri = NULL;
+ guint flags = 0;
+ gboolean filter = FALSE;
+ GtkTreePath *path;
+
+ gtk_tree_model_get (GTK_TREE_MODEL (store), iter,
+ GEDIT_FILE_BROWSER_STORE_COLUMN_URI, &uri,
+ GEDIT_FILE_BROWSER_STORE_COLUMN_FLAGS, &flags,
+ -1);
+
+ if (!uri || FILE_IS_DUMMY (flags))
+ {
+ g_free (uri);
+ return FALSE;
+ }
+
+ path = gtk_tree_model_get_path (GTK_TREE_MODEL (store), iter);
+ set_item_message (wdata, iter, path, data->message);
+ gtk_tree_path_free (path);
+
+ gedit_message_set (data->message, "filter", filter, NULL);
+
+ gedit_message_bus_send_message_sync (wdata->bus, data->message);
+ gedit_message_get (data->message, "filter", &filter, NULL);
+
+ return !filter;
+}
+
+static void
+message_add_filter_cb (GeditMessageBus *bus,
+ GeditMessage *message,
+ GeditWindow *window)
+{
+ gchar *object_path = NULL;
+ gchar *method = NULL;
+ gulong id;
+ GeditMessageType *message_type;
+ GeditMessage *cbmessage;
+ FilterData *filter_data;
+ WindowData *data = get_window_data (window);
+
+ gedit_message_get (message,
+ "object_path", &object_path,
+ "method", &method,
+ NULL);
+
+ // Check if there exists such a 'callback' message
+ if (!object_path || !method)
+ {
+ g_free (object_path);
+ g_free (method);
+
+ return;
+ }
+
+ message_type = gedit_message_bus_lookup (bus, object_path, method);
+
+ if (!message_type)
+ {
+ g_free (object_path);
+ g_free (method);
+
+ return;
+ }
+
+ // Check if the message type has the correct arguments
+ if (gedit_message_type_lookup (message_type, "id") != G_TYPE_STRING ||
+ gedit_message_type_lookup (message_type, "uri") != G_TYPE_STRING ||
+ gedit_message_type_lookup (message_type, "is_directory") != G_TYPE_BOOLEAN ||
+ gedit_message_type_lookup (message_type, "filter") != G_TYPE_BOOLEAN)
+ {
+ return;
+ }
+
+ cbmessage = gedit_message_type_instantiate (message_type,
+ "id", NULL,
+ "uri", NULL,
+ "is_directory", FALSE,
+ "filter", FALSE,
+ NULL);
+
+ // Register the custom filter on the widget
+ filter_data = filter_data_new (window, cbmessage);
+ id = gedit_file_browser_widget_add_filter (data->widget,
+ (GeditFileBrowserWidgetFilterFunc)custom_message_filter_func,
+ filter_data,
+ (GDestroyNotify)filter_data_free);
+
+ filter_data->id = id;
+}
+
+static void
+message_remove_filter_cb (GeditMessageBus *bus,
+ GeditMessage *message,
+ WindowData *data)
+{
+ gulong id = 0;
+
+ gedit_message_get (message, "id", &id, NULL);
+
+ if (!id)
+ return;
+
+ gedit_file_browser_widget_remove_filter (data->widget, id);
+}
+
+static void
+message_up_cb (GeditMessageBus *bus,
+ GeditMessage *message,
+ WindowData *data)
+{
+ GeditFileBrowserStore *store = gedit_file_browser_widget_get_browser_store (data->widget);
+
+ gedit_file_browser_store_set_virtual_root_up (store);
+}
+
+static void
+message_history_back_cb (GeditMessageBus *bus,
+ GeditMessage *message,
+ WindowData *data)
+{
+ gedit_file_browser_widget_history_back (data->widget);
+}
+
+static void
+message_history_forward_cb (GeditMessageBus *bus,
+ GeditMessage *message,
+ WindowData *data)
+{
+ gedit_file_browser_widget_history_forward (data->widget);
+}
+
+static void
+message_refresh_cb (GeditMessageBus *bus,
+ GeditMessage *message,
+ WindowData *data)
+{
+ gedit_file_browser_widget_refresh (data->widget);
+}
+
+static void
+message_set_show_hidden_cb (GeditMessageBus *bus,
+ GeditMessage *message,
+ WindowData *data)
+{
+ gboolean active = FALSE;
+ GeditFileBrowserStore *store;
+ GeditFileBrowserStoreFilterMode mode;
+
+ gedit_message_get (message, "active", &active, NULL);
+
+ store = gedit_file_browser_widget_get_browser_store (data->widget);
+ mode = gedit_file_browser_store_get_filter_mode (store);
+
+ if (active)
+ mode &= ~GEDIT_FILE_BROWSER_STORE_FILTER_MODE_HIDE_HIDDEN;
+ else
+ mode |= GEDIT_FILE_BROWSER_STORE_FILTER_MODE_HIDE_HIDDEN;
+
+ gedit_file_browser_store_set_filter_mode (store, mode);
+}
+
+static void
+message_set_show_binary_cb (GeditMessageBus *bus,
+ GeditMessage *message,
+ WindowData *data)
+{
+ gboolean active = FALSE;
+ GeditFileBrowserStore *store;
+ GeditFileBrowserStoreFilterMode mode;
+
+ gedit_message_get (message, "active", &active, NULL);
+
+ store = gedit_file_browser_widget_get_browser_store (data->widget);
+ mode = gedit_file_browser_store_get_filter_mode (store);
+
+ if (active)
+ mode &= ~GEDIT_FILE_BROWSER_STORE_FILTER_MODE_HIDE_BINARY;
+ else
+ mode |= GEDIT_FILE_BROWSER_STORE_FILTER_MODE_HIDE_BINARY;
+
+ gedit_file_browser_store_set_filter_mode (store, mode);
+}
+
+static void
+message_show_bookmarks_cb (GeditMessageBus *bus,
+ GeditMessage *message,
+ WindowData *data)
+{
+ gedit_file_browser_widget_show_bookmarks (data->widget);
+}
+
+static void
+message_show_files_cb (GeditMessageBus *bus,
+ GeditMessage *message,
+ WindowData *data)
+{
+ gedit_file_browser_widget_show_files (data->widget);
+}
+
+static void
+register_methods (GeditWindow *window,
+ GeditFileBrowserWidget *widget)
+{
+ GeditMessageBus *bus = gedit_window_get_message_bus (window);
+ WindowData *data = get_window_data (window);
+
+ /* Register method calls */
+ gedit_message_bus_register (bus,
+ MESSAGE_OBJECT_PATH, "set_root",
+ 1,
+ "uri", G_TYPE_STRING,
+ "virtual", G_TYPE_STRING,
+ NULL);
+
+ gedit_message_bus_register (bus,
+ MESSAGE_OBJECT_PATH, "set_emblem",
+ 0,
+ "id", G_TYPE_STRING,
+ "emblem", G_TYPE_STRING,
+ NULL);
+
+ gedit_message_bus_register (bus,
+ MESSAGE_OBJECT_PATH, "add_filter",
+ 1,
+ "object_path", G_TYPE_STRING,
+ "method", G_TYPE_STRING,
+ "id", G_TYPE_ULONG,
+ NULL);
+
+ gedit_message_bus_register (bus,
+ MESSAGE_OBJECT_PATH, "remove_filter",
+ 0,
+ "id", G_TYPE_ULONG,
+ NULL);
+
+ gedit_message_bus_register (bus, MESSAGE_OBJECT_PATH, "up", 0, NULL);
+
+ gedit_message_bus_register (bus, MESSAGE_OBJECT_PATH, "history_back", 0, NULL);
+ gedit_message_bus_register (bus, MESSAGE_OBJECT_PATH, "history_forward", 0, NULL);
+
+ gedit_message_bus_register (bus, MESSAGE_OBJECT_PATH, "refresh", 0, NULL);
+
+ gedit_message_bus_register (bus,
+ MESSAGE_OBJECT_PATH, "set_show_hidden",
+ 0,
+ "active", G_TYPE_BOOLEAN,
+ NULL);
+ gedit_message_bus_register (bus,
+ MESSAGE_OBJECT_PATH, "set_show_binary",
+ 0,
+ "active", G_TYPE_BOOLEAN,
+ NULL);
+
+ gedit_message_bus_register (bus, MESSAGE_OBJECT_PATH, "show_bookmarks", 0, NULL);
+ gedit_message_bus_register (bus, MESSAGE_OBJECT_PATH, "show_files", 0, NULL);
+
+ BUS_CONNECT (bus, set_root, data);
+ BUS_CONNECT (bus, set_emblem, data);
+ BUS_CONNECT (bus, add_filter, window);
+ BUS_CONNECT (bus, remove_filter, data);
+
+ BUS_CONNECT (bus, up, data);
+ BUS_CONNECT (bus, history_back, data);
+ BUS_CONNECT (bus, history_forward, data);
+
+ BUS_CONNECT (bus, refresh, data);
+
+ BUS_CONNECT (bus, set_show_hidden, data);
+ BUS_CONNECT (bus, set_show_binary, data);
+
+ BUS_CONNECT (bus, show_bookmarks, data);
+ BUS_CONNECT (bus, show_files, data);
+}
+
+static void
+store_row_inserted (GeditFileBrowserStore *store,
+ GtkTreePath *path,
+ GtkTreeIter *iter,
+ MessageCacheData *data)
+{
+ gchar *uri = NULL;
+ guint flags = 0;
+
+ gtk_tree_model_get (GTK_TREE_MODEL (store), iter,
+ GEDIT_FILE_BROWSER_STORE_COLUMN_URI, &uri,
+ GEDIT_FILE_BROWSER_STORE_COLUMN_FLAGS, &flags,
+ -1);
+
+ if (!FILE_IS_DUMMY (flags) && !FILE_IS_FILTERED (flags))
+ {
+ WindowData *wdata = get_window_data (data->window);
+
+ set_item_message (wdata, iter, path, data->message);
+ gedit_message_bus_send_message_sync (wdata->bus, data->message);
+ }
+
+ g_free (uri);
+}
+
+static void
+store_row_deleted (GeditFileBrowserStore *store,
+ GtkTreePath *path,
+ MessageCacheData *data)
+{
+ GtkTreeIter iter;
+ gchar *uri = NULL;
+ guint flags = 0;
+
+ if (!gtk_tree_model_get_iter (GTK_TREE_MODEL (store), &iter, path))
+ return;
+
+ gtk_tree_model_get (GTK_TREE_MODEL (store), &iter,
+ GEDIT_FILE_BROWSER_STORE_COLUMN_URI, &uri,
+ GEDIT_FILE_BROWSER_STORE_COLUMN_FLAGS, &flags,
+ -1);
+
+ if (!FILE_IS_DUMMY (flags) && !FILE_IS_FILTERED (flags))
+ {
+ WindowData *wdata = get_window_data (data->window);
+
+ set_item_message (wdata, &iter, path, data->message);
+ gedit_message_bus_send_message_sync (wdata->bus, data->message);
+ }
+
+ g_free (uri);
+}
+
+static void
+store_virtual_root_changed (GeditFileBrowserStore *store,
+ GParamSpec *spec,
+ MessageCacheData *data)
+{
+ WindowData *wdata = get_window_data (data->window);
+ gchar *uri;
+
+ uri = gedit_file_browser_store_get_virtual_root (store);
+
+ if (!uri)
+ return;
+
+ gedit_message_set (data->message,
+ "uri", uri,
+ NULL);
+
+ gedit_message_bus_send_message_sync (wdata->bus, data->message);
+
+ g_free (uri);
+}
+
+static void
+store_begin_loading (GeditFileBrowserStore *store,
+ GtkTreeIter *iter,
+ MessageCacheData *data)
+{
+ GtkTreePath *path;
+ WindowData *wdata = get_window_data (data->window);
+
+ path = gtk_tree_model_get_path (GTK_TREE_MODEL (store), iter);
+
+ set_item_message (wdata, iter, path, data->message);
+
+ gedit_message_bus_send_message_sync (wdata->bus, data->message);
+ gtk_tree_path_free (path);
+}
+
+static void
+store_end_loading (GeditFileBrowserStore *store,
+ GtkTreeIter *iter,
+ MessageCacheData *data)
+{
+ GtkTreePath *path;
+ WindowData *wdata = get_window_data (data->window);
+
+ path = gtk_tree_model_get_path (GTK_TREE_MODEL (store), iter);
+
+ set_item_message (wdata, iter, path, data->message);
+
+ gedit_message_bus_send_message_sync (wdata->bus, data->message);
+ gtk_tree_path_free (path);
+}
+
+static void
+register_signals (GeditWindow *window,
+ GeditFileBrowserWidget *widget)
+{
+ GeditMessageBus *bus = gedit_window_get_message_bus (window);
+ GeditFileBrowserStore *store;
+ GeditMessageType *inserted_type;
+ GeditMessageType *deleted_type;
+ GeditMessageType *begin_loading_type;
+ GeditMessageType *end_loading_type;
+ GeditMessageType *root_changed_type;
+
+ GeditMessage *message;
+ WindowData *data;
+
+ /* Register signals */
+ root_changed_type = gedit_message_bus_register (bus,
+ MESSAGE_OBJECT_PATH, "root_changed",
+ 0,
+ "id", G_TYPE_STRING,
+ "uri", G_TYPE_STRING,
+ NULL);
+
+ begin_loading_type = gedit_message_bus_register (bus,
+ MESSAGE_OBJECT_PATH, "begin_loading",
+ 0,
+ "id", G_TYPE_STRING,
+ "uri", G_TYPE_STRING,
+ NULL);
+
+ end_loading_type = gedit_message_bus_register (bus,
+ MESSAGE_OBJECT_PATH, "end_loading",
+ 0,
+ "id", G_TYPE_STRING,
+ "uri", G_TYPE_STRING,
+ NULL);
+
+ inserted_type = gedit_message_bus_register (bus,
+ MESSAGE_OBJECT_PATH, "inserted",
+ 0,
+ "id", G_TYPE_STRING,
+ "uri", G_TYPE_STRING,
+ "is_directory", G_TYPE_BOOLEAN,
+ NULL);
+
+ deleted_type = gedit_message_bus_register (bus,
+ MESSAGE_OBJECT_PATH, "deleted",
+ 0,
+ "id", G_TYPE_STRING,
+ "uri", G_TYPE_STRING,
+ "is_directory", G_TYPE_BOOLEAN,
+ NULL);
+
+ store = gedit_file_browser_widget_get_browser_store (widget);
+
+ message = gedit_message_type_instantiate (inserted_type,
+ "id", NULL,
+ "uri", NULL,
+ "is_directory", FALSE,
+ NULL);
+
+ data = get_window_data (window);
+
+ data->row_inserted_id =
+ g_signal_connect_data (store,
+ "row-inserted",
+ G_CALLBACK (store_row_inserted),
+ message_cache_data_new (window, message),
+ (GClosureNotify)message_cache_data_free,
+ 0);
+
+ message = gedit_message_type_instantiate (deleted_type,
+ "id", NULL,
+ "uri", NULL,
+ "is_directory", FALSE,
+ NULL);
+ data->row_deleted_id =
+ g_signal_connect_data (store,
+ "row-deleted",
+ G_CALLBACK (store_row_deleted),
+ message_cache_data_new (window, message),
+ (GClosureNotify)message_cache_data_free,
+ 0);
+
+ message = gedit_message_type_instantiate (root_changed_type,
+ "id", NULL,
+ "uri", NULL,
+ NULL);
+ data->root_changed_id =
+ g_signal_connect_data (store,
+ "notify::virtual-root",
+ G_CALLBACK (store_virtual_root_changed),
+ message_cache_data_new (window, message),
+ (GClosureNotify)message_cache_data_free,
+ 0);
+
+ message = gedit_message_type_instantiate (begin_loading_type,
+ "id", NULL,
+ "uri", NULL,
+ NULL);
+ data->begin_loading_id =
+ g_signal_connect_data (store,
+ "begin_loading",
+ G_CALLBACK (store_begin_loading),
+ message_cache_data_new (window, message),
+ (GClosureNotify)message_cache_data_free,
+ 0);
+
+ message = gedit_message_type_instantiate (end_loading_type,
+ "id", NULL,
+ "uri", NULL,
+ NULL);
+ data->end_loading_id =
+ g_signal_connect_data (store,
+ "end_loading",
+ G_CALLBACK (store_end_loading),
+ message_cache_data_new (window, message),
+ (GClosureNotify)message_cache_data_free,
+ 0);
+}
+
+static void
+message_unregistered (GeditMessageBus *bus,
+ GeditMessageType *message_type,
+ GeditWindow *window)
+{
+ gchar *identifier = gedit_message_type_identifier (gedit_message_type_get_object_path (message_type),
+ gedit_message_type_get_method (message_type));
+ FilterData *data;
+ WindowData *wdata = get_window_data (window);
+
+ data = g_hash_table_lookup (wdata->filters, identifier);
+
+ if (data)
+ gedit_file_browser_widget_remove_filter (wdata->widget, data->id);
+
+ g_free (identifier);
+}
+
+void
+gedit_file_browser_messages_register (GeditWindow *window,
+ GeditFileBrowserWidget *widget)
+{
+ window_data_new (window, widget);
+
+ register_methods (window, widget);
+ register_signals (window, widget);
+
+ g_signal_connect (gedit_window_get_message_bus (window),
+ "unregistered",
+ G_CALLBACK (message_unregistered),
+ window);
+}
+
+static void
+cleanup_signals (GeditWindow *window)
+{
+ WindowData *data = get_window_data (window);
+ GeditFileBrowserStore *store;
+
+ store = gedit_file_browser_widget_get_browser_store (data->widget);
+
+ g_signal_handler_disconnect (store, data->row_inserted_id);
+ g_signal_handler_disconnect (store, data->row_deleted_id);
+ g_signal_handler_disconnect (store, data->root_changed_id);
+ g_signal_handler_disconnect (store, data->begin_loading_id);
+ g_signal_handler_disconnect (store, data->end_loading_id);
+
+ g_signal_handlers_disconnect_by_func (data->bus, "unregistered", window);
+}
+
+void
+gedit_file_browser_messages_unregister (GeditWindow *window)
+{
+ GeditMessageBus *bus = gedit_window_get_message_bus (window);
+
+ cleanup_signals (window);
+ gedit_message_bus_unregister_all (bus, MESSAGE_OBJECT_PATH);
+
+ window_data_free (window);
+}
Added: trunk/plugins/filebrowser/gedit-file-browser-messages.h
==============================================================================
--- (empty file)
+++ trunk/plugins/filebrowser/gedit-file-browser-messages.h Mon Dec 29 18:52:22 2008
@@ -0,0 +1,35 @@
+/*
+ * gedit-file-browser-messages.h - Gedit plugin providing easy file access
+ * from the sidepanel
+ *
+ * Copyright (C) 2008 - Jesse van den Kieboom <jesse icecrew nl>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __GEDIT_FILE_BROWSER_MESSAGES_H__
+#define __GEDIT_FILE_BROWSER_MESSAGES_H__
+
+#include <gedit/gedit-window.h>
+#include <gedit/gedit-message-bus.h>
+#include "gedit-file-browser-widget.h"
+
+void gedit_file_browser_messages_register (GeditWindow *window,
+ GeditFileBrowserWidget *widget);
+void gedit_file_browser_messages_unregister (GeditWindow *window);
+
+#endif /* __GEDIT_FILE_BROWSER_MESSAGES_H__ */
+
+// ex:ts=8:noet:
Modified: trunk/plugins/filebrowser/gedit-file-browser-plugin.c
==============================================================================
--- trunk/plugins/filebrowser/gedit-file-browser-plugin.c (original)
+++ trunk/plugins/filebrowser/gedit-file-browser-plugin.c Mon Dec 29 18:52:22 2008
@@ -37,6 +37,7 @@
#include "gedit-file-browser-utils.h"
#include "gedit-file-browser-error.h"
#include "gedit-file-browser-widget.h"
+#include "gedit-file-browser-messages.h"
#define WINDOW_DATA_KEY "GeditFileBrowserPluginWindowData"
#define FILE_BROWSER_BASE_KEY "/apps/gedit-2/plugins/filebrowser"
@@ -779,7 +780,10 @@
"tab-added",
G_CALLBACK (on_tab_added_cb),
data);
-
+
+ /* Register messages on the bus */
+ gedit_file_browser_messages_register (window, data->tree_widget);
+
impl_updateui (plugin, window);
}
@@ -792,6 +796,9 @@
data = get_plugin_data (window);
+ /* Unregister messages from the bus */
+ gedit_file_browser_messages_unregister (window);
+
/* Disconnect signals */
g_signal_handlers_disconnect_by_func (window,
G_CALLBACK (on_tab_added_cb),
Modified: trunk/plugins/filebrowser/gedit-file-browser-view.c
==============================================================================
--- trunk/plugins/filebrowser/gedit-file-browser-view.c (original)
+++ trunk/plugins/filebrowser/gedit-file-browser-view.c Mon Dec 29 18:52:22 2008
@@ -125,7 +125,10 @@
gtk_tree_path_free (obj->priv->hover_path);
if (obj->priv->expand_state)
+ {
g_hash_table_destroy (obj->priv->expand_state);
+ obj->priv->expand_state = NULL;
+ }
gdk_cursor_unref (obj->priv->busy_cursor);
@@ -143,7 +146,11 @@
return;
file = g_file_new_for_uri (uri);
- g_hash_table_insert (view->priv->expand_state, file, file);
+
+ if (view->priv->expand_state)
+ g_hash_table_insert (view->priv->expand_state, file, file);
+ else
+ g_object_unref (file);
}
static void
@@ -156,7 +163,10 @@
return;
file = g_file_new_for_uri (uri);
- g_hash_table_remove (view->priv->expand_state, file);
+
+ if (view->priv->expand_state)
+ g_hash_table_remove (view->priv->expand_state, file);
+
g_object_unref (file);
}
Modified: trunk/plugins/filebrowser/gedit-file-browser-widget.c
==============================================================================
--- trunk/plugins/filebrowser/gedit-file-browser-widget.c (original)
+++ trunk/plugins/filebrowser/gedit-file-browser-widget.c Mon Dec 29 18:52:22 2008
@@ -99,6 +99,7 @@
gulong id;
GeditFileBrowserWidgetFilterFunc func;
gpointer user_data;
+ GDestroyNotify destroy_notify;
} FilterFunc;
typedef struct
@@ -249,7 +250,8 @@
static FilterFunc *
filter_func_new (GeditFileBrowserWidget * obj,
GeditFileBrowserWidgetFilterFunc func,
- gpointer user_data)
+ gpointer user_data,
+ GDestroyNotify notify)
{
FilterFunc *result;
@@ -258,7 +260,7 @@
result->id = ++obj->priv->filter_id;
result->func = func;
result->user_data = user_data;
-
+ result->destroy_notify = notify;
return result;
}
@@ -1646,6 +1648,7 @@
obj->priv->glob_filter_id =
gedit_file_browser_widget_add_filter (obj,
filter_glob,
+ NULL,
NULL);
}
@@ -1705,16 +1708,32 @@
bookmarks_store));
}
+static void
+show_files_real (GeditFileBrowserWidget *obj,
+ gboolean do_root_changed)
+{
+ gedit_file_browser_view_set_model (obj->priv->treeview,
+ GTK_TREE_MODEL (obj->priv->
+ file_store));
+
+ if (do_root_changed)
+ on_virtual_root_changed (obj->priv->file_store, NULL, obj);
+}
+
+void
+gedit_file_browser_widget_show_files (GeditFileBrowserWidget * obj)
+{
+ show_files_real (obj, TRUE);
+}
+
void
gedit_file_browser_widget_set_root_and_virtual_root (GeditFileBrowserWidget *obj,
gchar const *root,
gchar const *virtual_root)
{
GeditFileBrowserStoreResult result;
-
- gedit_file_browser_view_set_model (obj->priv->treeview,
- GTK_TREE_MODEL (obj->priv->
- file_store));
+
+ show_files_real (obj, FALSE);
if (!virtual_root)
result =
@@ -1725,8 +1744,7 @@
gedit_file_browser_store_set_root_and_virtual_root
(obj->priv->file_store, root, virtual_root);
- if (result == GEDIT_FILE_BROWSER_STORE_RESULT_NO_CHANGE)
- on_virtual_root_changed (obj->priv->file_store, NULL, obj);
+ show_files_real (obj, result == GEDIT_FILE_BROWSER_STORE_RESULT_NO_CHANGE);
}
void
@@ -1793,14 +1811,15 @@
gulong
gedit_file_browser_widget_add_filter (GeditFileBrowserWidget * obj,
- GeditFileBrowserWidgetFilterFunc
- func, gpointer user_data)
+ GeditFileBrowserWidgetFilterFunc func,
+ gpointer user_data,
+ GDestroyNotify notify)
{
FilterFunc *f;
GtkTreeModel *model =
gtk_tree_view_get_model (GTK_TREE_VIEW (obj->priv->treeview));
- f = filter_func_new (obj, func, user_data);
+ f = filter_func_new (obj, func, user_data, notify);
obj->priv->filter_funcs =
g_slist_append (obj->priv->filter_funcs, f);
@@ -1818,10 +1837,15 @@
GSList *item;
FilterFunc *func;
- for (item = obj->priv->filter_funcs; item; item = item->next) {
+ for (item = obj->priv->filter_funcs; item; item = item->next)
+ {
func = (FilterFunc *) (item->data);
- if (func->id == id) {
+ if (func->id == id)
+ {
+ if (func->destroy_notify)
+ func->destroy_notify (func->user_data);
+
obj->priv->filter_funcs =
g_slist_remove_link (obj->priv->filter_funcs,
item);
@@ -2178,6 +2202,46 @@
g_object_unref (volume);
}
+void
+gedit_file_browser_widget_refresh (GeditFileBrowserWidget *obj)
+{
+ GtkTreeModel *model =
+ gtk_tree_view_get_model (GTK_TREE_VIEW (obj->priv->treeview));
+
+ if (GEDIT_IS_FILE_BROWSER_STORE (model))
+ gedit_file_browser_store_refresh (GEDIT_FILE_BROWSER_STORE
+ (model));
+ else if (GEDIT_IS_FILE_BOOKMARKS_STORE (model)) {
+ g_hash_table_ref (obj->priv->bookmarks_hash);
+ g_hash_table_destroy (obj->priv->bookmarks_hash);
+
+ gedit_file_bookmarks_store_refresh
+ (GEDIT_FILE_BOOKMARKS_STORE (model));
+ }
+}
+
+void
+gedit_file_browser_widget_history_back (GeditFileBrowserWidget *obj)
+{
+ if (obj->priv->locations) {
+ if (obj->priv->current_location)
+ jump_to_location (obj,
+ obj->priv->current_location->
+ next, TRUE);
+ else {
+ jump_to_location (obj, obj->priv->locations, TRUE);
+ }
+ }
+}
+
+void
+gedit_file_browser_widget_history_forward (GeditFileBrowserWidget *obj)
+{
+ if (obj->priv->locations)
+ jump_to_location (obj, obj->priv->current_location->prev,
+ FALSE);
+}
+
/* Callbacks */
static void
on_bookmark_activated (GeditFileBrowserView *tree_view,
@@ -2712,24 +2776,14 @@
static void
on_action_directory_next (GtkAction * action, GeditFileBrowserWidget * obj)
{
- if (obj->priv->locations)
- jump_to_location (obj, obj->priv->current_location->prev,
- FALSE);
+ gedit_file_browser_widget_history_forward (obj);
}
static void
on_action_directory_previous (GtkAction * action,
GeditFileBrowserWidget * obj)
{
- if (obj->priv->locations) {
- if (obj->priv->current_location)
- jump_to_location (obj,
- obj->priv->current_location->
- next, TRUE);
- else {
- jump_to_location (obj, obj->priv->locations, TRUE);
- }
- }
+ gedit_file_browser_widget_history_back (obj);
}
static void
@@ -2810,19 +2864,7 @@
on_action_directory_refresh (GtkAction * action,
GeditFileBrowserWidget * obj)
{
- GtkTreeModel *model =
- gtk_tree_view_get_model (GTK_TREE_VIEW (obj->priv->treeview));
-
- if (GEDIT_IS_FILE_BROWSER_STORE (model))
- gedit_file_browser_store_refresh (GEDIT_FILE_BROWSER_STORE
- (model));
- else if (GEDIT_IS_FILE_BOOKMARKS_STORE (model)) {
- g_hash_table_ref (obj->priv->bookmarks_hash);
- g_hash_table_destroy (obj->priv->bookmarks_hash);
-
- gedit_file_bookmarks_store_refresh
- (GEDIT_FILE_BOOKMARKS_STORE (model));
- }
+ gedit_file_browser_widget_refresh (obj);
}
static gboolean
Modified: trunk/plugins/filebrowser/gedit-file-browser-widget.h
==============================================================================
--- trunk/plugins/filebrowser/gedit-file-browser-widget.h (original)
+++ trunk/plugins/filebrowser/gedit-file-browser-widget.h Mon Dec 29 18:52:22 2008
@@ -76,6 +76,8 @@
GtkWidget *gedit_file_browser_widget_new (const gchar *data_dir);
void gedit_file_browser_widget_show_bookmarks (GeditFileBrowserWidget * obj);
+void gedit_file_browser_widget_show_files (GeditFileBrowserWidget * obj);
+
void gedit_file_browser_widget_set_root (GeditFileBrowserWidget * obj,
gchar const *root,
gboolean virtual_root);
@@ -104,13 +106,18 @@
gulong gedit_file_browser_widget_add_filter (GeditFileBrowserWidget * obj,
GeditFileBrowserWidgetFilterFunc func,
- gpointer user_data);
+ gpointer user_data,
+ GDestroyNotify notify);
void gedit_file_browser_widget_remove_filter (GeditFileBrowserWidget * obj,
gulong id);
void gedit_file_browser_widget_set_filter_pattern (GeditFileBrowserWidget * obj,
gchar const *pattern);
+void gedit_file_browser_widget_refresh (GeditFileBrowserWidget * obj);
+void gedit_file_browser_widget_history_back (GeditFileBrowserWidget * obj);
+void gedit_file_browser_widget_history_forward (GeditFileBrowserWidget * obj);
+
G_END_DECLS
-#endif /* __GEDIT_FILE_BROWSER_WIDGET_H__ */
+#endif /* __GEDIT_FILE_BROWSER_WIDGET_H__ */
// ex:ts=8:noet:
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]