Documentation/Maemo 5 Developer Guide/Application Development/Writing Desktop Widgets

m (Writing Desktop Widgets: minor language correction.)
(The .desktop File: desktop file link)
 
(11 intermediate revisions not shown)
Line 1: Line 1:
-
=Writing Desktop Widgets=
+
The following code examples are used in this chapter:
 +
* [https://vcs.maemo.org/svn/maemoexamples/tags/maemo_5.0/hildon-timeout-home-widget-example/ hildon-timeout-home-widget-example]
 +
* [https://vcs.maemo.org/svn/maemoexamples/tags/maemo_5.0/hildon-status-menu-widget-example/ hildon-status-menu-widget-example]
 +
 
Desktop widgets are programs designed to provide a certain functionality from the desktop area. These programs are usually limited, in the sense that they are not complex applications, normally representing "small" utilities or an extension of an existing application.
Desktop widgets are programs designed to provide a certain functionality from the desktop area. These programs are usually limited, in the sense that they are not complex applications, normally representing "small" utilities or an extension of an existing application.
Desktop widgets are written as shared libraries and need also to provide a desktop file that describes them. Depending on their placement, they can be Status Menu widgets or Home Area widgets.
Desktop widgets are written as shared libraries and need also to provide a desktop file that describes them. Depending on their placement, they can be Status Menu widgets or Home Area widgets.
-
They need to have a .desktop file describing them. The file contents are fields that describe certain properties of the widget.
+
They must have a .desktop file describing them. The file contents are fields that describe certain properties of the widget.
-
 
+
==Home Widgets==
==Home Widgets==
 +
Home widgets are located in the Home Area of the desktop. Home Area widgets are not resizable.
Home widgets are located in the Home Area of the desktop. Home Area widgets are not resizable.
To better show how to write a Home Area widget, consider a widget "TimeOut" that allows the user to choose an action to be performed at a given time.
To better show how to write a Home Area widget, consider a widget "TimeOut" that allows the user to choose an action to be performed at a given time.
-
Home widgets should inherit from libhildondesktop's HDHomePluginItem. The following example presents a header file for the mentioned widget.
+
Home widgets must inherit from libhildondesktop's <code>HDHomePluginItem</code>. The following example presents a header file for the mentioned widget.
'''Example 1.1. Header file for TimeOut widget: lib-timeout-home-widget.h'''
'''Example 1.1. Header file for TimeOut widget: lib-timeout-home-widget.h'''
-
#ifndef TIME_OUT_PLUGIN_H
+
<source lang="c">
-
#define TIME_OUT_PLUGIN_H
+
#ifndef TIME_OUT_PLUGIN_H
 +
#define TIME_OUT_PLUGIN_H
 +
 
 +
#include <glib-object.h>
 +
 
 +
#include <libhildondesktop/libhildondesktop.h>
 +
 
 +
G_BEGIN_DECLS
 +
 
 +
typedef struct _TimeOutPlugin TimeOutPlugin;
 +
typedef struct _TimeOutPluginClass TimeOutPluginClass;
 +
 
 +
#define TIME_OUT_TYPE_HOME_PLUGIN  (time_out_home_plugin_get_type ())
 +
 
 +
#define TIME_OUT_HOME_PLUGIN(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), \
 +
                        TIME_OUT_TYPE_HOME_PLUGIN, TimeOutHomePlugin))
 +
 
 +
#define TIME_OUT_HOME_PLUGIN_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), \
 +
                        TIME_OUT_TYPE_HOME_PLUGIN,  TimeOutHomePluginClass))
 +
 
 +
#define TIME_OUT_IS_HOME_PLUGIN(obj)  (G_TYPE_CHECK_INSTANCE_TYPE ((obj), \
 +
                        TIME_OUT_TYPE_HOME_PLUGIN))
   
   
-
#include <glib-object.h>
+
#define TIME_OUT_IS_HOME_PLUGIN_CLASS(klass)  (G_TYPE_CHECK_CLASS_TYPE ((klass), \
-
+
                        TIME_OUT_TYPE_HOME_PLUGIN))
-
#include <libhildondesktop/libhildondesktop.h>
+
 
-
+
#define TIME_OUT_HOME_PLUGIN_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), \
-
G_BEGIN_DECLS
+
                        TIME_OUT_TYPE_HOME_PLUGIN, TimeOutHomePluginClass))
-
+
-
typedef struct _TimeOutPlugin TimeOutPlugin;
+
-
typedef struct _TimeOutPluginClass TimeOutPluginClass;
+
-
+
-
#define TIME_OUT_TYPE_HOME_PLUGIN  (time_out_home_plugin_get_type ())
+
-
   
+
-
#define TIME_OUT_HOME_PLUGIN(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), \
+
-
                        TIME_OUT_TYPE_HOME_PLUGIN, TimeOutHomePlugin))
+
-
+
-
#define TIME_OUT_HOME_PLUGIN_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), \
+
-
                        TIME_OUT_TYPE_HOME_PLUGIN,  TimeOutHomePluginClass))
+
-
+
-
#define TIME_OUT_IS_HOME_PLUGIN(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), \
+
-
                        TIME_OUT_TYPE_HOME_PLUGIN))
+
-
 
+
-
  #define TIME_OUT_IS_HOME_PLUGIN_CLASS(klass)  (G_TYPE_CHECK_CLASS_TYPE ((klass), \
