GKrellM 2.0 Plugin Programmers Reference


Data Allocation Functions
GkrellmChart Functions
GkrellmChartdata Functions
GkrellmChartconfig Functions
GkrellmPanel Functions
GkrellmKrell Functions
GkrellmDecal Functions
GkrellmDecalbutton Functions
GkrellmPiximage and GdkPixbuf Functions
Misc Support Functions
GkrellmAlert Functions
GkrellmStyle and GkrellmTextstyle Functions
Accessing GKrellM Piximages and Pixmaps Functions
Accessing GKrellM data
Misc Utility Functions
gkrellm_gtk Functions
Client/Server Functions

GKrellM Plugins

A GKrellM plugin is a shared object file (ends with a .so extension) which is placed in a plugin directory where GKrellM can find and load it at program startup time. Directories searched for plugins are:
    ~/.gkrellm2/plugins/
    /usr/local/lib/gkrellm2/plugins/
    /usr/lib/gkrellm2/plugins/
Users will probably install plugins into one of the first two directories while packages for a distribution will probably install under /usr/lib.

The one requirement of a plugin is that it must have a global function named gkrellm_init_plugin() which returns the address of an initialized GkrellmMonitor data structure. A basic do nothing GKrellM plugin would look like this:

#include <gkrellm2/gkrellm.h>

#define PLUGIN_PLACEMENT	MON_MAIL

static void
update_plugin()
    {
    /* See examples below */
    }

static void
create_plugin(GtkWidget *vbox, gint first_create)
    {
    /* See examples below */
    }

static GkrellmMonitor  plugin_mon  =
	{
	"Demo",         /* Name, for config tab.        */
	0,              /* Id,  0 if a plugin           */
	create_plugin,  /* The create_plugin() function */
	update_plugin,  /* The update_plugin() function */
	NULL,           /* The create_plugin_tab() config function */
	NULL,           /* The apply_plugin_config() function      */

	NULL,           /* The save_plugin_config() function  */
	NULL,           /* The load_plugin_config() function  */
	"DemoA",        /* config keyword                     */

	NULL,           /* Undefined 2  */
	NULL,           /* Undefined 1  */
	NULL,           /* Undefined 0  */

	PLUGIN_PLACEMENT, /* Insert plugin before this monitor.       */
	NULL,           /* Handle if a plugin, filled in by GKrellM */
	NULL            /* path if a plugin, filled in by GKrellM   */
	};

GkrellmMonitor *
gkrellm_init_plugin(void)
	{
	return &plugin_mon;
	}
where the functions update_plugin() and create_plugin() refer to functions that will be used in example programs later in this document. The above define of PLUGIN_PLACEMENT as MON_MAIL will cause the plugin to appear just above the mail monitor. You could also choose MON_UPTIME, MON_APM, MON_FS, MON_MEM, MON_INET, MON_NET, MON_DISK, MON_PROC, MON_CPU, or MON_CLOCK depending on where you think the plugin looks best. This is an initial placement because the user can re-place plugins.
Plugin Placement
When multiple plugins specify placement above the same monitor, the order of the plugins is not deterministic. It depends on the order the plugin.so was written into the plugin directory and is not sorted. To give plugins additional placement control, there are two values that can be added to the placement parameter (both cannot be used at once):
Compiling a Plugin
If the plugin is a single source file, it can be compiled into a .so file and installed with the commands:
    gcc -fPIC `pkg-config gtk+-2.0 --cflags` -c plugin.c
    gcc -shared -Wl -o plugin.so plugin.o
    cp plugin.so ~/.gkrellm2/plugins
When developing a plugin, you don't need to install after each compile. Just run:
    gkrellm -p plugin.so
See demo4 in the gkrellm_demos.tar.gz file for an example of setting a plugin up with a Makefile.

Coding Style Issues

Charts

When a chart is created, it must be associated with a GkrellmChartconfig structure. The chart then has the builtin ability to be user configured with very little coding effort in the plugin. However, it is the plugins responsibility to save and load the configuration state and to possibly connect some callbacks so it can make adjustments when user configuration changes are made. The things to know are: All chart monitors currently in GKrellM consist of a chart and a panel just below it. Panel creation is generally more involved and is discussed later, but here is an example demo1.c which creates a stand alone chart without a panel. It is heavily commented so it can be a reasonable tutorial for creating a chart, and it is included along with the example monitors listed below in gkrellm2-demos.tar.gz

