gedit r6625 - in branches/message_system: gedit plugin-loaders/python/bindings



Author: jessevdk
Date: Wed Nov 26 16:45:01 2008
New Revision: 6625
URL: http://svn.gnome.org/viewvc/gedit?rev=6625&view=rev

Log:
Basic, unfinished message bus implementation


Added:
   branches/message_system/gedit/gedit-commands-messages.c
   branches/message_system/gedit/gedit-message-bus.c
   branches/message_system/gedit/gedit-message-bus.h
   branches/message_system/gedit/gedit-message.c
   branches/message_system/gedit/gedit-message.h
   branches/message_system/plugin-loaders/python/bindings/geditmessage.override
Modified:
   branches/message_system/gedit/Makefile.am
   branches/message_system/gedit/gedit-commands.h
   branches/message_system/gedit/gedit.c
   branches/message_system/plugin-loaders/python/bindings/Makefile.am
   branches/message_system/plugin-loaders/python/bindings/gedit.defs
   branches/message_system/plugin-loaders/python/bindings/gedit.override

Modified: branches/message_system/gedit/Makefile.am
==============================================================================
--- branches/message_system/gedit/Makefile.am	(original)
+++ branches/message_system/gedit/Makefile.am	Wed Nov 26 16:45:01 2008
@@ -21,7 +21,9 @@
 	-DGEDIT_ICONDIR=\""$(datadir)/gedit-2/icons"\"
 
 gedit_SOURCES = \
-	gedit.c
+	gedit.c \
+	gedit-message.c \
+	gedit-message-bus.c
 
 gedit_LDADD = libgedit.la $(GEDIT_LIBS)
  
@@ -84,7 +86,9 @@
 	gedit-encodings-option-menu.h	\
 	gedit-file-chooser-dialog.h	\
 	gedit-help.h 			\
+	gedit-message.h			\
 	gedit-message-area.h		\
+	gedit-message-bus.h		\
 	gedit-metadata-manager.h	\
 	gedit-notebook.h		\
 	gedit-panel.h			\