+
-
                        TIME_OUT_TYPE_HOME_PLUGIN))
+
   
   
-
#define TIME_OUT_HOME_PLUGIN_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), \
+
struct _TimeOutPlugin
-
                        TIME_OUT_TYPE_HOME_PLUGIN,  TimeOutHomePluginClass))
+
{
-
 
+
    HDHomePluginItem hitem;
-
struct _TimeOutPlugin
+
};
-
{
+
-
    HDHomePluginItem hitem;
+
-
};
+
-
 
+
-
struct _TimeOutPluginClass
+
-
{
+
-
    HDHomePluginItemClass parent_class;
+
-
};
+
-
 
+
-
GType time_out_home_plugin_get_type(void);
+
   
   
-
G_END_DECLS
+
struct _TimeOutPluginClass
 +
{
 +
    HDHomePluginItemClass parent_class;
 +
};
   
   
-
#endif
+
GType time_out_home_plugin_get_type(void);
 +
G_END_DECLS
-
The first and more important function is HD_DEFINE_PLUGIN_MODULE. This function receives three parameters to register the object that is supplied by the plug-in. The first argument should be the object type name in Camel case, the second is the type name in lowercase with underscores separating the words. The third is the GType of the object's parent. Apart from this macro, three other functions should be used. The name of the functions should be the name given as second argument to HD_DEFINE_PLUGIN_MODULE with the suffixes _init, _class_init and _class_finalize.
+
#endif
 +
</source>
 +
 
 +
The first and more important function is <code>HD_DEFINE_PLUGIN_MODULE</code>. This function receives three parameters to register the object that is supplied by the plug-in. The first argument is the object type name in Camel case, the second is the type name in lowercase with underscores separating the words. The third is the <code>GType</code> of the object's parent. Apart from this macro, use also three other functions. The name of the functions is the name given as second argument to <code>HD_DEFINE_PLUGIN_MODULE</code> with the suffixes _init, _class_init and _class_finalize.
The following example shows the source code for "TimeOut" widget.
The following example shows the source code for "TimeOut" widget.
Line 68: Line 72:
'''Example 1.2. Source file for TimeOut widget: lib-timeout-home-widget.c'''
'''Example 1.2. Source file for TimeOut widget: lib-timeout-home-widget.c'''
-
#include <gtk/gtk.h>
+
<source lang="c">
-
#include <hildon/hildon.h>
+
#include <gtk/gtk.h>
-
 
+
#include <hildon/hildon.h>
-
#include <libhildondesktop/libhildondesktop.h>
+
   
   
-
#include "lib-timeout-home-widget.h"
+
#include <libhildondesktop/libhildondesktop.h>
-
+
 
-
HD_DEFINE_PLUGIN_MODULE (TimeOutPlugin, time_out_plugin,      HD_TYPE_HOME_PLUGIN_ITEM)
+
#include "lib-timeout-home-widget.h"
-
 
+
 
