gedit r6434 - in branches/new_plugins: bindings/python gedit



Author: jessevdk
Date: Wed Aug 20 09:53:09 2008
New Revision: 6434
URL: http://svn.gnome.org/viewvc/gedit?rev=6434&view=rev

Log:
Implemented message system



Added:
   branches/new_plugins/gedit/gedit-message-bus.c
   branches/new_plugins/gedit/gedit-message-bus.h
   branches/new_plugins/gedit/gedit-message.c
   branches/new_plugins/gedit/gedit-message.h
Modified:
   branches/new_plugins/bindings/python/Makefile.am
   branches/new_plugins/bindings/python/gedit.defs
   branches/new_plugins/bindings/python/gedit.override
   branches/new_plugins/gedit/Makefile.am

Modified: branches/new_plugins/bindings/python/Makefile.am
==============================================================================
--- branches/new_plugins/bindings/python/Makefile.am	(original)
+++ branches/new_plugins/bindings/python/Makefile.am	Wed Aug 20 09:53:09 2008
@@ -58,13 +58,15 @@
 	gedit/gedit-encodings.h		\
 	gedit/gedit-plugin.h		\
 	gedit/gedit-view.h		\
-	gedit/gedit-status-bar.h	\
+	gedit/gedit-statusbar.h		\
 	gedit/gedit-tab.h 		\
 	gedit/gedit-panel.h 		\
 	gedit/gedit-window.h 		\
 	gedit/gedit-help.h		\
 	gedit/gedit-debug.h		\
-	gedit/gedit-language-manager.h
+	gedit/gedit-language-manager.h	\
+	gedit/gedit-message-bus.h	\
+	gedit/gedit-message.h
 
 BINDING_UTILS_HEADERS_SRCDIR_IN = \
 	gedit/gedit-utils.h

Modified: branches/new_plugins/bindings/python/gedit.defs
==============================================================================
--- branches/new_plugins/bindings/python/gedit.defs	(original)
+++ branches/new_plugins/bindings/python/gedit.defs	Wed Aug 20 09:53:09 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")
@@ -971,6 +985,254 @@
   )
 )
 
+
+;; 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
+  (c-name "gedit_message_bus_get")
+  (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")
+  )
+)
+
 ;; From ../../gedit/gedit-debug.h
 
 (define-function debug

Modified: branches/new_plugins/bindings/python/gedit.override
==============================================================================
--- branches/new_plugins/bindings/python/gedit.override	(original)
+++ branches/new_plugins/bindings/python/gedit.override	Wed Aug 20 09:53:09 2008
@@ -11,6 +11,8 @@
 #include "gedit-enum-types.h"
 #include "gedit-statusbar.h"
 #include "gedit-debug.h"
+#include "gedit-message-bus.h"
+#include "gedit-message.h"
 
 void pygedit_register_classes (PyObject *d); 
 void pygedit_add_constants (PyObject *module, const gchar *strip_prefix);
@@ -58,6 +60,213 @@
     }
     return py_list;
 }