I must emphasize that the create function for all monitors is a "create event" function which will be called for every theme and horizontal size change. The first_create variable is true only for the initial creation and should be used to allocate data and make calls that should be done only once.

After the create function is called, the background image and pixmaps for drawing on are initialized. The entire chart is a gtk drawing_area and you get allocated expose and background pixmaps in the GkrellmChart structure (see gkrellm.h). You can draw on these pixmaps and drawing_area however you want, or make local pixmaps to work on and then copy to the chart pixmaps. The thing to remember is that bg_pixmap has a rendered theme background image pre-loaded which you probably want to preserve, but there could be exceptions depending on the type of drawing done on the chart. A plugin can have its own chart drawing routines for all drawing or can use the gkrellm chart drawing routine if it will do the job.

Panels

A chart monitor usually has a panel area below the chart, while a meter monitor has one or more meter areas and no chart. The panel and meter areas of monitors are both created by allocating a GkrellmPanel structure and calling gkrellm_panel_create(). The difference between them is that they have different theme styles and background images. So many gkrellm_xxx() functions will operate on the common GkrellmPanel structure, while others that reference styles and images will have distinct functions to use for the panel or meter areas. For example, common functions include gkrellm_panel_create(), gkrellm_panel_configure(), and gkrellm_panel_destroy(). But panel areas also have their own functions such as gkrellm_panel_style(), gkrellm_bg_panel_piximage(), etc while the meter areas have the corresponding gkrellm_meter_style(), gkrellm_bg_meter_piximage(), etc.

It may be confusing, but the terminology to keep in mind is that while a GkrellmPanel structure applies equally to a panel area and a meter area of a monitor (perhaps think of the GkrellmPanel structure as a panel_meter structure), there are separate style and image sets to associate with these panel and meter areas.

Panels are created to hold krells, decals, and labels, so code examples for them will be in the sections below. Finally, a plugin is actually free to mix chart, panel, or meter areas in any order or combination in a single plugin so long as you are aware of the style and image theming implications.

Again, it is important to emphasize that the create_plugin() routine is a create event which will be called multiple times. Plugins are expected to re-create each decal or krell they may have every time the create_plugin() routine is called because the GKrellM rebuild routine automatically destroys all decals and krells in all panels. However, this automatic destroy can be overridden if you have a reason to manage the lists yourself.

Krells

demo2.jpg A krell is a pixmap graphic which can be moved across the face of a panel or meter area. Krell drawing functions (gkrellm_update_krell() or gkrellm_move_krell_yoff()) draw to the panel pixmap only. After all krell and decal drawing is done in a monitor update routine, the changes should be drawn to the screen by calling gkrellm_draw_panel_layers(). This example program demo2.c creates a default meter style krell with a "Plugin" label for a meter area.

Decals and Decal Buttons

There are two types of decals, pixmap and text, which can be drawn on a meter or panel area. Decal drawing functions (gkrellm_draw_decal_text(), gkrellm_decal_text_insert(), gkrellm_draw_decal_pixmap(), gkrellm_move_decal()) draw to the panel pixmap only. After all krell and decal drawing is done in a monitor update routine, the changes should be drawn to the screen by calling gkrellm_draw_panel_layers(). A pixmap decal is a single displayed pixmap frame out of an image which was drawn as a vertical stack of pixmap frames. The frame displayed is changed by simply calling the decal draw routine with a different frame index. A text decal is a single pixmap which can have text drawn on it.

There are two types of buttons that can be created. There are pixmap decal buttons which can be created directly out of a GkrellmPiximage or which can be created by converting an existing pixmap decal into a button. A pixmap decal can be directly converted into a button because it has a set of vertical frames from which a in and out button image can be assigned. The second button type applies if you want to use a single pixmap text decal (no frames) as a button. To do this it must be indirectly put into a button. This "putting" operation simply overlays the text decal with a default pixmap decal button that has in and out images with transparent interiors so the text decal will show through.