-
static GtkWidget *
+
HD_DEFINE_PLUGIN_MODULE (TimeOutPlugin, time_out_plugin,      HD_TYPE_HOME_PLUGIN_ITEM)
-
build_ui (void)
+
-
{
+
-
    GtkVBox *contents = GTK_VBOX (gtk_vbox_new (0, FALSE));
+
-
    GtkLabel *label = GTK_LABEL (gtk_label_new ("Time out widget."));
+
-
    HildonPickerButton *action;
+
-
    action = HILDON_PICKER_BUTTON (hildon_picker_button_new  (HILDON_SIZE_FINGER_HEIGHT,
+
-
                                        HILDON_BUTTON_ARRANGEMENT_VERTICAL));
+
-
    HildonTouchSelector *action_selector;
+
-
    action_selector = HILDON_TOUCH_SELECTOR (hildon_touch_selector_new_text ());
+
-
    hildon_button_set_title (HILDON_BUTTON (action), "Action");
+
-
    hildon_touch_selector_append_text (action_selector, "Blank Screen");
+
-
    hildon_touch_selector_append_text (action_selector, "Suspend");
+
-
    hildon_touch_selector_append_text (action_selector, "Turn Off");
+
-
    hildon_picker_button_set_selector (action, action_selector);
+
-
    hildon_picker_button_set_active (action, 0);
+
-
+
-
    HildonTimeButton *time;
+
-
    time = HILDON_TIME_BUTTON (hildon_time_button_new (HILDON_SIZE_FINGER_HEIGHT,
+
-
                                        HILDON_BUTTON_ARRANGEMENT_VERTICAL));
+
-
    hildon_time_button_set_time (time, 22, 00);
+
-
+
-
    GtkHBox *buttons = GTK_HBOX (gtk_hbox_new (0, TRUE));
+
-
    gtk_container_add (GTK_CONTAINER (buttons), GTK_WIDGET (action));
+
-
    gtk_container_add (GTK_CONTAINER (buttons), GTK_WIDGET (time));
+
-
   
+
-
    gtk_box_pack_start (GTK_BOX (contents), GTK_WIDGET (label), FALSE, FALSE, 0);
+
-
    gtk_box_pack_end (GTK_BOX (contents), GTK_WIDGET (buttons), FALSE, FALSE, 0);
+
-
    gtk_widget_show_all (GTK_WIDGET (contents));
+
   
   
-
    return GTK_WIDGET (contents);
+
static GtkWidget *
-
}
+
build_ui (void)
-
+
{
-
  static void
+
    GtkVBox *contents = GTK_VBOX (gtk_vbox_new (0, FALSE));
-
time_out_plugin_init (TimeOutPlugin *desktop_plugin)
+
    GtkLabel *label = GTK_LABEL (gtk_label_new ("Time out widget."));
-
{
+
    HildonPickerButton *action;
-
  GtkWidget *contents = build_ui ();
+
    action = HILDON_PICKER_BUTTON (hildon_picker_button_new (HILDON_SIZE_FINGER_HEIGHT,
-
  gtk_container_add (GTK_CONTAINER (desktop_plugin), contents);
+
                                        HILDON_BUTTON_ARRANGEMENT_VERTICAL));
-
}
+
    HildonTouchSelector *action_selector;
-
+
    action_selector = HILDON_TOUCH_SELECTOR (hildon_touch_selector_new_text ());
-
static void
+
    hildon_button_set_title (HILDON_BUTTON (action), "Action");
-
time_out_plugin_class_init (TimeOutPluginClass *class) {}
+
    hildon_touch_selector_append_text (action_selector, "Blank Screen");
-
+
    hildon_touch_selector_append_text (action_selector, "Suspend");
-
static void
+
    hildon_touch_selector_append_text (action_selector, "Turn Off");
-
time_out_plugin_class_finalize (TimeOutPluginClass *class) {}
+
    hildon_picker_button_set_selector (action, action_selector);
 +
    hildon_picker_button_set_active (action, 0);
 +
    HildonTimeButton *time;
 +
    time = HILDON_TIME_BUTTON (hildon_time_button_new (HILDON_SIZE_FINGER_HEIGHT,
 +
                                        HILDON_BUTTON_ARRANGEMENT_VERTICAL));
 +
    hildon_time_button_set_time (time, 22, 00);
 +
 +
    GtkHBox *buttons = GTK_HBOX (gtk_hbox_new (0, TRUE));
 +
    gtk_container_add (GTK_CONTAINER (buttons), GTK_WIDGET (action));
 +
    gtk_container_add (GTK_CONTAINER (buttons), GTK_WIDGET (time));
 +
   
 +
    gtk_box_pack_start (GTK_BOX (contents), GTK_WIDGET (label), FALSE, FALSE, 0);
 +
    gtk_box_pack_end (GTK_BOX (contents), GTK_WIDGET (buttons), FALSE, FALSE, 0);
 +
    gtk_widget_show_all (GTK_WIDGET (contents));
 +
 +
    return GTK_WIDGET (contents);
 +
}
 +
 +
static void
 +
time_out_plugin_init (TimeOutPlugin *desktop_plugin)
 +
{
 +
  GtkWidget *contents = build_ui ();
 +
  gtk_container_add (GTK_CONTAINER (desktop_plugin), contents);
 +
}
 +
 +
static void
 +
time_out_plugin_class_init (TimeOutPluginClass *class) {}
 +
 +
static void
 +
time_out_plugin_class_finalize (TimeOutPluginClass *class) {}
 +
</source>
              
              
-
As you can see in the example above, the controls used in the widget (build_ui function) should be added to "TimeOutPlugin". In this case, the widget works as a standalone application, but it could just provide a widget to activate a program defined in another header and independent from the widget.
+
As you can see in the example above, the controls used in the widget (build_ui function) must be added to "TimeOutPlugin". In this case, the widget works as a standalone application, but it can just provide a widget to activate a program defined in another header and independent from the widget.
===The .desktop File===
===The .desktop File===
-
Although other fields can be assigned in a .desktop file, the example bellow shows a simple .desktop file for the "TimeOut" widget. The "Name" field will be the widget's name in the list when the user is choosing widgets to add to the desktop. The "X-Path" field should be set to the .so file that was previously generated.
 
-
Example 1.3. A .desktop file for the TimeOut widget: timeout-widget.desktop
+
Although other fields can be assigned in a [[Desktop file format|.desktop file]], the example bellow shows a simple .desktop file for the "TimeOut" widget. The "Name" field is the widget's name in the list when the user is choosing widgets to add to the desktop. The "X-Path" field should be set to the .so file that was previously generated.
-
 
+
-
[Desktop Entry]
+
-
Name=TimeOut  Widget
+
-
Comment=Execute an action at a given time
+
-
Type=default
+
-
X-Path=lib-timeout-home-widget.so
+
 +
Example 1.3. A .desktop file for the TimeOut widget: timeout-widget.desktop
 +
<pre>
 +
[Desktop Entry]
 +
Name=TimeOut Widget
 +
Comment=Execute an action at a given time
 +
Type=default
 +
X-Path=lib-timeout-home-widget.so
 +
</pre>
                  
                  
-
For Home Area widget, .desktop files should be placed in the directory outputed by the following command:
+
For Home Area widget, place .desktop files in the directory outputed by the following command:
-
  pkg-config libhildondesktop-1 --variable=hildonhomedesktopentrydir --variable=homedesktopentrydir
+
  pkg-config libhildondesktop-1 --variable=hildonhomedesktopentrydir