+
+static int
+_helper_wrap_message_types(PyObject *args, const gchar ***keys, GType **types, gint *num, gboolean direct)
+{
+    guint len, i;
+    
+    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_new(GType, num);
+        *keys = g_new(const gchar *, num);
+        
+        while (PyDict_Next(dict, &i, &key, &value)) {
+            *keys[i] = PyString_AsString(key);
+            
+            if (direct) {
+                *types[i] = pyg_type_from_object(value);
+            } else {
+                PyObject *pytype = PyObject_Type(value);
+                *types[i] = pytype ? pyg_type_from_object(pytype) : 0;
+                Py_DECREF(pytype);
+            }
+            
+            if (*types[i] == 0 || *keys[i] == NULL) {
+                g_free(*types);
+                g_free(*keys);
+                return 0;
+            }
+        }
+    }
+    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_new(const gchar *, *num);
+
+        for (i = 0; i < *num; i++) {
+            PyObject *key = PyTuple_GetItem(args, i * 2);
+            PyObject *value = PyTuple_GetItem(args, i * 2 + 1);
+    
+            *keys[i] = PyString_AsString(key);
+            
+            if (direct) {
+                *types[i] = pyg_type_from_object(value);
+            } else {
+                PyObject *pytype = PyObject_Type(value);
+                *types[i] = pytype ? pyg_type_from_object(pytype) : 0;
+                Py_DECREF(pytype);
+            }
+
+            if (*types[i] == 0 || *keys[i] == NULL) {
+                g_free(*types);
+                g_free(*keys);
+                return 0;
+            }
+        }
+    }
+    
+    return 1;
+}
+
+static int
+_helper_wrap_message_set_value(PyGObject *self, PyObject *pykey, PyObject *pyvalue)
+{
+    const gchar *key;
+    GType gtype;
+    GValue value = {0,};
+
+    key = PyString_AsString(pykey);
+    
+    if (key == NULL)
+        return 0;
+
+    gtype = gedit_message_get_key_type(GEDIT_MESSAGE(self->obj), key);
+    
+    if (gtype == 0) {
+        PyErr_SetString(PyExc_TypeError, "invalid key");
+        return 0;
+    }
+
+    g_value_init(&value, gtype);
+    
+    if (pyg_value_from_pyobject(&value, pyvalue)) {
+        PyErr_SetString(PyExc_TypeError,
+                        "value is of the wrong type for this key");
+        return 0;
+    }
+
+    gedit_message_set_value(GEDIT_MESSAGE(self->obj), key, &value);
+    g_value_unset(&value);
+    
+    return 1;
+}
+
+static int
+_helper_wrap_message_set_values(PyGObject *self, PyObject *args)
+{
+    guint len, 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;
+
+        while (PyDict_Next(dict, &i, &pykey, &pyvalue)) {
+            if (!_helper_wrap_message_set_value(self, 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(self, pykey, pyvalue))
+                return 0;
+        }
+    }
+    
+    return 1;
+}
+
+static GeditMessage *
+_helper_wrap_create_message(PyObject *args)
+{
+    guint len, num;
+    const gchar *domain;
+    const gchar *name;
+    GType *types;
+    const 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 = PyString_AsString(PyTuple_GetItem(args, 0));
+    name = PyString_AsString(PyTuple_GetItem(args, 1));
+    
+    if (!domain || !name) {
+        PyErr_SetString(PyExc_TypeError,
+                        "First two arguments need to be strings");
+        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, keys, types, num);
+
+    g_free(types);
+    g_free(keys);
+
+    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);
+}
+
 %%
 modulename gedit 
 %%
@@ -77,6 +286,13 @@
   *_get_type
   gedit_document_error_quark
   gedit_panel_add_item_with_stock_icon
+  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_app_create_window kwargs
 static PyObject *
@@ -435,3 +651,220 @@
     return Py_None;
 }
 %%
+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)
+{
+    guint num;
+    GType *types;
+    const gchar **keys;
+
+    if (!_helper_wrap_message_types (args, &keys, &types, &num, TRUE)) {
+    	return NULL;
+    }
+ 
+    gedit_message_set_types (GEDIT_MESSAGE(self->obj), keys, types, num);
+
+    g_free(types);
+    g_free(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(self, 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(self, args))
+        return NULL;
+    
+    Py_INCREF(Py_None);
+    return Py_None;
+}
+%%
+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);
+}
+%%

Modified: branches/new_plugins/gedit/Makefile.am
==============================================================================
--- branches/new_plugins/gedit/Makefile.am	(original)
+++ branches/new_plugins/gedit/Makefile.am	Wed Aug 20 09:53:09 2008
@@ -93,6 +93,8 @@
 	gedit-encodings-option-menu.h	\
 	gedit-file-chooser-dialog.h	\
 	gedit-help.h 			\
+	gedit-message.h			\
+	gedit-message-bus.h		\
 	gedit-message-area.h		\
 	gedit-metadata-manager.h	\
 	gedit-notebook.h		\