Added: branches/message_system/gedit/gedit-commands-messages.c
==============================================================================
--- (empty file)
+++ branches/message_system/gedit/gedit-commands-messages.c	Wed Nov 26 16:45:01 2008
@@ -0,0 +1,321 @@
+/*
+ * gedit-commands-messages.c
+ * This file is part of gedit
+ *
+ * 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 of the License, 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.
+ */
+
+#include "gedit-commands.h"
+
+#include "gedit-app.h"
+#include "gedit-window.h"
+#include "gedit-encodings.h"
+#include "gedit-message-bus.h"
+
+#include <gdk/gdkx.h>
+#include <string.h>
+
+#define BUS_CONNECT(domain, name, callback) gedit_message_bus_connect (bus, domain, name, callback, NULL, NULL)
+
+static GdkDisplay *
+display_open_if_needed (const gchar *name)
+{
+	GSList *displays;
+	GSList *l;
+	GdkDisplay *display = NULL;
+
+	displays = gdk_display_manager_list_displays (gdk_display_manager_get ());
+
+	for (l = displays; l != NULL; l = l->next)
+	{
+		if (strcmp (gdk_display_get_name ((GdkDisplay *) l->data), name) == 0)
+		{
+			display = l->data;
+			break;
+		}
+	}
+
+	g_slist_free (displays);
+
+	return display != NULL ? display : gdk_display_open (name);
+}
+
+static GeditWindow *
+get_window_from_message (GeditMessage *message)
+{
+	gboolean new_window = FALSE;
+	GeditApp *app;
+	const gchar *invalid_key;
+	
+	/* optional parameters, used to specify correct workspace/viewport */
+	GdkScreen *screen = NULL;
+	gint screen_number = -1;
+	gint workspace = -1;
+	gint viewport_x = -1;
+	gint viewport_y = -1;
+	gchar *display_name = NULL;
+
+	if (!gedit_message_get_type_safe (message,
+				          &invalid_key,
+				          "new_window", G_TYPE_BOOLEAN, &new_window,
+				          "screen_number", G_TYPE_INT, &screen_number,
+				          "workspace", G_TYPE_INT, &workspace,
+				          "viewport_x", G_TYPE_INT, &viewport_x,
+				          "viewport_y", G_TYPE_INT, &viewport_y,
+				          "display_name", G_TYPE_STRING, &display_name,
+				          NULL))
+	{
+		g_warning ("Message contains invalid value for key `%s'", invalid_key);
+		g_free (display_name);
+		return NULL;
+	}
+
+	app = gedit_app_get_default ();
+	
+	/* get correct screen using the display_name and screen_number */
+	if (display_name != NULL)
+	{
+		GdkDisplay *display;
+		
+		display = display_open_if_needed (display_name);
+		screen = gdk_display_get_screen (display, screen_number == -1 ? 0 : screen_number);
+	}
+	
+	if (new_window)
+		return gedit_app_create_window (app, screen);
+	else if (screen != NULL)
+		return _gedit_app_get_window_in_viewport (app,
+							  screen,
+							  workspace == -1 ? 0 : workspace,
+							  viewport_x == -1 ? 0 : viewport_x,
+							  viewport_y == -1 ? 0 : viewport_y);
+	else
+		return gedit_app_get_active_window (app);
+}
+
+static void
+set_interaction_time_and_present (GeditWindow *window,
+				  guint32      startup_timestamp)
+{
+	/* set the proper interaction time on the window.
+	 * Fall back to roundtripping to the X server when we
+	 * don't have the timestamp, e.g. when launched from
+	 * terminal. We also need to make sure that the window
+	 * has been realized otherwise it will not work. lame.
+	 */
+	if (!GTK_WIDGET_REALIZED (window))
+		gtk_widget_realize (GTK_WIDGET (window));
+
+	if (startup_timestamp <= 0)
+		startup_timestamp = gdk_x11_get_server_time (GTK_WIDGET (window)->window);
+
+	gdk_x11_window_set_user_time (GTK_WIDGET (window)->window,
+				      startup_timestamp);
+
+	gtk_window_present (GTK_WINDOW (window));
+}
+
+static void
+on_message_commands_open (GeditMessageBus *bus, 
+			  GeditMessage    *message,
+			  gpointer         userdata)
+{
+	GStrv uris = NULL;
+	gchar *encoding_charset = NULL;
+	gint line_position = 0;
+	const GeditEncoding *encoding = NULL;
+	GSList *uri_list = NULL;
+	const gchar *invalid_key;
+	GStrv ptr;
+	guint32 startup_timestamp = 0;
+	GeditWindow *window;
+
+	if (gedit_message_has_key (message, "uris") && 
+	    gedit_message_type_check (message, NULL, G_TYPE_STRV, "uris", NULL))
+	{
+		/* good, this is what we want, list of uris */
+		gedit_message_get (message, "uris", &uris, NULL);
+		
+	}
+	else if (gedit_message_has_key (message, "uri") &&
+	         gedit_message_type_check (message, NULL, G_TYPE_STRING, "uri", NULL))
+	{
+		/* single uri is also supported, we put it in uris */
+		uris = g_new0 (gchar *, 2);
+		gedit_message_get (message, "uri", uris, NULL);
+	}
+	
+	/* check if we got at least one uri */
+	if (uris == NULL || *uris == NULL)
+	{
+		g_strfreev (uris);
+		return;
+	}
+	
+	window = get_window_from_message (message);
+	
+	if (window == NULL)
+	{
+		g_strfreev (uris);
+		return;
+	}
+	
+	/* get all the other parameters */
+	if (!gedit_message_get_type_safe (message,
+				          &invalid_key,
+				          "encoding", G_TYPE_STRING, &encoding_charset,
+				          "line_position", G_TYPE_INT, &line_position,
+				          "startup_timestamp", G_TYPE_UINT, &startup_timestamp,
+				          NULL))
+	{
+		g_warning ("Message commands.open contains invalid value for key `%s'", invalid_key);
+
+		g_strfreev (uris);
+		g_free (encoding_charset);
+		return;
+	}
+
+	if (encoding_charset != NULL)
+		encoding = gedit_encoding_get_from_charset (encoding_charset);
+
+	ptr = uris;
+	
+	while (*ptr)
+	{
+		uri_list = g_slist_prepend (uri_list, *ptr);
+		ptr++;
+	}
+	
+	uri_list = g_slist_reverse (uri_list);
+	
+	_gedit_cmd_load_files_from_prompt (window, uri_list, encoding, line_position);
+	
+	/* set the proper interaction time on the window.
+	 * Fall back to roundtripping to the X server when we
+	 * don't have the timestamp, e.g. when launched from
+	 * terminal. We also need to make sure that the window
+	 * has been realized otherwise it will not work. lame.
+	 */
+	set_interaction_time_and_present (window, startup_timestamp);
+
+	g_strfreev (uris);
+	g_free (encoding_charset);
+
+	g_slist_free (uri_list);
+}
+
+static void
+on_message_commands_new_document (GeditMessageBus *bus,
+				  GeditMessage    *message,
+				  gpointer         userdata)
+{
+	GeditWindow *window;
+	const gchar *invalid_key;
+	guint32 startup_timestamp = 0;
+	
+	window = get_window_from_message (message);
+	
+	if (window == NULL)
+		return;
+
+	if (!gedit_message_get_type_safe (message,
+				          &invalid_key,
+				          "startup_timestamp", G_TYPE_UINT, &startup_timestamp,
+				          NULL))
+	{
+		g_warning ("Message contains invalid value for key `%s'", invalid_key);
+		return;
+	}
+	
+	gedit_window_create_tab (window, TRUE);
+	
+	/* set the proper interaction time on the window.
+	 * Fall back to roundtripping to the X server when we
+	 * don't have the timestamp, e.g. when launched from
+	 * terminal. We also need to make sure that the window
+	 * has been realized otherwise it will not work. lame.
+	 */
+	set_interaction_time_and_present (window, startup_timestamp);
+}
+
+static void
+on_message_commands_present (GeditMessageBus *bus,
+			     GeditMessage    *message,
+			     gpointer         userdata)
+{
+	GeditWindow *window;
+	const gchar *invalid_key;
+	guint32 startup_timestamp = 0;
+	gboolean new_document = FALSE;
+	GeditDocument *doc;
+
+	window = get_window_from_message (message);
+	
+	if (window == NULL)
+		return;
+
+	if (!gedit_message_get_type_safe (message,
+				          &invalid_key,
+				          "new_document", G_TYPE_BOOLEAN, &new_document,
+				          "startup_timestamp", G_TYPE_UINT, &startup_timestamp,
+				          NULL))
+	{
+		g_warning ("Message contains invalid value for key `%s'", invalid_key);
+		return;
+	}
+	
+	
+	doc = gedit_window_get_active_document (window);
+
+	if (doc == NULL ||
+	    !gedit_document_is_untouched (doc) ||
+	    new_document)
+		gedit_window_create_tab (window, TRUE);
+	
+	/* set the proper interaction time on the window.
+	 * Fall back to roundtripping to the X server when we
+	 * don't have the timestamp, e.g. when launched from
+	 * terminal. We also need to make sure that the window
+	 * has been realized otherwise it will not work. lame.
+	 */
+	set_interaction_time_and_present (window, startup_timestamp);
+}
+
+void
+_gedit_commands_messages_register ()
+{
+	GeditMessageBus *bus;
+	
+	/* register message handlers on the message bus */
+	bus = gedit_message_bus_get_default ();
+	
+	/* open list of uris, or single uri */
+	BUS_CONNECT ("core", "open", on_message_commands_open);
+	
+	/* alias "open_uris", "open_uri", "load", "load_uris", "load_uri" */
+	BUS_CONNECT ("core", "open_uris", on_message_commands_open);
+	BUS_CONNECT ("core", "open_uri", on_message_commands_open);
+	BUS_CONNECT ("core", "load", on_message_commands_open);
+	BUS_CONNECT ("core", "load_uris", on_message_commands_open);
+	BUS_CONNECT ("core", "load_uri", on_message_commands_open);
+	
+	/* new document message, used by gedit startup */
+	BUS_CONNECT ("core", "new_document", on_message_commands_new_document);
+	
+	BUS_CONNECT ("core", "present", on_message_commands_present);
+}

Modified: branches/message_system/gedit/gedit-commands.h
==============================================================================
--- branches/message_system/gedit/gedit-commands.h	(original)
+++ branches/message_system/gedit/gedit-commands.h	Wed Nov 26 16:45:01 2008
@@ -151,6 +151,8 @@
 void		_gedit_cmd_file_save_documents_list	(GeditWindow *window,
 							 GList       *docs);
 
+//void		_gedit_commands_messages_register	(void);
+
 G_END_DECLS
 
 #endif /* __GEDIT_COMMANDS_H__ */ 