==Status Menu widgets==
==Status Menu widgets==
-
Status Menu widgets are placed in the Status Menu and can be divided into three categories: permanent, conditional and temporary. Permanent widgets are shown all the time. Conditional and temporary widgets are shown when a certain condition is fulfilled.
 
-
The way to write a widget for the Status Menu is pretty similar to writing it for the Home Area. The widget should inherit from HDStatusMenuItem. The next examples present a Status Menu widget which only shows a message when clicked.
+
Status Menu widgets are located in the Status Menu and can be divided into three categories: permanent, conditional and temporary. Permanent widgets are shown all the time. Conditional and temporary widgets are shown when a certain condition is fulfilled.
 +
 
 +
The way to write a widget for the Status Menu is pretty similar to writing it for the Home Area. The widget inherits from <code>HDStatusMenuItem</code>. The next examples present a Status Menu widget which only shows a message when clicked.
Example 1.4. Header file for Example Status Menu Widget: lib-example-status-menu-widget.h
Example 1.4. Header file for Example Status Menu Widget: lib-example-status-menu-widget.h
-
#ifndef __EXAMPLE_STATUS_PLUGIN_H__
+
<source lang="c">
-
#define __EXAMPLE_STATUS_PLUGIN_H__
+
#ifndef __EXAMPLE_STATUS_PLUGIN_H__
-
+
#define __EXAMPLE_STATUS_PLUGIN_H__
-
#include <libhildondesktop/libhildondesktop.h>
+
 
-
+
#include <libhildondesktop/libhildondesktop.h>
-
G_BEGIN_DECLS
+
 
-
+
G_BEGIN_DECLS
-
#define TYPE_EXAMPLE_STATUS_PLUGIN            (example_status_plugin_get_type ())
+
 
-
+
#define TYPE_EXAMPLE_STATUS_PLUGIN            (example_status_plugin_get_type ())
-
#define EXAMPLE_STATUS_PLUGIN(obj)            (G_TYPE_CHECK_INSTANCE_CAST ((obj), \
+
 
-
                                    TYPE_EXAMPLE_STATUS_PLUGIN, ExampleStatusPlugin))
+
#define EXAMPLE_STATUS_PLUGIN(obj)            (G_TYPE_CHECK_INSTANCE_CAST ((obj), \
-
 
+
                                    TYPE_EXAMPLE_STATUS_PLUGIN, ExampleStatusPlugin))
-
#define EXAMPLE_STATUS_PLUGIN_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST ((klass), \
+
-
                                TYPE_EXAMPLE_STATUS_PLUGIN, ExampleStatusPluginClass))
+
   
   
-
#define IS_EXAMPLE_STATUS_PLUGIN(obj)        (G_TYPE_CHECK_INSTANCE_TYPE ((obj), \
+
#define EXAMPLE_STATUS_PLUGIN_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST ((klass), \
-
                                                    TYPE_EXAMPLE_STATUS_PLUGIN))
+
                                TYPE_EXAMPLE_STATUS_PLUGIN, ExampleStatusPluginClass))
-
+
 
-
#define IS_EXAMPLE_STATUS_PLUGIN_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), \
+
#define IS_EXAMPLE_STATUS_PLUGIN(obj)        (G_TYPE_CHECK_INSTANCE_TYPE ((obj), \
-
                                                    TYPE_EXAMPLE_STATUS_PLUGIN))
+
                                                    TYPE_EXAMPLE_STATUS_PLUGIN))
-
+
 
-
#define EXAMPLE_STATUS_PLUGIN_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS ((obj), \
+
#define IS_EXAMPLE_STATUS_PLUGIN_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), \
-
                            TYPE_EXAMPLE_STATUS_PLUGIN, ExampleStatusPluginClass))
+
                                                    TYPE_EXAMPLE_STATUS_PLUGIN))
-
+
 
-
#define STATUS_AREA_EXAMPLE_ICON_SIZE 22
+
#define EXAMPLE_STATUS_PLUGIN_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS ((obj), \
-
+
                            TYPE_EXAMPLE_STATUS_PLUGIN, ExampleStatusPluginClass))
-
typedef struct _ExampleStatusPlugin        ExampleStatusPlugin;
+
 
-
typedef struct _ExampleStatusPluginClass  ExampleStatusPluginClass;
+
#define STATUS_AREA_EXAMPLE_ICON_SIZE 22
-
typedef struct _ExampleStatusPluginPrivate ExampleStatusPluginPrivate;  
+
 
-
+
typedef struct _ExampleStatusPlugin        ExampleStatusPlugin;
-
struct _ExampleStatusPlugin
+
typedef struct _ExampleStatusPluginClass  ExampleStatusPluginClass;
-
{
+
typedef struct _ExampleStatusPluginPrivate ExampleStatusPluginPrivate;  
-
    HDStatusMenuItem parent;
+
 
-
+
struct _ExampleStatusPlugin
-
    ExampleStatusPluginPrivate *priv;
+
{
-
};
+
    HDStatusMenuItem parent;
-
+
 
-
struct _ExampleStatusPluginClass
+
    ExampleStatusPluginPrivate *priv;
-
{
+
};
-
    HDStatusMenuItemClass parent;
+
 
-
};
+
struct _ExampleStatusPluginClass
-
+
{
-
GType example_status_plugin_get_type (void);
+
    HDStatusMenuItemClass parent;
-
+
};
-
G_END_DECLS
+
 
