Usando la Biblioteca libgnome

La biblioteca libgnome es la biblioteca de utilidades para aplicaciones GNOME no específica del conjunto de herramientas (GTK+). Incluye aspectos como lectura de archivos de configuración, manejo del archivo .desktop, funciones útiles especiales similares a las contenidas en GLib, obtención de la localización de los archivos estándar para GNOME, manejo de tipos MIME, manejo de meta-datos en archivos, sonido, "triggers", y otros aspectos útiles que uno querría usar en cualquier aplicación. Por ejemplo, si usted está escribiendo una aplicación en, digamos Motif, y quiere que su aplicación sea compatible con GNOME, entonces podría hacer uso de esta biblioteca para conseguirlo.

Archivos de Configuración

Las funciones gnome-config proporcionan una forma sencilla de almacenar información de configuración dentro de archivos. Para ver una lista completa de las funciones, mire en el archivo de cabecera libgnome/gnome-config.h.

Todas las funciones trabajan con un camino o ruta (N.T: path). El camino es semejante a un camino de Unix, y representa la ruta al archivo de configuración (empezando ésta desde el directorio ~/.gnome/) y la clave que estamos buscando dentro. Así, /some/config/path/file/sectionA/keyB, se refiere al archivo ~/.gnome/some/config/path/file, y dentro del archivo usando la sección sectionA y la clave keyB.

Leyendo Información de Configuración

Para leer información de los archivos de configuración se usan las funciones gnome_config_get_*. El * se cambia por el tipo de dato, el cual puede ser int, float, string, bool y vector. Las funciones int trabajan con gint, las funciones float trabajan con gdouble, las funciones string trabajan con gchar *, las funciones booltrabajan con gboolean y las vector manejan un entero con un número de elementos y un vector de cadenas que contiene dichos elementos (gint y gchar**). Las funciones gnome_config_get_*, pueden aceptar valores por defecto si usted los añade a la ruta después de un signo '='. Si necesita saber si el valor por omisión fue usado, puede añadir un _with_default al nombre de la función y pasarle un gboolean *, a través del cual la función devuelve si se empleó ese valor por defecto o si realmente se encontró otro valor válido en el archivo de configuración. A continuación se muestra un ejemplo:

gint contador;
gchar *texto;
gboolean def;
...
contador = gnome_config_get_int_with_default("/ejemplo/seccion/contador=1",
                                            &def);
if(def) g_print("Usamos el contador por defecto\n");
texto = gnome_config_get_string("/ejemplo/seccion/texto=TEXT");
...
g_free(text);

Observe que la cadena devuelta por gnome_config_get_string debería ser liberada con g_free, el vector de gnome_config_get_vector debería ser también liberado con g_free.

Escribiendo la Configuración

Para escribir la configuración en un archivo, se usan las funciones gnome_config_set_*. Su uso es muy parecido a las anteriores gnome_config_get_*. Los tipos se usan exactamente igual. Excepto con las funciones "set", se pasan los datos que se quieren almacenar después de la ruta o camino y no hay valor por omisión dentro de ella. Si el directorio en la ruta no existe, será creado cuando las funciones escriban en el disco. Después de configurar todos sus datos, necesitará llamar a gnome_config_sync para escribir sus datos a un archivo. La biblioteca no escribirá los datos a un archivo inmediatamente por razones de eficiencia. A continuación se muestra un ejemplo:

char *text;
int counter;
...
/*después de haber establecido un texto y un contador a algún valor,
podemos escribirlos a nuestro lugar de configuración*/
gnome_config_set_int("/example/section/counter",counter);
gnome_config_set_string("/example/section/text",text);
gnome_config_sync();

Funciones Privadas

