Hace unos días tuve la curiosidad de ver el código fuente de gnome-do, sobre todo de los docklets, y viendo que no era tan difícil decidí hacer un pequeño ejemplo, y dado que aún no existe documentación para desarrollar docklets pensé que sería una buena idea publicar la manera en que se puede desarrollar un docklet sencillo.
El Docklet que escribí es un simple sensor de temperatura para el procesador, muestra un termómetro que cambia su nivel de acuerdo a la temperatura obtenida del archivo:
[cc lang="bash"]/proc/acpi/thermal_zone/THM/temperature[/cc]
También cuando se posiciona el puntero del mouse sobre el Docklet muestra la temperatura actual del procesador en °C.
Debido a la falta de documentación tuve que descargar el branch del repositorio de gnome-do y ver el código de los docklets ya implementados para así tener una idea de como se implementaban.
Para comenzar, debemos crear una nueva solución en Monodevelop, para lo cual hacemos Archivo/Nueva Solución -> C# ->Librería, y ponemos un nombre, yo lo nombré MyDocklet. presionamos Adelante, nos aparecerá una pantalla de Funcionalidades del proyecto, a la cual solo le damos Aceptar. La estructura de la solución se ha creado, ahora tenemos que agregar los Recursos que necesitamos para nuestro Docklet, estos son: iconos(en el caso de usar los propios), y una archivo xml que describiré mas adelante.
Para este caso yo agregué 7 iconos que corresponden a cada nivel del termómetro. El archivo xml deberá llevar el nombre del proyecto MyDocklet.addin.xml y su contenido es el siguiente:
[cc lang="xml"]
id="MyDocklet"
namespace="Do"
version="1.0"
name="My Docklet"
description="Example of docklet"
author="Angel Perez"
category="Docklet"
>
[/cc]
En la sección los siguientes campos son los importantes:
- id : el cual deberá tener el nombre del proyecto
- namespace: el espacio de nombres que deseamos usar, en este caso al tratarse de un proyecto para gnome-do, pues el espacio de nombres a utilizar es Do
- Category: en gnome-do existen 2 tipos de plugins, los “normales” y los Docklets, usaremos Docklets.
En Runtime se importan los assemblies necesarios, en este caso solo importaremos el dll de nuestro docklet: MyDocklet.dll
En Dependencies se añade el id de la Interface Docky, “Interface.Linux.Docky” en mi caso usé la versión 1.0
En Extension, path lo dejamos tal cual y en el tipo de docklet ponemos el nombre de nuestro proyecto de esta manera “MyDocklet.MyDocklet”
Una vez agregados los recursos debemos agregar las referencias que utilizaremos, eso depende de cada Docklet, sus capacidades y funcionalidades, en este caso el docklet solo hace referencia a librerías básicas y son las siguientes:
- Do.Interface.Linux
- Do.Interface.Linux.Docky
- Do.Platform
- gdk-sharp
- gtk-sharp
- glib-sharp
- Mono.Cairo
- System
- System.Core
Sopas, ya tenemos todo para codificar, a continuación el código del docklet, el cual está comentado:
[cc lang="csharp"]
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Text.RegularExpressions;
using Gdk;
using Gtk;
using Cairo;
using Do.Platform;
using Do.Interface;
using Docky.Interface;
using Docky.Interface.Menus;
namespace MyDocklet{
//heredamos del clase abstracta AbstractDockletItem que nos permitirá implementar el docklet
//y que a su vez hereda de AbstractDockItem
public class MyDocklet : AbstractDockletItem{
//Ruta al archivo log de temperatura
const string LogTemperature = “/proc/acpi/thermal_zone/THM/temperature”;
int MaxTemperature; //temperatura máxima del termometro
int MinTemperature; //temperatura mínima
int CurrentTemperature; //temperatura actual del procesador
Regex number_regex; //expresión regular que se usará para detectar enteros
//Redefinimos Nombre del Docklet. Contenido en Clase abstrata
public override string Name {
get { return “My Docklet”; }
}
//Constructor, inicializamos variables y temporizador
public MyDocklet() {
MaxTemperature = 45;
MinTemperature = 30;
number_regex = new Regex (”[0-9]+”); //se inicializa la expresión regular
GetTemperature(); //se obtiene la temperatura actual del procesador
//Agregamos a un timer el método GetTemperature, para que sense
//la temperatura cada 3 segundos
GLib.Timeout.Add (3 * 1000, GetTemperature);
}
//Método que accede al log de temperatura
bool GetTemperature(){
if (!File.Exists(LogTemperature)) {//si no existe el log
SetText (”No Thermometer Found”);
CurrentTemperature = 0;
MaxTemperature = 0;
MinTemperature = 0;
//metodo perteneciente a clase abstracta que redibuja el icono
RedrawIcon ();
return true;
}
//si existe el log
try{
//lee el log de temperatura
using ( StreamReader reader = new StreamReader(LogTemperature) ){
if (!reader.EndOfStream) {
string line = reader.ReadLine ();
if ( line.StartsWith (”temperature”)){
try {//expresion regular para obtener los grados centrigrados
CurrentTemperature = Convert.ToInt32 (number_regex.Matches (line) [0].Value);
} catch { }
}
}
}
}catch { }
//Método de la clase abstracta que nos permite agregar texto al tooltip del Docklet
//este aparece cada vez que se posiciona el mouse sobre el docklet
SetText (”Temperature: ” + CurrentTemperature + “°C”);
//se redibuja el icono
RedrawIcon ();
return true;
}
//dependiendo del maximo y minimo de temperatura se calcula la escala[1-7]
//para así selecionar el icono que debera dibujarse
int GetScale(){
int diffMaxMin = MaxTemperature – MinTemperature;
int diffCurMin = CurrentTemperature – MinTemperature;
if (diffCurMin <= 0) return 1;
float step = ((float)diffMaxMin)/((float)7);
int scale = (int)(diffCurMin/step)+1;
if(scale > 7) scale = 7;
return scale;
}
//Método de la clase abstracta que obtiene el icono de nuestro docklet
//en caso de iconos personalizados es necesario reimplementarlo
//si se usan iconos definidos en el sistema solo basta implementar el metodo ge
//para Icon y ahi definir el nombre de los iconos del sistema.
protected override Surface MakeIconSurface (Cairo.Surface similar, int size) {
Surface tmp_surface = similar.CreateSimilar (similar.Content, size, size);
//Dependiendo de la escala se coloca un icono diferente para el termometro
string icon = “termo” + GetScale()+”.png@”;
using (Context cr = new Context (tmp_surface)) {
using (Gdk.Pixbuf pbuf = IconProvider.PixbufFromIconName (icon + GetType().Assembly.FullName, size)) {
CairoHelper.SetSourcePixbuf (cr, pbuf, 0, 0);
cr.Paint ();
}
}
return tmp_surface;
}
}
}
[/cc]
una vez que se ha codificado el docklet, nos vamos a Proyecto/Construir Solución, si todo va bién no debe marcar errores, ahora en la carpeta de nuestro proyecto, se creó la carpeta bin/Debug/, en esta se encuentra 2 archivos: MyDocklet.dll y MyDocklet.dll.mdb, esto es todo lo que necesitamos, ahora solo falta copiarlos al directorio en donde se encuentran los plugins de gnome-do, para esto, suponiendo que en nuestra terminal ya nos ubicamos en el directorio bin/Debug de nuestro proyecto, hacemos lo siguiente con privilegios de root:
[cc lang="bash"]cp MyDocklet.* /usr/local/lib/gnome-do/plugins/[/cc]
ahora reiniciamos gnome-do y activamos nuestro docklet y debemos verlo funcionar