-
+
GType example_status_plugin_get_type (void);
-
#endif
+
 
-
+
G_END_DECLS
-
           
+
 
 +
#endif
 +
</source>
 +
         
'''Example 1.5. Source file for Example Status Menu  Widget: lib-example-status-menu-widget.c'''
'''Example 1.5. Source file for Example Status Menu  Widget: lib-example-status-menu-widget.c'''
-
#include <stdio.h>
+
<source lang="c">
-
#include <stdlib.h>
+
#include <stdio.h>
-
#include <gtk/gtk.h>
+
#include <stdlib.h>
-
#include <hildon/hildon.h>
+
#include <gtk/gtk.h>
-
+
#include <hildon/hildon.h>
-
#include "lib-example-status-menu-applet.h"
+
-
+
-
#define EXAMPLE_STATUS_PLUGIN_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE (obj,  \
+
-
                            TYPE_EXAMPLE_STATUS_PLUGIN, ExampleStatusPluginPrivate))
+
-
+
-
struct _ExampleStatusPluginPrivate
+
-
{
+
-
    GtkWidget *label;
+
-
    gpointer data;
+
-
};
+
-
+
-
HD_DEFINE_PLUGIN_MODULE (ExampleStatusPlugin, example_status_plugin,  HD_TYPE_STATUS_MENU_ITEM);
+
-
+
-
static void
+
-
example_status_plugin_class_finalize (ExampleStatusPluginClass *klass) {}
+
-
+
-
static void
+
-
example_status_plugin_class_init (ExampleStatusPluginClass *klass)
+
-
{
+
-
    g_type_class_add_private (klass, sizeof (ExampleStatusPluginPrivate));
+
-
}
+
-
+
-
static void
+
-
example_status_plugin_init (ExampleStatusPlugin *plugin)
+
-
{
+
-
    plugin->priv = EXAMPLE_STATUS_PLUGIN_GET_PRIVATE (plugin);
+
-
+
-
    GtkIconTheme *icon_theme = gtk_icon_theme_get_default ();
+
-
    GList *list = gtk_icon_theme_list_icons (icon_theme, NULL);
+
-
    GdkPixbuf *pixbuf = gtk_icon_theme_load_icon (icon_theme, "general_email",
+
-
                    STATUS_AREA_EXAMPLE_ICON_SIZE, GTK_ICON_LOOKUP_NO_SVG, NULL);
+
-
    hd_status_plugin_item_set_status_area_icon (HD_STATUS_PLUGIN_ITEM (plugin), pixbuf);
+
-
    g_object_unref (pixbuf);
+
-
+
-
    GtkWidget *b = gtk_label_new ("Example message");
+
-
    gtk_widget_show_all (b);
+
-
+
-
    plugin->priv->label = b;
+
-
+
-
    gtk_container_add (GTK_CONTAINER (plugin), plugin->priv->label);
+
-
+
-
    gtk_widget_show_all (plugin->priv->label);
+
-
+
-
    gtk_widget_show (GTK_WIDGET (plugin));
+
-
}
+
-
       
+
-
===The .desktop File===
+
-
The .desktop file for the Status Menu is analogous to the Home Area one but should also contain the "Category" field where the priority of the applet is set (permanent, conditional or temporary) and the "Icon" field to set the icon's name. If the "Category" key is not set, it is considered as permanent.
+
-
Example 1.6. A .desktop file for the Status Menu example widget: lib-example-widget.desktop
+
#include "lib-example-status-menu-widget.h"
-
[Desktop Entry]
+
#define EXAMPLE_STATUS_PLUGIN_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE (obj,  \
-
Name=Example
+
                            TYPE_EXAMPLE_STATUS_PLUGIN, ExampleStatusPluginPrivate))
-
Icon=general_email
+
-
Comment=An example status menu widget
+
-
Category=permanent
+
-
Type=default
+
-
X-Path=lib-example-status-menu-widget.so
+
 +
struct _ExampleStatusPluginPrivate
 +
{
 +
    GtkWidget *label;
 +
    gpointer data;
 +
};
 +
 +
HD_DEFINE_PLUGIN_MODULE (ExampleStatusPlugin, example_status_plugin,  HD_TYPE_STATUS_MENU_ITEM);
 +
 +
static void
 +
example_status_plugin_class_finalize (ExampleStatusPluginClass *klass) {}
 +
 +
static void
 +
example_status_plugin_class_init (ExampleStatusPluginClass *klass)
 +
{
 +
    g_type_class_add_private (klass, sizeof (ExampleStatusPluginPrivate));
 +
}
 +
 +
static void
 +
example_status_plugin_init (ExampleStatusPlugin *plugin)
 +
{
 +
    plugin->priv = EXAMPLE_STATUS_PLUGIN_GET_PRIVATE (plugin);
 +
 +
    GtkIconTheme *icon_theme = gtk_icon_theme_get_default ();
 +
    GList *list = gtk_icon_theme_list_icons (icon_theme, NULL);
 +
    GdkPixbuf *pixbuf = gtk_icon_theme_load_icon (icon_theme, "general_email",
 +
                    STATUS_AREA_EXAMPLE_ICON_SIZE, GTK_ICON_LOOKUP_NO_SVG, NULL);
 +
    hd_status_plugin_item_set_status_area_icon (HD_STATUS_PLUGIN_ITEM (plugin), pixbuf);
 +
    g_object_unref (pixbuf);
 +
 +
    GtkWidget *b = gtk_label_new ("Example message");
 +
    gtk_widget_show_all (b);
 +
 +
    plugin->priv->label = b;
 +
 +
    gtk_container_add (GTK_CONTAINER (plugin), plugin->priv->label);
 +
 +
    gtk_widget_show_all (plugin->priv->label);
 +
 +
  gtk_widget_show (GTK_WIDGET (plugin));
 +
}
 +