Added: branches/message_system/gedit/gedit-message-bus.c
==============================================================================
--- (empty file)
+++ branches/message_system/gedit/gedit-message-bus.c	Wed Nov 26 16:45:01 2008
@@ -0,0 +1,941 @@
+#include "gedit-message-bus.h"
+
+#include <string.h>
+#include <stdarg.h>
+#include <gobject/gvaluecollector.h>
+
+#define GEDIT_MESSAGE_BUS_GET_PRIVATE(object)(G_TYPE_INSTANCE_GET_PRIVATE((object), GEDIT_TYPE_MESSAGE_BUS, GeditMessageBusPrivate))
+
+typedef struct
+{
+	gchar *domain;
+	gchar *name;
+
+	GList *listeners;
+} Message;
+
+typedef struct
+{
+	gchar *key;
+	GType type;
+	gboolean required;
+} PolicyItem;
+
+typedef struct
+{
+	gchar *domain;
+	gchar *name;
+	
+	GList *policies; /* list of PolicyItem */
+} Policy;
+
+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 *policies;
+};
+
+/* signals */
+enum
+{
+	DISPATCH,
+	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
+policy_item_free (PolicyItem *pitem)
+{
+	g_free (pitem->key);
+	g_free (pitem);
+}
+
+static void
+policy_free (Policy *policy)
+{
+	GList *item;
+	
+	g_free (policy->domain);
+	g_free (policy->name);
+	
+	for (item = policy->policies; item; item = item->next)
+		policy_item_free ((PolicyItem *)item->data);
+	
+	g_list_free (policy->policies);
+	g_free (policy);
+}
+
+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->name);
+	g_free (message->domain);
+	
+	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_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;
+
+	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);
+
+	g_type_class_add_private (object_class, sizeof(GeditMessageBusPrivate));
+}
+
+inline static gchar *
+msg_identifier (const gchar *domain,
+		const gchar *name)
+{
+	return g_strconcat (domain, "::", name, NULL);
+}
+
+static Message *
+message_new (GeditMessageBus *bus,
+	     const gchar     *domain,
+	     const gchar     *name)
+{
+	Message *message = g_new (Message, 1);
+	
+	message->domain = g_strdup (domain);
+	message->name = g_strdup (name);
+	message->listeners = NULL;
+
+	g_hash_table_insert (bus->priv->messages, 
+			     msg_identifier (domain, name),
+			     message);
+	return message;
+}
+
+static Message *
+lookup_message (GeditMessageBus *bus,
+	       const gchar      *domain,
+	       const gchar      *name,
+	       gboolean          create)
+{
+	gchar *identifier;
+	Message *message;
+	
+	identifier = msg_identifier (domain, name);
+	message = (Message *)g_hash_table_lookup (bus->priv->messages, identifier);
+	g_free (identifier);
+
+	if (!message && !create)
+		return NULL;
+	
+	if (!message)
+		message = message_new (bus, domain, name);
+	
+	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 *domain;
+	const gchar *name;
+	Message *msg;
+	
+	domain = gedit_message_get_domain (message);
+	name = gedit_message_get_name (message);
+
+	msg = lookup_message (bus, domain, name, 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          *domain,
+	          const gchar          *name,
+	          GeditMessageCallback  callback,
+	          gpointer              userdata,
+	          MatchCallback         processor)
+{
+	Message *message;
+	GList *item;
+	
+	message = lookup_message (bus, domain, name, FALSE);
+	
+	if (!message)
+	{
+		g_warning ("No such handler registered for %s::%s", domain, name);
+		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", domain, name);
+}
+
+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->policies = g_hash_table_new_full (g_str_hash,
+						      g_str_equal,
+						      (GDestroyNotify)g_free,
+						      (GDestroyNotify)policy_free);
+}
+
+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;
+}
+
+void
+gedit_message_bus_register (GeditMessageBus *bus,
+			    const gchar     *domain,
+			    const gchar	    *name,
+			    guint	     num_optional,
+			    ...)
+{
+	gchar *identifier;
+	gpointer data;
+	Policy *policy;
+	va_list var_args;
+	const gchar *key;
+	GList *item;
+	
+	g_return_if_fail (GEDIT_IS_MESSAGE_BUS (bus));
+	
+	identifier = msg_identifier (domain, name);
+	data = g_hash_table_lookup (bus->priv->policies, identifier);
+	
+	if (data != NULL)
+	{
+		/* policy is already registered */
+		g_free (identifier);
+		return;
+	}
+	
+	policy = g_new(Policy, 1);
+	policy->domain = g_strdup (domain);
+	policy->name = g_strdup (name);
+	policy->policies = NULL;
+	
+	/* construct policy items */
+	va_start (var_args, num_optional);
+
+	/* read in required items */
+	while ((key = va_arg (var_args, const gchar *)) != NULL)
+	{
+		GType gtype;
+		PolicyItem *pitem;
+		
+		gtype = va_arg (var_args, GType);
+		
+		if (!_gedit_message_gtype_supported (gtype))
+		{
+			g_warning ("Type `%s' is not supported on the message bus",
+				   g_type_name (gtype));
+			continue;
+		}
+		
+		pitem = g_new(PolicyItem, 1);
+		pitem->key = g_strdup (key);
+		pitem->type = gtype;
+
+		policy->policies = g_list_prepend (policy->policies, pitem);
+	}
+	
+	for (item = policy->policies; num_optional-- > 0 && item; item = item->next)
+		((PolicyItem *)item->data)->required = FALSE;
+	
+	policy->policies = g_list_reverse (policy->policies);
+	g_hash_table_insert (bus->priv->policies, identifier, policy);
+}
+
+void
+gedit_message_bus_unregister (GeditMessageBus *bus,
+			      const gchar     *domain,
+			      const gchar     *name)
+{
+	gchar *identifier;
+	
+	g_return_if_fail (GEDIT_IS_MESSAGE_BUS (bus));
+
+	identifier = msg_identifier (domain, name);
+	g_hash_table_remove (bus->priv->policies, name);
+	g_free (identifier);
+}
+
+void
+gedit_message_bus_unregister_all (GeditMessageBus *bus,
+			          const gchar     *domain)
+{
+	GList *pols;
+	GList *item;
+	g_return_if_fail (GEDIT_IS_MESSAGE_BUS (bus));
+
+	pols = g_hash_table_get_values (bus->priv->policies);
+	
+	for (item = pols; item; item = item->next)
+	{
+		Policy *policy = (Policy *)item->data;
+		
+		if (strcmp (policy->domain, domain) == 0)
+		{
+			gchar *identifier = msg_identifier (policy->domain, policy->name);
+			g_hash_table_remove (bus->priv->policies, identifier);
+			g_free (identifier);
+		}
+	}
+	
+	g_list_free (pols);
+}
+
+guint
+gedit_message_bus_connect (GeditMessageBus	*bus, 
+		           const gchar		*domain,
+		           const gchar		*name,
+		           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 (domain != NULL, 0);
+	g_return_val_if_fail (name != 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, domain, name, TRUE);
+	
+	return add_listener (bus, message, callback, userdata, destroy_data);
+}
+
+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);
+}
+
+void
+gedit_message_bus_disconnect_by_func (GeditMessageBus      *bus,
+				      const gchar	   *domain,
+				      const gchar	   *name,
+				      GeditMessageCallback  callback,
+				      gpointer		    userdata)
+{
+	g_return_if_fail (GEDIT_IS_MESSAGE_BUS (bus));
+	
+	process_by_match (bus, domain, name, callback, userdata, remove_listener);
+}
+
+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);
+}
+
+void
+gedit_message_bus_block_by_func (GeditMessageBus      *bus,
+				 const gchar	      *domain,
+				 const gchar	      *name,
+				 GeditMessageCallback  callback,
+				 gpointer	       userdata)
+{
+	g_return_if_fail (GEDIT_IS_MESSAGE_BUS (bus));
+	
+	process_by_match (bus, domain, name, callback, userdata, block_listener);
+}
+
+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);
+}
+
+void
+gedit_message_bus_unblock_by_func (GeditMessageBus      *bus,
+				   const gchar	        *domain,
+				   const gchar	        *name,
+				   GeditMessageCallback  callback,
+				   gpointer	         userdata)
+{
+	g_return_if_fail (GEDIT_IS_MESSAGE_BUS (bus));
+	
+	process_by_match (bus, domain, name, callback, userdata, unblock_listener);
+}
+
+static gboolean
+check_message_policy (GeditMessageBus *bus,
+		      GeditMessage    *message)
+{
+	const gchar *domain = gedit_message_get_domain (message);
+	const gchar *name = gedit_message_get_name (message);
+	
+	gchar *identifier = msg_identifier (domain, name);
+	Policy *policy = (Policy *)g_hash_table_lookup (bus->priv->policies, identifier);
+	PolicyItem *pitem;
+	GList *item;
+	
+	g_free (identifier);
+
+	if (policy == NULL)
+	{
+		g_warning ("Policy for '%s::%s' could not be found", domain, name);
+		return FALSE;
+	}
+	
+	/* check all required and optional arguments */
+	for (item = policy->policies; item; item = item->next)
+	{
+		GType gtype;
+		gboolean haskey;
+		
+		pitem = (PolicyItem *)item->data;
+		
+		/* check if key exists */
+		haskey = gedit_message_has_key (message, pitem->key);
+		
+		if (pitem->required && !haskey)
+		{
+			g_warning ("Required key %s not found for %s::%s", pitem->key, domain, name);
+			return FALSE;
+		}
+		else if (!haskey && !pitem->required)
+		{
+			continue;
+		}
+		
+		gtype = gedit_message_get_key_type (message, pitem->key);
+		
+		if (!g_type_is_a (pitem->type, gtype) && 
+		    !g_value_type_transformable (pitem->type, gtype))
+		{
+			g_warning ("Invalid key type for %s::%s, expected %s, got %s", domain, name, g_type_name (pitem->type), g_type_name (gtype));
+			return FALSE;
+		}
+	}
+	
+	return TRUE;
+}
+
+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));
+	
+	if (!check_message_policy (bus, 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);
+}
+
+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));
+	
+	if (!check_message_policy (bus, message))
+		return;
+
+	dispatch_message (bus, message);
+}
+
+static GType
+policy_find_type (Policy      *policy, 
+		  const gchar *key)
+{
+	GList *item;
+	
+	for (item = policy->policies; item; item = item->next)
+	{
+		PolicyItem *pitem = (PolicyItem *)item->data;
+		
+		if (strcmp (pitem->key, key) == 0)
+			return pitem->type;
+	}
+	
+	return 0;
+}
+
+static GeditMessage *
+create_message (GeditMessageBus *bus,
+		const gchar     *domain,
+		const gchar     *name,
+		va_list          var_args)
+{
+	const gchar **keys = NULL;
+	GType *types = NULL;
+	GValue *values = NULL;
+	gint num = 0;
+	const gchar *key;
+	gchar *identifier;
+	GeditMessage *message;
+	Policy *policy;
+	gint i;
+	
+	identifier = msg_identifier (domain, name);
+	policy = g_hash_table_lookup (bus->priv->policies, identifier);
+	g_free (identifier);
+	
+	if (policy == NULL)
+	{
+		g_warning ("Policy for %s::%s not found", domain, name);
+		return NULL;
+	}
+	
+	while ((key = va_arg (var_args, const gchar *)) != NULL)
+	{
+		gchar *error = NULL;
+		GType gtype;
+		GValue value = {0,};
+		
+		gtype = policy_find_type (policy, key);
+		
+		if (!gtype)
+		{
+			g_warning ("Key %s not registered in policy for %s::%s", key, domain, name);
+			return NULL;
+		}
+		
+		g_value_init (&value, gtype);
+		G_VALUE_COLLECT (&value, var_args, 0, &error);
+		
+		if (error)
+		{
+			g_warning ("%s: %s", G_STRLOC, error);
+			g_free (error);
+			
+			/* leak value, might have gone bad */
+			continue;
+		}
+		
+		num++;
+		
+		keys = g_realloc (keys, sizeof(gchar *) * num);
+		types = g_realloc (types, sizeof(GType) * num);
+		values = g_realloc (values, sizeof(GValue) * num);
+		
+		keys[num - 1] = key;
+		types[num - 1] = gtype;
+		
+		memset (&values[num - 1], 0, sizeof(GValue));
+		g_value_init (&values[num - 1], types[num - 1]);
+		g_value_copy (&value, &values[num - 1]);
+		
+		g_value_unset (&value);
+	}
+		
+	message = gedit_message_new (domain, name, NULL);
+	gedit_message_set_types (message, keys, types, num);
+	gedit_message_set_valuesv (message, keys, values, num);
+	
+	g_free (keys);
+	g_free (types);
+	
+	for (i = 0; i < num; i++)
+		g_value_unset (&values[i]);
+
+	g_free (values);
+	
+	return message;
+}
+
+void
+gedit_message_bus_send (GeditMessageBus *bus,
+			const gchar     *domain,
+			const gchar     *name,
+			...)
+{
+	va_list var_args;
+	GeditMessage *message;
+	
+	va_start (var_args, name);
+
+	message = create_message (bus, domain, name, var_args);
+	
+	if (message)
+	{
+		gedit_message_bus_send_message (bus, message);
+		g_object_unref (message);
+	}
+
+	va_end (var_args);
+}
+
+GeditMessage *
+gedit_message_bus_send_sync (GeditMessageBus *bus,
+			     const gchar     *domain,
+			     const gchar     *name,
+			     ...)
+{
+	va_list var_args;
+	GeditMessage *message;
+	
+	va_start (var_args, name);
+	message = create_message (bus, domain, name, var_args);
+	
+	if (message)
+		gedit_message_bus_send_message_sync (bus, message);
+
+	va_end (var_args);
+	
+	return message;
+}
+
+typedef struct
+{
+	gchar *domain;
+	gchar *name;
+	GeditMessageBus *bus;
+} PropertyProxy;
+
+static void
+property_proxy_message (GObject         *object,
+			GParamSpec      *spec,
+			PropertyProxy   *proxy)
+{
+	GeditMessage *message;
+	GValue value = {0,};
+	
+	message = gedit_message_new (proxy->domain,
+				     proxy->name,
+				     spec->name, spec->value_type,
+				     NULL);
+
+	g_value_init (&value, spec->value_type);
+	g_object_get_property (object, spec->name, &value);
+	gedit_message_set_value (message, spec->name, &value);
+	    
+	gedit_message_bus_send_message (proxy->bus, message);
+
+	g_object_unref (message);
+	g_value_unset (&value);
+}
+
+static PropertyProxy *
+property_proxy_new (GeditMessageBus *bus,
+		    const gchar     *domain,
+		    const gchar     *name)
+{
+	PropertyProxy *proxy;
+	
+	proxy = g_new (PropertyProxy, 1);
+	proxy->domain = g_strdup (domain);
+	proxy->name = g_strdup (name);
+	proxy->bus = bus;
+	
+	return proxy;
+}
+
+static void
+property_proxy_free (PropertyProxy *proxy,
+		     GClosure      *closure)
+{
+	g_free (proxy->domain);
+	g_free (proxy->name);
+	g_free (proxy);
+}
+
+void 
+gedit_message_bus_proxy_property (GeditMessageBus *bus,
+				  const gchar     *domain,
+				  const gchar     *name,
+				  GObject	  *object,
+				  const gchar 	  *property)
+{
+	GParamSpec *spec;
+	gchar *detailed;
+	
+	spec = g_object_class_find_property (G_OBJECT_GET_CLASS (object), 
+					     property);
+
+	if (!spec)
+	{
+		g_warning ("Could not connect proxy because property `%s' does not exist for %s", 
+			   property,
+			   g_type_name (G_OBJECT_TYPE (object)));
+		return;
+	}
+	
+	if (!_gedit_message_gtype_supported (spec->value_type))
+	{
+		g_warning ("Type of property `%s' is not supported on the message bus",
+			   g_type_name (spec->value_type));
+		return;
+	}
+	
+	detailed = g_strconcat ("notify::", property, NULL);
+	g_signal_connect_data (object, 
+			       detailed, 
+			       G_CALLBACK (property_proxy_message), 
+			       property_proxy_new (bus, domain, name),
+			       (GClosureNotify)property_proxy_free,
+			       0);
+	g_free (detailed);
+}