@@ -140,6 +142,8 @@
 	gedit-history-entry.c		\
 	gedit-io-error-message-area.c	\
 	gedit-language-manager.c	\
+	gedit-message.c			\
+	gedit-message-bus.c		\
 	gedit-message-area.c		\
 	gedit-metadata-manager.c	\
 	gedit-module.c			\

Added: branches/new_plugins/gedit/gedit-message-bus.c
==============================================================================
--- (empty file)
+++ branches/new_plugins/gedit/gedit-message-bus.c	Wed Aug 20 09:53:09 2008
@@ -0,0 +1,564 @@
+#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
+{
+	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;
+};
+
+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->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_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;
+
+	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
+dispatch_message (GeditMessageBus *bus,
+		  GeditMessage    *message)
+{
+	Message *msg;
+	const gchar *domain;
+	const gchar *name;
+
+	domain = gedit_message_get_domain (message);
+	name = gedit_message_get_name (message);
+	
+	msg = lookup_message (bus, domain, name, FALSE);
+	
+	if (!msg)
+		return;
+	
+	dispatch_message_real (bus, msg, 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);
+}
+
+GeditMessageBus *
+gedit_message_bus_get (void)
+{
+	static GeditMessageBus *bus = NULL;
+	
+	if (G_UNLIKELY (!bus))
+		bus = g_object_new (GEDIT_TYPE_MESSAGE_BUS, NULL);
+	
+	return bus;
+}
+
+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);
+}
+
+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));
+	
+	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));
+	
+	dispatch_message (bus, message);
+}
+
+static GeditMessage *
+create_message (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;
+	GeditMessage *message;
+	gint i;
+	
+	while ((key = va_arg (var_args, const gchar *)) != NULL)
+	{
+		gchar *error = NULL;
+		GType gtype;
+		GValue value = {0,};
+		
+		gtype = va_arg (var_args, GType);
+		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 (domain, name, var_args);
+	
+	gedit_message_bus_send_message (bus, message);
+	va_end (var_args);
+	
+	g_object_unref (message);
+}
+
+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 (domain, name, var_args);
+	
+	gedit_message_bus_send_message_sync (bus, message);
+	va_end (var_args);
+	
+	return message;
+}

Added: branches/new_plugins/gedit/gedit-message-bus.h
==============================================================================
--- (empty file)
+++ branches/new_plugins/gedit/gedit-message-bus.h	Wed Aug 20 09:53:09 2008
@@ -0,0 +1,86 @@
+#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;
+};
+
+typedef void (* GeditMessageCallback) 	(GeditMessageBus	*bus,
+					 GeditMessage		*message,
+					 gpointer		 userdata);
+
+GType gedit_message_bus_get_type (void) G_GNUC_CONST;
+
+GeditMessageBus *gedit_message_bus_get 	  (void);
+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);
+
+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);
+
+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;
+G_END_DECLS
+
+#endif /* __GEDIT_MESSAGE_BUS_H__ */

Added: branches/new_plugins/gedit/gedit-message.c
==============================================================================
--- (empty file)
+++ branches/new_plugins/gedit/gedit-message.c	Wed Aug 20 09:53:09 2008
@@ -0,0 +1,502 @@
+#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);
+}
+
+static gboolean
+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;
+}
+
+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 (!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)
+		{
+			g_warning ("%s: Invalid key `%s'",
+				   G_STRLOC,
+				   key);
+			
+			/* 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);
+}

Added: branches/new_plugins/gedit/gedit-message.h
==============================================================================
--- (empty file)
+++ branches/new_plugins/gedit/gedit-message.h	Wed Aug 20 09:53:09 2008
@@ -0,0 +1,72 @@
+#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);
+
+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);
+
+GType gedit_message_get_key_type	(GeditMessage    *message,
+					 const gchar	 *key);
+G_END_DECLS
+
+#endif /* __GEDIT_MESSAGE_H__ */



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