</source>
 +
     
 +
===The .desktop File===
 +
 +
The .desktop file for the Status Menu is similar to the Home Area one but also contains the "Category" field where the priority of the widget is set (permanent, conditional or temporary) and the "Icon" field to set the icon's name. If the "Category" key is not set, it is considered as permanent.
 +
 +
Example 1.6. A .desktop file for the Status Menu example widget: lib-example-widget.desktop
 +
<pre>
 +
[Desktop Entry]
 +
Name=Example
 +
Icon=general_email
 +
Comment=An example status menu widget
 +
Category=permanent
 +
Type=default
 +
X-Path=lib-example-status-menu-widget.so
 +
</pre>
                  
                  
-
For Home Area widget, .desktop files should be placed in the directory outputed by the following command:
+
For Status Menu widget, .desktop files should be placed in the directory outputted by the following command:
-
  pkg-config libhildondesktop-1 --variable=homedesktopentrydir
+
  pkg-config --variable=hildonstatusmenudesktopentrydir libhildondesktop-1
==Building Widgets==
==Building Widgets==
-
To use a widget, it needs to be built as a shared library. This is done by passing the -shared flag to gcc.
 
-
  gcc -shared `pkg-config hildon-1 libhildondesktop-1 --libs --cflags` widget.c -o lib-widget.so
+
To use a widget, it needs to be built as a shared library. This is done by passing the <code>-shared</code> flag to gcc.
 +
 
 +
  gcc -shared `pkg-config --libs --cflags hildon-1 libhildondesktop-1` widget.c -o lib-widget.so
 +
 
 +
Status Menu and Home Area widgets binaries are located in the same directory, so assign distinguishable names to them, such as "lib-example-home-widget.so" and "lib-example-status-menu-widget.so" for the Home Area and Status Menu widgets, respectively. The directory where the binary files are copied to is given by the following command (which normally outputs <code>/usr/lib/hildon-desktop</code>):
-
Status Menu and Home Area widgets binaries should be placed in the same directory, so, assign distinguishable names to them. For example, "lib-example-home-widget.so" and "lib-example-status-menu-widget.so" for the Home Area and Status Menu widgets, respectively. The directory where the binary files should be copied to is given by the following command (which normally outputs "/usr/share/applications/hildon-desktop"):
+
pkg-config --variable=hildondesktoplibdir libhildondesktop-1
-
pkg-config libhildondesktop-1 --variable=hildondesktoplibdir
+
[[Category:Development]]
 +
[[Category:Documentation]]
 +
[[Category:Fremantle]]

Latest revision as of 15:07, 2 September 2010

The following code examples are used in this chapter:

Desktop widgets are programs designed to provide a certain functionality from the desktop area. These programs are usually limited, in the sense that they are not complex applications, normally representing "small" utilities or an extension of an existing application.

Desktop widgets are written as shared libraries and need also to provide a desktop file that describes them. Depending on their placement, they can be Status Menu widgets or Home Area widgets.

They must have a .desktop file describing them. The file contents are fields that describe certain properties of the widget.

Contents

[edit] Home Widgets

Home widgets are located in the Home Area of the desktop. Home Area widgets are not resizable.

To better show how to write a Home Area widget, consider a widget "TimeOut" that allows the user to choose an action to be performed at a given time.

Home widgets must inherit from libhildondesktop's HDHomePluginItem. The following example presents a header file for the mentioned widget.

Example 1.1. Header file for TimeOut widget: lib-timeout-home-widget.h

#ifndef TIME_OUT_PLUGIN_H
#define TIME_OUT_PLUGIN_H
 
#include <glib-object.h>
 
#include <libhildondesktop/libhildondesktop.h>
 
G_BEGIN_DECLS
 
typedef struct _TimeOutPlugin TimeOutPlugin;
typedef struct _TimeOutPluginClass TimeOutPluginClass;
 
#define TIME_OUT_TYPE_HOME_PLUGIN   (time_out_home_plugin_get_type ())
 
#define TIME_OUT_HOME_PLUGIN(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), \
                        TIME_OUT_TYPE_HOME_PLUGIN, TimeOutHomePlugin))
 
#define TIME_OUT_HOME_PLUGIN_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), \
                        TIME_OUT_TYPE_HOME_PLUGIN,  TimeOutHomePluginClass))
 
#define TIME_OUT_IS_HOME_PLUGIN(obj)  (G_TYPE_CHECK_INSTANCE_TYPE ((obj), \
                        TIME_OUT_TYPE_HOME_PLUGIN))
 
#define TIME_OUT_IS_HOME_PLUGIN_CLASS(klass)  (G_TYPE_CHECK_CLASS_TYPE ((klass), \
                        TIME_OUT_TYPE_HOME_PLUGIN))
 
