The message bus is currently being implemented on the message_system branch in gedit SVN. This page describes globally how the message bus is intended to work.

The Bus

A message bus is the central hub/router which handles all the message registering, callbacks and message sending. There exists one application wide message bus (gedit_message_bus_get_default()) and one message bus per GeditWindow. The GeditWindow message bus is very useful for plugins which usually operate seperately in different windows (like the file browser plugin).

The first version of the message bus allowed for any arbitrary message send over the bus and it was up to the receiver to check the message was actually valid. There was no contract on the bus to ensure certain argument types for instance. This has changed and it is now required to first register a so called GeditMessageType on the message bus. A message type is like an interface definition for a method defined on a certain object. It defines which arguments are required for the method (and which are optional) and what the GType of the argument is.

After registering a message type, instantiations of the message type can be send over the bus. There are usually two kinds of messages that can be send over the message bus, methods and signals. There is no distinction between these messages on the bus, the sender and receiver have simply switched places. To take the file browser plugin as an example, a possible signal message could be that the root of the view has changed (file browser 'sends' a 'root_changed' message over the bus). On the other hand, the file browser plugin could register a message type for changing the root of the view 'set_root', and would connect a callback for this message on the bus. Some other plugin might then send a 'set_root' message.

Registering message types

Message types are registered using gedit_message_bus_register. This specifies the object path, method name, number of optional arguments and argument name/type pairs. A new GeditMessageType is created and registered within the bus. There is also gedit_message_bus_unregister to unregister message types which is useful for plugins which need to unregister types when they are deactivated. Note that 'object path' and 'method' is similar to DBus

Connecting callbacks

Callbacks can be connected for messages on the bus with gedit_message_bus_connect(). This is similar as to connecting to signals on GObject. The bus also provides similar ways to disconnect, block and unblock callbacks. Callbacks have a function prototype like: GeditMessageBus, GeditMessage, UserData.

Sending messages

There are two different ways to send messages over the bus, asynchronous or synchronous. The default is to send messages asynchronous, which in the current implementation means that messages are send in an idle callback function (there is no smart dispatching implemented at the moment, but we could have some policies of dispatching messages so that message sending only takes a certain amount of time). Synchronous messages are send directly and the use case for these messages is to allow receivers to set return value arguments on the message.

Messages can furthermore be send with the convenience methods gedit_message_bus_send() and gedit_message_bus_send_sync(), or with the functions gedit_message_bus_send_message() and gedit_message_bus_send_message_sync(). The later ones are used in the python bindings and can be used to cache messages so that they don't have to be constructed each time. The send and send_sync functions on the bus implicitly create a new GeditMessage instance each time.

DBus bindings

Because the way the bus works is very similar to how DBus works (in a limited fashion), the gedit message bus can be very easily tied automatically to DBus. The glib DBus bindings provide an easy way to send string/gvalue hashes which is exactly what a GeditMessage is. Currently, these bindings have not been implemented in the branch yet, but some experimental previous work showed that creating such bindings proved to be quite easy.

Having automatic DBus bindings for the internal bus would mean that it is very easy and straightforward to make gedit DBus enabled, thus also making it easy to replace the bacon connection with proper DBus messages.

API documentation

Current API documentation can be found on http://www.icecrew.nl/files/gedit/message-system-docs (or can be generated from the branch)

Example usage

   1 GeditMessageBus *bus = gedit_message_bus_get_default ();
   2 
   3 /* 
   4  * register message type with one required string argument "bar"
   5  * and one optional argument "result"
   6  */
   7 GeditMessageType *message_type = gedit_message_bus_register ("/plugins/example", "foo", 
   8                                                              1, 
   9                                                              "bar", G_TYPE_STRING, 
  10                                                              "result", G_TYPE_BOOLEAN, 
  11                                                              NULL);
  12 
  13 static void
  14 plugins_example_foo_cb (GeditMessageBus *bus, 
  15                         GeditMessage    *message, 
  16                         gpointer         userdata)
  17 {
  18         gchar *bar = NULL;
  19         gedit_message_get (message, "bar", &bar, NULL);
  20 
  21         g_message ("/plugins/example.foo was called with: %s", bar);
  22         g_free (bar);
  23 
  24         if (gedit_message_has_key (message, "result"))
  25                 gedit_message_set (message, "result", TRUE, NULL);
  26 }
  27 
  28 guint id = gedit_message_bus_connect (bus, 
  29                                       "/plugins/example", "foo", 
  30                                       plugins_example_foo_cb, NULL, NULL);
  31 
  32 // send async
  33 gedit_message_bus_send (bus, 
  34                         "/plugins/example", "foo", 
  35                         "bar", "Hello World Async", 
  36                         NULL);
  37 
  38 // send sync
  39 gboolean result = FALSE;
  40 GeditMessage *message = gedit_message_bus_send_sync (bus, 
  41                                                      "/plugins/example", "foo", 
  42                                                      "bar", "Hello World Sync", 
  43                                                      "result", result, 
  44                                                      NULL);
  45 
  46 gedit_message_get (message, "result", &result, NULL);
  47 g_message ("Result is: %d", result);
  48 g_object_unref (message);
  49 
  50 gedit_message_bus_disconnect (bus, id);
  51 gedit_message_bus_unregister (bus, message_type);

Apps/Gedit/Attic/MessageSystemImplementation (last edited 2020-05-04 20:52:18 by SébastienWilmet)