The basic sequence to follow is create decals (and krells), and then create buttons. The buttons may be pixmap decals converted into buttons, text decals put into overlay buttons, or may be pixmap decal buttons created directly out of a GkrellmPiximage with gkrellm_make_scaled_button(). Then gkrellm_panel_configure() should be called so a panel height to accomodate all the krells, decals, and buttons may be calculated. Finally, the panel is created. Note: decals may be converted into buttons after the panel is created as was required with GkrellM 1.2.x. However, with GKrellM 2.0, most buttons may be created before or after the panel is created with these exceptions: Buttons made with gkrellm_make_scaled_button() should be done before the panel is created so that gkrellm_panel_configure() will know of their size. Otherwise you will have to explicitely manage the panel size to accomodate the buttons that will be created. And buttons that must still be created only after the panel is created are gkrellm_put_label_in_xxx_button() where xxx is meter or panel because the label won't exist unless the panel is created.

Having buttons which are created out of decals may seem unusual, but provides some advantages. A button can have its pixmap rapidly switched with the same code that switches the pixmaps for a normal decal, so it can be efficient to have an animated or state displaying button. However, note that there is a gkrellm_set_decal_button_index() call to switch the displayed frame of a decal button while the frame displayed for a decal pixmap is set via an argument to gkrellm_draw_decal_pixmap(). Also, since pixmap decals can have transparency and can overlap, pixmap decal buttons can do the same, and are not restricted to rectangular shapes (the only complication would be the code to check for the mouse in the button, see demo4). Note that this way of creating buttons out of pixmap decals requires that the images for the in and out button states (there can be multiple out states) must be drawn as frames of a single vertical image - you cannot draw them the more traditional way as separate images.

demo3.png To demonstrate the decal and decal button features, this example program demo3.c will create:
  • a text decal that will be scrolled in the update routine,
  • a large scaled button made from the default button image.
  • a smaller auto hiding scaled button.
  • a text decal that will be put into an overlay button and the text toggled when the button is pressed,
  • a pixmap decal that will be converted into a decal button.

demo4.png

demo4_1.png

There is an advanced demo4 in the gkrellm2-demos.tar.gz tar file which includes a small test-theme that has plugin specific theme images and gkrellmrc lines. The screenshots to the left show the default layout and one of the themed alternatives in the test-theme. Here's the demo4.c and the gkrellmrc_1 for the themed alternative screenshot.

Styles, Text Styles, and Themes

There is a Themes document that describes a GKrellM theme in detail. Read this to understand how chart, panel, and meter areas are used to construct monitors in GKrellM, and how background images are applied to these areas.

When GKrellM loads a theme, style parameters are initialized to values set by the theme designer. These parameters are stored in a GkrellmStyle structure for each of the chart, panel, and meter areas. A GkrellmStyle structure has information about the default krells, borders for background images, label positions, margins, and two sets of text styles. There are functions to access the GkrellmStyle structure for a chart, panel, or meter area, and there are convenience functions to access each of the GkrellmTextstyle structures within these GkrellmStyle structures. There are also functions to access background images for the areas of each monitor. These styles and images may reference theme wide defaults, but also may have been customized at the monitor level depending on the theme. When building a plugin monitor, you typically access the GkrellmStyle and/or GkrellmTextstyle structures appropriate for the monitor by passing a style_id value to the style and image functions. The style_id argument should usually be a value returned from a gkrellm_add_chart_style() or gkrellm_add_meter_style() call, but could be DEFAULT_STYLE_ID or a looked up style_id value for other monitors. But be aware that using a style set for another monitor may preclude a theme author from customizing your plugin and you may get unexpected results with some themes.

It is also easy to provide for theming any images you have local to your plugin. I suggest putting a short Themes file in the source directory which documents the image names and gkrellmrc extensions you create for your plugin. It's hard to say if theme authors will actually do much plugin theming, but there certainly will be none if you don't tell anybody how to do it. See the demo4 for a complete themed plugin example, and here are a couple of additional fragment examples to give you and idea of what might be involved in theming a plugin: