En esta mini guía intentaré explicar como funciona el programa. Leer los comentarios en el código fuente es muy útil como complemento de este documento incompleto.

El archivo de configuración de openbox (rc.xml/lxde.xml)

Antes que cualquier otra cosa, echemos un vistazo al archivo de configuración de openbox (*~/.config/openbox/rc.xml*)

<?xml version="1.0" encoding="UTF-8"?>
<openbox_config>
 <resistance>
   (...)
 </resistance>
 <focus>
   (...)
 </focus>
 <placement>
   (...)
 </placement>
 <theme>
   (...)
 </theme>
 <desktops>
   (...)
 </desktops>
 <resize>
   (...)
 </resize>
 <margins>
   (...)
 </margins>
 <dock>
   (...)
 </dock>
 <keyboard>
   (...)
 </keyboard>
 <mouse>
   (...)
 </mouse>
 <menu>
   (...)
 </menu>
 <applications>
   (...)
 </applications>
</openbox_config>

La sección que me interesa es <keyboard> , que está dentro de <openbox_config> .

Dentro del elemento <keyboard> hay varios elementos <keybind> . Algunos ejemplos:

<keyboard>

 <keybind key="C-A-Left">
   <action name="DesktopLeft"><dialog>no</dialog><wrap>no</wrap></action>
 </keybind>

 <keybind key="W-F1">
   <action name="Desktop"><desktop>1</desktop></action>
 </keybind>

 <keybind key="W-d">
   <action name="ToggleShowDesktop"/>
 </keybind>

 <keybind key="A-Escape">
   <action name="Lower"/>
   <action name="FocusToBottom"/>
   <action name="Unfocus"/>
 </keybind>

 <keybind key="W-e">
   <action name="Execute">
     <startupnotify>
       <enabled>true</enabled>
       <name>Konqueror</name>
     </startupnotify>
     <command>kfmclient openProfile filemanagement</command>
   </action>
 </keybind>


   <keybind key="C-A-Tab">
     <action name="NextWindow">
       <panels>true</panels>
       <desktop>true</desktop>
       <dialog>true</dialog>
       <bar>true</bar>
       <raise>false</raise>
       <allDesktops>false</allDesktops>
       <linear>false</linear>
       <finalactions>
         <action name="Focus" />
         <action name="Raise" />
         <action name="Unshade" />
       </finalactions>
     </action>
   </keybind>

</keyboard>

KeyBinds

Un elemento <keybind> representa una combinación de teclas que sirve para llamar a al menos una acción. Cada elemento <keybind> tiene la propiedad key . Esta propiedad es la combinación de teclas que activa el KeyBind.

Los KeyBind pueden tener uno o varios elementos <action> o <keybind> dentro.

Un <keybind> dentro de otro <keybind> es llamado keychain ("cadena de teclas").

Actions

Un elemento <action> representa una acción que el gestor de ventana ejecutará. Por ejemplo cerrar una ventana, cambiar el escritorio, o ejecutar un comando. Cada <action> tiene una propiedad name , que especifica el tipo de acción. Algunas Action tienen parametros, por ejemplo
   <action name="DesktopLeft"><dialog>no</dialog><wrap>no</wrap></action>
Esta Action tiene 2 parámetros ( <dialog> y <wrap> ), y es del tipo "DesktopLeft"

Algunas Action también tienen un elemento <finalactions> . Dentro de este elemento se guarda una lista de Actions que serán ejecutadas después de ejecutar la Action principal.

Parámetros

Hay cinco tipos de parametros:

Booleano (Boolean)

activado/desactivado, sí/no, verdadero/falso (on/off, yes/no, true/false)
<wrap>no</wrap>

Numerico (Number)

Un número entero (postivo o negativo)
<desktop>1</desktop>

Cadena de texto (String)

<command>kfmclient openProfile filemanagement</command>

Notificación de inicio (Startup notify)

(Usado sólo para la Action de tipo Execute ). Este parámetro es un poco más complicado, porque tiene cuatro "/subparámetros/":
       <startupnotify>
         <enabled>true</enabled>
         <wmclass>window class</wmclass>
         <name>start network services</name>
         <icon>/usr/share/icons/Crux/24x24/places/network.png</icon>
       </startupnotify>

Eje (Edge)

(Usado sólo para la Action de tipo Resize ). Indica una dirección. Puede tener uno de los siguientes valores.

