gedit r6755 - in trunk: . docs/reference docs/reference/tmpl gedit plugin-loaders/python/bindings plugins/filebrowser



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 (&copy, G_VALUE_TYPE (container));
+		g_value_copy (container, &copy);
+		
+		G_VALUE_LCOPY (&copy, 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 (&copy);
+	}
+}
+
+/**
+ * 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]