Added: branches/message_system/gedit/gedit-message-bus.h
==============================================================================
--- (empty file)
+++ branches/message_system/gedit/gedit-message-bus.h	Wed Nov 26 16:45:01 2008
@@ -0,0 +1,115 @@
+#ifndef __GEDIT_MESSAGE_BUS_H__
+#define __GEDIT_MESSAGE_BUS_H__
+
+#include <glib-object.h>
+#include <gedit/gedit-message.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);
+};
+
+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);
+
+/* registering messages */
+void gedit_message_bus_register    	  (GeditMessageBus	*bus,
+					   const gchar 		*domain,
+					   const gchar		*name,
+					   guint		 num_optional,
+					   ...) G_GNUC_NULL_TERMINATED;
+
+void gedit_message_bus_unregister	  (GeditMessageBus	*bus,
+					   const gchar 		*domain,
+					   const gchar		*name);
+
+void gedit_message_bus_unregister_all	  (GeditMessageBus	*bus,
+					   const gchar		*domain);
+
+/* connecting to message events */		   
+guint gedit_message_bus_connect	 	  (GeditMessageBus	*bus, 
+					   const gchar		*domain,
+					   const gchar		*name,
+					   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		*domain,
+					   const gchar		*name,
+					   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		*domain,
+					   const gchar		*name,
+					   GeditMessageCallback	 callback,
+					   gpointer		 userdata);
+
+void gedit_message_bus_unblock		  (GeditMessageBus	*bus,
+					   guint		 id);
+void gedit_message_bus_unblock_by_func	  (GeditMessageBus	*bus,
+					   const gchar		*domain,
+					   const gchar		*name,
+					   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		*domain,
+					   const gchar		*name,
+					   ...) G_GNUC_NULL_TERMINATED;
+GeditMessage *gedit_message_bus_send_sync (GeditMessageBus	*bus,
+					   const gchar		*domain,
+					   const gchar		*name,
+					   ...) G_GNUC_NULL_TERMINATED;
+
+/* automatic property proxy over the bus */
+void gedit_message_bus_proxy_property	  (GeditMessageBus 	*bus,
+					   const gchar          *domain,
+					   const gchar          *name,
+					   GObject		*object,
+					   const gchar 		*property);
+
+G_END_DECLS
+
+#endif /* __GEDIT_MESSAGE_BUS_H__ */

