13
abr 10

Empacando widgets en tablas

Otra forma de posicionar widgets es usando tablas, estas crean una cuadricula en la que se irán colocando.

Para crear una tabla se usa la función:

GtkWidget *gtk_table_new ( guint rows, guint columns, gboolean homogeneous );

el primer argumento es el número de filas, el segundo el número de columnas y el tercero tiene que ver con el tamaño del espacio; si es TRUE, entonces todos los espacios son del mismo tamaño (el del widget mas grande en la tabla), si es FALSE entonces depende del widget mas alto en la fila y el mas ancho en la columna.

El número de filas y columnas se distribuye de la siguiente forma:

 0          1          2
0+----------+----------+
 |          |          |
1+----------+----------+
 |          |          |
2+----------+----------+

Para agrega widgets en este plano cartesiano:

void gtk_table_attach ( GtkTable *table, GtkWidget *child, guint left_attach, guint right_attach, guint top_attach, guint bottom_attach, GtkAttachOptions xoptions, GtkAttachOptions yoptions, guint xpadding, guint ypadding );

El argumento table es la tabla, child es el widget que añadir a la tabla, left_attach es en que punto del plano comienza y right_attach en que punto termina, horizontalmente, top_attach donde comienza y bottom_attach donde termina, verticalmente.

Por ejemplo para poner un widget en el espacio de abajo y a la izquierda, left_attach = 0, right_attach = 1, top_attach = 1 y bottom_attach = 2.

Los argumentos yoptions y xoptions pueden ser:

GTK_FIL : si la caja en la tabla es mas grande que el widget, el mismo se expande para ocupar el espacio disponible.
GTK_SHRINK : los widgets se ajustan al tamaño de la tabla; cuando la tabla no tiene suficiente espacio los widgets se salen da la ventana.
GTK_EXPAND : la tabla se expandirá para usar todo el espacio de la ventana.

Los argumentos de padding como en las cajas crean espacio alrededor del widget.

La versión corta de la función gtk_table_attach es:

void gtk_table_attach_defaults ( GtkTable *table, GtkWidget *child, guint left_attach, guint right_attach, guint top_attach, guint bottom_attach );

esta función tiene como valores por default GTK_FILL | GTK_EXPAND y un padding de 0.

También existe la función gtk_table_set_row_spacing y gtk_table_set_col_spacing, para determinar el espacio entre filas y columnas:

void gtk_table_set_row_spacing ( GtkTable *table,  guint row, guint spacing );
void gtk_table_set_col_spacing ( GtkTable *table,  guint row, guint spacing );

Para hacer lo mismo pero de forma general para todas las filas o columnas:

void gtk_table_set_row_spacings ( GtkTable *table, guint spacing );
void gtk_table_set_col_spacings ( GtkTable *table, guint spacing );

08
abr 10

diff & patch

diff sirve para ver las diferencias entre dos archivos de texto, por ejemplo un programa como este:

#include 

int main ( int argc, char **argv )
{
	printf ( "Hello World!" );
	return 0;
}

antes de editar el archivo file.c se crea un respaldo con el comando:

cp file.c file.c.orig

se hacen las ediciones del archivo, por ejemplo añadir una función:

#include 

void bye ()
{
	printf ( "Bye!!!" );
}

int main ( int argc, char **argv )
{
	printf ( "Hello World!" );
	bye ();
	return 0;
}

Al usar diff de la siguiente forma:

diff -u file.c.orig file.c

se muestra en pantalla la siguiente salida:

--- file.c.orig	2010-04-06 09:50:48.782103382 -0500
+++ file.c	2010-04-06 09:51:28.575199406 -0500
@@ -1,8 +1,14 @@
 #include 

+void bye ()
+{
+	printf ( "Bye!!!" );
+}
+
 int main ( int argc, char **argv )
 {
 	printf ( "Hello World!" );
+	bye ();
 	return 0;
 }