#define TIME_OUT_HOME_PLUGIN_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), \
                        TIME_OUT_TYPE_HOME_PLUGIN,  TimeOutHomePluginClass))
 
struct _TimeOutPlugin
{
    HDHomePluginItem hitem;
};
 
struct _TimeOutPluginClass
{
    HDHomePluginItemClass parent_class;
};
 
GType time_out_home_plugin_get_type(void);
 
G_END_DECLS
 
#endif

The first and more important function is HD_DEFINE_PLUGIN_MODULE. This function receives three parameters to register the object that is supplied by the plug-in. The first argument is the object type name in Camel case, the second is the type name in lowercase with underscores separating the words. The third is the GType of the object's parent. Apart from this macro, use also three other functions. The name of the functions is the name given as second argument to HD_DEFINE_PLUGIN_MODULE with the suffixes _init, _class_init and _class_finalize.

The following example shows the source code for "TimeOut" widget.

Example 1.2. Source file for TimeOut widget: lib-timeout-home-widget.c

#include <gtk/gtk.h>
#include <hildon/hildon.h>
 
#include <libhildondesktop/libhildondesktop.h>
 
#include "lib-timeout-home-widget.h"
 
HD_DEFINE_PLUGIN_MODULE (TimeOutPlugin, time_out_plugin,      HD_TYPE_HOME_PLUGIN_ITEM)
 
static GtkWidget *
build_ui (void)
{
    GtkVBox *contents = GTK_VBOX (gtk_vbox_new (0, FALSE));
    GtkLabel *label = GTK_LABEL (gtk_label_new ("Time out widget."));
    HildonPickerButton *action;
    action = HILDON_PICKER_BUTTON (hildon_picker_button_new  (HILDON_SIZE_FINGER_HEIGHT,
                                        HILDON_BUTTON_ARRANGEMENT_VERTICAL));
    HildonTouchSelector *action_selector;
    action_selector = HILDON_TOUCH_SELECTOR (hildon_touch_selector_new_text ());
    hildon_button_set_title (HILDON_BUTTON (action), "Action");
    hildon_touch_selector_append_text (action_selector, "Blank Screen");
    hildon_touch_selector_append_text (action_selector, "Suspend");
    hildon_touch_selector_append_text (action_selector, "Turn Off");
    hildon_picker_button_set_selector (action, action_selector);
    hildon_picker_button_set_active (action, 0); 
 
    HildonTimeButton *time;
    time = HILDON_TIME_BUTTON (hildon_time_button_new (HILDON_SIZE_FINGER_HEIGHT,
                                        HILDON_BUTTON_ARRANGEMENT_VERTICAL));
    hildon_time_button_set_time (time, 22, 00); 
 
    GtkHBox *buttons = GTK_HBOX (gtk_hbox_new (0, TRUE));
    gtk_container_add (GTK_CONTAINER (buttons), GTK_WIDGET (action));
    gtk_container_add (GTK_CONTAINER (buttons), GTK_WIDGET (time));
 
    gtk_box_pack_start (GTK_BOX (contents), GTK_WIDGET (label), FALSE, FALSE, 0);
    gtk_box_pack_end (GTK_BOX (contents), GTK_WIDGET (buttons), FALSE, FALSE, 0);
    gtk_widget_show_all (GTK_WIDGET (contents)); 
 
    return GTK_WIDGET (contents);
}
 
static void
time_out_plugin_init (TimeOutPlugin *desktop_plugin)
{
  GtkWidget *contents = build_ui ();
  gtk_container_add (GTK_CONTAINER (desktop_plugin), contents);
} 
 
static void
time_out_plugin_class_init (TimeOutPluginClass *class) {} 
 
static void
time_out_plugin_class_finalize (TimeOutPluginClass *class) {}

As you can see in the example above, the controls used in the widget (build_ui function) must be added to "TimeOutPlugin". In this case, the widget works as a standalone application, but it can just provide a widget to activate a program defined in another header and independent from the widget.

[edit] The .desktop File

Although other fields can be assigned in a .desktop file, the example bellow shows a simple .desktop file for the "TimeOut" widget. The "Name" field is the widget's name in the list when the user is choosing widgets to add to the desktop. The "X-Path" field should be set to the .so file that was previously generated.

Example 1.3. A .desktop file for the TimeOut widget: timeout-widget.desktop

[Desktop Entry] 
Name=TimeOut Widget 
Comment=Execute an action at a given time
Type=default
X-Path=lib-timeout-home-widget.so

For Home Area widget, place .desktop files in the directory outputed by the following command:

pkg-config libhildondesktop-1 --variable=hildonhomedesktopentrydir

[edit] Status Menu widgets

Status Menu widgets are located in the Status Menu and can be divided into three categories: permanent, conditional and temporary. Permanent widgets are shown all the time. Conditional and temporary widgets are shown when a certain condition is fulfilled.

The way to write a widget for the Status Menu is pretty similar to writing it for the Home Area. The widget inherits from HDStatusMenuItem. The next examples present a Status Menu widget which only shows a message when clicked.

Example 1.4. Header file for Example Status Menu Widget: lib-example-status-menu-widget.h

#ifndef __EXAMPLE_STATUS_PLUGIN_H__
#define __EXAMPLE_STATUS_PLUGIN_H__
 
#include <libhildondesktop/libhildondesktop.h>
 