Si quiere almacenar información comprometedora, que otros usuarios no deberían leer, use las funciones gnome_config_private_*: éstas se comportan de igual modo que las anteriores, con la excepción de que estas escriben en un directorio privado llamado ~/.gnome_private sobre el que se fuerzan los permisos 0700. Esto no es extremadamente seguro, pero debido a las descerebradas restricciones de exportación de los EEUU, no se puede usar encriptación. La función gnome_config_sync (y algunas otras) no tiene una equivalencia privada, ya que funciona para ambos tipos de funciones.

Usando Gnome-Config para Archivos Arbitrarios

Si desea usar gnome-config para lectura y escritura de archivos arbitrarios en el sistema de archivos (estos archivos estarán en formato gnome-config), usted puede añadir '=' al principio de la ruta y otro '=' al final del nombre del archivo. A continuación se muestra un ejemplo:

char buf[256];
...
/* escribe algunos datos en un archivo temporal */
g_snprintf(buf,256,"=%s=/seccion/clave",tmpnam(tmpnam));
gnome_config_set_int(buf,999);
gnome_config_sync();

Observe que realmente no tiene sentido usar las versiones privadas cuando se usa una ruta absoluta arbitraria, ya que no habrá ninguna diferencia entre privadas y normales.

Prefijos Automáticos

Algunas veces, especialmente si tiene una ruta larga, será útil tener una cadena dada que se pase de forma automática como prefijo a la ruta. Esto es para lo que están gnome_config_push_prefix y gnome_config_pop_prefix. Se pasa la cadena que ha de servir como prefijo a gnome_config_push_prefix y se llama a gnome_config_pop_prefix cuando haya acabado de usarlo. Observe que estas funciones son comunes a las funciones de configuración privadas y normales. Ejemplo:

gnome_config_push_prefix("/archivo/seccion/");
gnome_config_set_int("clave1",1);
gnome_config_set_int("clave2",2);
gnome_config_set_int("clave3",-88);
gnome_config_pop_prefix();

Miscelánea Gnome-Config

Si necesita borrar su archivo de configuración, debe usar gnome_config_clean_file. Esta función planificará qué archivo sera borrado en el próximo gnome_config_sync. Usted puede hacer un gnome_config_clean_file y después usar el archivo y hacer un gnome_config_sync, y esto tendrá el comportamiento esperado.

Si ha escrito o leído de un archivo y quiere sacarlo de memoria (los cambios no se guardarán en disco hasta hacer 'sync') use gnome_config_drop_file. Esto se puede usar para deshacer los cambios hechos a este archivo, o simplemente ahorrar recursos, ya que de otra forma gnome-config conservará una copia de los datos en memoria para un acceso más rápido.

Archivos .desktop

Los archivos .desktop son los que contienen información sobre programas. Estos archivos estan en formato gnome-config y son leídos internamente usando gnome-config. Su aplicación necesitará uno de estos archivos si quiere que sea accesible en el menú de GNOME.

Puede usar las funciones gnome_desktop_entry_* para manipular esos archivos. Estas funciones trabajan con una estructura llamada GnomeDesktopEntry y debería de mirar al archivo de cabecera libgnome/gnome-dentry.h para ver el formato de esta estructura.

Las funciones básicas que se usan para manipular estos archivos son gnome_desktop_entry_load que devuelve una nueva estructura GnomeDesktopEntry asignada, gnome_desktop_entry_launch que toma la estructura GnomeDesktopEntry como un argumento y lanza el programa que esta describe y gnome_desktop_entry_free que libera la memoria asignada dentro de la estructura.

Un ejemplo de archivo .desktop para su aplicación podría ser algo así:

[Desktop Entry]
Name=Clock
Name[cz]=Hodiny
Comment=Digital Clock
Comment[cz]=Digitalni Hodiny
Exec=digital-clock
Icon=clock.png
Terminal=0
Type=Application