Added: branches/message_system/gedit/gedit-message.c
==============================================================================
--- (empty file)
+++ branches/message_system/gedit/gedit-message.c	Wed Nov 26 16:45:01 2008
@@ -0,0 +1,578 @@
+#include "gedit-message.h"
+
+#include <string.h>
+#include <gobject/gvaluecollector.h>
+
+#define GEDIT_MESSAGE_GET_PRIVATE(object)(G_TYPE_INSTANCE_GET_PRIVATE((object), GEDIT_TYPE_MESSAGE, GeditMessagePrivate))
+
+enum {
+	PROP_0,
+
+	PROP_DOMAIN,
+	PROP_NAME
+};
+
+struct _GeditMessagePrivate
+{
+	gchar *domain;
+	gchar *name;
+	
+	GHashTable *values;
+};
+
+G_DEFINE_TYPE (GeditMessage, gedit_message, G_TYPE_OBJECT)
+
+static void
+gedit_message_finalize (GObject *object)
+{
+	GeditMessage *message = GEDIT_MESSAGE (object);
+	
+	g_free (message->priv->domain);
+	g_free (message->priv->name);
+	
+	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_DOMAIN:
+			g_value_set_string (value, msg->priv->domain);
+			break;
+		case PROP_NAME:
+			g_value_set_string (value, msg->priv->name);
+			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_DOMAIN:
+			msg->priv->domain = g_strdup (g_value_get_string (value));
+			break;
+		case PROP_NAME:
+			msg->priv->name = g_strdup (g_value_get_string (value));
+			break;
+		default:
+			G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+			break;
+	}
+}
+
+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;
+	
+	g_object_class_install_property (object_class, PROP_DOMAIN,
+					 g_param_spec_string ("domain",
+							      "DOMAIN",
+							      "The message domain",
+							      NULL,
+							      G_PARAM_READWRITE |
+							      G_PARAM_STATIC_STRINGS |
+							      G_PARAM_CONSTRUCT_ONLY));
+
+	g_object_class_install_property (object_class, PROP_NAME,
+					 g_param_spec_string ("name",
+							      "NAME",
+							      "The message name",
+							      NULL,
+							      G_PARAM_READWRITE |
+							      G_PARAM_STATIC_STRINGS |
+							      G_PARAM_CONSTRUCT_ONLY));
+
+	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);
+}
+
+gboolean
+_gedit_message_gtype_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;
+}
+
+static void
+add_value (GeditMessage *message,
+	   const gchar 	*key,
+	   GType	 gtype)
+{
+	GValue *value;
+	
+	value = g_new0 (GValue, 1);
+	g_value_init (value, gtype);
+	g_value_reset (value);
+
+	g_hash_table_insert (message->priv->values, g_strdup (key), 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)
+{
+	return (GValue *)g_hash_table_lookup (message->priv->values, key);
+}
+
+GeditMessage*
+gedit_message_new (const gchar *domain,
+		   const gchar *name,
+		   ...)
+{
+	va_list var_args;
+	GeditMessage *message;
+	
+	va_start (var_args, name);
+	message = gedit_message_new_valist (domain, name, var_args);
+	va_end (var_args);
+	
+	return message;
+}
+
+GeditMessage *
+gedit_message_new_valist (const gchar *domain,
+			  const gchar *name,
+			  va_list      var_args)
+{
+	GeditMessage *message;
+	const gchar *key;
+	GArray *keys;
+	GArray *types;
+
+	message = g_object_new (GEDIT_TYPE_MESSAGE, "domain", domain, "name", name, NULL);
+	
+	keys = g_array_new (FALSE, FALSE, sizeof (const gchar *));
+	types = g_array_new (FALSE, FALSE, sizeof (GType));
+
+	while ((key = va_arg (var_args, const gchar *)) != NULL)
+	{
+		/* get corresponding GType */
+		GType gtype = va_arg (var_args, GType);
+		
+		g_array_append_val (keys, key);
+		g_array_append_val (types, gtype);
+	}
+	
+	gedit_message_set_types (message, 
+				 (const gchar **)keys->data,
+				 (GType *)types->data,
+				 keys->len);
+	
+	g_array_free (keys, TRUE);
+	g_array_free (types, TRUE);
+	
+	return message;
+}
+
+GeditMessage *
+gedit_message_new_hash (const gchar *domain,
+			const gchar *name,
+			GHashTable  *values)
+{
+	GeditMessage *message;
+	const gchar *key;
+	GList *keys;
+	GList *item;
+	GValue *value;
+	
+	message = g_object_new (GEDIT_TYPE_MESSAGE, "domain", domain, "name", name, NULL);	
+	keys = g_hash_table_get_keys (values);
+	
+	for (item = keys; item; item = item->next)
+	{
+		key = (const gchar *)(item->data);
+		value = g_hash_table_lookup (values, key);
+		
+		if (value == NULL)
+			continue;
+		
+		if (!_gedit_message_gtype_supported (G_VALUE_TYPE (value)))
+		{
+			g_warning ("GType %s is not supported, ignoring key %s", 
+				   g_type_name (G_VALUE_TYPE (value)), 
+				   key);
+			continue;
+		}
+		
+		add_value (message, key, G_VALUE_TYPE (value));
+		gedit_message_set_value (message, key, value); 
+	}
+	
+	g_list_free (keys);
+	
+	return message;
+}
+
+void
+gedit_message_set_types (GeditMessage  *message,
+			 const gchar  **keys,
+			 GType	       *types,
+			 gint		n_types)
+{
+	gint i;
+
+	g_return_if_fail (GEDIT_IS_MESSAGE (message));
+	
+	g_hash_table_ref (message->priv->values);
+	g_hash_table_destroy (message->priv->values);
+	
+	for (i = 0; i < n_types; i++)
+	{
+		if (!_gedit_message_gtype_supported (types[i]))
+		{
+			g_warning ("GType %s is not supported, ignoring key %s", g_type_name (types[i]), keys[i]);
+			continue;
+		}
+		
+		add_value (message, keys[i], types[i]);
+	}	
+}
+
+const gchar *
+gedit_message_get_name (GeditMessage *message)
+{
+	g_return_val_if_fail (GEDIT_IS_MESSAGE (message), NULL);
+	
+	return message->priv->name;
+}
+
+const gchar *
+gedit_message_get_domain (GeditMessage *message)
+{
+	g_return_val_if_fail (GEDIT_IS_MESSAGE (message), NULL);
+	
+	return message->priv->domain;
+}
+
+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);
+}
+
+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);
+		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);
+	}
+}
+
+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);
+	
+	if (!container)
+	{
+		g_warning ("%s: Cannot set value for %s, does not exist", 
+			   G_STRLOC, 
+			   key);
+		return;
+	}
+	
+	set_value_real (container, value);
+}
+
+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]);
+	}
+}
+
+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);
+}
+
+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);
+	
+		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);
+	}
+}
+
+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);
+	
+	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);
+}
+
+GType 
+gedit_message_get_key_type (GeditMessage    *message,
+			    const gchar	    *key)
+{
+	GValue *container;
+
+	g_return_val_if_fail (GEDIT_IS_MESSAGE (message), 0);
+	
+	container = value_lookup (message, key);
+	
+	if (!container)
+	{
+		g_warning ("%s: Invalid key `%s'",
+			   G_STRLOC,
+			   key);
+		return 0;
+	}
+	
+	return G_VALUE_TYPE (container);
+}
+
+GStrv
+gedit_message_get_keys (GeditMessage *message)
+{
+	GList *keys;
+	GList *item;
+	GStrv result;
+	gint i = 0;
+	
+	g_return_val_if_fail (GEDIT_IS_MESSAGE (message), NULL);
+	
+	result = g_new0 (gchar *, g_hash_table_size (message->priv->values) + 1);
+	
+	keys = g_hash_table_get_keys (message->priv->values);
+	
+	for (item = keys; item; item = item->next)
+		result[i++] = g_strdup ((gchar *)(item->data));
+	
+	g_list_free (keys);
+	return result;
+}
+
+GHashTable *
+gedit_message_get_hash (GeditMessage *message)
+{
+	g_return_val_if_fail (GEDIT_IS_MESSAGE (message), NULL);
+	return message->priv->values;
+}
+
+gboolean
+gedit_message_has_key (GeditMessage *message,
+		       const gchar  *key)
+{
+	GValue *container;
+	
+	g_return_val_if_fail (GEDIT_IS_MESSAGE (message), FALSE);
+	
+	container = value_lookup (message, key);
+	
+	return container != NULL;
+}