G_BEGIN_DECLS
 
#define TYPE_EXAMPLE_STATUS_PLUGIN            (example_status_plugin_get_type ())
 
#define EXAMPLE_STATUS_PLUGIN(obj)            (G_TYPE_CHECK_INSTANCE_CAST ((obj), \
                                    TYPE_EXAMPLE_STATUS_PLUGIN, ExampleStatusPlugin))
 
#define EXAMPLE_STATUS_PLUGIN_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST ((klass), \
                                TYPE_EXAMPLE_STATUS_PLUGIN, ExampleStatusPluginClass))
 
#define IS_EXAMPLE_STATUS_PLUGIN(obj)         (G_TYPE_CHECK_INSTANCE_TYPE ((obj), \
                                                    TYPE_EXAMPLE_STATUS_PLUGIN))
 
#define IS_EXAMPLE_STATUS_PLUGIN_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), \
                                                    TYPE_EXAMPLE_STATUS_PLUGIN))
 
#define EXAMPLE_STATUS_PLUGIN_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS ((obj), \
                            TYPE_EXAMPLE_STATUS_PLUGIN, ExampleStatusPluginClass))
 
#define STATUS_AREA_EXAMPLE_ICON_SIZE 22
 
typedef struct _ExampleStatusPlugin        ExampleStatusPlugin;
typedef struct _ExampleStatusPluginClass   ExampleStatusPluginClass;
typedef struct _ExampleStatusPluginPrivate ExampleStatusPluginPrivate; 
 
struct _ExampleStatusPlugin
{
    HDStatusMenuItem parent;
 
    ExampleStatusPluginPrivate *priv;
};
 
struct _ExampleStatusPluginClass
{
    HDStatusMenuItemClass parent;
};
 
GType example_status_plugin_get_type (void);
 
G_END_DECLS
 
#endif

Example 1.5. Source file for Example Status Menu Widget: lib-example-status-menu-widget.c

#include <stdio.h>
#include <stdlib.h>
#include <gtk/gtk.h>
#include <hildon/hildon.h>
 
#include "lib-example-status-menu-widget.h"
 
#define EXAMPLE_STATUS_PLUGIN_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE (obj,   \
                            TYPE_EXAMPLE_STATUS_PLUGIN, ExampleStatusPluginPrivate))
 
struct _ExampleStatusPluginPrivate
{
    GtkWidget *label;
    gpointer data;
};
 
HD_DEFINE_PLUGIN_MODULE (ExampleStatusPlugin, example_status_plugin,   HD_TYPE_STATUS_MENU_ITEM);
 
static void
example_status_plugin_class_finalize (ExampleStatusPluginClass *klass) {}
 
static void
example_status_plugin_class_init (ExampleStatusPluginClass *klass)
{
    g_type_class_add_private (klass, sizeof (ExampleStatusPluginPrivate));
}
 
static void
example_status_plugin_init (ExampleStatusPlugin *plugin)
{
    plugin->priv = EXAMPLE_STATUS_PLUGIN_GET_PRIVATE (plugin);
 
    GtkIconTheme *icon_theme = gtk_icon_theme_get_default ();
    GList *list = gtk_icon_theme_list_icons (icon_theme, NULL);
    GdkPixbuf *pixbuf = gtk_icon_theme_load_icon (icon_theme, "general_email",
                    STATUS_AREA_EXAMPLE_ICON_SIZE, GTK_ICON_LOOKUP_NO_SVG, NULL);
    hd_status_plugin_item_set_status_area_icon (HD_STATUS_PLUGIN_ITEM (plugin), pixbuf);
    g_object_unref (pixbuf);
 
    GtkWidget *b = gtk_label_new ("Example message");
    gtk_widget_show_all (b);
 
    plugin->priv->label = b;
 
    gtk_container_add (GTK_CONTAINER (plugin), plugin->priv->label);
 
    gtk_widget_show_all (plugin->priv->label);
 
   gtk_widget_show (GTK_WIDGET (plugin));
}

[edit] The .desktop File

The .desktop file for the Status Menu is similar to the Home Area one but also contains the "Category" field where the priority of the widget is set (permanent, conditional or temporary) and the "Icon" field to set the icon's name. If the "Category" key is not set, it is considered as permanent.

Example 1.6. A .desktop file for the Status Menu example widget: lib-example-widget.desktop

[Desktop Entry]
Name=Example
Icon=general_email 
Comment=An example status menu widget
Category=permanent
Type=default
X-Path=lib-example-status-menu-widget.so

For Status Menu widget, .desktop files should be placed in the directory outputted by the following command:

pkg-config --variable=hildonstatusmenudesktopentrydir libhildondesktop-1

[edit] Building Widgets

To use a widget, it needs to be built as a shared library. This is done by passing the -shared flag to gcc.

gcc -shared `pkg-config --libs --cflags hildon-1 libhildondesktop-1` widget.c -o lib-widget.so

Status Menu and Home Area widgets binaries are located in the same directory, so assign distinguishable names to them, such as "lib-example-home-widget.so" and "lib-example-status-menu-widget.so" for the Home Area and Status Menu widgets, respectively. The directory where the binary files are copied to is given by the following command (which normally outputs /usr/lib/hildon-desktop):

pkg-config --variable=hildondesktoplibdir libhildondesktop-1