Habrá observado que hay traducciones al checo para los campos Name y Comment. Para otros programas GNOME observe su archivo .desktop, está normalmente en algún lugar bajo <prefijo>/share/apps/, el cual contiene la jerarquía del sistema de menús. Para que el sistema encuentre su icono debería estar situado dentro del directorio <prefijo>/share/pixmaps. Observe que 'prefijo' se refiere a la ruta donde GNOME fue instalado.

Utilidades y Archivos

Archivos

Hay una forma estándar de encontrar archivos que pertenezcan a la instalación de GNOME, usted no debería realmente usar su propio código para encontrarlos ya que dispone de funciones para obtener los nombres de los archivos para los iconos, sonido u otros datos. Estas funciones son sólo para encontrar archivos que fueron instalados con las bibliotecas GNOME. No hay en este momento funciones para tratar con los datos instalados por su aplicación. Dichas funciones son:

Tabla 1. Funciones para encontrar archivos

PrototipoDescripción
char *gnome_libdir_file (const char *nombre_arch)Obtiene la ruta completa de un archivo en el directorio de la biblioteca o NULL si el archivo no existe
char *gnome_unconditional_libdir_file (const char *nombre_arch)Obtiene la ruta completa de un archivo en el directorio de la biblioteca
char *gnome_datadir_file (const char *nombre_arch)Obtiene la ruta completa de un archivo en el directorio de datos o NULL si el archivo no existe
char *gnome_unconditional_datadir_file (const char *nombre_arch)Obtiene la ruta completa de un archivo en el directorio de datos
char *gnome_sound_file (const char *nombre_arch)Obtiene la ruta completa de un archivo en el directorio de sonido o NULL si el archivo no existe
char *gnome_unconditional_sound_file (const char *nombre_arch)Obtiene la ruta completa de un archivo en el directorio de sonido
char *gnome_pixmap_file (const char *nombre_arch)Obtiene la ruta completa de un archivo en el directorio de 'pixmaps' o NULL si el archivo no existe
char *gnome_unconditional_pixmap_file (const char *nombre_arch)Obtiene la ruta completa de un archivo en el directorio 'pixmaps'
char *gnome_config_file (const char *nombre_arch)Obtiene la ruta completa de un archivo en el directorio de configuración o NULL si el archivo no existe
char *gnome_unconditional_config_file (const char *filename)Obtiene el path completo de un archivo en el directorio de configuración

Estas funciones devuelven una cadena cuya memoria se asignó con g_malloc así que debería usar g_free sobre la cadena cuando termine. Las funciones gnome_unconditional_* no comprobarán si el archivo actualmente existe y siempre devolverán un nombre de archivo. Las funciones normales efectuarán comprobaciones y devolverán NULL si el archivo no existe. Así que no debería usar estas funciones cuando esté guardando. Este ejemplo obtendrá un pixmap del directorio estándar de pixmaps, por ejemplo necesitamos obtener el icono "gnome-help.png":

gchar *nombre;
...
nombre = gnome_pixmap_file("gnome-help.png");
if(!nombre) {
        g_warning("gnome-help.png ¡no existe!");
} else {
        /*aquí usamos el archivo*/
        ...
        g_free(nombre);
}

También son de interés las funciones (actualmente macros) gnome_util_home_file y gnome_util_user_home. gnome_util_home_file toma un argumento (cadena) y devuelve una nueva cadena precedida por el directorio de inicio del usuario ($HOME) seguido de '.gnome'. Así por ejemplo si le pasa, digamos archivillo, devolvería /home/jirka/.gnome/archivillo. Parecida es gnome_util_user_home, toma un argumento y devuelve el archivo con solo el directorio de inicio añadido. Así que si se le pasa .oculto, devolvería /home/jirka/.oculto.

Utilidades