Added: branches/message_system/gedit/gedit-message.h
==============================================================================
--- (empty file)
+++ branches/message_system/gedit/gedit-message.h	Wed Nov 26 16:45:01 2008
@@ -0,0 +1,83 @@
+#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;
+
+GeditMessage *gedit_message_new		(const gchar 	 *domain,
+					 const gchar	 *name,
+					 ...) G_GNUC_NULL_TERMINATED; 
+GeditMessage *gedit_message_new_valist  (const gchar 	 *domain,
+					 const gchar 	 *name,
+					 va_list	  var_args);
+GeditMessage *gedit_message_new_hash	(const gchar	 *domain,
+					 const gchar	 *name,
+					 GHashTable	 *values);
+
+void gedit_message_set_types		(GeditMessage	 *message,
+					 const gchar 	**keys,
+					 GType		 *types,
+					 gint		  n_types);
+
+const gchar *gedit_message_get_domain	(GeditMessage	 *message);
+const gchar *gedit_message_get_name	(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);
+
+gboolean gedit_message_has_key		(GeditMessage	 *message,
+					 const gchar     *key);
+
+GStrv gedit_message_get_keys		(GeditMessage	 *message);
+GType gedit_message_get_key_type	(GeditMessage    *message,
+					 const gchar	 *key);
+
+GHashTable *gedit_message_get_hash	(GeditMessage	 *message);
+gboolean _gedit_message_gtype_supported (GType type);
+
+G_END_DECLS
+
+#endif /* __GEDIT_MESSAGE_H__ */

