Documentation/Maemo 5 Developer Guide/Application Development/Writing Desktop Widgets: Difference between revisions

From Maemo Wiki
Jump to navigationJump to search
imported>danielwilms
m 1 revision
imported>amigadave
The .desktop File: desktop file link
 
(15 intermediate revisions by 7 users 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. According to where they'll be placed there can be Status Menu widgets and 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. Since Hildon 2.2, Home Area widgets stopped being 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 11.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))
 
#define TIME_OUT_HOME_PLUGIN_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), \
                        TIME_OUT_TYPE_HOME_PLUGIN,  TimeOutHomePluginClass))
   
   
#include <libhildondesktop/hildondesktop.h>
struct _TimeOutPlugin
{
    HDHomePluginItem hitem;
};
   
   
G_BEGIN_DECLS
struct _TimeOutPluginClass
{
    HDHomePluginItemClass parent_class;
};
   
   
typedef struct _TimeOutPlugin TimeOutPlugin;
GType time_out_home_plugin_get_type(void);
typedef struct _TimeOutPluginClass TimeOutPluginClass;
 
G_END_DECLS
#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


#endif
</source>


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.
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.


'''Example 11.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>
 
#include "lib-timeout-home-widget.h"
 
HD_DEFINE_PLUGIN_MODULE (TimeOutPlugin, time_out_plugin,      HD_TYPE_HOME_PLUGIN_ITEM)
   
   
HD_DEFINE_PLUGIN_MODULE (TimeOutPlugin, time_out_plugin,      HD_TYPE_HOME_PLUGIN_ITEM)
static GtkWidget *
 
build_ui (void)
static GtkWidget *
{
build_ui (void)
    GtkVBox *contents = GTK_VBOX (gtk_vbox_new (0, FALSE));
{
    GtkLabel *label = GTK_LABEL (gtk_label_new ("Time out widget."));
    GtkVBox *contents = GTK_VBOX (gtk_vbox_new (0, FALSE));
    HildonPickerButton *action;
    GtkLabel *label = GTK_LABEL (gtk_label_new ("Time out widget."));
    action = HILDON_PICKER_BUTTON (hildon_picker_button_new  (HILDON_SIZE_FINGER_HEIGHT,
    HildonPickerButton *action;
                                        HILDON_BUTTON_ARRANGEMENT_VERTICAL));
    action = HILDON_PICKER_BUTTON (hildon_picker_button_new  (HILDON_SIZE_FINGER_HEIGHT,
    HildonTouchSelector *action_selector;
                                        HILDON_BUTTON_ARRANGEMENT_VERTICAL));
    action_selector = HILDON_TOUCH_SELECTOR (hildon_touch_selector_new_text ());
    HildonTouchSelector *action_selector;
    hildon_button_set_title (HILDON_BUTTON (action), "Action");
    action_selector = HILDON_TOUCH_SELECTOR (hildon_touch_selector_new_text ());
    hildon_touch_selector_append_text (action_selector, "Blank Screen");
    hildon_button_set_title (HILDON_BUTTON (action), "Action");
    hildon_touch_selector_append_text (action_selector, "Suspend");
    hildon_touch_selector_append_text (action_selector, "Blank Screen");
    hildon_touch_selector_append_text (action_selector, "Turn Off");
    hildon_touch_selector_append_text (action_selector, "Suspend");
    hildon_picker_button_set_selector (action, action_selector);
    hildon_touch_selector_append_text (action_selector, "Turn Off");
    hildon_picker_button_set_active (action, 0);  
    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,
    HildonTimeButton *time;
                                        HILDON_BUTTON_ARRANGEMENT_VERTICAL));
    time = HILDON_TIME_BUTTON (hildon_time_button_new (HILDON_SIZE_FINGER_HEIGHT,
    hildon_time_button_set_time (time, 22, 00);  
                                        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));
    GtkHBox *buttons = GTK_HBOX (gtk_hbox_new (0, TRUE));
    gtk_container_add (GTK_CONTAINER (buttons), GTK_WIDGET (time));
    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_box_pack_start (GTK_BOX (contents), GTK_WIDGET (label), FALSE, FALSE, 0);
    gtk_widget_show_all (GTK_WIDGET (contents));  
    gtk_box_pack_end (GTK_BOX (contents), GTK_WIDGET (buttons), FALSE, FALSE, 0);
 
    gtk_widget_show_all (GTK_WIDGET (contents));  
    return GTK_WIDGET (contents);
}
    return GTK_WIDGET (contents);
 
}
static void
time_out_plugin_init (TimeOutPlugin *desktop_plugin)
static void
{
time_out_plugin_init (TimeOutPlugin *desktop_plugin)
  GtkWidget *contents = build_ui ();
{
  gtk_container_add (GTK_CONTAINER (desktop_plugin), contents);
  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_init (TimeOutPluginClass *class) {}
static void
time_out_plugin_class_finalize (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 11.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.
 
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, place .desktop files in the directory outputed by the following command:
 
pkg-config libhildondesktop-1 --variable=hildonhomedesktopentrydir
 
==Status Menu widgets==


[Desktop Entry]
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.
Name=TimeOut  Widget
Comment=Execute an action at a given time
Type=default
X-Path=lib-timeout-home-widget.so


               
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.
For Home Area widget, .desktop files should be placed in the directory outputed by the following command:


pkg-config libhildondesktop-1 --variable=hildonhomedesktopentrydir --variable=homedesktopentrydir
Example 1.4. Header file for Example Status Menu Widget: lib-example-status-menu-widget.h


<source lang="c">
#ifndef __EXAMPLE_STATUS_PLUGIN_H__
#define __EXAMPLE_STATUS_PLUGIN_H__


==Status Menu widgets==
#include <libhildondesktop/libhildondesktop.h>
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.
G_BEGIN_DECLS


Example 11.4. Header file for Example Status Menu Widget: lib-example-status-menu-widget.h
#define TYPE_EXAMPLE_STATUS_PLUGIN            (example_status_plugin_get_type ())


#ifndef __EXAMPLE_STATUS_PLUGIN_H__
#define EXAMPLE_STATUS_PLUGIN(obj)            (G_TYPE_CHECK_INSTANCE_CAST ((obj), \
#define __EXAMPLE_STATUS_PLUGIN_H__
                                    TYPE_EXAMPLE_STATUS_PLUGIN, ExampleStatusPlugin))
   
   
#include <libhildondesktop/libhildondesktop.h>
#define EXAMPLE_STATUS_PLUGIN_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST ((klass), \
                                TYPE_EXAMPLE_STATUS_PLUGIN, ExampleStatusPluginClass))
G_BEGIN_DECLS
 
#define IS_EXAMPLE_STATUS_PLUGIN(obj)        (G_TYPE_CHECK_INSTANCE_TYPE ((obj), \
#define TYPE_EXAMPLE_STATUS_PLUGIN            (example_status_plugin_get_type ())
                                                    TYPE_EXAMPLE_STATUS_PLUGIN))
 
#define EXAMPLE_STATUS_PLUGIN(obj)            (G_TYPE_CHECK_INSTANCE_CAST ((obj), \
#define IS_EXAMPLE_STATUS_PLUGIN_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), \
                                    TYPE_EXAMPLE_STATUS_PLUGIN, ExampleStatusPlugin))
                                                    TYPE_EXAMPLE_STATUS_PLUGIN))
 
 
#define EXAMPLE_STATUS_PLUGIN_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST ((klass), \
#define EXAMPLE_STATUS_PLUGIN_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS ((obj), \
                                TYPE_EXAMPLE_STATUS_PLUGIN, ExampleStatusPluginClass))
                            TYPE_EXAMPLE_STATUS_PLUGIN, ExampleStatusPluginClass))
 
#define IS_EXAMPLE_STATUS_PLUGIN(obj)        (G_TYPE_CHECK_INSTANCE_TYPE ((obj), \
#define STATUS_AREA_EXAMPLE_ICON_SIZE 22
                                                    TYPE_EXAMPLE_STATUS_PLUGIN))
 
typedef struct _ExampleStatusPlugin        ExampleStatusPlugin;
#define IS_EXAMPLE_STATUS_PLUGIN_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), \
typedef struct _ExampleStatusPluginClass  ExampleStatusPluginClass;
                                                    TYPE_EXAMPLE_STATUS_PLUGIN))
typedef struct _ExampleStatusPluginPrivate ExampleStatusPluginPrivate;  
 
#define EXAMPLE_STATUS_PLUGIN_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS ((obj), \
struct _ExampleStatusPlugin
                            TYPE_EXAMPLE_STATUS_PLUGIN, ExampleStatusPluginClass))
{
    HDStatusMenuItem parent;
#define STATUS_AREA_EXAMPLE_ICON_SIZE 22
 
    ExampleStatusPluginPrivate *priv;
typedef struct _ExampleStatusPlugin        ExampleStatusPlugin;
};
typedef struct _ExampleStatusPluginClass  ExampleStatusPluginClass;
 
typedef struct _ExampleStatusPluginPrivate ExampleStatusPluginPrivate;  
struct _ExampleStatusPluginClass
{
struct _ExampleStatusPlugin
    HDStatusMenuItemClass parent;
{
};
    HDStatusMenuItem parent;
 
GType example_status_plugin_get_type (void);
    ExampleStatusPluginPrivate *priv;
 
};
G_END_DECLS
 
struct _ExampleStatusPluginClass
#endif
{
</source>
    HDStatusMenuItemClass parent;
         
};
'''Example 1.5. Source file for Example Status Menu  Widget: lib-example-status-menu-widget.c'''
 
GType example_status_plugin_get_type (void);
<source lang="c">
#include <stdio.h>
G_END_DECLS
#include <stdlib.h>
#include <gtk/gtk.h>
#endif
#include <hildon/hildon.h>
 
           
#include "lib-example-status-menu-widget.h"
'''Example 11.5. Source file for Example Status Menu  Widget: lib-example-status-menu-widget.c'''
 
#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);


#include <stdio.h>
  gtk_widget_show (GTK_WIDGET (plugin));
#include <stdlib.h>
}
#include <gtk/gtk.h>
</source>
#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===
The .desktop file for the Status Menu is analogous to the Home Area one but should have also 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, then it is considered as permanent.


Example 11.6. A .desktop file for the Status Menu example widget: lib-example-widget.desktop
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.


[Desktop Entry]
Example 1.6. A .desktop file for the Status Menu example widget: lib-example-widget.desktop
Name=Example
<pre>
Icon=general_email  
[Desktop Entry]
Comment=An example status menu widget
Name=Example
Category=permanent
Icon=general_email  
Type=default
Comment=An example status menu widget
X-Path=lib-example-status-menu-widget.so
Category=permanent
Type=default
X-Path=lib-example-status-menu-widget.so
</pre>
               
For Status Menu widget, .desktop files should be placed in the directory outputted by the following command:


               
pkg-config --variable=hildonstatusmenudesktopentrydir libhildondesktop-1
For Home Area widget, .desktop files should be placed in the directory outputed by the following command:


pkg-config libhildondesktop-1 --variable=homedesktopentrydir
==Building Widgets==


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.


==Building Widgets==
gcc -shared `pkg-config --libs --cflags hildon-1 libhildondesktop-1` 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 -shared flag to gcc.


gcc -shared `pkg-config hildon-1 libhildondesktop-1 --libs --cflags` 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.

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

<source lang="c">

  1. ifndef TIME_OUT_PLUGIN_H
  2. define TIME_OUT_PLUGIN_H
  1. include <glib-object.h>
  1. include <libhildondesktop/libhildondesktop.h>

G_BEGIN_DECLS

typedef struct _TimeOutPlugin TimeOutPlugin; typedef struct _TimeOutPluginClass TimeOutPluginClass;

  1. define TIME_OUT_TYPE_HOME_PLUGIN (time_out_home_plugin_get_type ())
  1. define TIME_OUT_HOME_PLUGIN(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), \
                       TIME_OUT_TYPE_HOME_PLUGIN, TimeOutHomePlugin))
  1. define TIME_OUT_HOME_PLUGIN_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), \
                       TIME_OUT_TYPE_HOME_PLUGIN,  TimeOutHomePluginClass))
  1. define TIME_OUT_IS_HOME_PLUGIN(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), \
                       TIME_OUT_TYPE_HOME_PLUGIN))

  1. define TIME_OUT_IS_HOME_PLUGIN_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), \
                       TIME_OUT_TYPE_HOME_PLUGIN))
  1. 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

  1. endif

</source>

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

<source lang="c">

  1. include <gtk/gtk.h>
  2. include <hildon/hildon.h>
  1. include <libhildondesktop/libhildondesktop.h>
  1. 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) {} </source>

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

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

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

<source lang="c">

  1. ifndef __EXAMPLE_STATUS_PLUGIN_H__
  2. define __EXAMPLE_STATUS_PLUGIN_H__
  1. include <libhildondesktop/libhildondesktop.h>

G_BEGIN_DECLS

  1. define TYPE_EXAMPLE_STATUS_PLUGIN (example_status_plugin_get_type ())
  1. define EXAMPLE_STATUS_PLUGIN(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), \
                                   TYPE_EXAMPLE_STATUS_PLUGIN, ExampleStatusPlugin))

  1. define EXAMPLE_STATUS_PLUGIN_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), \
                               TYPE_EXAMPLE_STATUS_PLUGIN, ExampleStatusPluginClass))
  1. define IS_EXAMPLE_STATUS_PLUGIN(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), \
                                                   TYPE_EXAMPLE_STATUS_PLUGIN))
  1. define IS_EXAMPLE_STATUS_PLUGIN_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), \
                                                   TYPE_EXAMPLE_STATUS_PLUGIN))
  1. define EXAMPLE_STATUS_PLUGIN_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), \
                           TYPE_EXAMPLE_STATUS_PLUGIN, ExampleStatusPluginClass))
  1. 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

  1. endif

</source>

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

<source lang="c">

  1. include <stdio.h>
  2. include <stdlib.h>
  3. include <gtk/gtk.h>
  4. include <hildon/hildon.h>
  1. include "lib-example-status-menu-widget.h"
  1. 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));

} </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

[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

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