Hay también numerosas funciones de GLib para hacer su vida mas fácil manejando archivos: g_file_exists, la cual toma un nombre de archivo y devuelve TRUE si existe o FALSE si no existe; o g_concat_dir_and_file, que toma un nombre de archivo y un nombre de directorio, teniendo en cuenta el '/' (esto es útil cuando se trabaja con cadenas donde no se quiere chequear el '/', sólo se quiere añadir un directorio a algún archivo u otro directorio). Observe que tendrá que usar g_free sobre la cadena que devuelven. Para más funciones de utilidad, mire dentro de libgnome/gnome-util.h, está muy bien comentada.

Tipos MIME

Algunas veces es útil saber el tipo MIME de un archivo. Se puede hacer esto usando la función gnome_mime_type_or_default, que toma dos argumentos: el nombre del archivo y una cadena con el tipo MIME por defecto que será devuelta si no se puede averiguar el tipo MIME del archivo. Se intenta descubrir el tipo de un archivo mirando en el nombre del mismo. La cadena que devuelve la función es un puntero a una base de datos interna y no debería liberarla ya que podría desembocar más tarde en una violación de segmento. También puede usar gnome_mime_type, que devolverá NULL si no puede averiguar el tipo MIME.

Es también posible trabajar con listas URI, como aquellas usadas en las acciones de "arrastrar y soltar". Normalmente, de una lista URI usted querrá extraer los nombres de los archivos que recibió. Para eso use la función gnome_uri_list_extract_filenames, la cual toma la lista URI como un argumento de tipo cadena, y devuelve una GList* de cadenas asignadas dinámicamente. Una vez haya terminado con los archivos, deberá liberar las cadenas y la lista. Puede usar la función gnome_uri_list_free_strings que hace esto para usted.

En el siguiente ejemplo se implementa un manejador de "arrastrar y soltar" que acepta archivos y devuelve la información sobre el tipo MIME de los mismos, después usted podría escribir código que hiciera operaciones basadas en el tipo MIME de los archivos.

/* este es el manejador para la señal 'dragdatareceive', asumiendo que
   nuestro widget solo acepta el tipo MIME de datos "text/uri-list". 
   Para una explicación más detallada de como implementar las operaciones
   de arrastrar y soltar, consulte la documentación de GTK+ */

static void
dnd_drop_internal (GtkWidget        *widget,
                   GdkDragContext   *context,
                   gint              x,
                   gint              y,
                   GtkSelectionData *selection_data,
                   guint             info,
                   guint             time)
{
        GList *files, *li;

        /*aquí extraemos los nombres de los archivos desde la lista
          URI que recibimos */ 
         files = gnome_uri_list_extract_filenames(selection_data->data);

        /*Pasamos por un bucle a los archivos y obtenemos sus tipos MIME*/
        for(li = files; li!=NULL ; li = g_list_next(li)) {
                  char *mimetype;
                  char *filename = li->data;

    /*suponemos el tipo MIME del archivo*/
                  mimetype = gnome_mime_type(filename);

                  /*si no lo podemos averiguar, simplemente saltamos
                   al siguiente nombre de archivo*/
                  if(!mimetype) continue;

                  /*A continuación va el código que realmente puede
                   hacer algo basado en los tipos MIME del archivo que 
                   recibimos*/
                  ...
        }
        /*Libera la lista de archivos que obtuvimos*/
        gnome_uri_list_free_strings (files);
}

Obsérvese lo fácil que es descubrir qué archivos obtuvo y de qué tipo eran. Ahora sólo tiene que añadir algún código en vez de los tres puntos ('...') para hacer algo útil con esa información.

Meta-Datos

Algunas veces es útil almacenar alguna información junto con el nombre de archivo, esto se puede hacer fácilmente con gnome-metadata: un conjunto de funciones para gestionar estos datos. Ya que Unix no soporta de forma nativa meta-datos, usted debe ayudarle. Por ejemplo si su aplicación copia, renombra o borra archivos, use las siguientes funciones para mantener la consistencia en los meta-datos:

Tabla 2. Funciones de Meta-Datos