Lista de acciones finales (Final actions list)

       <finalactions>
         <action name="Focus" />
         <action name="Raise" />
         <action name="Unshade" />
       </finalactions>

Bueno, ahora que terminamos de analizar la estructura del archivo de configuración de openbox, empezaremos a analizar el diseño del programa.

La clase Container (Container.cpp)

El archivo de configuración es un XML en forma de árbol. Por lo tanto, lo primero que escribí fue una clase para gestionar datos como si se tratara de un arbol. Un elemento de la clase Container puede contener cualquier tipo de datos, incluyendo otros Container s. Por ejemplo, un Container que represente un <keybind> puede contener varios elementos <action> . Esos elementos <action> a su vez, pueden contener parámetros.

La clase Container está definida en el archivo "Container.cpp". Esta clase tiene métodos para insertar elementos, removerlos, especificar un nombre para el Container, y especificar un tipo de dato para cada elemento contenido. Veamos un poco de código de ejemplo:

Container *keybind;
Container *action;
Parameter *dialog;

dialog = new Parameter("dialog", FALSE); //Crear un parámetro <dialog>false</dialog>

action = new Container(); //Crear un Container que represente una Action
action->setName( (void*) "DesktopLeft" ); //Definir el tipo de Action
action->insertElement(TIPO_PARAMETRO, (void*) dialog); //Insertar el parámetro dentro de la Action

keybind = new Container(); //Crear un KeyBind
keybind->setName( (void*) "C-A-Left" ); //especificar la propiedad key="C-A-Left" (El método setName() es útil para esto)
keybind->insertElement(TIPO_ACTION, (void*) action ); //Insertar la acción dentro del keybind

NOTAS:

Núcleo de keybinder (keybinder_core.cpp/.h)

Todas las clases y métodos que sirven para contener, crear, borrar, y modificar elementos (como KeyBinds, Actions, etc) son definidas en el archivo keybinder_core.cpp, y su header, keybinder_core.h. En estos archivos no hay código relacionado con la interfaz gráfica.

Adapted Containers

Adapted Containers son clases derivadas de la clase Container.

Todos los AdaptedContainers disponen del método writeXML() . Este método escribe la configuración en formato XML en un archivo.

Todos los AdaptedContainers (excepto Keyboard) se desasocian de su elemento padre cuando son destruidos.

Las clases derivadas de AdaptedContainer son:

Clase Keyboard

Los objetos de esta clase representan un elemento <keyboard>

Para crear un objeto de esta clase, se necesita pasar como argumento al constructor una ruta al archivo de configuración. Por ejemplo:

Keyboard *k = new Keyboard((char*)"/home/user/.config/openbox/rc.xml");
El Keyboard leerá el archivo de configuración y creará automáticamente todos los objetos KeyBind hijos.

Clase KeyBind

Los objetos de esta clase representa un elemento <keybind>

Si el objeto fue creado automáticamente por un Keyboard, creará automáticamente todos sus Action y keychains hijos.

También puede ser creado especificando su tipo:

KeyBind *keybind = new KeyBind("C-F3", parent); //Ejemplo

Clase Action

Los objetos de esta clase representan un elemento <action>

Si fue creado automáticamente por un KeyBind, creará automáticamente sus parámetros y su FinalActionsList.

Además, puede crearse una instancia especificando su tipo y padre:

Action *action = new Action("Close", parent ); //Example

Clase FinalActionsList

Un objeto de esta clase representa un elemento <finalactions>

Si el objeto fue creado automáticamente por un Action, creará automáticamente todos sus Action hijos.

También, es posible crear uno vacío:

action->finalActionsList = new FinalActionsList();

Clase Parameter

Los parámetros son el nivel más bajo en el árbol XML. Representan una opción de configuración para una Action. Hay varios constructores para crear una instancia de esta clase:

Parameter(char *name_, char *value_, Container *parent_); //Parámetro de texto
Parameter(char *name_, int value_, Container *parent_); //Parámetro numérico
Parameter(char *name_, EdgeType value_, Container *parent_); //Parámetro eje
Parameter(char *name_, Boolean value_, Container *parent_); //Parámetro booleano
Parameter(xmlDocPtr doc, xmlNodePtr node, Container *parent_); //Este constructor es llamado al crear una Action automáticamente

Como los AdaptedContainer, los Parameter disponen del método writeXML(), y al ser eliminados, se remueven a si mismos de su padre en el árbol XML.

