Panel Design

Design Implemented
The design phase is now over and an implementation similar to what is described below is available from Xfce SVN.

What is still under development is the Panel User Interface for configuration of the new panel. Please join the discussion with your suggestions. -- JasperHuijsmans 08:48, 19 Oct 2005 (UTC)

Introduction
Read this first for the initial thoughts about changes in the panel design for Xfce 4.4:
 * Slides FOSDEM 2005

This page is meant for discussion of a new design for the Xfce Panel and specifically for panel plugins. I'd be very interested in input from (potential) plugin writers.

Goals
The goals for the new panel design are (among others ;-):
 * Improve robustness
 * Use out-of-process plugins, to prevent malfunctioning plugins to influence panel stability.


 * Improve panel interfaces, both internal (panel subsystems) and external (panel plugins).
 * Have a plugin library with a nice API to handle all communication with the panel, without having to care about implementation details (D-BUS, X messages, pipes, ...).
 * Use custom gtk widgets where possible to improve separation of interfaces and implementation.


 * Combine taskbar and iconbox in one panel widget and allow multiple panels
 * Improve multihead support

Panel

 * New custom gtk widgets
 * Already partly implemented in current CVS.
 * Implementation will change to meet the needs of the plugin system.


 * Allow some in-process panel items for speed and reduced memory footprint. Here are some candidates:
 * Launcher
 * Clock
 * Taskbar, Pager, Desktop Switcher
 * Status area (systray)
 * System buttons (needs a better name)
 * Menu (unless it remains part of xfdesktop)


 * Redesign the 'Add Item' dialog to allow DND to the panel
 * Compare with firefox/galeon/Terminal way to edit toolbars
 * When using .desktop files for plugins (see below) it will be easy to add launchers by using an appfinder-like widget (and appfinder itself, of course).
 * Plugin categories may be nice to have.

Panel Plugins

 * Use GtkPlug/GtkSocket for out-of-proces plugins
 * XfcePanelPlugin will be derived from GtkPlug and will handle all communication with the panel.


 * API design for XfcePanelPlugin is most important. It has to provide means to obtain:
 * Panel settings (orientation, size, etc)
 * Plugin configuration. This should ideally still be part of the panel config file, so a way to communicate with the panel is important. Perhaps an API like for McsSettings would work for plugins as well.


 * Allow plugins to add menu items to the right-click menu
 * void xfce_panel_plugin_add_menu_item (XfcePanelPlugin *plugin, GtkMenuItem *item);

[Xfce Plugin] Name = Mail notification Comment = Show mailbox status. Supports multiple mailboxes and protocols. Icon = xfce-mail Exec = xfce-mail-plugin
 * Use .desktop files to find and run plugins, e.g.:

UML

Well, probably not entirely correct UML, but some graphical representation of the classes and interfaces for the new panel:

http://xfce.loculus.nl/files/panel-design.png

API

Let's try and come up with an API that will be sufficient for any kind of plugin. Comments at the end of the code block, please.

typedef _XfcePanelPlugin XfcePanelPlugin; typedef _XfcePanelPluginClass XfcePanelPluginClass;

struct _XfcePanelPlugin {     GtkPlug parent; }

struct _XfcePanelPluginClass {     GtkPlugClass parent_class;

/* signals */ void (*orientation_changed) (XfcePanelPlugin *, GtkOrientation);

void (*icon_size_changed) (XfcePanelPlugin *, int);

/* timing could be a problem with async communication */ void (*save_yourself) (XfcePanelPlugin *); }

/* Create plugin widget * Pass on commandline arguments that should give: * - current panel settings * - plugin configuration * - GtkSocket to connect to  */ GtkWidget *xfce_panel_plugin_new (int argc, char **argv);

/* get panel settings */ GtkOrientation xfce_panel_plugin_get_orientation (XfcePanelPlugin *plugin);

int xfce_panel_plugin_get_icon_size (XfcePanelPlugin *plugin);

/* expand */ gboolean xfce_panel_plugin_get_expand (XfcePanelPlugin *plugin);

void xfce_panel_plugin_set_expand (XfcePanelPlugin *plugin, gboolean expand);

/* right-click menu */ void xfce_panel_plugin_add_menu_item (XfcePanelPlugin *plugin,                                       GtkMenuItem *item,                                        GCallback activate_callback);

/* configuration */