PrototipoDescripción
int gnome_metadata_rename (const char *desde, const char *hacia)Notifica a la base de datos de los meta-datos que un archivo ha sido renombrado
int gnome_metadata_copy (const char *desde, const char *hacia)Notifica a la base de datos de los meta-datos que un archivo ha sido copiado
int gnome_metadata_delete (const char *archivo)Notifica a la base de datos de los metadatos que un archivo ha sido borrado
int gnome_metadata_set (const char *archivo, const char *nombre, int tam, const char *datos)Establece los datos con la clave 'nombre', asociados con el archivo 'archivo'. El dato que se incluye es el apuntado por 'datos' y su tamaño esta representado en bytes por 'tam'. En caso de éxito se devuelve GNOME_METADATA_OK.
int gnome_metadata_get (const char *archivo, const char *nombre, int *tam, char **buffer)Obtiene datos con la clave 'nombre', asociados con el archivo 'archivo'. Los datos son almacenados en 'buffer' y en 'tam' el tamaño de dicho buffer. En caso de éxito se devuelve GNOME_METADATA_OK.
char **gnome_metadata_list (const char *archivo)Obtiene una lista de claves para las cuales hay datos asociados en 'archivo'. La lista será asignada dinámicamente y será terminada con una cadena NULL. Debe liberarla con g_strfreev

Tabla 3. Valores de Retorno de los Meta-Datos

NombreDescripción
GNOME_METADATA_OKNo hay error (Actualmente 0)
GNOME_METADATA_IO_ERRORError de Entrada/Salida u otro error de comunicaciones o almacenamiento de bajo nivel.
GNOME_METADATA_NOT_FOUNDInformación no encontrada.

Estas funciones actualmente no hacen operaciones sobre los archivos, sólo cambian los meta-datos de forma consistente. Así que si su aplicación hace alguna de esas operaciones, debe notificar a la base de datos de los meta-datos los cambios. No debe confiar en que los datos van a ser almacenados. Sólo los datos no críticos deberían ser almacenados en los meta-datos, ya que si su aplicación no notifica a la base de datos los cambios con las funciones mencionadas anteriormente, se perderán los datos que haya asociado al archivo. Esas funciones devolverán 0 o GNOME_METADATA_OK si no hubo error, o un código de error en caso contrario (descritos anteriormente).

Si quiere usar los meta-datos para asociar información a los archivos, usted debe usar las funciones gnome_metadata_set, gnome_metadata_remove y gnome_metadata_get. De nuevo estas funciones devuelven un entero, el cual es un GNOME_METADATA_OK en caso de que no hubiera error, o uno de los códigos de error que se usaban en las funciones anteriores en caso contrario.

Las funciones operan con una clave que es una cadena para la cual almacenan una porción de datos. Los datos son representados por un entero para el tamaño y un puntero a una cadena. gnome_metadata_set toma como primer argumento el nombre del archivo, el nombre o la clave del dato como segundo argumento, el tamaño como el tercero y un puntero al dato actual como cuarto argumento. Esta función sólo asocia el dato para cada archivo y clave. gnome_metadata_remove borrara un elemento particular sobre un archivo, así que toma un archivo y después el nombre de la clave como segundo argumento. gnome_metadata_get toma el nombre del archivo como primer argumento y el nombre de la clave como segundo, después devuelve el tamaño del dato mediante un puntero a entero que se pasa con el tercer argumento y el actual dato a través de un puntero a puntero que se pasa como cuarto argumento. El dato devuelto es asignado dinámicamente y debería ser liberado después de su uso. A continuación se muestra un pequeño ejemplo (en la vida real debería comprobar también el valor devuelto por la función para los errores).

int tam;
char *data;
...
/*Establece algunos datos ficticios asociados a un archivo*/
gnome_metadata_set("/algun/nombre/archivo","bogus",5,"BLAH");
...
/*Recupera de nuevo los datos*/
gnome_metadata_get("/algun/nombre/archivo","bogus",&tam,&data);