Para poder desarrollar el Docklet lo importante es la herencia que se hace de la clase abstracta AbstractDockletItem, misma que hereda de AbstractDockItem, la primer en si solo contiene la definición del atributo Name y su método Get, mismos que deben reimplementarse para que contengan y devuelvan el nombre del docklet, la clase AbstractDockItem es la que contiene la mayoría de los métodos que debemos reimplementar para el Docklet. Algunos de los que reimplementé son los siguientes:
- Name: Nombre del Docklet
- MakeIconSurface : la cual reimplementé debido a que quería establecer un icono personalizado, si hubiese querido utilizar un icono de los que ya se encuentran definidos en el sistema, no es necesario implementar este método, solo basta con agregar e implementar el atributo Icon y su método Get, en el cual se definirían solo los nombres de los iconos del sistema y no sus extensiones.
un ejemplo para icono del sistema sería:
[cc lang="csharp"]
protected override string Icon {
get {
if (Muted || CurrentVolume == 0)
return “audio-volume-muted”;
if (CurrentVolume < 33)
return "audio-volume-low";
if (CurrentVolume < 66)
return "audio-volume-medium";
return "audio-volume-high";
}
}
[/cc]
Este ejemplo hace uso de los iconos del sistema usados en el control de volumen, así no es necesario implementar el método MakeIconSurface.
Otros métos utilizados fueron:
- RedrawIcon( ): utilizado para refrescar el icono del Docklet.
- SetText(string a): utilizada para agregar texto al tooltip del docklet, el cual aparece cuando el mouse se posiciona por encima del docklet.
Dejo el Link para el Proyecto en Mono, los Archivos Compilados y los fuentes svg de Los Iconos.
Como ya comenté, no existe documentación aún, y lo poco que muestro aquí lo obtuve por leectura de código del proyecto y algunas pruebas. Si desean saber mas sobre la clases abstractas aquí estan las ligas de su código fuente: AbstractDockletItem, AbstractDockItem
saludos!