/* TO BE DONE * - Suggestions are welcome. * - A simple McsSetting-like API might be sufficient. */ gboolean xfce_panel_plugin_has_key (XfcePanelPlugin *plugin,                                      const char *key);

void xfce_panel_plugin_remove_key (XfcePanelPlugin *plugin,                                    const char *key);

gboolean xfce_panel_plugin_get_key_value (XfcePanelPlugin *plugin,                                           const char *key,                                             char **value);

void xfce_panel_plugin_set_key_value (XfcePanelPlugin *plugin,                                       const char *key,                                        const char *value);

/* convenience functions? _as_int, _as_float? */

Suggestions

For the configuration API: I'd use a simply key/value based API with only string values

const gchar *xfce_panel_plugin_get_setting(XfcePanelPlugin *plugin, const gchar *name); void xfce_panel_plugin_set_setting(XfcePanelPlugin *plugin, const gchar *name, const gchar *value);

This fits all needs, as everything can easily be encoded into a string; maybe provide wrappers in the plugin-side library to convert the string to other values, similar to what XfceRc does. The get_setting implementation in the Panel would check for translated values first (in the global config) and fallback to untranslated values.

And add:

gboolean xfce_panel_plugin_has_setting(XfcePanelPlugin *plugin, const gchar *name); void xfce_panel_plugin_unlink_setting(XfcePanelPlugin *plugin, const gchar *name);

to allow plugins to cleanup obsolete settings after an upgrade.

For more advanced usage, there could even be

gchar **xfce_panel_plugin_get_keys(XfcePanelPlugin *plugin);

in the core API to query all setting names for a given plugin.


 * It seems to me all the neccessary equipment for this is already in XfceRc, and that it would make sense to just have a single function to give the panel configuration:

XfceRc *xfce_panel_plugin_open_settings(XfcePanelPlugin *plug); --Ori

This is indeed what I have done now. Just as easy to use and less restrictive. -- Jasper 08:37, 27 Aug 2005 (CEST)

To speed up the plugin start with out-of-process plugins, the plugin-side library should query all settings for the plugin at once and cache them on the plugin-side to avoid the message ping-pong with several get_setting calls on plugin startup. --Benny 14:42, 16 Mar 2005 (CET)

Yes, that is quite smart. Leave the parsing to the plugin writer. Most people will only need simple types (int or string), but more complex things would still be possible. -- Jasper 14:22, 16 Mar 2005 (CET)

The important point here is (IMHO): When you start with simple string key/value based core API, it's easy to extend it later if necessary; but if you start with complex key/value based core API (like gconf) it's hard or impossible to drop functions, that cause trouble or add too much unneeded complexity, later without causing too much breakage. --Benny 14:42, 16 Mar 2005 (CET)

About robustness: How about instead of heavy weight processes with a thick layer of communication, lightweight threads with a small shared memory portion for communication? Segv's and other fatal signals received for plugin threads could be taken care of since the main program memory is off limits for the plugins. This would cut down total system resources consumed. --Edscott

I'm concerned about in process plugins. Is it really needed? Doesn't Gnome do everything out of process? Admittedly, we've only had some problems with plugin stability thus far, but third part plugin writers are really picking up steam. . . --Erik

Yes, gnome does most/all plugins out of process with bonobo. This is now being reconsidered because of their current efforts to reduce memory footprint. -- Jasper 19:14, 16 Mar 2005 (CET)

I think most of the plugins would be of this type. First of all this is easier to program than using thread. But also we don't need to have always a process or thread running for each plugin.(don't forget, XFCE is a lightweight desktop:) ). Also, you want to pass to the plugin all the configuration stuff of the panel to the plugin what he loads... What about passing a pointer to the panel itself?

You can't do this for out-of-process plugins. Plus as far as I can see it will be only orientation and icon size that are useful for the plugins. -- Jasper 19:14, 16 Mar 2005 (CET)

This way plugins can:
 * query the informations they need. I mean something like XfcePanelOptions *xfce_panel_get_options(XfcePanel *panel);
 * act on the panel ex:xfce_panel_hide(XfcePanel *panel). Perhaps is it useless, but perhaps not. You can always choose to not implement this kind of func if no plugin use, or add another func you didn't tought about when needed...  --bountykiller

If something like this would be useful I think it can better be implemented as a message to the panel (using the appropriate panel plugin api). -- Jasper 19:14, 16 Mar 2005 (CET)