Modified: branches/message_system/gedit/gedit.c
==============================================================================
--- branches/message_system/gedit/gedit.c	(original)
+++ branches/message_system/gedit/gedit.c	Wed Nov 26 16:45:01 2008
@@ -520,6 +520,9 @@
 		g_warning ("Cannot create the 'gedit' connection.");
 	}
 
+	/* register message bus commands */
+	//_gedit_commands_messages_register ();
+
 	gedit_debug_message (DEBUG_APP, "Set icon");
 	
 	gtk_icon_theme_append_search_path (gtk_icon_theme_get_default (),

Modified: branches/message_system/plugin-loaders/python/bindings/Makefile.am
==============================================================================
--- branches/message_system/plugin-loaders/python/bindings/Makefile.am	(original)
+++ branches/message_system/plugin-loaders/python/bindings/Makefile.am	Wed Nov 26 16:45:01 2008
@@ -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 \

Modified: branches/message_system/plugin-loaders/python/bindings/gedit.defs
==============================================================================
--- branches/message_system/plugin-loaders/python/bindings/gedit.defs	(original)
+++ branches/message_system/plugin-loaders/python/bindings/gedit.defs	Wed Nov 26 16:45:01 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")
@@ -991,6 +1005,271 @@
   )
 )
 
+
+;; 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-method connect
+  (of-object "GeditMessageBus")
+  (c-name "gedit_message_bus_connect")
+  (return-type "guint")
+  (parameters
+    '("const-gchar*" "domain")
+    '("const-gchar*" "name")
+    '("GeditMessageCallback" "callback")
+    '("gpointer" "userdata")
+  )
+)
+
+(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*" "domain")
+    '("const-gchar*" "name")
+    '("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*" "domain")
+    '("const-gchar*" "name")
+    '("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*" "domain")
+    '("const-gchar*" "name")
+    '("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*" "domain")
+    '("const-gchar*" "name")
+  )
+  (varargs #t)
+)
+
+(define-method send_sync
+  (of-object "GeditMessageBus")
+  (c-name "gedit_message_bus_send_sync")
+  (return-type "GeditMessage*")
+  (parameters
+    '("const-gchar*" "domain")
+    '("const-gchar*" "name")
+  )
+  (varargs #t)
+)
+
+
+
+;; From gedit-message.h
+
+(define-function gedit_message_get_type
+  (c-name "gedit_message_get_type")
+  (return-type "GType")
+)
+
+(define-function gedit_message_new
+  (c-name "gedit_message_new")
+  (is-constructor-of "GeditMessage")
+  (return-type "GeditMessage*")
+  (parameters
+    '("const-gchar*" "domain")
+    '("const-gchar*" "name")
+  )
+  (varargs #t)
+)
+
+(define-function gedit_message_new_valist
+  (c-name "gedit_message_new_valist")
+  (return-type "GeditMessage*")
+  (parameters
+    '("const-gchar*" "domain")
+    '("const-gchar*" "name")
+    '("va_list" "var_args")
+  )
+)
+
+(define-method set_types
+  (of-object "GeditMessage")
+  (c-name "gedit_message_set_types")
+  (return-type "none")
+  (parameters
+    '("const-gchar**" "keys")
+    '("GType*" "types")
+    '("gint" "n_types")
+  )
+)
+
+(define-method get_domain
+  (of-object "GeditMessage")
+  (c-name "gedit_message_get_domain")
+  (return-type "const-gchar*")
+)
+
+(define-method get_name
+  (of-object "GeditMessage")
+  (c-name "gedit_message_get_name")
+  (return-type "const-gchar*")
+)
+
+(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 has_key
+  (of-object "GeditMessage")
+  (c-name "gedit_message_has_key")
+  (return-type "gboolean")
+  (parameters
+    '("const-gchar*" "key")
+  )
+)
+
+(define-method get_keys
+  (of-object "GeditMessage")
+  (c-name "gedit_message_get_keys")
+  (return-type "gchar**")
+  (parameters
+  )
+)
+
 ;; From ../../gedit/gedit-debug.h
 
 (define-function debug

Modified: branches/message_system/plugin-loaders/python/bindings/gedit.override
==============================================================================
--- branches/message_system/plugin-loaders/python/bindings/gedit.override	(original)
+++ branches/message_system/plugin-loaders/python/bindings/gedit.override	Wed Nov 26 16:45:01 2008
@@ -61,6 +61,7 @@
 }
 %%
 include
+  geditmessage.override
   geditplugin.override
 %%
 modulename gedit 

Added: branches/message_system/plugin-loaders/python/bindings/geditmessage.override
==============================================================================
--- (empty file)
+++ branches/message_system/plugin-loaders/python/bindings/geditmessage.override	Wed Nov 26 16:45:01 2008
@@ -0,0 +1,544 @@
+%%
+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_message_types(PyObject *args, gchar ***keys, GType **types, gint *num, gboolean direct)
+{
+    guint len, i;
+    Py_ssize_t pos;
+    
+    len = PyTuple_Size(args);
+
+    if (len == 1 && PyDict_Check(PyTuple_GetItem(args, 0)))
+    {
+    	/* get key -> gtype from mapping */
+    	PyObject *dict = PyTuple_GetItem(args, 0);
+    	PyObject *key;
+    	PyObject *value;
+
+    	*num = PyDict_Size(dict);
+    	*types = g_new0(GType, *num);
+        *keys = g_new0(gchar *, *num + 1);
+        pos = 0;
+        i = 0;
+        
+        while (PyDict_Next(dict, &pos, &key, &value)) {
+            (*keys)[i] = _helper_wrap_get_string (key);
+            
+            if (direct) {
+                (*types)[i] = _helper_wrap_get_gtype_from_pytype(value);
+            } else {
+                (*types)[i] = _helper_wrap_get_gtype_from_pytype((PyObject *)value->ob_type);
+            }
+            
+            if ((*types)[i] == 0 || (*keys)[i] == NULL) {
+                g_free(*types);
+                g_strfreev(*keys);
+                return 0;
+            }
+            
+            i++;
+        }
+    }
+    else
+    {
+        if (len % 2 != 0) {
+            PyErr_SetString(PyExc_TypeError,
+                            "Even number of arguments expected (name/type pairs)");
+            return 0;
+        }
+
+        *num = len / 2;
+        *types = g_new(GType, *num);
+        *keys = g_new0(gchar *, *num + 1);
+
+        for (i = 0; i < *num; i++) {
+            PyObject *key = PyTuple_GetItem(args, i * 2);
+            PyObject *value = PyTuple_GetItem(args, i * 2 + 1);
+    
+            (*keys)[i] = _helper_wrap_get_string (key);
+            
+            if (direct) {
+                (*types)[i] = _helper_wrap_get_gtype_from_pytype(value);
+            } else {
+                (*types)[i] = _helper_wrap_get_gtype_from_pytype((PyObject *)value->ob_type);
+            }
+
+            if ((*types)[i] == 0 || (*keys)[i] == NULL) {
+                g_free(*types);
+                g_strfreev(*keys);
+                return 0;
+            }
+        }
+    }
+    
+    return 1;
+}
+
+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;
+}
+
+static int
+_helper_wrap_message_set_values(GeditMessage *message, PyObject *args)
+{
+    guint len;
+    Py_ssize_t i;
+    
+    len = PyTuple_Size(args);
+
+    if (len == 1 && PyDict_Check(PyTuple_GetItem(args, 0)))
+    {
+    	/* do key -> value from mapping */
+    	PyObject *dict = PyTuple_GetItem(args, 0);
+    	PyObject *pykey, *pyvalue;
+    	
+    	i = 0;
+
+        while (PyDict_Next(dict, &i, &pykey, &pyvalue)) {
+            if (!_helper_wrap_message_set_value(message, pykey, pyvalue))
+                return 0;
+        }
+    } else {
+        if (len % 2 != 0) {
+            PyErr_SetString(PyExc_TypeError,
+                            "Even number of arguments expected (name/type pairs)");
+            return 0;
+        }
+
+        for (i = 0; i < len / 2; i++) {
+            PyObject *pykey = PyTuple_GetItem(args, i * 2);
+            PyObject *pyvalue = PyTuple_GetItem(args, i * 2 + 1);
+            
+            if (!_helper_wrap_message_set_value(message, pykey, pyvalue))
+                return 0;
+        }
+    }
+    
+    return 1;
+}
+
+static GeditMessage *
+_helper_wrap_create_message(PyObject *args)
+{
+    guint len;
+    gint num;
+    gchar *domain;
+    gchar *name;
+    GType *types;
+    gchar **keys;
+    PyObject *slice;
+    GeditMessage *message;
+
+    len = PyTuple_Size(args);
+
+    if (len < 2) {
+        PyErr_SetString(PyExc_TypeError,
+                        "GeditMessage requires at least two arguments");
+        return NULL;
+    }
+    
+    domain = _helper_wrap_get_string(PyTuple_GetItem(args, 0));
+    name = _helper_wrap_get_string(PyTuple_GetItem(args, 1));
+    
+    if (!domain || !name) {
+        PyErr_SetString(PyExc_TypeError,
+                        "First two arguments need to be strings");
+        g_free (domain);
+        g_free (name);
+        return NULL;
+    }
+    
+    slice = PyTuple_GetSlice (args, 2, len);
+
+    if (!_helper_wrap_message_types (slice, &keys, &types, &num, FALSE)) {
+        Py_DECREF(slice);
+    	return NULL;
+    }
+
+    message = g_object_new(GEDIT_TYPE_MESSAGE, "domain", domain, "name", name, NULL);
+    gedit_message_set_types (message, (const gchar **)keys, types, num);
+
+    g_free(types);
+    g_strfreev(keys);
+    g_free (name);
+    g_free (domain);
+    
+    _helper_wrap_message_set_values(message, slice);
+    Py_DECREF(slice);
+
+    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_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_new
+static int
+_wrap_gedit_message_new(PyGObject *self, PyObject *args)
+{
+    self->obj = (GObject *)_helper_wrap_create_message(args);
+    
+    if (!self->obj) {
+        PyErr_SetString(PyExc_RuntimeError,
+                        "could not create GeditMessage object");
+        return -1;
+    }
+    pygobject_register_wrapper((PyObject *)self);
+
+    return 0;
+}
+%%
+override gedit_message_set_types args
+static PyObject *
+_wrap_gedit_message_set_types(PyGObject *self, PyObject *args)
+{
+    gint num;
+    GType *types;
+    gchar **keys;
+
+    if (!_helper_wrap_message_types (args, &keys, &types, &num, TRUE)) {
+    	return NULL;
+    }
+ 
+    gedit_message_set_types (GEDIT_MESSAGE(self->obj), (const gchar **)keys, types, num);
+
+    g_free(types);
+    g_strfreev(keys);
+
+    Py_INCREF (Py_None);
+    return Py_None;
+}
+%%
+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);
+        const gchar *key;
+        
+        if (!PyString_Check(py_key)) {
+	    PyErr_SetString(PyExc_TypeError, "keys must be strings");
+	    Py_DECREF(ret);
+	    return NULL;
+	}
+	
+	key = PyString_AsString(py_key);
+	gedit_message_get_value (GEDIT_MESSAGE (self->obj), key, &value);
+	
+	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 args
+static PyObject *
+_wrap_gedit_message_set (PyGObject *self, PyObject *args) {
+    if (!_helper_wrap_message_set_values(GEDIT_MESSAGE(self->obj), args))
+        return NULL;
+    
+    Py_INCREF(Py_None);
+    return Py_None;
+}
+%%
+override gedit_message_get_keys args
+static PyObject *
+_wrap_gedit_message_get_keys (PyGObject *self, PyObject *args) {
+    PyObject *py_list;
+    gchar **keys;
+    gchar **ptr;
+    
+    if ((py_list = PyList_New(0)) == NULL) {
+        Py_INCREF(Py_None);
+        return Py_None;
+    }
+    
+    keys = gedit_message_get_keys (GEDIT_MESSAGE (self->obj));
+    ptr = keys;
+    
+    if (!keys)
+    	return py_list;
+    
+    while (*ptr)
+    	PyList_Append(py_list, PyString_FromString (*ptr));
+
+    g_strfreev (keys);
+    return py_list;
+}
+
+%%
+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;
+
+    gedit_message_bus_connect(GEDIT_MESSAGE_BUS(self->obj),
+                              domain,
+                              name,
+                              pygedit_message_bus_connect_cb,
+                              (gpointer)cunote,
+                              pygedit_custom_destroy_notify);
+    Py_INCREF(Py_None);
+    return Py_None;
+}
+%%
+override gedit_message_bus_send args
+static PyObject *
+_wrap_gedit_message_bus_send (PyGObject *self, PyObject *args)
+{
+    /* create a new message object */
+    GeditMessage *message;
+    
+    message = _helper_wrap_create_message(args);
+    
+    if (!message)
+        return NULL;
+    
+    gedit_message_bus_send_message(GEDIT_MESSAGE_BUS(self->obj), 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)
+{
+    /* create a new message object */
+    GeditMessage *message;
+    
+    message = _helper_wrap_create_message(args);
+    
+    if (!message)
+        return NULL;
+    
+    gedit_message_bus_send_message_sync(GEDIT_MESSAGE_BUS(self->obj), message);
+    return pygobject_new((GObject *)message);
+}
+%%



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]