Clase StartupNotify

StartupNotify es una clase usada para representar una tipo especial de Parameter. (Ver explicación en "El archivo de configuración de openbox")

Interfaz gráfica de keybinder (keybinder_GUI.cpp/.h)

El código relacionado con la interfaz gráfica del programa está escrito en los archivos keybinder_GUI.cpp y keybinder_GUI.h . Las clases usadas para crear la interfaz gráficas tienen el prefijo GUI_ en el nombre.

Drawings

Drawings son clases usadas para "dibujar" un AdaptedContainer. Hay tres clases Drawing:

Nota: Los Parameters y FinalActionsList no disponen de su respectiva clase Drawing porque no son mostrados en la ventana principal del programa. Sin embargo, pueden ser manejados desde una ventana Editor .

GUI_KeyboardDrawing

Esta es una clase usada para dibujar un Keyboard. Tiene una ventana con una barra de desplazamientos con GUI_KeyBindDrawings dentro, y los botones "Añadir", "Aplicar" y "Limpiar" para gestionar los KeyBind. El constructor de la clase es:
GUI_KeyboardDrawing::GUI_KeyboardDrawing(Keyboard *keyboard_, GtkWidget *embedIn);

Cuando se crea un GUI_KeyboardDrawing, automáticamente se crean sus GUI_KeyBindDrawings hijos, y se guardan en el Container subKeyBindDrawings.

GUI_KeyBindDrawing

Esta clase es usada para dibujar un KeyBind. Tiene una cabecera (botones que representan la combinación de teclas), y un GtkExpander, donde serán empaquetados sus GUI_ActionDrawings o GUI_KeyBindDrawings hijos.

Cuando un objeto de clase GUI_KeyBindDrawing es creado, este crea automáticamente todos sus objetos GUI_KeyBindDrawings (keychains) y GUI_ActionDrawings hijos, y los guarda en los Container subKeyBindDrawings y subActionDrawings.

Cuando un GUI_KeyBindDrawing es destruido, destruye también a sus Drawings hijos, su KeyBind y su Editor, y se remueve a si mismo de su Drawing padre (GUI_KeyboardDrawing, o GUI_KeyBindDrawing, si es una keychain)

GUI_ActionDrawing

Los objetos de esta clase son usados para dibujar una Action. Tiene un botón "Configurar" y una etiqueta que muestra que tipo de acción es.

Cuando un GUI_ActionDrawing es destruido, destruye también a sus Drawings hijos, su Action y su Editor, y se remueve a si mismo de su Drawing padre (GUI_KeyBindDrawing, o GUI_ActionEditor si es una FinalAction )

Editores

Los Editores son clases que sirven para editar un KeyBind (la combinación de teclas) o una Action (Sus parámetros y lista de acciones finales). Cuando la ventana de un editor es cerrada, el KeyBind o Action es actualizado. Sus constructores necesitan un Drawing como argumento.

Hay dos clases Editor:

GUI_KeyBindEditor

La ventana de un GUI_KeyBindEditor muestra botones para activar o desactivar modificadores de teclas (ctrl, alt, shift, win), y un combobox para seleccionar una tecla. Debería ser reescrito para soportar entrada directa desde el teclado.

GUI_ActionEditor

La ventana de un GUI_ActionEditor muestra los widgets necesarios para editar los parámetros de la acción. Además, muestra una lista editable de FinalActions.

Menus

KeyBindMenu

ActionMenu

ActionSelectorMenu

Modelos de Actions (keybinder_actionModel.h)

En keybinder_actionModel.h se define un array que sirve como base de datos para almacenar los tipos de Actions permitidos, así como sus descripciones, sus parámetros (con sus respectivos valores predeterminados y descripciones), y lista de acciones finales.

Para entender el formato del array, veamos la siguiente linea de ejemplo, extraída del archivo:

{"SendToDesktop", "Send the window to another desktop", "N desktop 1| B follow T", "desktop: Desktop number| follow: Change to desktop", NULL},

Un caracter '|' seguido por un espacio en blanco, es un separador.

Se usa NULL para dejar un campo sin definir. (Como en el ejemplo)

Definiciones:

Signal Handlers (signal_handlers.cpp/.h)

En el archivo signal_handlers.cpp se definen las funciones necesarias para gestionar los eventos GTK.