OK, so if I understand well, you want to use separate processes (and not thread like I firstly tought) to improve robustness. I can agree this, but is it really needed? Can we try to use just thread instead? (EdScott wrote something about that above). I say that because I never had big problems with plugins, and I don't really feel the need to use separate process. (If some other people can say what they think about that...thx) --bountykiller 

Well basically, I'm a bit afraid of using threads with gtk. It's a mess and requires a lot of discipline to get right. We did try before, but there were all kinds of unexplained problems. Also I'd like to see the effect of separate processes first, before saying much about speed and memory issues. I have good hope it won't be too bad. -- Jasper 07:00, 18 Mar 2005 (CET)

I fully agree with Jasper. Making the panel threaded again would really hurt the stability. Gtk+ is not thread-safe and so we'd need all kinds of weird work-arounds/hacks to get things working. And the whole point in separating the plugins context from the panels context is to increase the stability/robustness of the panel, not to decrease it.--Benny 10:41, 18 Mar 2005 (CET)

OK :-) --bountykiller

The overhead of having separate processes is important, tho. IMHO, the best way to come around this problem would be to have the plugins available as loadable modules, and these modules can either be loaded into the context of the panel process or the context of a helper process, which then communicates with the panel. And give the user the possibility to decide (using a config file as this does not need a GUI) whether the plugin should be loaded into the panel or a helper process. The plugin should provide a hint to the panel (using a key in the .desktop file) if it prefers to run in the panel or a helper process; new plugins should set this hint to helper process until they've proven to work fine. This, of course, requires a well-thought and well-implemented API. --Benny 10:41, 18 Mar 2005 (CET)

Ooh, are you a mind reader now as well? ;-) I have been thinking about having a xfce4-panel-plugin-loader helper app, to load dynamic modules. Might be a bit of a double lookup (panel->fork helperapp->load module), but it also gives some flexibility.

I hadn't actually thought about making it optional though. Very interesting, thanks.

It's no biggie from the implementation. It just needs a good and stable plugin api. I think making it configurable is the only way for this to work out. There should be a way for a plugin to request to be run out-of-process, though, as some plugins may be design to run solely out-of-process (like a mailchecker, which can then use multiple threads or whatever); something like

X-XfcePanel-OutOfProcess=True

in the .desktop file should do the job. This is also necessary for plugins not written using the Gtk C API, but using a high-level language binding, like Xfc or PyGTK. For these kinds of plugins, there's also no need for a plugin helper binary, as it'll probably be impossible to ship these plugins as shared library that can be dlopen'ed. Instead, the plugin provides the binary/script.

API suggestion by Alexander Iliev: provide a way for the plugin to set whether it is available, with explanation.

I think it should be sufficient to have a 'Unique = True' field in the desktop file. -- Jasper 07:56, 30 Mar 2005 (CEST)

Ideas and Requests
Let's use this place to collect loose ideas and requests about the new panel and plugin system.


 * Plugin categories.


 * Use RGBA visual to get transparent panel with non-transparent icons.


 * A r/evoluyionary idea: use an interface like the KDE application kxdocker (an OS X dock style with better use of mouse buttons and wheel) - left button selects current application, right button selects launcher menu, wheel changes current application and icon, properties and configuration is just one of the right menu entries. It can be an anathema for the CDE heritage, but it seems a natural evolution of the CDE/XFCE horizontal menu concept.


 * Why not a "gnome area" in panel or taskbar. This gnome area allow that we could add (only in that area) the applets of gnome without loading all the gnome-panel. So xfce users could use gnome applets without using gnome or loading some (big) components of gnome. The same for kde. (Xan) Why not use the GNOME panel then? Anyone is free to write a plugin to do this though.


 * Iconized taskbar ala the OS X dock. I'm not sure of the viability of this, however, it would save a lot of space by removing the need for a second toolbar as a dedicated taskbar. Just realised this could easily be implemented by using Lil' Star Iconbox and embed it in the panel (or have the option to do so).

The idea is that the iconbox and taskbar items will just be normal panel plugins. So, I think you will get what you want. -- Jasper


 * Well, you remember my playing around with unifying both taskbutton and launcher buttons into the same button :) I'm testing that for a few months in my panel idea-catcher prototype, and I'm growing quite accustomed to that. It's really convenient not having to search around where the new icon for the application you just launched popped up when you only want to activate it's window again :) -- dannym :)