esto es un parche, que se puede guardar redirigiendo la salida del comando (por ejemplo al archivo bye-function.patch:

diff -u file.c.orig file.c > bye-function.patch

para aplicar el parche a un archivo file.c que no tenga los cambios se usa el comando:

patch -p0 < bye-function.patch

diff y patch tienen muchas opciones... hay que leer el manual.

Vídeo de explicación: diff & patch


08
abr 10

x11-drivers/xf86-input-evdev ebuild

Este es un ebuild que aplica un ajuste en el código que encontré en ubuntuforums.com y lo hice un parche. Es para evitar que las teclas multimedia se queden trabadas haciendo inútil la sesión.

ebuild: xf86-input-evdev-2.4.0.ebuild
parche: dell-laptop-volume-keys.patch

obviamente esto es para gentoo… :P


07
abr 10

GTK: Empacando Widgets… en Cajas

Si se quiere poner varios widgets en algún contenedor, como una ventana, gran parte de esto se logra usando cajas, para crearlas se usan las funciones gtk_hbox_new y gtk_vbox_new, que crean cajas horizontales y verticales, respectivamente. Estas funciones son de la forma:

GtkWidget *gtk_hbox_new ( gboolean homogeneous, gint spacing );
GtkWidget *gtk_vbox_new ( gboolean homogeneous, gint spacing );

donde el primer argumento determina si los widgets empacados tienen el mismo tamaño o no y el argumento spacingdetermina el espacio entre los widgets.

Para agregar widgets a estos contenedores se usan las funciones gtk_box_pack_start y gtk_box_pack_end. Para cajas horizontales gtk_box_pack_start agrega widgets de izquierda a derecha y gtk_box_pack_end de derecha a izquierda, para cajas verticales gtk_box_pack_start agrega widgets de arriba a abajo y gtk_box_pack_end de abajo a arriba.

void gtk_box_pack_start ( GtkBox *box, GtkWidget *child, gboolean expand, gboolean fill, guint padding );

el primer argumento es la caja, seguido de el widget que hay que empacar, el tercer argumento indica si la caja se expandira cuando el contenedor en el que esta es expandido (por ejemplo al maximizar una ventana), el argumento fill define si el espacio extra al redimensionar el widget contenedor es agregado a los widgets empacados en la caja o como padding.

La diferencia entre spacing y padding es que el padding es espacio que se agrega a ambos lados del widget y el spacing es espacio entre los widgets.

Acá un código de ejemplo: testingboxes


06
abr 10

libxml: análisis de archivos XML en C

Púes eso, una librería para el manejo de archivos XML…

Para compilar (con gcc):

gcc -c file.c `xml2-config --cflags`

y para enlazar:

gcc -o file `xml2-config --libs` file.o

libxml declara algunos tipos de datos:

xmlChar: un remplazo del tipo char, es un byte en una cadena codificada en UTF-8. Toda la información de texto que se use debe ser convertida a UTF-8 para usarse con las funciones de libxml.

xmlDoc: la estructura que contiene el árbol creado cuando se analiza un documento xml. xmlDocPtr es el puntero a la estructura.

xmlNode: una estructura que contiene un nodo del docuento. xmlNodePtr es el puntero ala estructura.

Un ejemplo (incluye el archivo XML para probar)…

ejemplo.tar

La función main del programa recibe un argumento desde línea de comandos; el nombre del archivo que va a analizar, y lo pasa como argumento a la función parseDoc.

int main( int argc, char **argv )
{
	char *docname;

	if ( argc <= 1 )
	{
		printf ( "Usage: %s docname\n", argv [0] );
		return ( 0 );
	}

	docname = argv [1];
	parseDoc ( docname );

	return ( 1 );
}

parseDoc esta definida como:

static void parseDoc ( char *docname )

comienza con la declaración de dos variables: doc, de tipo xmlDocPtr, para el documento y cur, de tipo xmlNodePtr, para ir moviéndose a través de los nodos del documento.

xmlDocPtr doc;
xmlNodePtr cur;

Se carga el documento con la función xmlParseFile, que requiere el nombre completo del archivo que va a analizar.

doc = xmlParseFile ( docname );

Se comprueba que no hubo errores en el análisis.

if ( doc == NULL )
{
	fprintf ( stderr, "Document not parsed successfully. \n");

	return;
}

La función xmlDocGetRootElement obtiene el nodo raíz del documento

cur = xmlDocGetRootElement ( doc );

if ( cur == NULL )
{
	fprintf ( stderr,"empty document\n" );
	xmlFreeDoc ( doc );

	return;
}

Se revisa si es el nodo raíz que se espera

if ( xmlStrcmp ( cur -> name, ( const xmlChar * ) "story" ) )
{
	fprintf ( stderr, "document of the wrong type, root node != story" );
	xmlFreeDoc ( doc );

	return;
}

Se posiciona la variable cur en el primer nodo hijo.

cur = cur -> xmlChildrenNode;

En este ciclo se busca el nodo storyinfo, si el nodo en cur no corresponde se pasa al siguiente con cur -> next (el siguiente en el mismo nivel). Al encontrar storyinfo se llama a la función parseStory.

while ( cur != NULL )
{
	if ( ( !xmlStrcmp ( cur -> name, ( const xmlChar * ) "storyinfo" ) ) )
	{
		parseStory ( doc, cur );
	}

	cur = cur -> next;
}

Se libera la memoria reservada para el documento.

xmlFreeDoc ( doc );

return;

parseStory se usa para buscar entre los nodos hijos de storyinfo y esta definida como:

void parseStory ( xmlDocPtr doc, xmlNodePtr cur )

Se declaran variables necesarias key y cur, se asigna al primer nodo hijo.

xmlChar *key;
cur = cur -> xmlChildrenNode;

El siguiente ciclo busca el nodo headline y lo imprime en pantalla; para extraer el contenido del nodo como cadena de caracteres se usa la función xmlNodeString, que tiene tres argumentos, el primero el puntero al documento, seguido de el nodo (recordar que el texto es conisderado como un nodo hijo), y al final si queremos que se remplazen las xml character entities o no... por ejemplo & por &.

while ( cur != NULL )
{
	if ( ( !xmlStrcmp ( cur -> name, ( const xmlChar * ) "headline" ) ) )
	{
		key = xmlNodeListGetString ( doc, cur -> xmlChildrenNode, 1 );
		printf ( "keyword: %s\n", key );
		xmlFree ( key );
	}

	cur = cur->next;
}

return;

Ya con esto el siguiente, un programa para contar las ocurrencias de algún nodo, es bastante fácil de hacer y de entender...

parser2