]> Pileus Git - ~andy/gtk/blob - docs/tutorial/gtk_tut_12.es.sgml
use text colors from widget style to draw cursor instead of hardcoded
[~andy/gtk] / docs / tutorial / gtk_tut_12.es.sgml
1 <!doctype linuxdoc system>
2
3 <!--
4         Traducción realizada por:
5            Joaquín Cuenca Abela (e98cuenc@criens.u-psud.fr)
6            Eduardo Anglada Varela (eduardo.anglada@adi.uam.es)
7
8         Versión beta 2 de la traducción del GTK+
9         Tutorial 1.2. Cualquier sugerencia será bienvenida.
10         Los cambios más significativos de esta versión son la traducción
11         de las variables de los programas y XXX.
12
13         Si quiere obtener este documento puede encontrarlo en Linux Landia:
14         http://www.croftj.net/~barreiro/spanish/gnome-es/
15 -->
16
17 <article>
18 <title>GTK Tutorial v1.2
19 <author>Tony Gale <tt><htmlurl url="mailto:gale@gtk.org"
20                               name="&lt;gale@gtk.org&gt;"></tt>,
21 Ian Main <tt><htmlurl url="mailto:imain@gtk.org"
22                               name="&lt;imain@gtk.org&gt;"></tt>
23 <date>21 de Febrero de 1999
24 <abstract>
25 Este documento es un tutorial sobre como utilizar GTK (el GIMP
26 Toolkit) en C
27 </abstract>
28
29 <toc>
30
31 <!-- ***************************************************************** -->
32 <sect>Introducción
33 <!-- ***************************************************************** -->
34 <p>
35 GTK (GIMP Toolkit) es una biblioteca para crear interfaces gráficas
36 de usuario. Su licencia es la LGPL, así que mediante GTK podrá
37 desarrollar programas con licencias abiertas, gratuitas, libres, y
38 hasta licencias comerciales no libres sin mayores problemas.
39
40 Se llama el GIMP toolkit porque fue escrito para el desarrollo del
41 General Image Manipulation Program (GIMP), pero ahora GTK se utiliza
42 en un gran número de proyectos de programación, incluyendo el
43 proyecto GNU Network Object Model Environment (GNOME). GTK está
44 construido encima de GDK (GIMP Drawing Kit) que básicamente es un
45 recubrimiento de las funciones de bajo nivel que deben haber para
46 acceder al sistema de ventanas sobre el que se programe (Xlib en el
47 caso de X windows). Los principales autores de GTK son:
48
49 <itemize>
50 <item> Peter Mattis   <tt><htmlurl url="mailto:petm@xcf.berkeley.edu"
51                            name="petm@xcf.berkeley.edu"></tt>
52 <item> Spencer Kimball <tt><htmlurl url="mailto:spencer@xcf.berkeley.edu"
53                            name="spencer@xcf.berkeley.edu"></tt>
54 <item> Josh MacDonald <tt><htmlurl url="mailto:jmacd@xcf.berkeley.edu"
55                            name="jmacd@xcf.berkeley.edu"></tt>
56 </itemize>
57
58 GTK es esencialmente una interfaz para la programación de
59 aplicaciones orientadas al objeto (API). Aunque está completamente
60 escrito en C, esta implementado haciendo uso de la idea de clases y de
61 funciones respuesta o de <em/callback/ (punteros o funciones).
62
63 Tenemos un tercer componente llamado glib, que contiene unas cuantas
64 funciones para reemplazar algunas llamadas estándar, así como
65 funciones adicionales para manejar listas enlazadas, etc... Se
66 reemplazan algunas funciones para aumentar la portabilidad de GTK, ya
67 que algunas de las funciones implementadas no están disponibles o
68 no son estándar en otros unixs, como por ejemplo
69 g_strerror(). Algunas otras contienen mejoras a la versión de libc,
70 como g_malloc que mejora las posibilidades de encontrar errores.
71
72 Este tutorial describe la interfaz C de GTK. Hay recubrimientos GTK
73 para muchos otros lenguajes, incluyendo C++, Guile, Perl, Python, TOM,
74 Ada95, Objective C, Free Pascal, y Eiffel. Si va a utilizar el
75 recubrimiento para alguno de estos lenguajes, mire primero su
76 documentación. En algunos casos la documentación puede describir
77 algún convenio importante (que debería conocer de antemano) y
78 después puede volver a este tutorial. También hay algún API
79 multiplataforma (como wxWindows y V) que utilizan GTK como una de sus
80 plataformas destino; de nuevo, consulte primero la documentación
81 que viene con estos paquetes.
82
83 Si está desarrollando su aplicación GTK en C++, hay algunas
84 cosas que debería saber. Hay un recubriento a GTK para C++ llamado
85 GTK--, que proporciona una interfaz C++ a GTK; probablemente
86 debería empezar mirando ahí. Si no le gusta esa aproximación
87 al problema, por los motivos que sean, tiene dos
88 alternativas. Primero, puede ceñirse al subconjunto C de C++ cuando
89 realice alguna llamada a GTK a través de su interfaz en C. Segundo,
90 puede utilizar GTK y C++ al mismo tiempo declarando todas las
91 funciones respuesta como funciones estáticas en clases C++, y de
92 nuevo, llamar a GTK utilizando su interfaz C. Si elige esta última
93 forma de actuar, puede incluir como dato de la función respuesta un
94 puntero al objeto a manipular (el también llamado valor
95 «this»). La elección de una u otra opción es cuestión de
96 gustos personales, ya que de las tres maneras conseguirá utilizar
97 GTK en C++. Ninguna de estas aproximaciones requiere el uso de un
98 preprocesador especializado, por lo que sin importar la opción que
99 escoja podrá utilizar C++ estándar en C++.
100
101 Este tutorial es un intento de documentar GTK tanto como sea posible,
102 pero no está completo. Este tutorial asume un buen conocimiento de
103 C y de como crear programas bajo este lenguaje. Se verá beneficiado
104 si tiene un conocimiento previo de la programación en X, pero no
105 debería ser necesario. Si está aprendiendo GTK y es el primer
106 conjunto de <em/widgets/ que utiliza, por favor envíenos sus
107 comentarios sobre este tutorial y los problemas que ha
108 encontrado.
109
110 Este documento es un `trabajo pendiente de finalizar'. Para encontrar
111 actualizaciones mire en http://www.gtk.org/ <htmlurl
112 url="http://www.gtk.org/" name="http://www.gtk.org/">.
113
114 Me gustaría escuchar cualquier problema que le surja mientras
115 aprende GTK siguiendo este documento, y apreciaré cualquier
116 información sobre como mejorarlo. Por favor, vea la sección <ref
117 id="sec_Contributing" name="Contribuyendo"> para encontrar más
118 información.
119
120 <!-- ***************************************************************** -->
121 <sect>Comenzando
122 <!-- ***************************************************************** -->
123
124 <p>
125 Por supuesto lo primero que hay que hacer es descargar las fuentes de
126 GTK e instalarlas. La última versión siempre se puede obtener de
127 ftp.gtk.org (en el directorio /pub/gtk). En <htmlurl
128 url="http://www.gtk.org/" name="http://www.gtk.org/"> hay más
129 información sobre GTK. Para configurar GTK hay que usar GNU
130 autoconf. Una vez descomprimido se pueden obtener las opciones usando
131 <tt>./configure --help</tt>.
132
133 El código de GTK además contiene las fuentes completas de todos
134 los ejemplos usados en este manual, así como los makefiles para
135 compilarlos.
136
137 Para comenzar nuestra introducción a GTK vamos a empezar con el
138 programa más sencillo posible. Con él vamos a crear una ventana de
139 200x200 <em/pixels/ que sólo se puede destruir desde el shell.
140
141 <tscreen><verb>
142 /* principio del ejemplo base base.c */
143
144 #include <gtk/gtk.h>
145
146 int main (int argc, char *argv[])
147 {
148     GtkWidget *ventana;
149     
150     gtk_init (&amp;argc, &amp;argv);
151     
152     ventana = gtk_window_new (GTK_WINDOW_TOPLEVEL);
153     gtk_widget_show (ventana);
154     
155     gtk_main ();
156     
157     return 0;
158 }
159 /* final del ejemplo */
160 </verb></tscreen>
161
162 Puede compilar el programa anterior con gcc tecleando:
163 <tscreen><verb>
164 gcc base.c -o base `gtk-config --cflags --libs`
165 </verb></tscreen>
166
167 El significado de la extraña opción de compilación se explica
168 más adelante.
169
170 Todo programa que use GTK debe llamar a <tt>gtk/gtk.h</tt> donde se
171 declaran todas las variables, funciones, estructuras, etc. que serán
172 usadas en el programa.
173
174 La siguiente línea:
175
176 <tscreen><verb>
177 gtk_init (&amp;argc, &amp;argv);
178 </verb></tscreen>
179
180 Llama a la función gtk_init (gint *argc, gchar *** argv) responsable
181 de `arrancar' la biblioteca y de establecer algunos parámetros (como son
182 los colores y los visuales por defecto), llama a gdk_init (gint *argc,
183 gchar *** argv) que inicializa la biblioteca para que pueda
184 utilizarse, establece los controladores de las señales y comprueba los
185 argumentos pasados a la aplicación desde la línea de comandos,
186 buscando alguno de los siguientes:
187
188 <itemize>
189 <item> <tt/--gtk-module/
190 <item> <tt/--g-fatal-warnings/
191 <item> <tt/--gtk-debug/
192 <item> <tt/--gtk-no-debug/
193 <item> <tt/--gdk-debug/
194 <item> <tt/--gdk-no-debug/
195 <item> <tt/--display/
196 <item> <tt/--sync/
197 <item> <tt/--no-xshm/
198 <item> <tt/--name/
199 <item> <tt/--class/
200 </itemize>
201
202 En el caso de que encuentre alguno lo quita de la lista, dejando todo
203 aquello que no reconozca para que el programa lo utilice o lo
204 ignore. Así se consigue crear un conjunto de argumentos que son
205 comunes a todas las aplicaciones basadas en GTK.
206
207 Las dos líneas de código siguientes crean y muestran una ventana.
208
209 <tscreen><verb>
210   ventana = gtk_window_new (GTK_WINDOW_TOPLEVEL);
211   gtk_widget_show (ventana);
212 </verb></tscreen>
213
214 El argumento GTK_WINDOW_TOPLEVEL especifica que queremos que el gestor
215 de ventanas decore y sitúe la ventana. En lugar de crear una ventana
216 de tamaño 0 x 0 toda ventana sin hijos por defecto es de 200 x 200, con
217 lo que se consigue que pueda ser manipulada.
218
219 La función gtk_widget_show() le comunica a GTK que hemos acabado de
220 especificar los atributos del <em/widget/, y que por tanto puede
221 mostrarlo.
222
223 La última línea comienza el proceso del bucle principal de GTK.
224
225 <tscreen><verb>
226 gtk_main ();
227 </verb></tscreen>
228
229 Otra llamada que siempre está presente en cualquier aplicación es
230 gtk_main(). Cuando el control llega a ella, GTK se queda dormido
231 esperando a que suceda algún tipo de evento de las X (como puede ser
232 pulsar un botón), que pase el tiempo necesario para que el usuario
233 haga algo, o que se produzcan notificaciones de IO de archivos. En
234 nuestro caso concreto todos los eventos serán ignorados.
235
236
237 <!-- ----------------------------------------------------------------- -->
238 <sect1>Programa «Hola Mundo» en GTK
239 <p>
240 El siguiente ejemplo es un programa con un <em/widget/ (un
241 botón). Simplemente es la versión de GTK del clásico «hola mundo».
242
243 <tscreen><verb>
244 /* comienzo del ejemplo holamundo */
245 #include <gtk/gtk.h>
246
247 /* Ésta es una función respuesta (callback). Sus argumentos
248    son ignorados por en este ejemplo */
249 void hello (GtkWidget *widget, gpointer data)
250 {
251     g_print ("Hola mundo\n");
252 }
253
254 gint delete_event(GtkWidget *widget, GdkEvent *event, gpointer data)
255 {
256     /* si se devuelve FALSE al administrador de llamadas
257      * "delete_event", GTK emitirá la señal de destrucción
258      * "destroy". Esto es útil para diálogos emergentes del
259      * tipo: ¿Seguro que desea salir?
260
261     g_print ("Ha ocurrido un evento delete\n");
262
263     /* Cambiando TRUE por FALSE la ventana se destruirá con
264      * "delete_event"*/
265
266     return (TRUE);
267 }
268
269 /* otra respuesta */
270 void destroy (GtkWidget *widget, gpointer data)
271 {
272     gtk_main_quit ();
273 }
274
275 int main (int argc, char *argv[])
276 {
277
278     /* GtkWidget es el tipo de almacenamiento usado para los
279      * widgets */
280     GtkWidget *ventana;
281     GtkWidget *boton;
282
283     /* En cualquier aplicación hay que realizar la siguiente
284      * llamada. Los argumentos son tomados de la línea de comandos
285      * y devueltos a la aplicación. */
286
287     gtk_init (&amp;argc, &amp;argv);
288     
289     /* creamos una ventana nueva */
290     ventana = gtk_window_new (GTK_WINDOW_TOPLEVEL);
291     
292     /* Cuando la ventana recibe la señal "delete_event" (emitida
293      * por el gestor de ventanas, normalmente mediante la opción
294      * 'close', o en la barra del título) hacemos que llame a la
295      * función delete_event() tal y como ya hemos visto. Los datos
296      * pasados a la función de respuesta son NULL, y serán ignorados. */
297     gtk_signal_connect (GTK_OBJECT (ventana), "delete_event",
298                         GTK_SIGNAL_FUNC (delete_event), NULL);
299
300     /* Aquí conectamos el evento "destroy" con el administrador de
301      * señales. El evento se produce cuando llamamos a
302      * gtk_widget_destroy() desde la ventana o si devolvemos 'FALSE'
303      * en la respuesta "delete_event". */
304     gtk_signal_connect (GTK_OBJECT (ventana), "destroy",
305                         GTK_SIGNAL_FUNC (destroy), NULL);
306     
307     /* establecemos el ancho del borde de la ventana. */
308     gtk_container_border_width (GTK_CONTAINER (ventana), 10);
309     
310     /* creamos un botón nuevo con la  etiqueta "Hola mundo" */
311     boton = gtk_button_new_with_label ("Hola mundo");
312     
313     /* Cuando el botón recibe la señal "clicked" llama a la
314      * función hello() pasándole NULL como argumento. (La
315      * función ya ha sido definida arriba). */
316     gtk_signal_connect (GTK_OBJECT (boton), "clicked",
317                         GTK_SIGNAL_FUNC (hello), NULL);
318     
319     /* Esto hará que la ventana sea destruida llamando a
320      * gtk_widget_destroy(ventana) cuando se produzca "clicked". Una
321      * vez mas la señal de destrucción puede provenir del gestor
322      * de ventanas o de aquí. */
323      gtk_signal_connect_object (GTK_OBJECT (boton), "clicked",
324                                GTK_SIGNAL_FUNC (gtk_widget_destroy),
325                                GTK_OBJECT (ventana));
326     
327     /* Ahora empaquetamos el botón en la ventana (usamos un gtk
328      * container ). */
329     gtk_container_add (GTK_CONTAINER (ventana), boton);
330     
331     /* El último paso es representar el nuevo widget... */
332     gtk_widget_show (boton);
333     
334     /* y la ventana */
335     gtk_widget_show (ventana);
336     
337     /* Todas las aplicaciones basadas en GTK deben tener una llamada
338      * gtk_main() ya que el control termina justo aquí y debe
339      * esperar a que suceda algún evento */
340
341     gtk_main ();
342     
343     return 0;
344 }
345 /* final del ejemplo*/
346 </verb></tscreen>
347
348 <!-- ----------------------------------------------------------------- -->
349 <sect1>Compilando Hello World
350 <p>
351 Para compilar el ejemplo hay que usar:
352
353 <tscreen><verb>
354 gcc -Wall -g helloworld.c -o hello_world `gtk-config --cflags` \
355     `gtk-config --libs`
356 </verb></tscreen>
357
358 Usamos el programa <tt>gtk-config</>, que ya viene (y se instala) con
359 la biblioteca. Es muy útil porque `conoce' que opciones son
360 necesarias para compilar programas que usen gtk. <tt>gtk-config
361 --cflags</tt> dará una lista con los directorios donde el
362 compilador debe buscar ficheros «include». A su vez <tt>gtk-config
363 --libs</tt> nos permite saber las bibliotecas que el compilador
364 intentará enlazar y dónde buscarlas.
365
366 Hay que destacar que las comillas simples en la orden de
367 compilación son absolutamente necesarias.
368
369 Las bibliotecas que se enlazan normalmente son:
370
371 <itemize>
372
373 <item>La biblioteca GTK (-lgtk), la biblioteca de <em/widgets/ que se
374 encuentra encima de GDK.
375
376 <item>La biblioteca GDK (-lgdk), el wrapper de Xlib.
377
378 <item>La biblioteca glib (-lglib), que contiene diversas funciones. En
379 nuestro ejemplo sólo hemos usado g_print(). GTK está construida
380 encima de glib por lo que simpre se usará. Vea la sección <ref
381 id="sec_glib" name="glib"> para más detalles.
382
383 <item>La biblioteca Xlib (-lX11) que es usada por GDK.
384
385 <item> La biblioteca Xext (-lXext) contiene código para
386 <em/pixmaps/ de memoria compartida y otras extensiones.
387
388 <item>La biblioteca matemática (-lm). Es usada por GTK para
389 diferentes cosas.
390
391 </itemize>
392
393 <!-- ----------------------------------------------------------------- -->
394 <sect1>Teoría de señales y respuestas
395 <p>
396 Antes de profundizar en <tt/holamundo/ vamos a discutir las
397 señales y las respuestas. GTK es un toolkit (conjunto de
398 herramientas) gestionadas mediante eventos. Esto quiere decir que GTK
399 «duerme» en gtk_main hasta que se recibe un evento, momento en el
400 cual se transfiere el control a la función adecuada.
401
402 El control se transfiere mediante «señales». (Conviene destacar
403 que las señales de GTK  no son iguales que las de los sistemas
404 UNIX, aunque la terminología es la misma.) Cuando sucede un evento,
405 como por ejemplo la pulsación de un botón, se «emitirá» la
406 señal apropiada por el <em/widget/ pulsado. Así es como GTK
407 proporciona la mayor parte de su utilidad. Hay un conjunto de
408 señales que todos los <em/widgets/ heredan, como por ejemplo
409 «destroy» y hay señales que son específicas de cada
410 <em/widget/, como por ejemplo la señal «toggled» de un botón
411 de selección (botón <em/toggle/).
412
413 Para que un botón haga algo crearemos un controlador que se encarga de
414 recoger las señales y llamar a la función apropiada. Esto se hace
415 usando una función como:
416
417 <tscreen><verb>
418 gint gtk_signal_connect( GtkObject     *objeto,
419                          gchar         *nombre,
420                          GtkSignalFunc  func,
421                          gpointer       datos_func );
422 </verb></tscreen>
423
424 Donde el primer argumento es el <em/widget/ que emite la señal, el
425 segundo el nombre de la señal que queremos `cazar', el tercero es
426 la función a la que queremos que se llame cuando se `cace' la
427 señal y el cuarto los datos que queremos pasarle a esta función.
428
429 La función especificada en el tercer argumento se denomina «función
430 de respuesta» y debe tener la forma siguiente:
431
432 <tscreen><verb>
433 void callback_func( GtkWidget *widget,
434                     gpointer   datos_respuesta );
435 </verb></tscreen>
436
437 Donde el primer argumento será un puntero al <em/widget/ que emitió la
438 señal, y el segundo un puntero a los datos pasados a la función tal y
439 como hemos visto en el último argumento a gtk_signal_connect().
440
441 Conviene destacar que la declaración de la función de respuesta debe
442 servir sólo como guía general, ya que algunas señales específicas
443 pueden generar diferentes parámetros de llamada. Por ejemplo, la señal
444 de GtkCList «select_row» proporciona los parámetros fila y columna. 
445
446 Otra llamada usada en el ejemplo del hola mundo es:
447
448 <tscreen><verb>
449 gint gtk_signal_connect_object( GtkObject     *objeto,
450                                 gchar         *nombre,
451                                 GtkSignalFunc  func,
452                                 GtkObject     *slot_object );
453 </verb></tscreen>
454
455 gtk_signal_connect_object() es idéntica a gtk_signal_connect() excepto
456 en que la función de llamada sólo usa un argumento, un puntero a un
457 objeto GTK. Por tanto cuando usemos esta función para conectar
458 señales, la función de respuesta debe ser de la forma: 
459
460 <tscreen><verb>
461 void callback_func( GtkObject *object );
462 </verb></tscreen>
463
464 Donde, por regla general, el objeto es un <em/widget/. Sin embargo no
465 es normal establecer una respuesta para gtk_signal_connect_object. En
466 lugar de ello llamamos a una función de GTK que acepte un <em/widget/
467 o un objeto como un argumento, tal y como se vio en el ejemplo hola
468 mundo.
469
470 ¿Para qué sirve tener dos funciones para conectar señales? Simplemente
471 para permitir que las funciones de respuesta puedan tener un número
472 diferente de argumentos. Muchas funciones de GTK sólo aceptan un
473 puntero a un GtkWidget como argumento, por lo que tendrá que usar
474 gtk_signal_connect_object() con estas funciones, mientras que
475 probablemente tenga que suministrarle información adicional a sus
476 funciones.
477
478 <!-- XXX Completamente revisado hasta aquí -------------------------- -->
479 <sect1>Eventos
480 <p>
481 Además del mecanismo de señales descrito arriba existe otro conjunto
482 de <em>eventos</em> que reflejan como las X manejan los eventos. Se
483 pueden asignar funciones de respuesta a estos eventos. Los eventos
484 son:
485
486 <itemize>
487 <item> event
488 <item> button_press_event
489 <item> button_release_event
490 <item> motion_notify_event
491 <item> delete_event
492 <item> destroy_event
493 <item> expose_event
494 <item> key_press_event
495 <item> key_release_event
496 <item> enter_notify_event
497 <item> leave_notify_event
498 <item> configure_event
499 <item> focus_in_event
500 <item> focus_out_event
501 <item> map_event
502 <item> unmap_event
503 <item> property_notify_event
504 <item> selection_clear_event
505 <item> selection_request_event
506 <item> selection_notify_event
507 <item> proximity_in_event
508 <item> proximity_out_event
509 <item> drag_begin_event
510 <item> drag_request_event
511 <item> drag_end_event
512 <item> drop_enter_event
513 <item> drop_leave_event
514 <item> drop_data_available_event
515 <item> other_event
516 </itemize>
517
518 Para conectar una función de respuesta a alguno de los eventos
519 anteriores debe usar la función gtk_signal_connect, tal y como se
520 descrivió anteriormente, utilizando en el parámetro <tt/name/ uno de
521 los nombres de los eventos que se acaban de mencionar. La función de
522 respuesta para los eventos tiene un forma ligeramente diferente de la
523 que tiene para las señales:
524
525 <tscreen><verb>
526 void callback_func( GtkWidget *widget,
527                     GdkEvent  *event,
528                     gpointer   callback_data );
529 </verb></tscreen>
530
531 GdkEvent es una estructura <tt/union/ cuyo tipo depende de cual de los
532 eventos anteriores haya ocurrido. Para que podamos decir que evento se
533 ha lanzado cada una de las posibles alternativas posee un parámetro
534 <tt/type/ que refleja cual es el evento en cuestión. Los otros
535 componentes de la estructura dependerán del tipo de evento. Algunos
536 valores posibles son:
537
538 <tscreen><verb>
539   GDK_NOTHING
540   GDK_DELETE
541   GDK_DESTROY
542   GDK_EXPOSE
543   GDK_MOTION_NOTIFY
544   GDK_BUTTON_PRESS
545   GDK_2BUTTON_PRESS
546   GDK_3BUTTON_PRESS
547   GDK_BUTTON_RELEASE
548   GDK_KEY_PRESS
549   GDK_KEY_RELEASE
550   GDK_ENTER_NOTIFY
551   GDK_LEAVE_NOTIFY
552   GDK_FOCUS_CHANGE
553   GDK_CONFIGURE
554   GDK_MAP
555   GDK_UNMAP
556   GDK_PROPERTY_NOTIFY
557   GDK_SELECTION_CLEAR
558   GDK_SELECTION_REQUEST
559   GDK_SELECTION_NOTIFY
560   GDK_PROXIMITY_IN
561   GDK_PROXIMITY_OUT
562   GDK_DRAG_BEGIN
563   GDK_DRAG_REQUEST
564   GDK_DROP_ENTER
565   GDK_DROP_LEAVE
566   GDK_DROP_DATA_AVAIL
567   GDK_CLIENT_EVENT
568   GDK_VISIBILITY_NOTIFY
569   GDK_NO_EXPOSE
570   GDK_OTHER_EVENT       /* En desuso, usar filtros en lugar de ella */
571 </verb></tscreen>
572
573 Por lo tanto para conectar una función de respuesta a uno de estos
574 eventos debemos usar algo como:
575
576 <tscreen><verb>
577 gtk_signal_connect( GTK_OBJECT(boton), "button_press_event",
578                     GTK_SIGNAL_FUNC(button_press_callback), 
579                     NULL);
580 </verb></tscreen>
581
582 Por supuesto se asume que <tt/boton/ es un <em/widget/
583 GtkButton. Cada vez que el puntero del ratón se encuentre sobre el
584 botón y éste sea presionado, se llamará a la función
585 <tt/button_press_callback/. Esta función puede declararse así:
586
587 <tscreen><verb>
588 static gint button_press_event (GtkWidget      *widget, 
589                                 GdkEventButton *event,
590                                 gpointer        data);
591 </verb></tscreen>
592
593 Conviene destacar que se puede declarar el segundo argumento como
594 <tt/GdkEventButton/ porque sabemos que este tipo de evento ocurrirá
595 cuando se llame a la función.
596
597 El valor devuelto por esta función es usado para saber si el evento
598 debe ser propagado a un nivel más profundo dentro del mecanismo de
599 GTK para gestionar los eventos. Si devuelve TRUE el evento ya ha sido
600 gestionado y por tanto no tiene que ser tratado por el mecanismo de
601 gestión. Por contra si devuelve FALSE se continua con la gestión
602 normal del evento. Para más detalles se recomienda leer la sección
603 donde se aclara como se produce el proceso de propagación.
604
605 Para más detalles acerca de los tipos de información GdkEvent
606 consultar el apéndice <ref id="sec_GDK_Event_Types" name="Tipos de
607 eventos GDK">.
608
609 <!-- ----------------------------------------------------------------- -->
610 <sect1>Aclaración de Hello World
611 <p>
612 Ahora que conocemos la teoría vamos a aclarar las ideas estudiando
613 en detalle el programa <tt/helloworld/.
614
615 Ésta es la función respuesta a la que se llamará cuando se
616 pulse el botón. En el ejemplo ignoramos tanto el <em/widget/ como
617 la información, pero no es difícil usarlos. El siguiente ejemplo
618 usará la información que recibe como argumento para decirnos que
619 botón fue presionado.
620
621 <tscreen><verb>
622 void hello (GtkWidget *widget, gpointer data)
623 {
624     g_print ("Hello World\n");
625 }
626 </verb></tscreen>
627
628 La siguiente respuesta es un poco especial, el «delete_event» ocurre
629 cuando el gestor de ventanas envía este evento a la aplicación. Aquí
630 podemos decidir que hacemos con estos eventos. Los podemos ignorar,
631 dar algún tipo de respuesta, o simplemente terminar la aplicación.
632
633 El valor devuelto en esta respuesta le permite a GTK saber que tiene
634 que hacer. Si devolvemos TRUE, estamos diciendo que no queremos que se
635 emita la señal «destroy» y por lo tanto queremos que nuestra
636 aplicación siga ejecutándose. Si devolvemos FALSE, decimos que
637 se emita «destroy», lo que hará que se ejecute nuestro manejador
638 de señal de «destroy».
639
640 <tscreen><verb>
641 gint delete_event(GtkWidget *widget, GdkEvent *event, gpointer data)
642 {
643     g_print ("delete event occured\n");
644
645     return (TRUE); 
646 }
647 </verb></tscreen>
648
649 Con el siguiente ejemplo presentamos otra función de respuesta que hace 
650 que el programa salga llamando a gtk_main_quit(). Con esta función le
651 decimos a GTK que salga de la rutina gtk_main() cuando vuelva a estar
652 en ella.
653
654 <tscreen><verb>
655 void destroy (GtkWidget *widget, gpointer data)
656 {
657     gtk_main_quit ();
658 }
659 </verb></tscreen>
660
661 Como el lector probablemente ya sabe toda aplicación debe tener una 
662 función main(), y una aplicación GTK no va a ser menos. Todas las
663 aplicaciones GTK también tienen una función de este tipo.
664
665 <tscreen><verb>
666 int main (int argc, char *argv[])
667 </verb></tscreen>
668
669 Las líneas siguientes declaran un puntero a una estructura del tipo 
670 GtkWidget, que se utilizarán más adelante para crear una ventana y un
671 botón.
672
673 <tscreen><verb>
674     GtkWidget *ventana;
675     GtkWidget *boton;
676 </verb></tscreen>
677
678 Aquí tenemos otra vez a gtk_init. Como antes arranca el conjunto de 
679 herramientas y filtra las opciones introducidas en la línea de
680 órdenes. Cualquier argumento que sea reconocido será borrado de la
681 lista de argumentos, de modo que la aplicación recibirá el resto.
682
683 <tscreen><verb>
684     gtk_init (&amp;argc, &amp;argv);
685 </verb></tscreen>
686
687 Ahora vamos a crear una ventana. Simplemente reservamos memoria para 
688 la estructura GtkWindow *ventana, con lo que ya tenemos una nueva
689 ventana, ventana que no se mostrará hasta que llamemos a
690 gtk_widget_show (ventana) hacia el final del programa. 
691
692 <tscreen><verb>
693     ventana = gtk_window_new (GTK_WINDOW_TOPLEVEL);
694 </verb></tscreen>
695
696 Aquí tenemos un ejemplo de como conectar un manejador de señal a un
697 objeto, en este caso, la ventana. La señal a cazar será
698 «destroy». Esta señal se emite cuando utilizamos el administrador de
699 ventanas para matar la ventana (y devolvemos TRUE en el manejador
700 «delete_event»), o cuando usamos llamamos a gtk_widget_destroy()
701 pasándole el <em/widget/ que representa la ventana como argumento. 
702 Así conseguimos manejar los dos casos con una simple llamada a la
703 función destroy () (definida arriba) pasándole NULL como argumento y
704 ella acabará con la aplicación por nosotros. 
705
706 GTK_OBJECT y GTK_SIGNAL_FUNC son macros que realizan la comprobación y
707 transformación de tipos por nosotros. También aumentan la legibilidad
708 del código.
709
710 <tscreen><verb>
711     gtk_signal_connect (GTK_OBJECT (ventana), "destroy",
712                         GTK_SIGNAL_FUNC (destroy), NULL);
713 </verb></tscreen>
714
715 La siguiente función establece un atributo a un objeto contenedor 
716 (discutidos luego). En este caso le pone a la ventana un área 
717 negra de 10 <em/pixels/ de ancho donde no habrán <em/widgets/. Hay
718 funciones similares que serán tratadas con más detalle en la sección
719 <ref id="sec_setting_widget_attributes" name="Estableciendo los
720 atributos de los <em/widgets/">
721
722 De nuevo, GTK_CONTAINER es una macro que se encarga de la conversión
723 entre tipos
724
725 <tscreen><verb>
726     gtk_container_border_width (GTK_CONTAINER (ventana), 10);
727 </verb></tscreen>
728
729 La siguiente llamada crea un nuevo botón. Reserva espacio en la 
730 memoria para una nueva estructura del tipo GtkWidget, la inicializa
731 y hace que el puntero <tt/boton/ apunte a esta estructura. Su etiqueta
732 será: "Hola mundo".
733
734 <tscreen><verb>
735     boton = gtk_button_new_with_label ("Hola mundo");
736 </verb></tscreen>
737
738 Ahora hacemos que el botón sea útil, para ello enlazamos el botón con
739 el manejador de señales para que cuando emita la señal «clicked», se
740 llame a nuestra función hola(). Los datos adicionales serán
741 ignorados, por lo que simplemente le pasaremos NULL a la función
742 respuesta. Obviamente se emitirá la señal «clicked» cuando pulsemos
743 en el botón con el ratón.
744
745 <tscreen><verb>
746     gtk_signal_connect (GTK_OBJECT (boton), "clicked",
747                         GTK_SIGNAL_FUNC (hola), NULL);
748 </verb></tscreen>
749 XXX
750 Ahora vamos a usar el botón para terminar nuestro programa. Así
751 aclararemos cómo es posible que la señal «destroy» sea emitida tanto
752 por el gestor de ventanas como por nuestro programa. Cuando el botón
753 es pulsado, al igual que arriba, se llama a la primera función
754 respuesta hello() y después se llamará a esta función. Las funciones
755 respuesta serán ejecutadas en el orden en que sean conectadas. Como la
756 función gtk_widget_destroy() sólo acepta un GtkWidget como argumento,
757 utilizaremos gtk_signal_connect_object() en lugar de
758 gtk_signal_connect().
759
760 <tscreen><verb>
761 gtk_signal_connect_object (GTK_OBJECT (boton), "clicked",
762                            GTK_SIGNAL_FUNC (gtk_widget_destroy),
763                            GTK_OBJECT (ventana));
764 </verb></tscreen>
765
766 La siguiente llamada sirve para empaquetar (más detalles luego). Se
767 usa para decirle a GTK que el botón debe estar en la ventana dónde
768 será mostrado. Conviene destacar que un contenedor GTK sólo puede
769 contener un <em/widget/. Existen otros <em/widgets/ (descritos
770 después) que sirven para contener y establecer la disposición de
771 varios <em/widgets/ de diferentes formas.
772
773 <tscreen><verb>
774     gtk_container_add (GTK_CONTAINER (ventana), boton);
775 </verb></tscreen>
776
777 Ahora ya tenemos todo bien organizado. Como todos los controladores de
778 las señales ya están en su sitio, y el botón está situado en la
779 ventana donde queremos que esté, sólo nos queda pedirle a GTK que
780 muestre todos los <em/widgets/ en pantalla. El <em/widget/ ventana será
781 el último en mostrarse queremos que aparezca todo de golpe, en vez de
782 ver aparecer la ventana, y después ver aparecer el botón. De todas
783 formas con un ejemplo tan simple nunca se notaría cual es el orden de
784 aparición.
785
786 <tscreen><verb>
787     gtk_widget_show (boton);
788
789     gtk_widget_show (ventana);
790 </verb></tscreen>
791
792 Llamamos  a gtk_main() que espera hasta que el servidor X le comunique
793 que se ha producido algún evento para emitir las señales apropiadas.
794
795 <tscreen><verb>
796     gtk_main ();
797 </verb></tscreen>
798
799 Por último el `return' final que devuelve el control cuando gtk_quit()
800 sea invocada.
801
802 <tscreen><verb>
803     return 0;
804 </verb></tscreen>
805
806 Cuando pulsemos el botón del ratón el <em/widget/ emite la señal
807 correspondiente «clicked». Para que podamos usar la información el
808 programa activa el gestor de eventos que al recibir la señal llama a
809 la función que hemos elegido. En nuestro ejemplo cuando pulsamos el
810 botón se llama a la función hello() con NULL como argumento y además
811 se invoca al siguiente manipulador de señal. Así conseguimos que se
812 llame a la función gtk_widget_destroy() con el <em/widget/ asociado a
813 la ventana como argumento, lo que destruye al <em/widget/. Esto hace
814 que la ventana emita la señal «destroy», que es cazada, y que llama
815 a nuestra función respuesta destroy(), que simplemente sale de GTK.
816
817 Otra posibilidad es usar el gestor de ventanas para acabar con la
818 aplicación. Esto emitirá «delete_event» que hará que se
819 llame a nuestra función manejadora correspondiente. Si en la
820 función manejadora «delete_event» devolvemos TRUE la ventana se
821 quedará como si nada hubiese ocurrido, pero si devolvemos FALSE GTK
822 emitirá la señal «destroy» que, por supuesto, llamará a la
823 función respuesta «destroy», que saldrá de GTK.
824
825 <!-- ***************************************************************** -->
826 <sect>Avanzando
827 <!-- ***************************************************************** -->
828
829 <!-- ----------------------------------------------------------------- -->
830 <sect1>Tipos de datos
831 <p>
832 Existen algunos detalles de los ejemplos anteriores que hay que aclarar. 
833 Los tipos gint, gchar, etc. que puede ver por ahí son typedefs a int y
834 a char respectivamente. Sirven para que no haya que tener en cuenta el
835 tamaño de cada uno de ellos a la hora de hacer cálculos.
836
837 Un buen ejemplo es <tt/gint32/ que es un entero de 32 bits independientemente 
838 de la plataforma, bien sea un Alpha de 64 bits o un i386 de 32. Todas las 
839 definiciones son muy intuitivas y se encuentran definidas en glib/glib.h
840 (que se incluye desde gtk.h).
841
842 Probablemente el lector se haya dado cuenta de que se puede usar GtkWidget
843 cuando la función llama a un GtkObject. Esto es debido a que GTK
844 está orienta a objetos y un <em/widget/ es un GtkObject.
845
846 <!-- ----------------------------------------------------------------- -->
847 <sect1>Más sobre el manejo de señales
848 <p>
849 Si estudiamos en mayor profundidad la declaración de
850 gtk_signal_connect:
851
852 <tscreen><verb>
853 gint gtk_signal_connect( GtkObject *object,
854                          gchar *name,
855                          GtkSignalFunc func,
856                          gpointer func_data );
857 </verb></tscreen>
858
859 Podemos darnos cuenta de que el valor devuelto es del tipo gint. Este
860 valor es una etiqueta que identifica a la función de respuesta. Tal
861 y como ya vimos podemos tener tantas funciones de respuesta por
862 seÑal y objeto como sean necesarias, y cada una de ellas se
863 ejecutará en el mismo orden en el que fueron enlazadas.
864
865 Esta etiqueta nos permite eliminar la función respuesta de la lista 
866 usando:
867
868 <tscreen><verb>
869 void gtk_signal_disconnect( GtkObject *object,
870                             gint id );
871 </verb></tscreen>
872
873 Por lo tanto podemos desconectar un manejador de señal pasándole
874 a la función anterior el <em/widget/ del que queremos desconectar y
875 la etiqueta o id devuelta por una de las funciones signal_connect.
876
877 Otra función que se usa para quitar desconectar todos los
878 controladores de un objeto es:
879
880 <tscreen><verb>
881 void gtk_signal_handlers_destroy( GtkObject *object );
882 </verb></tscreen>
883
884 Esta llamada es bastante auto explicativa. Simplemente quitamos todos los 
885 controladores de señales del objeto que pasamos como primer argumento.
886
887 <!-- ----------------------------------------------------------------- -->
888 <sect1>Un Hello World mejorado.
889 <p>
890 Vamos a mejorar el ejemplo para obtener una visión más amplia
891 sobre el manejo de señales y respuestas. También introduciremos
892 los <em/widgets/ usados para empaquetar.
893
894 <tscreen><verb>
895 /* principio del ejemplo helloworld2 */
896
897 #include <gtk/gtk.h>
898
899 /* Nuestra respuesta mejorada. Los argumentos de la función se
900  * imprimen en el stdout.*/
901 void callback (GtkWidget *widget, gpointer data)
902 {
903     g_print ("Hello again - %s was pressed\n", (char *) data);
904 }
905
906 /* otra respuesta*/
907 void delete_event (GtkWidget *widget, GdkEvent *event, gpointer data)
908 {
909     gtk_main_quit ();
910 }
911
912 int main (int argc, char *argv[])
913 {
914     /* GtkWidget es el tipo de almacenamiento usado para los wigtes*/
915     GtkWidget *ventana;
916     GtkWidget *boton;
917     GtkWidget *caja1;
918     
919     /* Esta llamada está presente en todas las aplicaciones basadas
920      * en GTK. Los argumentos introducidos a la aplicación*/
921     gtk_init (&amp;argc, &amp;argv);
922
923     /* creamos una nueva ventana*/
924     ventana = gtk_window_new (GTK_WINDOW_TOPLEVEL);
925     
926     /* Esta función es nueva, pone como título de la ventana
927      * "¡Hola botones!"*/ 
928
929     gtk_window_set_title (GTK_WINDOW (ventana), "¡Hola botones!");
930
931     /* Establecemos el controlador para la llamada delete_event que
932      * termina la aplicación inmediatamente. */
933
934     gtk_signal_connect (GTK_OBJECT (ventana), "delete_event",
935                         GTK_SIGNAL_FUNC (delete_event), NULL);
936
937     
938     /* Establecemos el ancho del borde de la ventana.*/
939     gtk_container_border_width (GTK_CONTAINER (ventana), 10);
940
941     /* Creamos una caja donde empaquetaremos los widgets. El
942      * procedimiento de empaquetamiento se describe en detalle en la
943      * sección correspondiente. La caja no se ve realmente, sólo
944      * sirve para introducir los widgets. */
945     caja1 = gtk_hbox_new(FALSE, 0);
946
947     /* ponemos la caja en la ventana principal */
948     gtk_container_add (GTK_CONTAINER (ventana), caja1);
949
950     /* Creamos un nuevo botón con la etiqueta "Botón 1". */
951     boton = gtk_button_new_with_label ("Botón 1");
952     
953     /* Cada vez que el botón sea pulsado llamamos a la función
954      * "callback" con un puntero a "botón 1" como argumento. */
955     gtk_signal_connect (GTK_OBJECT (boton), "clicked",
956                         GTK_SIGNAL_FUNC (callback), (gpointer) "botón 1");
957     
958     /* En lugar de gtk_container_add empaquetamos el botón en la
959      * caja invisible, que a su vez ha sido empaquetado en la
960      * ventana. */
961     gtk_box_pack_start(GTK_BOX(caja1), boton, TRUE, TRUE, 0);
962
963     /* Siempre se debe realizar este paso. Sirve para decirle a GTK
964      * que los preparativos del botón ya se han finalizado y que
965      * por tanto puede ser mostrado. */
966     gtk_widget_show(boton);
967
968     /* hacemos lo mismo para crear un segundo botón. */
969     boton = gtk_button_new_with_label ("Botón 2");
970
971     /* Llamamos a la misma función de respuesta pero con diferente
972      * argumento: un puntero a "botón 2". */
973     gtk_signal_connect (GTK_OBJECT (boton), "clicked",
974                         GTK_SIGNAL_FUNC (callback), (gpointer) "botón 2");
975
976     gtk_box_pack_start(GTK_BOX(caja1), boton, TRUE, TRUE, 0);
977
978     /* El orden en que mostramos los botones no es realmente
979      * importante, pero se recomienda mostrar la ventana la última
980      * para que todo aparezca de golpe. */
981     gtk_widget_show(boton);
982
983     gtk_widget_show(caja1);
984
985     gtk_widget_show (ventana);
986
987     /* Esperamos en gtk_main a que comience el espectáculo.*/
988     gtk_main ();
989
990     return 0;
991 }
992 /* final del ejemplo*/
993 </verb></tscreen>
994
995 Compile el programa usando los mismos argumentos que en el ejemplo
996 anterior. Probablemente ya se habrá dado cuenta de que no hay una
997 forma sencilla para terminar el programa, se debe usar el gestor de
998 ventanas o la línea de comandos para ello. Un buen ejercicio para
999 el lector es introducir un tercer botón que termine el
1000 programa. También puede resultar interesante probar las diferentes
1001 opciones de gtk_box_pack_start() mientras lee la siguiente
1002 sección. Intente cambiar el tamaño de la ventana y observe el
1003 comportamiento. 
1004
1005 Como última nota, existe otra definición bastante útil:
1006 gtk_widow_new() - GTK_WINDOW_DIALOG. Su comportamiento es un poco
1007 diferente y debe ser usado para ventanas intermedias (cuadros de
1008 diálogo).
1009
1010 <!-- ***************************************************************** -->
1011 <sect><em/Widgets/ usados para empaquetar
1012 <!-- ***************************************************************** -->
1013 <p>
1014 Al crear una aplicación normalmente se quiere que haya más de un
1015 <em/widget/ por ventana. Nuestro primer ejemplo sólo usaba un
1016 <em/widget/ por lo que usábamos la función gtk_container_add
1017 para «empaquetar» el <em/widget/ en la ventana. Pero cuando cuando
1018 se quiere poner más de un <em/widget/ en una ventana, ¿Cómo
1019 podemos controlar donde aparecerá el <em/widget/?. Aquí es donde
1020 entra el empaquetamiento.
1021
1022 <!-- ----------------------------------------------------------------- -->
1023 <sect1>Empaquetamiento usando cajas
1024 <p>
1025 Normalmente para empaquetar se usan cajas, tal y como ya hemos
1026 visto. Éstas son <em/widgets/ invisibles que pueden contener
1027 nuestros <em/widgets/ de dos formas diferentes, horizontal o
1028 verticalmente. Al hacerlo de la primera forma los objetos son
1029 insertados de izquierda a derecha o al revés (dependiendo de que
1030 llamada se use). Lo mismo ocurre en los verticales (de arriba a bajo o
1031 al revés). Se pueden usar tantas cajas como se quieran para
1032 conseguir cualquier tipo de efecto.
1033
1034 Para crear una caja horizontal llamamos a gtk_hbox_new() y para las
1035 verticales gtk_vbox_new(). Las funciones usadas para introducir
1036 objetos dentro son gtk_box_pack_start() y gtk_box_pack_end(). La
1037 primera llenará de arriba a abajo o de izquierda a derecha. La
1038 segunda lo hará al revés.
1039 Usando estas funciones podemos ir metiendo <em/widgets/ con una
1040 justificación a la izquierda o a la derecha y además podemos
1041 mezclarlas de cualquier manera para conseguir el efecto
1042 deseado. Nosotros usaremos gtk_box_pack_start() en la mayoria de
1043 nuestros ejemplos. Un objeto puede ser otro contenedor o un
1044 <em/widget/. De hecho, muchos <em/widgets/ son contenedores,
1045 incluyendo el <em/widget/ botón (button) (aunque normalmente lo
1046 único que meteremos dentro será una etiqueta de texto).
1047
1048 Mediante el uso de estas funciones le decimos a GTK dónde queremos
1049 situar nuestros widgets, y GTK podrá, por ejemplo, cambiarles el
1050 tamaño de forma automática y hacer otras cosas de
1051 utilidad. También hay unas cuantas opciones que tienen que ver con
1052 la forma en la que los <em/widgets/ serán empaquetados. Como puede
1053 imaginarse, este método nos da una gran flexibilidad a la hora de
1054 colocar y crear <em/widgets/. 
1055
1056 <!-- ----------------------------------------------------------------- -->
1057 <sect1>Detalles de la cajas.
1058 <p>
1059 Debido a esta flexibilidad el empaquetamiento puede ser confuso al
1060 principio. Hay muchas opciones y no es obvio como encajan unas con
1061 otras. Pero en la práctica sólo hay cinco estilos diferentes.
1062
1063 <? <CENTER> >
1064 <?
1065 <IMG SRC="gtk_tut_packbox1.gif" VSPACE="15" HSPACE="10" WIDTH="528"
1066 HEIGHT="235" ALT="Imagen de ejemplo sobre el empaquetado con cajas">
1067 >
1068 <? </CENTER> >
1069
1070 Cada línea contiene una caja horizontal (hbox) con diferentes
1071 botones. La llamada a  gtk_box_pack es una manera de conseguir
1072 empaquetar cada uno de los botones dentro de la caja. Eso sí, cada uno
1073 de ellos se empaqueta de la misma forma que el resto (se llama con los
1074 mismos argumentos a gtk_box_pack_start()).
1075
1076 Esta es la declaración de la función gtk_box_pack_start:
1077
1078 <tscreen><verb>
1079 void gtk_box_pack_start( GtkBox    *box,
1080                          GtkWidget *hijo,
1081                          gint       expand,
1082                          gint       fill,
1083                          gint       padding );
1084 </verb></tscreen>
1085
1086 El primer argumento es la caja dónde se empaqueta, el segundo el
1087 objeto. Por ahora el objeto será un botón, ya que estamos
1088 empaquetando botones dentro de las cajas.
1089
1090 El argumento <tt/expand/ de gtk_box_pack_start() y de
1091 gtk_box_pack_end() controla si los <em/widgets/ son expandidos en la
1092 caja para rellenar todo el espacio de la misma (TRUE) o si por el
1093 contrario no se usa el espacio extra dentro de la caja
1094 (FALSE). Poniendo FALSE en <em/expand/ podremos hacer que nuestros
1095 <em/widgets/ tengan una justaficación a la derecha o a la
1096 izquierda. En caso contrario, los <em/widgets/ se expandirán para
1097 llenar toda la caja, y podemos conseguir el mismo efecto utilizando
1098 sólo una de las funciones gtk_box_pack_start o pack_end.
1099
1100 El argumento <tt/fill/ de gtk_box controla si el espacio extra se mete
1101 dentro de los objetos (TRUE) o como relleno extra (FALSE). Sólo
1102 tiene efecto si el argumento de expansión también es TRUE.
1103
1104 Al crear una nueva ventana la función debe ser parecida a esta:
1105
1106 <tscreen><verb>
1107 GtkWidget *gtk_hbox_new (gint homogeneous,
1108                          gint spacing);
1109 </verb></tscreen>
1110
1111 El argumento <tt/homogeneous/ (tanto para gtk_hbox_new como para
1112 gtk_vbox_new) controla si cada objeto en la caja tiene el mismo
1113 tamaño (anchura en una hbox o altura en una vbox). Si se activa, el
1114 argumento <tt/expand/ de las rutinas gtk_box_pack siempre estará
1115 activado.
1116
1117 Puede que el lector se esté haciendo la siguiente pregunta:
1118 ¿Cúal es la diferencia entre espaciar (establecido cuando se
1119 crea la caja) y rellenar (determinado cuando se empaquetan los
1120 elementos)? El espaciado se añade entre objetos, y el rellenado se
1121 hace en cada parte de cada objeto. La siguiente figura debe aclarar la
1122 cuestión.
1123
1124 <? <CENTER> >
1125 <?
1126 <IMG ALIGN="center" SRC="gtk_tut_packbox2.gif" WIDTH="509" HEIGHT="213"
1127 VSPACE="15" HSPACE="10" ALT="Imagen de ejemplo sobre el empaquetado con cajas">
1128 >
1129 <? </CENTER> >
1130
1131 Estudiemos el código usado para crear las imágenes
1132 anteriores. Con los comentarios no debería de haber ningún
1133 problema para entenderlo.
1134
1135 <!-- ----------------------------------------------------------------- -->
1136 <sect1>Programa demostración de empaquetamiento
1137 <p>
1138 <tscreen><verb>
1139 /* principio del ejemplo packbox packbox.c */
1140
1141 #include <stdio.h>
1142 #include "gtk/gtk.h"
1143
1144 void
1145 delete_event (GtkWidget *widget, GdkEvent *event, gpointer data)
1146 {
1147     gtk_main_quit ();
1148 }
1149
1150 /* Hacemos una hbox llena de etiquetas de botón. Los argumentos
1151  * para las variables que estamos interesados son pasados a esta
1152  * función. No mostramos la caja, pero hacemos todo lo que
1153  * queremos. */
1154 GtkWidget *make_box (gint homogeneous, gint spacing,
1155                      gint expand, gint fill, gint padding) 
1156 {
1157     GtkWidget *box;
1158     GtkWidget *boton;
1159     char padstr[80];
1160     
1161     /* creamos una nueva caja con los argumentos homogeneous y
1162      * spacing */
1163     box = gtk_hbox_new (homogeneous, spacing);
1164     
1165     /* crear una serie de botones */
1166     boton = gtk_button_new_with_label ("gtk_box_pack");
1167     gtk_box_pack_start (GTK_BOX (box), boton, expand, fill, padding);
1168     gtk_widget_show (boton);
1169     
1170     boton = gtk_button_new_with_label ("(box,");
1171     gtk_box_pack_start (GTK_BOX (box), boton, expand, fill, padding);
1172     gtk_widget_show (boton);
1173     
1174     boton = gtk_button_new_with_label ("boton,");
1175     gtk_box_pack_start (GTK_BOX (box), boton, expand, fill, padding);
1176     gtk_widget_show (boton);
1177     
1178     /* Este botón llevará por etiqueta el valor de expand */
1179     if (expand == TRUE)
1180             boton = gtk_button_new_with_label ("TRUE,");
1181     else
1182             boton = gtk_button_new_with_label ("FALSE,");
1183     
1184     gtk_box_pack_start (GTK_BOX (box), boton, expand, fill, padding);
1185     gtk_widget_show (boton);
1186     
1187     /* Este es el mismo caso que el de arriba, pero más compacto */
1188     boton = gtk_button_new_with_label (fill ? "TRUE," : "FALSE,");
1189     gtk_box_pack_start (GTK_BOX (box), boton, expand, fill, padding);
1190     gtk_widget_show (boton);
1191     
1192     sprintf (padstr, "%d);", padding);
1193     
1194     boton = gtk_button_new_with_label (padstr);
1195     gtk_box_pack_start (GTK_BOX (box), boton, expand, fill, padding);
1196     gtk_widget_show (boton);
1197     
1198     return box;
1199 }
1200
1201 int
1202 main (int argc, char *argv[])
1203 {
1204     GtkWidget *ventana;
1205     GtkWidget *boton;
1206     GtkWidget *caja1;
1207     GtkWidget *caja2;
1208     GtkWidget *separator;
1209     GtkWidget *etiqueta;
1210     GtkWidget *quitbox;
1211     int which;
1212     
1213     /* ¡No olvidar la siguiente llamada! */
1214     gtk_init (&amp;argc, &amp;argv);
1215     
1216     if (argc != 2) {
1217         fprintf (stderr, "usage: packbox num, where num is 1, 2, or 3.\n");
1218         /* hacemos limpieza en GTK y devolvemos el valor de 1 */
1219         gtk_exit (1);
1220     }
1221     
1222     which = atoi (argv[1]);
1223
1224     /* Creamos la ventana */
1225     ventana = gtk_window_new (GTK_WINDOW_TOPLEVEL);
1226
1227     /* Siempre hay que conectar la señal de destrucción con la
1228      * ventana principal. Esto es muy importante para que el
1229      * comportamiento de la ventana sea intuitivo. */
1230     gtk_signal_connect (GTK_OBJECT (ventana), "delete_event",
1231                         GTK_SIGNAL_FUNC (delete_event), NULL);
1232     gtk_container_border_width (GTK_CONTAINER (ventana), 10);
1233     
1234     /* Creamos una caja vertical donde empaquetaremos las cajas
1235      * horizontales. Así podemos apilar las cajas horizontales
1236      * llenas con botones una encima de las otras. */
1237     caja1 = gtk_vbox_new (FALSE, 0);
1238     
1239     /* Aclaramos cúal es el ejemplo a mostrar. Se corresponde con
1240      * las imágenes anteriores. */
1241     switch (which) {
1242     case 1:
1243       /* creamos una nueva etiqueta. */
1244         etiqueta = gtk_label_new ("gtk_hbox_new (FALSE, 0);");
1245         
1246       /* Alineamos la etiqueta a la izquierda. Está función
1247        * será discutida en detalle en la sección de los
1248        * atributos de los widgets. */
1249         gtk_misc_set_alignment (GTK_MISC (etiqueta), 0, 0);
1250
1251       /* Empaquetamos la etiqueta en la caja vertical (vbox
1252        * caja1). Siempre hay que recordar que los widgets añadidos a
1253        * una vbox serán empaquetados uno encimo de otro. */
1254         gtk_box_pack_start (GTK_BOX (caja1), etiqueta, FALSE, FALSE, 0);
1255
1256       /* mostramos la etiqueta. */
1257         gtk_widget_show (etiqueta);
1258         
1259       /* llamada a la función que hace las cajas. Los argumentos
1260        * son homogenous = FALSE, expand = FALSE, fill = FALSE,
1261        * padding = 0 */
1262         caja2 = make_box (FALSE, 0, FALSE, FALSE, 0);
1263         gtk_box_pack_start (GTK_BOX (caja1), caja2, FALSE, FALSE, 0);
1264         gtk_widget_show (caja2);
1265
1266         /* Llamad a la función para hacer cajas -
1267          * homogeneous = FALSE, spacing = 0, expand = FALSE,
1268          * fill = FALSE, padding = 0 */
1269         caja2 = make_box (FALSE, 0, TRUE, FALSE, 0);
1270         gtk_box_pack_start (GTK_BOX (caja1), caja2, FALSE, FALSE, 0);
1271         gtk_widget_show (caja2);
1272         
1273         /* Los argumentos son: homogeneous, spacing, expand, fill,
1274          * padding */
1275         caja2 = make_box (FALSE, 0, TRUE, TRUE, 0);
1276         gtk_box_pack_start (GTK_BOX (caja1), caja2, FALSE, FALSE, 0);
1277         gtk_widget_show (caja2);
1278         
1279         
1280         /* creamos un separador. Más tarde aprenderemos más cosas
1281          * sobre ellos, pero son bastante sencillos. */
1282         separator = gtk_hseparator_new ();
1283         
1284         /* empaquetamos el separador el la vbox. Los widgets serán
1285          * apilados verticalmente. */
1286         gtk_box_pack_start (GTK_BOX (caja1), separator, FALSE, TRUE, 5);
1287         gtk_widget_show (separator);
1288         
1289         /* creamos una nueva etiqueta y la mostramos */
1290         etiqueta = gtk_label_new ("gtk_hbox_new (TRUE, 0);");
1291         gtk_misc_set_alignment (GTK_MISC (etiqueta), 0, 0);
1292         gtk_box_pack_start (GTK_BOX (caja1), etiqueta, FALSE, FALSE, 0);
1293         gtk_widget_show (etiqueta);
1294         
1295         /* Los argumentos son: homogeneous, spacing, expand, fill,
1296          * padding */
1297         caja2 = make_box (TRUE, 0, TRUE, FALSE, 0);
1298         gtk_box_pack_start (GTK_BOX (caja1), caja2, FALSE, FALSE, 0);
1299         gtk_widget_show (caja2);
1300         
1301         /* Los argumentos son: homogeneous, spacing, expand, fill,
1302          * padding */
1303         caja2 = make_box (TRUE, 0, TRUE, TRUE, 0);
1304         gtk_box_pack_start (GTK_BOX (caja1), caja2, FALSE, FALSE, 0);
1305         gtk_widget_show (caja2);
1306         
1307         /* un nuevo separador */
1308         separator = gtk_hseparator_new ();
1309         /* Los tres últimos argumentos son: expand, fill, padding. */
1310         gtk_box_pack_start (GTK_BOX (caja1), separator, FALSE, TRUE, 5);
1311         gtk_widget_show (separator);
1312         
1313         break;
1314
1315     case 2:
1316
1317         /* Nueva etiqueta */
1318         etiqueta = gtk_label_new ("gtk_hbox_new (FALSE, 10);");
1319         gtk_misc_set_alignment (GTK_MISC (etiqueta), 0, 0);
1320         gtk_box_pack_start (GTK_BOX (caja1), etiqueta, FALSE, FALSE, 0);
1321         gtk_widget_show (etiqueta);
1322         
1323         /* Los argumentos son: homogeneous, spacing, expand, fill,
1324          * padding */
1325         caja2 = make_box (FALSE, 10, TRUE, FALSE, 0);
1326         gtk_box_pack_start (GTK_BOX (caja1), caja2, FALSE, FALSE, 0);
1327         gtk_widget_show (caja2);
1328         
1329         /* Los argumentos son: homogeneous, spacing, expand, fill,
1330          * padding */
1331         caja2 = make_box (FALSE, 10, TRUE, TRUE, 0);
1332         gtk_box_pack_start (GTK_BOX (caja1), caja2, FALSE, FALSE, 0);
1333         gtk_widget_show (caja2);
1334         
1335         separator = gtk_hseparator_new ();
1336         /* Los argumentos son: expand, fill, padding. */
1337         gtk_box_pack_start (GTK_BOX (caja1), separator, FALSE, TRUE, 5);
1338         gtk_widget_show (separator);
1339         
1340         etiqueta = gtk_label_new ("gtk_hbox_new (FALSE, 0);");
1341         gtk_misc_set_alignment (GTK_MISC (etiqueta), 0, 0);
1342         gtk_box_pack_start (GTK_BOX (caja1), etiqueta, FALSE, FALSE, 0);
1343         gtk_widget_show (etiqueta);
1344         
1345         /* Los argumentos son: homogeneous, spacing, expand, fill,
1346          * padding */
1347         caja2 = make_box (FALSE, 0, TRUE, FALSE, 10);
1348         gtk_box_pack_start (GTK_BOX (caja1), caja2, FALSE, FALSE, 0);
1349         gtk_widget_show (caja2);
1350         
1351         /* Los argumentos son: homogeneous, spacing, expand, fill,
1352          * padding */
1353         caja2 = make_box (FALSE, 0, TRUE, TRUE, 10);
1354         gtk_box_pack_start (GTK_BOX (caja1), caja2, FALSE, FALSE, 0);
1355         gtk_widget_show (caja2);
1356         
1357         separator = gtk_hseparator_new ();
1358         /* Los argumentos son: expand, fill, padding. */
1359         gtk_box_pack_start (GTK_BOX (caja1), separator, FALSE, TRUE, 5);
1360         gtk_widget_show (separator);
1361         break;
1362     
1363     case 3:
1364
1365         /* Con esto demostramos como hay que usar gtk_box_pack_end ()
1366          * para conseguir que los 
1367         widgets esten alineados a la izquierda. */
1368         caja2 = make_box (FALSE, 0, FALSE, FALSE, 0);
1369         
1370         /* la última etiqueta*/ 
1371         etiqueta = gtk_label_new ("end");
1372
1373         /* la empaquetamos usando gtk_box_pack_end(), por lo que se
1374          * sitúa en el lado derecho de la hbox.*/
1375         gtk_box_pack_end (GTK_BOX (caja2), etiqueta, FALSE, FALSE, 0);
1376
1377         /* mostrar la etiqueta */
1378         gtk_widget_show (etiqueta);
1379         
1380
1381         /* empaquetamos caja2 en caja1 */
1382         gtk_box_pack_start (GTK_BOX (caja1), caja2, FALSE, FALSE, 0);
1383         gtk_widget_show (caja2);
1384         
1385         
1386         /* el separador para la parte de abajo. */
1387         separator = gtk_hseparator_new ();
1388
1389         /* Así se determina el tamaño del separador a 400 pixels
1390          * de largo por 5 de alto. La hbox también tendrá 400
1391          * pixels de largo y la etiqueta "end" estará separada de 
1392          * las demás etiquetas en la hbox. Si no establecemos estos
1393          * parámetros todos los widgets en la hbox serán
1394          * empaquetados tan juntos como se pueda.*/ 
1395         gtk_widget_set_usize (separator, 400, 5);
1396
1397         /* Empaquetamos el separador creado al principio de main() en
1398          * la vbox (caja1). */
1399         gtk_box_pack_start (GTK_BOX (caja1), separator, FALSE, TRUE, 5);
1400         gtk_widget_show (separator);    
1401     }
1402     
1403     /* Creamos otra hbox... recordar que podemos crear tantas como
1404      * queramos. */
1405     quitbox = gtk_hbox_new (FALSE, 0);
1406     
1407     /* El botón de salida. */
1408     boton = gtk_button_new_with_label ("Quit");
1409     
1410     /* Establecemos la señal de destrucción de la ventana.
1411      * Recuerde que emitirá la señal de "destroy" que a su vez
1412      * será procesada por el controlador de señales, tal y como
1413      * ya hemos visto. */
1414   
1415     gtk_signal_connect_object (GTK_OBJECT (boton), "clicked",
1416                                GTK_SIGNAL_FUNC (gtk_main_quit),
1417                                GTK_OBJECT (ventana));
1418     /* Empaquetamos el botón en la caja de salida (quitbox).
1419      * los tres últimos argumentos de gtk_box_pack_start
1420      * son:expand, fill, padding. */
1421     gtk_box_pack_start (GTK_BOX (caja1), quitbox, FALSE, FALSE, 0);
1422     
1423     /* empaquetamos la vbox (caja1) que ya contiene todos los widgets
1424      * en la ventana principal. */
1425     gtk_container_add (GTK_CONTAINER (ventana), caja1);
1426     
1427     /* mostramos todo aquello que faltaba por mostrar */
1428     gtk_widget_show (boton);
1429     gtk_widget_show (quitbox);
1430     
1431     gtk_widget_show (caja1);
1432
1433     /* Si mostramos la ventana lo último todo aparece de golpe. */
1434     gtk_widget_show (ventana);
1435   
1436     /* por supuesto tenemos una función main. */
1437     gtk_main ();
1438
1439     /* El programa llega aquí cuando se llama a gtk_main_quit(),
1440      * pero no cuando se llama a gtk_exit(). */
1441     return 0;
1442 }
1443 /* final del ejemplo*/
1444 </verb></tscreen>
1445
1446 <!-- ----------------------------------------------------------------- -->
1447 <sect1>Empaquetamiento usando tablas
1448 <p>
1449 Existe otra forma de empaquetar: usando tablas. Estas pueden llegar a
1450 ser extremadamente útiles.
1451
1452 Usando tablas creamos una cuadrícula donde podemos poner los
1453 widgets. Estos pueden ocupar tanto espacio como queramos.
1454
1455 La primera función que conviene estudiar es gtk_table_new:
1456
1457 <tscreen><verb>
1458 GtkWidget *gtk_table_new( gint rows,
1459                           gint columns,
1460                           gint homogeneous );
1461 </verb></tscreen>
1462
1463 Como es lógico el primer argumento es el número de filas y el
1464 segundo el de columnas.
1465
1466 El tercero establece el tamaño de las celdas de la tabla. Si es TRUE
1467 se fuerza a que el tamaño de las celdas sea igual al de la celda
1468 mayor. Con FALSE se establece el ancho de toda una columna igual al de
1469 la celda más ancha de esa columna, y la altura de una fila será
1470 la de la celda más alta de esa fila.
1471
1472 El número de filas y columnas varía entre 0 y n, donde n es el
1473 número especificado en la llamada a gtk_table_new. Así si se
1474 especifica columnas = 2 y filas = 2 la apariencia será parecida a:
1475
1476 <tscreen><verb>
1477  0          1          2
1478 0+----------+----------+
1479  |          |          |
1480 1+----------+----------+
1481  |          |          |
1482 2+----------+----------+
1483 </verb></tscreen>
1484
1485 Conviene destacar que el origen de coordenadas se sitúa en la esquina superior izquierda. Para
1486 situar un widget en una ventana se usa la siguiente función:
1487
1488 <tscreen><verb>
1489 void gtk_table_attach( GtkTable  *table,
1490                        GtkWidget *hijo,
1491                        gint       left_attach,
1492                        gint       right_attach,
1493                        gint       top_attach,
1494                        gint       bottom_attach,
1495                        gint       xoptions,
1496                        gint       yoptions,
1497                        gint       xpadding,
1498                        gint       ypadding );
1499 </verb></tscreen>                                      
1500
1501 El primer argumento (<tt/table/) es el nombre de la tabla y el segundo
1502 (<tt/hijo/) el <em/widget/ que quiere poner en la tabla.
1503
1504 Los argumentos <tt/left_attach/, <tt/right_attach/ especifican donde
1505 se pone el widget y cuantas cajas se usan. Por ejemplo, supongamos que
1506 queremos poner un botón que sólo ocupe la esquina inferior
1507 izquierda en nuestra tabla 2x2. Los valores serán left_attach = 1,
1508 right_attach = 2, top_attach = 2, top_attach = 1, bottom_attach = 2. 
1509
1510 Supongamos que queremos ocupar toda la fila de nuestra tabla 2x2,
1511 usaríamos left_attach = 0, right_attach = 2, top_attach = 0,
1512 bottom_attach = 1.
1513
1514 Las opciones <tt/xoptions/ e <tt/yoptions/ son usadas para especificar
1515 como queremos el empaquetamiento y podemos utilizar multiples
1516 opciones simultaneamente con OR.
1517
1518 Las opciones son:
1519
1520 <itemize>
1521 <item>GTK_FILL - Si el relleno es más grande que el widget, y se
1522 especifica GTK_FILL, el <em/widget/ se expandirá ocupando todo el
1523 espacio disponible.
1524
1525 <item>GTK_SHRINK - En el caso de que hayamos dejado espacio sin usar
1526 cuando el usuario reajuste el tamaño de la ventana los <em/widgets/
1527 normalmente serán empujados al fondo de la ventana y
1528 desaparecerán. Si especifica GTK_SHRINK los widgets se reducirán
1529 con la tabla.
1530
1531 <item>GTK_EXPAND - Mediante esta opción la tabla se expande usando
1532 todo el espacio libre de la ventana.
1533 </itemize>
1534   
1535 El relleno es igual que con las cajas. Simplemente se crea una zona
1536 vacía alrededor del widget (el tamaño se especifica en pixels).
1537
1538 gtk_table_attach() tiene MUCHAS opciones. Asi que hay un atajo:
1539
1540 <tscreen><verb>
1541 void gtk_table_attach_defaults( GtkTable  *table,
1542                                 GtkWidget *widget,
1543                                 gint       left_attach,
1544                                 gint       right_attach,
1545                                 gint       top_attach,
1546                                 gint       bottom_attach );
1547 </verb></tscreen>
1548
1549 Las opciones X e Y se ponen por defecto a GTK_FILL | GTK_EXPAND, y el
1550 relleno X e Y se pone a 0. El resto de los argumentos son identicos a
1551 la función anterior.
1552
1553 Existen otras funciones como gtk_table_set_row_spacing() y
1554 gtk_table_set_col_spacing(), que sirven para especificar el espaciado
1555 entre las columnas/filas en la columna/fila que queramos.
1556
1557 <tscreen><verb>
1558 void gtk_table_set_row_spacing( GtkTable *table,
1559                                 gint      row,
1560                                 gint      spacing );
1561 </verb></tscreen>
1562
1563 y
1564
1565 <tscreen><verb>
1566 void gtk_table_set_col_spacing ( GtkTable *table,
1567                                  gint      column,
1568                                  gint      spacing );
1569 </verb></tscreen>
1570
1571 Conviene destacar que el espaciado se sitúa a la derecha de la
1572 columna y debajo de la fila.
1573
1574 Tambien se puede forzar que el espaciado sea el mismo para las filas
1575 y/o las columnas:
1576
1577 <tscreen><verb>
1578 void gtk_table_set_row_spacings( GtkTable *table,
1579                                  gint      spacing );
1580 </verb></tscreen>
1581
1582 y
1583
1584 <tscreen><verb>
1585 void gtk_table_set_col_spacings( GtkTable *table,
1586                                  gint      spacing );
1587 </verb></tscreen>
1588
1589 Usando estas funciones las últimas fila y columna no estarán
1590 espaciadas.
1591
1592 <!-- ----------------------------------------------------------------- -->
1593 <sect1>Ejemplo de empaquetamiento mediante tablas.
1594 <p>
1595 Haremos una ventana con tres botones en una tabla 2x2. Los dos
1596 primeros botones ocuparán la fila de arriba, mientras que el
1597 tercero (de salida) ocupará toda la fila de abajo. El resultado es
1598 el siguiente:
1599
1600 <? <CENTER> >
1601 <?
1602 <IMG SRC="gtk_tut_table.gif" VSPACE="15" HSPACE="10" 
1603 ALT="Imagen de ejemplo sobre el empaquetado mediante tablas" WIDTH="180" HEIGHT="120">
1604 >
1605 <? </CENTER> >
1606
1607 Este es el código:
1608 <tscreen><verb>
1609 /* principio del ejemplo table table.c */
1610
1611 #include <gtk/gtk.h>
1612
1613 /* La respuesta, que además se imprime en stdout. */
1614 void callback (GtkWidget *widget, gpointer data)
1615 {
1616     g_print ("Hello again - %s was pressed\n", (char *) data);
1617 }
1618
1619 /* Con esta otra respuesta terminamos el programa. */
1620 void delete_event (GtkWidget *widget, GdkEvent *event, gpointer data)
1621 {
1622     gtk_main_quit ();
1623 }
1624
1625 int main (int argc, char *argv[])
1626 {
1627     GtkWidget *ventana;
1628     GtkWidget *boton;
1629     GtkWidget *table;
1630
1631     gtk_init (&amp;argc, &amp;argv);
1632
1633     ventana = gtk_window_new (GTK_WINDOW_TOPLEVEL);
1634
1635     gtk_window_set_title (GTK_WINDOW (ventana), "Table");
1636
1637     gtk_signal_connect (GTK_OBJECT (ventana), "delete_event",
1638                         GTK_SIGNAL_FUNC (delete_event), NULL);
1639
1640     gtk_container_border_width (GTK_CONTAINER (ventana), 20);
1641
1642     table = gtk_table_new (2, 2, TRUE);
1643
1644     gtk_container_add (GTK_CONTAINER (ventana), table);
1645
1646     boton = gtk_button_new_with_label ("botón 1");
1647
1648     gtk_signal_connect (GTK_OBJECT (boton), "clicked",
1649               GTK_SIGNAL_FUNC (callback), (gpointer) "botón 1");
1650
1651     gtk_table_attach_defaults (GTK_TABLE(table), boton, 0, 1, 0, 1);
1652
1653     gtk_widget_show (boton);
1654
1655     boton = gtk_button_new_with_label ("botón 2");
1656
1657     gtk_signal_connect (GTK_OBJECT (boton), "clicked",
1658               GTK_SIGNAL_FUNC (callback), (gpointer) "botón 2");
1659     gtk_table_attach_defaults (GTK_TABLE(table), boton, 1, 2, 0, 1);
1660
1661     gtk_widget_show (boton);
1662
1663     boton = gtk_button_new_with_label ("Quit");
1664
1665     gtk_signal_connect (GTK_OBJECT (boton), "clicked",
1666                         GTK_SIGNAL_FUNC (delete_event), NULL);
1667     gtk_table_attach_defaults (GTK_TABLE(table), boton, 0, 2, 1, 2);
1668
1669     gtk_widget_show (boton);
1670
1671     gtk_widget_show (table);
1672     gtk_widget_show (ventana);
1673
1674     gtk_main ();
1675
1676     return 0;
1677 }
1678 /* final del ejemplo */
1679 </verb></tscreen>
1680
1681 <!-- ***************************************************************** -->
1682 <sect>Estudio general de los <em/widgets/
1683 <!-- ***************************************************************** -->
1684 <p>
1685 Los pasos generales a la hora de crear un <em/widget/ son:
1686
1687 <enum>
1688
1689 <item> Usar gtk_*_new - Una de las diferentes formas de crear un
1690 <em/widget/. (Todas serán explicadas en esta sección).
1691
1692 <item> Connectar todas las señales y los eventos a los
1693 controladores apropiados.
1694
1695 <item> Establecer los atributos del <em/widget/.
1696
1697 <item> Empaquetar el <em/widget/ en un contenedor usando las llamadas
1698 apropiadas, como gtk_container_add() o gtk_box_pack_start().
1699
1700 <item> Mostrar el <em/widget/ usando gtk_widget_show(). 
1701
1702 </enum>
1703
1704 Mediante esta última llamada GTK `sabe' que hemos acabado de
1705 establecer los atributos del <em/widget/, y que por lo tanto puede
1706 mostrarse. Se puede usar gtk_widget_hide para hacer que desaparezca.
1707 El orden en el que se muestran los <em/widgets/ no es importante, pero
1708 se recomienda mostrar al final la ventana para que todo aparezca de
1709 golpe. El hijo de un <em/widget/ no se muestra hasta que lo hace la
1710 propia ventana (que en este caso es un <em/widget/ padre) mediante 
1711 gtk_widget_show().
1712
1713
1714 <!-- ----------------------------------------------------------------- -->
1715 <sect1> Conversión de tipos
1716 <p>
1717 GTK usa un sistema de conversión de tipos mediante macros que 
1718 comprueban si se puede realizar la conversión y en caso 
1719 afirmativo la hacen. Las más comunes son:
1720
1721 <itemize>
1722 <item> GTK_WIDGET(widget)
1723 <item> GTK_OBJECT(object)
1724 <item> GTK_SIGNAL_FUNC(function)
1725 <item> GTK_CONTAINER(container)
1726 <item> GTK_WINDOW(ventana)
1727 <item> GTK_BOX(box)
1728 </itemize>
1729
1730 Todas son usadas para cambiar de tipo los argumentos de una función. 
1731 Aparecerán mucho en los ejemplos, para usarlas sólo hay que mirar la 
1732 declaración de la función.
1733
1734 Tal y como se puede ver en el árbol de clases (situado un poco
1735 más adelante) todos los <em/widgets/ derivan de la clase base
1736 GtkObject. Esto significa que siempre se puede usar un <em/widget/
1737 como argumento de una función (que acepte un objeto, claro)
1738 realizando la conversión de tipo GTK_OBJECT().
1739
1740 Por ejemplo:
1741
1742 <tscreen><verb>
1743 gtk_signal_connect( GTK_OBJECT(boton), "clicked",
1744                     GTK_SIGNAL_FUNC(callback_function), callback_data);
1745 </verb></tscreen> 
1746
1747 Hemos hecho que el botón pase a ser un objeto y que se cambie el
1748 puntero a la función a una función respuesta.
1749
1750 Muchos <em/widgets/ son contenedores, por lo que unos pueden derivar
1751 de otros (la mayoría lo hace de GtkContainer). Cualquiera puede ser
1752 usado junto con la macro GTK_CONTAINER como argumento a funciones en
1753 forma de puntero.
1754
1755 Desgraciadamente estas macros no son descritas en detalle en el
1756 tutorial, por lo que se recomienda echar un vistazo a los archivos de
1757 cabecera de GTK. En la práctica es posible aprender a manejar un
1758 <em/widget/ leyendo las declaraciones de las funciones.
1759
1760 <!-- ----------------------------------------------------------------- -->
1761 <sect1>Árbol formado por los <em/widgets/
1762 <p>
1763 A continuación se detallan todas las ramas del árbol que forman
1764 los <em/widgets/.
1765
1766 <tscreen><verb>
1767  GtkObject
1768   +GtkWidget
1769   | +GtkMisc
1770   | | +GtkLabel
1771   | | | +GtkAccelLabel
1772   | | | `GtkTipsQuery
1773   | | +GtkArrow
1774   | | +GtkImage
1775   | | `GtkPixmap
1776   | +GtkContainer
1777   | | +GtkBin
1778   | | | +GtkAlignment
1779   | | | +GtkFrame
1780   | | | | `GtkAspectFrame
1781   | | | +GtkButton
1782   | | | | +GtkToggleButton
1783   | | | | | `GtkCheckButton
1784   | | | | |   `GtkRadioButton
1785   | | | | `GtkOptionMenu
1786   | | | +GtkItem
1787   | | | | +GtkMenuItem
1788   | | | | | +GtkCheckMenuItem
1789   | | | | | | `GtkRadioMenuItem
1790   | | | | | `GtkTearoffMenuItem
1791   | | | | +GtkListItem
1792   | | | | `GtkTreeItem
1793   | | | +GtkWindow
1794   | | | | +GtkColorSelectionDialog
1795   | | | | +GtkDialog
1796   | | | | | `GtkInputDialog
1797   | | | | +GtkDrawWindow
1798   | | | | +GtkFileSelection
1799   | | | | +GtkFontSelectionDialog
1800   | | | | `GtkPlug
1801   | | | +GtkEventBox
1802   | | | +GtkHandleBox
1803   | | | +GtkScrolledWindow
1804   | | | `GtkViewport
1805   | | +GtkBox
1806   | | | +GtkButtonBox
1807   | | | | +GtkHButtonBox
1808   | | | | `GtkVButtonBox
1809   | | | +GtkVBox
1810   | | | | +GtkColorSelection
1811   | | | | `GtkGammaCurve
1812   | | | `GtkHBox
1813   | | |   +GtkCombo
1814   | | |   `GtkStatusbar
1815   | | +GtkCList
1816   | | | `GtkCTree
1817   | | +GtkFixed
1818   | | +GtkNotebook
1819   | | | `GtkFontSelection
1820   | | +GtkPaned
1821   | | | +GtkHPaned
1822   | | | `GtkVPaned
1823   | | +GtkLayout
1824   | | +GtkList
1825   | | +GtkMenuShell
1826   | | | +GtkMenuBar
1827   | | | `GtkMenu
1828   | | +GtkPacker
1829   | | +GtkSocket
1830   | | +GtkTable
1831   | | +GtkToolbar
1832   | | `GtkTree
1833   | +GtkCalendar
1834   | +GtkDrawingArea
1835   | | `GtkCurve
1836   | +GtkEditable
1837   | | +GtkEntry
1838   | | | `GtkSpinButton
1839   | | `GtkText
1840   | +GtkRuler
1841   | | +GtkHRuler
1842   | | `GtkVRuler
1843   | +GtkRange
1844   | | +GtkScale
1845   | | | +GtkHScale
1846   | | | `GtkVScale
1847   | | `GtkScrollbar
1848   | |   +GtkHScrollbar
1849   | |   `GtkVScrollbar
1850   | +GtkSeparator
1851   | | +GtkHSeparator
1852   | | `GtkVSeparator
1853   | +GtkPreview
1854   | `GtkProgress
1855   |   `GtkProgressBar
1856   +GtkData
1857   | +GtkAdjustment
1858   | `GtkTooltips
1859   `GtkItemFactory
1860 </verb></tscreen>
1861
1862 <!-- ----------------------------------------------------------------- -->
1863 <sect1><em/Widgets/ sin ventanas
1864 <p>
1865 Los siguientes <em/widgets/ no tienen ventanas asociadas. Si se
1866 quieren capturar eventos se tendrá que utilizar GtkEventBox. En la
1867 sección <ref id="sec_The_EventBox_Widget" name="El widget
1868 EventBox"> se pueden encontrar más detalles sobre su uso.
1869
1870 <tscreen><verb>
1871 GtkAlignment
1872 GtkArrow
1873 GtkBin
1874 GtkBox
1875 GtkImage
1876 GtkItem
1877 GtkLabel
1878 GtkPixmap
1879 GtkScrolledWindow
1880 GtkSeparator
1881 GtkTable
1882 GtkAspectFrame
1883 GtkFrame
1884 GtkVBox
1885 GtkHBox
1886 GtkVSeparator
1887 GtkHSeparator
1888 </verb></tscreen>
1889
1890 Vamos a continuar la explicación describiendo cada uno de los
1891 <em/widgets/ mediante ejemplos. También se puede consultar el
1892 programa testgtk.c (Se encuentra en gtk/testgtk.c).
1893
1894 <!-- ***************************************************************** -->
1895 <sect>El <em/widget/ Botón
1896 <!-- ***************************************************************** -->
1897
1898 <!-- ----------------------------------------------------------------- -->
1899 <sect1>Botones normales <label id="sec_Radio_Buttons">
1900 <p>
1901 Ya hemos visto prácticamente todo lo que hay que saber a cerca de
1902 este <em/widget/. Existen dos formas diferentes de crear un
1903 botón. Se puede usar gtk_button_new_with_label() para conseguir un
1904 botón con etiqueta o simplemente gtk_button_new(). Si se quiere se
1905 puede añadir una etiqueta a este último empaquetándola,
1906 primero se crea una nueva caja y luego se empaquetan los objetos que
1907 se quieran mediante gtk_box_pack_start. Una vez finalizado esto se
1908 relaciona la caja con el botón mediante gtk_container_add.
1909
1910 Estudiemos un ejemplo de gtk_button_new para crear un botón con una
1911 imagen y una etiqueta. El código está dividido en dos para que
1912 pueda ser reusado.
1913
1914 <tscreen><verb>
1915 /* principio del ejemplo buttons buttons.c */
1916
1917 #include <gtk/gtk.h>
1918
1919 /* Creamos la caja con una imagen y una etiqueta empaquetadas. Se
1920  * devuelve la caja. */
1921 GtkWidget *xpm_label_box (GtkWidget *parent, gchar *xpm_filename, gchar *label_text)
1922 {
1923     GtkWidget *caja1;
1924     GtkWidget *etiqueta;
1925     GtkWidget *pixmapwid;
1926     GdkPixmap *pixmap;
1927     GdkBitmap *mask;
1928     GtkStyle *style;
1929
1930     /* create box for xpm and etiqueta */
1931     caja1 = gtk_hbox_new (FALSE, 0);
1932     gtk_container_border_width (GTK_CONTAINER (caja1), 2);
1933
1934     /* obtenemos el estilo del botón (probablemente para el color
1935      * de fondo, pero no estoy seguro) */
1936     style = gtk_widget_get_style(parent);
1937
1938     /* cargamos el pixmap. Hay una sección que describe el proceso
1939      * en detalle */
1940     pixmap = gdk_pixmap_create_from_xpm (parent->window, &amp;mask,
1941                                          &amp;style->bg[GTK_STATE_NORMAL],
1942                                          xpm_filename);
1943     pixmapwid = gtk_pixmap_new (pixmap, mask);
1944
1945     etiqueta = gtk_label_new (label_text);
1946
1947     gtk_box_pack_start (GTK_BOX (caja1),
1948                         pixmapwid, FALSE, FALSE, 3);
1949
1950     gtk_box_pack_start (GTK_BOX (caja1), etiqueta, FALSE, FALSE, 3);
1951
1952     gtk_widget_show(pixmapwid);
1953     gtk_widget_show(etiqueta);
1954
1955     return (caja1);
1956 }
1957
1958 /* respuesta */
1959 void callback (GtkWidget *widget, gpointer data)
1960 {
1961     g_print ("Hola de nuevo.  Se ha pulsado %s\n", (char *) data);
1962 }
1963
1964
1965 int main (int argc, char *argv[])
1966 {
1967  
1968     GtkWidget *ventana;
1969     GtkWidget *boton;
1970     GtkWidget *caja1;
1971
1972     gtk_init (&amp;argc, &amp;argv);
1973
1974     ventana = gtk_window_new (GTK_WINDOW_TOPLEVEL);
1975
1976     gtk_window_set_title (GTK_WINDOW (ventana), "Botones con dibujos");
1977
1978     /* It's a good idea to do this for all windows. */
1979     gtk_signal_connect (GTK_OBJECT (ventana), "destroy",
1980                         GTK_SIGNAL_FUNC (gtk_exit), NULL);
1981
1982     gtk_signal_connect (GTK_OBJECT (ventana), "delete_event",
1983                         GTK_SIGNAL_FUNC (gtk_exit), NULL);
1984
1985     gtk_container_border_width (GTK_CONTAINER (ventana), 10);
1986     gtk_widget_realize(ventana);
1987
1988     boton = gtk_button_new ();
1989
1990     gtk_signal_connect (GTK_OBJECT (boton), "clicked",
1991                         GTK_SIGNAL_FUNC (callback),
1992                         (gpointer) "botón divertido");
1993
1994     caja1 = xpm_label_box(ventana, "info.xpm", "botón divertido");
1995
1996     gtk_widget_show(caja1);
1997
1998     gtk_container_add (GTK_CONTAINER (boton), caja1);
1999
2000     gtk_widget_show(boton);
2001
2002     gtk_container_add (GTK_CONTAINER (ventana), boton);
2003
2004     gtk_widget_show (ventana);
2005
2006     gtk_main ();
2007
2008     return 0;
2009 }
2010 /* final del ejemplo */
2011 </verb></tscreen>
2012
2013 La función xpm_label_box puede ser usada para empaquetar xpm y
2014 etiquetas en cualquier widget que pueda ser un contenedor.
2015
2016 El botón puede responder a las siguientes señales:
2017
2018 <itemize>
2019 <item> pressed
2020 <item> released
2021 <item> clicked
2022 <item> enter
2023 <item> leave
2024 </itemize>
2025
2026 <!-- ----------------------------------------------------------------- -->
2027 <sect1> Botones de selección
2028 <p>
2029 Estos botones son muy similares a los normales. La única diferencia
2030 es que sólo pueden estar en dos posiciones diferentes alternadas
2031 mediante pulsaciones del ratón.
2032
2033 Los botones de selección son la base de otros tipos: los de
2034 comprobación y los circulares. Por lo tanto muchas de sus llamadas
2035 seran heredadas por estos.
2036
2037 Creamos un nuevo botón de selección:
2038
2039 <tscreen><verb>
2040 GtkWidget *gtk_toggle_button_new( void );
2041
2042 GtkWidget *gtk_toggle_button_new_with_label( gchar *etiqueta );
2043 </verb></tscreen>
2044
2045 Como se ha podido imaginar estas funciones son iguales a las de un
2046 botón normal. La primera crea un botón, mientras que la segunda
2047 crea un botón con una etiqueta.
2048
2049 Para saber cual es el estado de un botón de selección,
2050 comprobación o circular se usa una de las macros del ejemplo
2051 siguiente. En éstas se comprueba el estado del botón mediante
2052 una respuesta. La señal que queremos recibir es
2053 «toggled». Generalmente para comprobar el estado de una señal se
2054 establece un controlador de señales y luego se usa la siguiente
2055 macro. La función de respuesta debe ser de la forma:
2056
2057 <tscreen><verb>
2058 void toggle_button_callback (GtkWidget *widget, gpointer data)
2059 {
2060     if (GTK_TOGGLE_BUTTON (widget)->active) 
2061     {
2062         /* Si el control llega aquí el botón está pulsado */
2063     
2064     } else {
2065     
2066         /* El botón no está pulsado (sobresale) */
2067     }
2068 }
2069 </verb></tscreen>
2070
2071 <tscreen><verb>
2072 void gtk_toggle_button_set_state( GtkToggleButton *toggle_button,
2073                                   gint             state );
2074 </verb></tscreen>
2075
2076 La llamada de arriba puede ser usada para establecer el estado de un
2077 botón de selección (o de cualquiera de sus hijos: el circular o
2078 el de comprobación). El primer argumento es el botón, el segundo
2079 TRUE cuando queremos que el botón no esté pulsado o FALSE para
2080 cuando lo esté. Por defecto se establece FALSE.
2081
2082 Hay que destacar que cuando se usa gtk_toggle_button_set_state() y se
2083 cambia el estado del botón este emite la señal «clicked».
2084
2085 <tscreen><verb>
2086 void gtk_toggle_button_toggled (GtkToggleButton *toggle_button);
2087 </verb></tscreen>
2088
2089 Cambia el estado del botón emitiendo la señal «toggled».
2090 <!-- ----------------------------------------------------------------- -->
2091 <sect1> Botones de comprobación
2092 <p>
2093 Los botones de comprobación son un poco diferentes a los anteriores, aunque
2094 sus propiedades y funciones son bastante similares. En lugar de ser botones
2095 con texto en su interior son pequeños cuadrados con texto a su derecha. 
2096 Normalmente son usados para (des)seleccionar opciones.
2097
2098 Las dos funciones que los crean son muy similares a las de los botones
2099 normales.
2100
2101 <tscreen><verb>
2102 GtkWidget *gtk_check_button_new( void );
2103
2104 GtkWidget *gtk_check_button_new_with_label ( gchar *etiqueta );
2105 </verb></tscreen>
2106
2107 La función new_with_label crea un botón de comprobación con
2108 una etiqueta dentro.
2109
2110 El proceso para comprobar el estado de un botón de este tipo es
2111 igual al de los de comprobación.
2112
2113 <!-- ----------------------------------------------------------------- -->
2114 <sect1> Botones circulares
2115 <p>
2116 Estos botones son similares a los de selección con la salvedad de
2117 que están agrupados, de modo que sólo uno puede estar
2118 seleccionado. Por tanto son usados para permitir al usuario
2119 seleccionar algo de una lista de opciones mutuamente excluyentes.
2120
2121 Las llamadas para crear un botón circular son:
2122 <tscreen><verb>
2123 GtkWidget *gtk_radio_button_new( GSList *group );
2124
2125 GtkWidget *gtk_radio_button_new_with_label( GSList *group,
2126                                             gchar  *etiqueta );
2127 </verb></tscreen>
2128
2129 El nuevo argumento sirve para especificar el grupo al que
2130 pertenecen. La primera llamada debe pasar NULL como primer
2131 argumento. A continuación de ésta se puede crear el grupo
2132 usando:
2133
2134 <tscreen><verb>
2135 GSList *gtk_radio_button_group( GtkRadioButton *radio_button );
2136 </verb></tscreen>
2137
2138 Para añadir un nuevo botón a un grupo hay que usar
2139 gtk_radio_button_group con el anterior botón como argumento. El
2140 resultado se le pasa a gtk_radio_button_new o a
2141 gtk_radio_button_new_with_label. Así se consigue enlazar una cadena
2142 de botones. (El ejemplo siguiente sirve para aclarar el proceso)
2143
2144 También se puede establecer cúal es el botón pulsado por
2145 defecto:
2146
2147 <tscreen><verb>
2148 void gtk_toggle_button_set_state( GtkToggleButton *toggle_button,
2149                                   gint             state );
2150 </verb></tscreen>
2151 El siguiente ejemplo crea un grupo de tres botones:
2152
2153 <tscreen><verb>
2154 /* Principio del ejemplo radiobuttons.c */
2155
2156 #include <gtk/gtk.h>
2157 #include <glib.h>
2158
2159 void close_application( GtkWidget *widget, GdkEvent *event, gpointer data ) {
2160   gtk_main_quit();
2161 }
2162
2163 main(int argc,char *argv[])
2164 {
2165   static GtkWidget *ventana = NULL;
2166   GtkWidget *caja1;
2167   GtkWidget *caja2;
2168   GtkWidget *boton;
2169   GtkWidget *separator;
2170   GSList *group;
2171   
2172   gtk_init(&amp;argc,&amp;argv);          
2173   ventana = gtk_window_new (GTK_WINDOW_TOPLEVEL);
2174   
2175   gtk_signal_connect (GTK_OBJECT (ventana), "delete_event",
2176                       GTK_SIGNAL_FUNC(close_application),
2177                       NULL);
2178
2179   gtk_window_set_title (GTK_WINDOW (ventana), "radio buttons");
2180   gtk_container_border_width (GTK_CONTAINER (ventana), 0);
2181
2182   caja1 = gtk_vbox_new (FALSE, 0);
2183   gtk_container_add (GTK_CONTAINER (ventana), caja1);
2184   gtk_widget_show (caja1);
2185
2186   caja2 = gtk_vbox_new (FALSE, 10);
2187   gtk_container_border_width (GTK_CONTAINER (caja2), 10);
2188   gtk_box_pack_start (GTK_BOX (caja1), caja2, TRUE, TRUE, 0);
2189   gtk_widget_show (caja2);
2190
2191   boton = gtk_radio_button_new_with_label (NULL, "botón1");
2192   gtk_box_pack_start (GTK_BOX (caja2), boton, TRUE, TRUE, 0);
2193   gtk_widget_show (boton);
2194
2195   group = gtk_radio_button_group (GTK_RADIO_BUTTON (boton));
2196   boton = gtk_radio_button_new_with_label(group, "botón2");
2197   gtk_toggle_button_set_state (GTK_TOGGLE_BUTTON (boton), TRUE);
2198   gtk_box_pack_start (GTK_BOX (caja2), boton, TRUE, TRUE, 0);
2199   gtk_widget_show (boton);
2200
2201   group = gtk_radio_button_group (GTK_RADIO_BUTTON (boton));
2202   boton = gtk_radio_button_new_with_label(group, "botón3");
2203   gtk_box_pack_start (GTK_BOX (caja2), boton, TRUE, TRUE, 0);
2204   gtk_widget_show (boton);
2205
2206   separator = gtk_hseparator_new ();
2207   gtk_box_pack_start (GTK_BOX (caja1), separator, FALSE, TRUE, 0);
2208   gtk_widget_show (separator);
2209
2210   caja2 = gtk_vbox_new (FALSE, 10);
2211   gtk_container_border_width (GTK_CONTAINER (caja2), 10);
2212   gtk_box_pack_start (GTK_BOX (caja1), caja2, FALSE, TRUE, 0);
2213   gtk_widget_show (caja2);
2214
2215   boton = gtk_button_new_with_label ("close");
2216   gtk_signal_connect_object (GTK_OBJECT (boton), "clicked",
2217                              GTK_SIGNAL_FUNC(close_application),
2218                              GTK_OBJECT (ventana));
2219   gtk_box_pack_start (GTK_BOX (caja2), boton, TRUE, TRUE, 0);
2220   GTK_WIDGET_SET_FLAGS (boton, GTK_CAN_DEFAULT);
2221   gtk_widget_grab_default (boton);
2222   gtk_widget_show (boton);
2223   gtk_widget_show (ventana);
2224      
2225   gtk_main();
2226   return(0);
2227 }
2228 /* final del ejemplo */
2229 </verb></tscreen>
2230
2231 <!-- TODO: checout out gtk_radio_button_new_from_widget function - TRG -->
2232
2233 <!-- ***************************************************************** -->
2234 <sect>Ajustes (<em/Adjustment/) <label id="sec_Adjustment">
2235 <!-- ***************************************************************** -->
2236 <p>
2237 Existen diferentes <em/widgets/ en GTK+ que pueden ser ajustados
2238 visualmente por el usuario mediante el ratón o el teclado. Un
2239 ejemplo son los <em/widgets/ de selección descritos en la
2240 sección <ref id="sec_Range_Widgets" name="Widgets de selección
2241 de rango">. También hay otros widgets que pueden ser ajustados
2242 parcialmente, por ejemplo el <em/widget/ de texto o el <em/viewport/.
2243
2244 Como es lógico el programa tiene que poder reaccionar a los
2245 cambios que el usuario realiza en los <em/widgets/ de selección de
2246 rango. Una forma de hacer que el programa reaccione sería tener
2247 cada <em/widget/ emitiendo su propio tipo de señal cuando cambie el
2248 ajuste, y bien pasar el nuevo valor al manejador de señal o bien
2249 obligarle a que mire dentro de la estructura de datos del <em/widget/
2250 para conocer este valor. Pero también puede ser que quiera conectar
2251 los ajustes de varios <em/widgets/, para que así cuando se ajuste
2252 uno, los demás se ajusten automáticamente. El ejemplo más
2253 obvio es conectar una barra de desplazamiento a una región con
2254 texto. Si cada <em/widget/ posee su propia forma de establecer u
2255 obtener sus valores de ajuste el programador puede que tenga que
2256 escribir sus propios controladores de señales para traducir el
2257 resultado de la señal producida por un <em/widget/ como el
2258 argumento de una función usada para determinar valores en otro
2259 <em/widget/.
2260
2261 Para resolver este problema GTK+ usa objetos del tipo GtkAdjustment.
2262 Con ellos se consigue almacenar y traspasar información de una forma 
2263 abstracta y flexible. El uso más obvio es el de almacenes de
2264 párametros para <em/widgets/ de escala (barras deslizantes y
2265 escalas). Como los GtkAdjustment derivan de GtkObject poseen
2266 cualidades intrínsecas que les permiten ser algo más que simples
2267 estructuras de datos. Lo más importante es que pueden emitir
2268 señales que a su vez pueden ser usadas tanto para reaccionar frente
2269 al cambio de datos introducidos por el usuario como para transferir
2270 los nuevos valores de forma transparente entre <em/widgets/ ajustables. 
2271
2272 <sect1>Creando un ajuste
2273 <p>
2274 Los ajustes se pueden crear usando:
2275
2276 <tscreen><verb>
2277 GtkObject *gtk_adjustment_new( gfloat value,
2278                                gfloat lower,
2279                                gfloat upper,
2280                                gfloat step_increment,
2281                                gfloat page_increment,
2282                                gfloat page_size );
2283 </verb></tscreen>
2284
2285 El argumento <tt/value/ es el valor inicial que le queremos dar
2286 al ajuste. Normalmente se corresponde con las posiciones situadas
2287 más arriba y a la izquierda de un <em/widget/ ajustable. El argumento
2288 <tt/lower/ especifica los valores más pequeños que el ajuste
2289 puede contener. A su vez con <tt/step_increment/ se especifica el
2290 valor más pequeño en el que se puede variar la magnitud en
2291 cuestión (valor de paso asociado), mientras que <tt/page_increment/
2292 es el mayor. Con <tt/page_size/ se determina el valor visible de un
2293 <em/widget/.
2294
2295 <!-- ----------------------------------------------------------------- -->
2296 <sect1> Forma sencilla de usar los ajustes
2297 <p>
2298 Los <em/widgets/ ajustábles se pueden dividir en dos categorias
2299 diferentes, aquellos que necesitan saber las unidades de la cantidad
2300 almacenada y los que no. Este último grupo incluye los <em/widgets/
2301 de tamaño (barras deslizantes, escalas, barras de estado, o botones
2302 giratorios). Normalmente estos <em/widgets/ son ajustados
2303 «directamente» por el usuario. Los argumentos <tt/lower/ y
2304 <tt/upper/ serán los limites dentro de los cuales el usuario puede
2305 manipular los ajustes. Por defecto sólo se modificará el
2306 <tt/value/ (valor) de un ajuste.
2307
2308 El otro grupo incluye los <em/widgets/ de texto, la lista compuesta o
2309 la ventana con barra deslizante. Estos <em/widgets/ usan valores en
2310 pixels para sus ajustes, y normalmente son ajustados
2311 «indirectamente» mediante barras deslizantes. Aunque todos los
2312 <em/widgets/ pueden crear sus propios ajustes o usar otros creados por
2313 el programador con el segundo grupo suele ser conveniente dejarles que
2314 creen sus propios ajustes. Normalmente no tendrán en cuenta ninguno
2315 de los valores de un ajuste proporcionado por el programador, excepto
2316 <tt/value/, pero los resultados son, en general, indefinidos
2317 (entiendase que tendrá que leer el código fuente para saber que
2318 pasa con cada widget).
2319
2320 Probablemente ya se habrá dado cuenta de que como los <em/widgets/
2321 de texto (y todos los <em/widgets/ del segundo grupo), insisten en
2322 establecer todos los valores excepto <tt/value/, mientras que las
2323 barras deslizantes sólo modifican <tt/value/, si se comparte un
2324 objeto de ajuste entre una barra deslizante y un <em/widget/ de texto
2325 al manipular la barra se modificará el <em/widget/ de texto. Ahora
2326 queda completamente demostrada la utilidad de los ajustes. Veamos un
2327 ejemplo:
2328
2329 <tscreen><verb>
2330   /* creamos un ajuste */
2331   text = gtk_text_new (NULL, NULL);
2332   /* lo usamos con la barra deslizante */
2333   vscrollbar = gtk_vscrollbar_new (GTK_TEXT(text)->vadj);
2334 </verb></tscreen>
2335
2336 </sect1>
2337 <!-- ----------------------------------------------------------------- -->
2338 <sect1> Descripción detallada de los ajustes
2339 <p>
2340 Puede que se esté preguntando cómo es posible crear sus propios
2341 controladores para responder a las modificaciones producidas por
2342 el usuario y cómo obtener el valor del ajuste hecho por este.
2343 Para aclarar esto y otras cosas vamos a estudiar la estructura
2344 del ajuste
2345
2346 <tscreen><verb>
2347 struct _GtkAdjustment
2348 {
2349   GtkData data;
2350   
2351   gfloat lower;
2352   gfloat upper;
2353   gfloat value;
2354   gfloat step_increment;
2355   gfloat page_increment;
2356   gfloat page_size;
2357 };     
2358 </verb></tscreen>
2359
2360 Lo primero que hay que aclarar es que no hay ninguna macro o función
2361 de acceso que permita obtener el <tt/value/ de un GtkAdjustment, por
2362 lo que tendrá que hacerlo usted mismo. Tampoco se preocupe mucho
2363 porque la macro <tt>GTK_ADJUSTMENT (Object)</tt> comprueba los tipos 
2364 durante el proceso de ejecución (como hacen todas las macros de GTK+
2365 que sirven para comprobar los tipos).
2366
2367 Cuando se establece el <tt/value/ de un ajuste normalmente se quiere
2368 que cualquier <em/widget/ se entere del cambio producido. Para ello
2369 GTK+ posee una función especial: 
2370
2371 <tscreen><verb>
2372 void gtk_adjustment_set_value( GtkAdjustment *adjustment,
2373                                gfloat         value );
2374 </verb></tscreen>
2375
2376 Tal y como se mencionó antes GtkAdjustment es una subclase de GtkObject
2377 y por tanto puede emitir señales. Así se consigue que se actualicen
2378 los valores de los ajustes cuando se comparten entre varios <em/widgets/.
2379 Por tanto todos los <em/widgets/ ajustables deben conectar controladores
2380 de señales a sus señales del tipo <tt/value_changed/. Esta es la 
2381 definición de la señal como viene en <tt/struct _GtkAdjustmentClass/
2382
2383 <tscreen><verb>
2384   void (* value_changed) (GtkAdjustment *adjustment);
2385 </verb></tscreen>
2386
2387 Todos los <em/widgets/ que usan GtkAdjustment deben emitir esta
2388 señal cuando cambie el valor de algún ajuste. Esto sucede cuando
2389 el usuario cambia algo o el programa modifica los ajustes
2390 mediante. Por ejemplo si queremos que rote una figura cuando
2391 modificamos un <em/widget/ de escala habría que usar una respuesta
2392 como esta:
2393
2394 <tscreen><verb>
2395 void cb_rotate_picture (GtkAdjustment *adj, GtkWidget *picture)
2396 {
2397   set_picture_rotation (picture, adj->value);
2398 ...
2399 </verb></tscreen>
2400
2401 y conectarla con el ajuste del <em/widget/ de escala mediante:
2402
2403 <tscreen><verb>
2404 gtk_signal_connect (GTK_OBJECT (adj), "value_changed",
2405                     GTK_SIGNAL_FUNC (cb_rotate_picture), picture);
2406 </verb></tscreen>
2407 ¿Qué pasa cuando un <em/widget/ reconfigura los valores
2408 <tt/upper/ o <tt/lower/ (por ejemplo cuando se añade más texto)?
2409 Simplemente que se emite la señal <tt/changed/, que debe ser
2410 parecida a:
2411
2412 <tscreen><verb>
2413   void (* changed)       (GtkAdjustment *adjustment);
2414 </verb></tscreen>
2415
2416 Los <em/widgets/ de tamaño normalmente conectan un controlador a
2417 esta señal, que cambia el aspecto de éste para reflejar el
2418 cambio. Por ejemplo el tamaño de la guía en una barra deslizante
2419 que se alarga o encoge según la inversa de la diferencia de los
2420 valores <tt/lower/ y <tt/upper/.
2421
2422 Probablemente nunca tenga que conectar un controlador a esta señal
2423 a no ser que esté escribiendo un nuevo tipo de <em/widget/. Pero si
2424 cambia directamente alguno de los valores de GtkAdjustment debe hacer
2425 que se emita la siguiente señal para reconfigurar todos aquellos
2426 <em/widgets/ que usen ese ajuste:
2427
2428 <tscreen><verb>
2429 gtk_signal_emit_by_name (GTK_OBJECT (adjustment), "changed");
2430 </verb></tscreen>
2431
2432 </sect1>
2433 </sect>
2434 <!-- ***************************************************************** -->
2435 <sect>Los <em/widgets/ de selección de rango <label id="sec_Range_Widgets">
2436 <!-- ***************************************************************** -->
2437 <p>
2438 Este tipo de <em/widgets/ incluye a las barras de desplazamiento
2439 (<em>scroollbar</em>) y la menos conocida escala
2440 (<em/scale</em>). Ambos pueden ser usados para muchas cosas, pero como
2441 sus funciones y su implementación son muy parecidas los describimos
2442 al mismo tiempo. Principalmente se utilizan para permitirle al usuario
2443 escoger un valor dentro de un rango ya prefijado.
2444
2445 Todos los <em/widgets/ de selección comparten elementos
2446 gráficos, cada uno de los cuales tiene su propia ventana X window y
2447 recibe eventos. Todos contienen una guía y un rectángulo para
2448 determinar la  posición dentro de la guía (en una procesador de
2449 textos con entorno gráfico se encuentra situado a la derecha del
2450 texto y sirve para situarnos en las diferentes partes del texto). Con
2451 el ratón podemos subir o bajar el rectángulo, mientras que si
2452 hacemos `click' dentro de la guía, pero no sobre el rectángulo,
2453 este se mueve hacia donde hemos hecho el click. Dependiendo del
2454 botón pulsado el rectángulo se moverá hasta la posición
2455 del click o una cantidad prefijada de ante mano.
2456
2457 Tal y como se mencionó en <ref id="sec_Adjustment" name="Ajustes">
2458 todos los <em/widgets/ usados para seleccionar un rango estan
2459 asociados con un objeto de ajuste, a partir del cual calculan la
2460 longitud de la barra y su posición. Cuando el usuario manipula la
2461 barra de desplazamiento el widget cambiará el valor del ajuste.
2462
2463 <sect1>El <em/widget/ barra de desplazamiento
2464 <p>
2465 El <em/widget/ barra de desplazamiento solamente debe utilizarse para
2466 hacer <em/scroll/ sobre otro <em/widget/, como una lista, una caja de
2467 texto, o un puerto de visión (y en muchos es más fácil utilizar
2468 el <em/widget/ scrolled window). Para el resto de los casos, debería
2469 utilizar los <em/widgets/ de escala, ya son más sencillos de usar y
2470 más potentes.
2471
2472 Hay dos tipos separados de barras de desplazamiento, según sea
2473 horizontal o vertical. Realmente no hay mucho que añadir. Puede
2474 crear estos <em/widgets/ utilizar las funciones siguientes, definidas
2475 en <tt>&lt;gtk/gtkhscrollbar.h&gt;</tt> y
2476 <tt>&lt;gtk/gtkvscrollbar.h&gt;</tt>:
2477
2478 <tscreen><verb>
2479 GtkWidget* gtk_hscrollbar_new( GtkAdjustment *adjustment );
2480
2481 GtkWidget* gtk_vscrollbar_new( GtkAdjustment *adjustment );
2482 </verb></tscreen>
2483
2484 y esto es todo lo que hay (si no me cree, ¡mire los ficheros de
2485 cabecera!). El argumento <tt/adjustment/ puede ser un puntero a un
2486 ajuste ya existente, o puede ser NULL, en cuyo caso se creará
2487 uno. Es útil especificar NULL si quiere pasar el ajuste recién
2488 creado a la función constructora de algún otro <em/widget/ (como
2489 por ejemplo el <em/widget/ texto) que se ocupará de configurarlo
2490 correctamente por usted.
2491
2492 <!-- ----------------------------------------------------------------- -->
2493 <sect1><em/Widgets/ de escala
2494 <p>
2495 Los <em/widgets/ de escala se usan para determinar el valor de una
2496 cantidad que se puede interpretar visualmente. El usuario
2497 probablemente fijará el valor a ojo. Por ejemplo el <em/widget/
2498 GtkColorSelection contiene <em/widgets/ de escala que controlan las
2499 componentes del color a seleccionar. Normalmente el valor preciso es
2500 menos importante que el efecto visual, por lo que el color se
2501 selecciona con el ratón y no mediante un número concreto.
2502
2503 <!-- ----------------------------------------------------------------- -->
2504 <sect2>Creación de un <em/widget/ de escala
2505 <p>
2506 Existen dos tipos de <em/widgets/ de escala: GtkHScale (que es
2507 horizontal) y GtkVscale (vertical). Como funcionan de la misma manera
2508 los vamos a describir a la vez. Las funciones definidas en
2509 <tt>&lt;gtk/gtkvscale.h&gt;</tt> y <tt>&lt;gtk/gtkhscale.h&gt;</tt>,
2510 crean <em/widgets/ de escala verticales y horizontales
2511 respectivamente.
2512
2513 <tscreen><verb>
2514 GtkWidget* gtk_vscale_new( GtkAdjustment *adjustment );
2515
2516 GtkWidget* gtk_hscale_new( GtkAdjustment *adjustment );
2517 </verb></tscreen>
2518
2519 El <tt/ajuste/ (adjustment) puede ser tanto un ajuste creado
2520 mediante <tt/gtk_adjustment_new()/ como <tt/NULL/. En este 
2521 último caso se crea un GtkAdjustment anónimo con todos sus
2522 valores iguales a <tt/0.0/. Si no ha quedado claro el uso de esta
2523 función consulte la sección <ref id="sec_Adjustment"
2524 name="Ajustes"> para una discusión más detallada.
2525
2526 <!-- ----------------------------------------------------------------- -->
2527 <sect2> Funciones y señales 
2528 <p>
2529 Los <em/widgets/ de escala pueden indicar su valor actual como un
2530 número. Su comportamiento por defecto es mostrar este valor, pero
2531 se puede modificar usando:
2532
2533 <tscreen><verb>
2534 void gtk_scale_set_draw_value( GtkScale *scale,
2535                                gint      draw_value );
2536 </verb></tscreen>
2537
2538 Los valores posibles de <tt/draw_value son/ son <tt/TRUE/ o <tt/FALSE/.
2539 Con el primero se muestra el valor y con el segundo no.
2540
2541 El valor mostrado por un <em/widget/ de escala por defecto se redondea
2542 a un valor decimal (igual que con <tt/value/ en un GtkAdjustment). Se
2543 puede cambiar con:
2544
2545 <tscreen>
2546 <verb>
2547 void gtk_scale_set_digits( GtkScale *scale,
2548                             gint     digits );
2549 </verb>
2550 </tscreen>
2551
2552 donde <tt/digits/ es el número de posiciones decimales que se
2553 quiera. En la práctica sólo se mostrarán 13 como máximo.
2554
2555 Por último, el valor se puede dibujar en diferentes posiciones con
2556 respecto a la posición del rectangulo que hay dentro de la guía:
2557
2558 <tscreen>
2559 <verb>
2560 void gtk_scale_set_value_pos( GtkScale        *scale,
2561                               GtkPositionType  pos );
2562 </verb>
2563 </tscreen>
2564
2565 Si ha leido la sección acerca del <em/widget/ libro de notas
2566 entonces ya conoce cuales son los valores posibles de <tt/pos/. Estan
2567 definidos en <tt>&lt;gtk/gtkscale.h&gt;</tt> como <tt/enum GtkPositionType/
2568 y son auto explicatorios. Si se escoge un lateral de la guía,
2569 entonces seguirá al rectángulo a lo largo de la guía.
2570
2571 Todas las funcioenes precedentes se encuentran definidas en:
2572 <tt>&lt;gtk/gtkscale.h&gt;</tt>.
2573 </sect2>
2574 </sect1>
2575
2576 <!-- ----------------------------------------------------------------- -->
2577 <sect1> Funciones comunes <label id="sec_funciones_range">
2578 <p>
2579 La descripción interna de la clase GtkRange es bastante complicada,
2580 pero al igual que con el resto de las «clases base» sólo es
2581 interesante si se quiere «hackear». Casi todas las señales y
2582 funciones sólo son útiles para desarrollar derivados. Para un
2583 usuario normal las funciones interesantes son aquellas definidas en:
2584 <tt>&lt;gtk/gtkrange.h&gt;</tt> y funcionan igual en todos los
2585 <em/widgets/ de rango.
2586
2587 <!-- ----------------------------------------------------------------- -->
2588 <sect2> Estableciendo cada cúanto se actualizan
2589 <p>
2590 La política de actualización de un <em/widget/ define en que
2591 puntos de la interacción con el usuario debe cambiar el valor
2592 <tt/value/ en su GtkAdjustment y emitir la señal
2593 «value_changed». Las actualizaciones definidas en
2594 <tt>&lt;gtk/gtkenums.h&gt;</tt> como <tt>enum GtkUpdateType</tt>, son:
2595
2596 <itemize>
2597 <item>GTK_UPDATE_POLICY_CONTINUOUS - Este es el valor por defecto.La
2598 señal «value_changed» se emite continuamente, por ejemplo cuando
2599 la barra deslizante se mueve incluso aunque sea un poquito.
2600 </item>
2601 <item>GTK_UPDATE_POLICY_DISCONTINUOUS - La señal «value_changed»
2602 sólo se emite cuando se ha parado de mover la barra y el usuario ha
2603 soltado el botón del ratón.
2604 </item>
2605 <item>GTK_UPDATE_POLICY_DELAYED - La señal sólo se emite cuando
2606 el usuario suelta el botón del ratón o si la barra no se mueve
2607 durante un periodo largo de tiempo.
2608 </item>
2609 </itemize>
2610
2611 Para establecer la política de actualización se usa la
2612 conversión definida en la macro
2613
2614 <tscreen><verb>
2615 void gtk_range_set_update_policy( GtkRange      *range,
2616                                   GtkUpdateType  policy) ;
2617 </verb></tscreen>
2618
2619 <!-- ----------------------------------------------------------------- -->
2620 <sect2>Obteniendo y estableciendo Ajustes
2621 <p>
2622 Para obtener o establecer el ajuste de un <em/widget/ de rango se usa:
2623
2624 <tscreen><verb>
2625 GtkAdjustment* gtk_range_get_adjustment( GtkRange *range );
2626
2627 void gtk_range_set_adjustment( GtkRange      *range,
2628                                GtkAdjustment *adjustment );
2629 </verb></tscreen>
2630
2631 La función <tt/gtk_range_get_adjustment()/ devuelve un puntero al
2632 ajuste al que <tt/range/ esté conectado.
2633
2634 La función <tt/gtk_range_set_adjustment()/ no hace nada si se le 
2635 pasa como argumento el valor <tt/range/ del ajuste que esta siendo
2636 usado (aunque se haya modificado algún valor). En el caso de que
2637 sea un ajuste nuevo (GtkAdjustment) dejará de usar el antiguo
2638 (probablemente lo destruirá) y conectará las señales
2639 apropiadas al nuevo. A continuación llamará a la función
2640 <tt/gtk_range_adjustment_changed()/ que en teoría recalculará el
2641 tamaño y/o la posición de la barra, redibujándola en caso de
2642 que sea necesario. Tal y como se mencionó en la sección de los
2643 ajustes si se quiere reusar el mismo GtkAdjustment cuando se modifican
2644 sus valores se debe emitir la señal «changed». Por ejemplo:
2645   
2646 <tscreen><verb>
2647 gtk_signal_emit_by_name (GTK_OBJECT (adjustment), "changed");
2648 </verb></tscreen>
2649 </sect2>
2650 </sect1>
2651
2652 <!-- ----------------------------------------------------------------- -->
2653 <sect1> Enlaces con el teclado y el ratón
2654 <p>
2655 Todos los <em/widgets/ de rango reaccionan más o menos de la misma 
2656 manera a las pulsaciones del ratón. Al pulsar el botón 1 sobre
2657 el rectángulo de la barra el <tt/value/ del ajuste aumentará o
2658 disminuirá según <tt/page_increment/. Con el botón 2 la barra
2659 se desplazará al punto en el que el botón fue pulsado. Con cada
2660 pulsación de cualquier botón sobre las flechas el valor del
2661 ajuste se modifica una cantidad igual a <tt/step_increment/.
2662
2663
2664 Acostumbrarse a que tanto las barras deslizantes como los <em/widgets/ de
2665 escala puedan tomar la atención del teclado puede ser un proceso largo.
2666 Si que se cree que los usuarios no lo van a entender se puede anular
2667 mediante la función GTK_WIDGET_UNSET_FLAGS y con GTK_CAN_FOCUS como
2668 argumento:
2669
2670 <tscreen><verb>
2671 GTK_WIDGET_UNSET_FLAGS (scrollbar, GTK_CAN_FOCUS);
2672 </verb></tscreen>
2673
2674 Los enlaces entre teclas (que sólo estan activos cuando el
2675 <em/widget/ tiene la atención (focus)) se comportan de manera
2676 diferente para los <em/widgets/ de rango horizontales que para los
2677 verticales. También son diferentes para los <em/widgets/ de escala
2678 y para las barras deslizantes. (Simplemente para evitar confusiones
2679 entre las teclas de las barras deslizantes horizontales y verticales,
2680 ya que ambas actúan sobre la misma área)
2681
2682 <sect2><em/Widgets/ de rango vertical
2683 <p>
2684 Todos los <em/widgets/ de rango pueden ser manipulados con las teclas
2685 arriba, abajo, <tt/Re Pág/, <tt/ Av Pág/. Las flechas mueven las
2686 barras la cantidad fijada mediante <tt/step_increment/, mientras que
2687 <tt/Re Pág/ y <tt/Av Pag/ lo hacen según <tt/page_increment/.
2688
2689 El usuario también puede mover la barra de un extremo al otro de la
2690 guía mediante el teclado. Con el <em/widget/ GtkVScale podemos ir a
2691 los extremos utilizando las teclas <tt/Inicio/ y <tt/Final/ mientras
2692 que con el <em/widget/ GtkVScrollbar habrá que utilizar
2693 <tt/Control-Re Pág/ y <tt/Control-Av Pág/.
2694
2695 <!-- ----------------------------------------------------------------- -->
2696 <sect2><em/Widgets/ de rango horizontal
2697 <p>
2698 Las teclas izquierda y derecha funcionan tal y como espera que
2699 funcionen en estos <em/widgets/: mueven la barra una cantidad dada por
2700 <tt/step_increment/. A su vez <tt/Inicio/ y <tt/Final/ sirven para
2701 pasar de un extremo al otro de la guía. Para el <em/widget/
2702 GtkHScale el mover la barra una cantidad dada por <tt/page_increment/
2703 se consigue mediante <tt>Control-Izquierda</tt> y
2704 <tt>Control-derecha</tt>, mientras que para el <em/widget/
2705 GtkHScrollbar se consigue con <tt/Control-Inicio/ y
2706 <tt/Control-Final/.
2707 </sect2>
2708 </sect1>
2709
2710 <!-- ----------------------------------------------------------------- -->
2711 <sect1> Ejemplo <label id="sec_Ejemplo_Rango">
2712 <p>
2713 Este ejemplo es una versión modificada del test «range controls»
2714 que a su vez forma parte de <tt/testgtk.c/. Simplemente dibuja una
2715 ventana con tres <em/widgets/ de rango conectados al mismo ajuste, y 
2716 un conjunto de controles para ajustar algunos de los parámetros
2717 ya mencionados. Así se consigue ver como funcionan estos
2718 <em/widgets/ al ser manipulados por el usuario.
2719
2720 <tscreen><verb>
2721 /* principio del ejemplo widgets de selección de rango rangewidgets.c */
2722
2723 #include <gtk/gtk.h>
2724
2725 GtkWidget *hscale, *vscale;
2726
2727 void cb_pos_menu_select( GtkWidget       *item,
2728                          GtkPositionType  pos )
2729 {
2730     /* Establece el valor position en los widgets de escala */
2731     gtk_scale_set_value_pos (GTK_SCALE (hscale), pos);
2732     gtk_scale_set_value_pos (GTK_SCALE (vscale), pos);
2733 }
2734
2735 void cb_update_menu_select( GtkWidget     *item,
2736                             GtkUpdateType  policy )
2737 {
2738     /* Establece la política de actualización para los widgets
2739      * de escala */
2740     gtk_range_set_update_policy (GTK_RANGE (hscale), policy);
2741     gtk_range_set_update_policy (GTK_RANGE (vscale), policy);
2742 }
2743
2744 void cb_digits_scale( GtkAdjustment *adj )
2745 {
2746     /* Establece el número de cifras decimales a las que se
2747      * redondeará adj->value */
2748     gtk_scale_set_digits (GTK_SCALE (hscale), (gint) adj->value);
2749     gtk_scale_set_digits (GTK_SCALE (vscale), (gint) adj->value);
2750 }
2751
2752 void cb_page_size( GtkAdjustment *get,
2753                    GtkAdjustment *set )
2754 {
2755     /* Establece el tamaño de la página y el incremento del
2756      * ajuste al valor especificado en la escala "Page Size" */
2757     set->page_size = get->value;
2758     set->page_increment = get->value;
2759     /* Ahora emite la señal "changed" para reconfigurar todos los
2760      * widgets que están enlazados a este ajuste */
2761     gtk_signal_emit_by_name (GTK_OBJECT (set), "changed");
2762 }
2763
2764 void cb_draw_value( GtkToggleButton *boton )
2765 {
2766     /* Activa o desactiva el valor display en los widgets de escala
2767      * dependiendo del estado del botón de comprobación */
2768     gtk_scale_set_draw_value (GTK_SCALE (hscale), boton->active);
2769     gtk_scale_set_draw_value (GTK_SCALE (vscale), boton->active);  
2770 }
2771
2772 /* Funciones varias */
2773
2774 GtkWidget *make_menu_item( gchar         *name,
2775                            GtkSignalFunc  callback,
2776                            gpointer       data )
2777 {
2778     GtkWidget *item;
2779   
2780     item = gtk_menu_item_new_with_label (name);
2781     gtk_signal_connect (GTK_OBJECT (item), "activate",
2782                         callback, data);
2783     gtk_widget_show (item);
2784
2785     return(item);
2786 }
2787
2788 void scale_set_default_values( GtkScale *scale )
2789 {
2790     gtk_range_set_update_policy (GTK_RANGE (scale),
2791                                  GTK_UPDATE_CONTINUOUS);
2792     gtk_scale_set_digits (scale, 1);
2793     gtk_scale_set_value_pos (scale, GTK_POS_TOP);
2794     gtk_scale_set_draw_value (scale, TRUE);
2795 }
2796
2797 /* crea la ventana principal */
2798
2799 void create_range_controls( void )
2800 {
2801     GtkWidget *ventana;
2802     GtkWidget *caja1, *caja2, *caja3;
2803     GtkWidget *boton;
2804     GtkWidget *scrollbar;
2805     GtkWidget *separator;
2806     GtkWidget *opt, *menu, *item;
2807     GtkWidget *etiqueta;
2808     GtkWidget *scale;
2809     GtkObject *adj1, *adj2;
2810
2811     /* creación estándar de una ventana */
2812     ventana = gtk_window_new (GTK_WINDOW_TOPLEVEL);
2813     gtk_signal_connect (GTK_OBJECT (ventana), "destroy",
2814                         GTK_SIGNAL_FUNC(gtk_main_quit),
2815                         NULL);
2816     gtk_window_set_title (GTK_WINDOW (ventana), "range controls");
2817
2818     caja1 = gtk_vbox_new (FALSE, 0);
2819     gtk_container_add (GTK_CONTAINER (ventana), caja1);
2820     gtk_widget_show (caja1);
2821
2822     caja2 = gtk_hbox_new (FALSE, 10);
2823     gtk_container_border_width (GTK_CONTAINER (caja2), 10);
2824     gtk_box_pack_start (GTK_BOX (caja1), caja2, TRUE, TRUE, 0);
2825     gtk_widget_show (caja2);
2826
2827     /* value, lower, upper, step_increment, page_increment, page_size */
2828     /* Observe que el valor de page_size solo sirve para los widgets
2829      * barras de desplazamiento (scrollbar), y que el valor más
2830      * alto que obtendrá será (upper - page_size). */
2831     adj1 = gtk_adjustment_new (0.0, 0.0, 101.0, 0.1, 1.0, 1.0);
2832   
2833     vscale = gtk_vscale_new (GTK_ADJUSTMENT (adj1));
2834     scale_set_default_values (GTK_SCALE (vscale));
2835     gtk_box_pack_start (GTK_BOX (caja2), vscale, TRUE, TRUE, 0);
2836     gtk_widget_show (vscale);
2837
2838     caja3 = gtk_vbox_new (FALSE, 10);
2839     gtk_box_pack_start (GTK_BOX (caja2), caja3, TRUE, TRUE, 0);
2840     gtk_widget_show (caja3);
2841
2842     /* Reutilizamos el mismo ajuste */
2843     hscale = gtk_hscale_new (GTK_ADJUSTMENT (adj1));
2844     gtk_widget_set_usize (GTK_WIDGET (hscale), 200, 30);
2845     scale_set_default_values (GTK_SCALE (hscale));
2846     gtk_box_pack_start (GTK_BOX (caja3), hscale, TRUE, TRUE, 0);
2847     gtk_widget_show (hscale);
2848
2849     /* Reutilizamos de nuevo el mismo ajuste */
2850     scrollbar = gtk_hscrollbar_new (GTK_ADJUSTMENT (adj1));
2851     /* Observe que con esto conseguimos que la escala siempre se
2852      * actualice de una forma continua cuando se mueva la barra de
2853      * desplazamiento */
2854     gtk_range_set_update_policy (GTK_RANGE (scrollbar), 
2855                                  GTK_UPDATE_CONTINUOUS);
2856     gtk_box_pack_start (GTK_BOX (caja3), scrollbar, TRUE, TRUE, 0);
2857     gtk_widget_show (scrollbar);
2858
2859     caja2 = gtk_hbox_new (FALSE, 10);
2860     gtk_container_border_width (GTK_CONTAINER (caja2), 10);
2861     gtk_box_pack_start (GTK_BOX (caja1), caja2, TRUE, TRUE, 0);
2862     gtk_widget_show (caja2);
2863
2864     /* Un botón para comprobar si el valor se muestra o no*/
2865     boton = gtk_check_button_new_with_label("Display value on scale widgets");
2866     gtk_toggle_button_set_state (GTK_TOGGLE_BUTTON (boton), TRUE);
2867     gtk_signal_connect (GTK_OBJECT (boton), "toggled",
2868                         GTK_SIGNAL_FUNC(cb_draw_value), NULL);
2869     gtk_box_pack_start (GTK_BOX (caja2), boton, TRUE, TRUE, 0);
2870     gtk_widget_show (boton);
2871   
2872     caja2 = gtk_hbox_new (FALSE, 10);
2873     gtk_container_border_width (GTK_CONTAINER (caja2), 10);
2874
2875     /* Una opción en el menú para cambiar la posición del
2876      * valor */
2877     etiqueta = gtk_label_new ("Scale Value Position:");
2878     gtk_box_pack_start (GTK_BOX (caja2), etiqueta, FALSE, FALSE, 0);
2879     gtk_widget_show (etiqueta);
2880   
2881     opt = gtk_option_menu_new();
2882     menu = gtk_menu_new();
2883
2884     item = make_menu_item ("Top",
2885                            GTK_SIGNAL_FUNC(cb_pos_menu_select),
2886                            GINT_TO_POINTER (GTK_POS_TOP));
2887     gtk_menu_append (GTK_MENU (menu), item);
2888   
2889     item = make_menu_item ("Bottom", GTK_SIGNAL_FUNC (cb_pos_menu_select), 
2890                            GINT_TO_POINTER (GTK_POS_BOTTOM));
2891     gtk_menu_append (GTK_MENU (menu), item);
2892   
2893     item = make_menu_item ("Left", GTK_SIGNAL_FUNC (cb_pos_menu_select),
2894                            GINT_TO_POINTER (GTK_POS_LEFT));
2895     gtk_menu_append (GTK_MENU (menu), item);
2896   
2897     item = make_menu_item ("Right", GTK_SIGNAL_FUNC (cb_pos_menu_select),
2898                             GINT_TO_POINTER (GTK_POS_RIGHT));
2899     gtk_menu_append (GTK_MENU (menu), item);
2900   
2901     gtk_option_menu_set_menu (GTK_OPTION_MENU (opt), menu);
2902     gtk_box_pack_start (GTK_BOX (caja2), opt, TRUE, TRUE, 0);
2903     gtk_widget_show (opt);
2904
2905     gtk_box_pack_start (GTK_BOX (caja1), caja2, TRUE, TRUE, 0);
2906     gtk_widget_show (caja2);
2907
2908     caja2 = gtk_hbox_new (FALSE, 10);
2909     gtk_container_border_width (GTK_CONTAINER (caja2), 10);
2910
2911     /* Sí, otra opción de menú, esta vez para la política
2912      * de actualización de los widgets */
2913     etiqueta = gtk_label_new ("Scale Update Policy:");
2914     gtk_box_pack_start (GTK_BOX (caja2), etiqueta, FALSE, FALSE, 0);
2915     gtk_widget_show (etiqueta);
2916   
2917     opt = gtk_option_menu_new();
2918     menu = gtk_menu_new();
2919   
2920     item = make_menu_item ("Continuous",
2921                            GTK_SIGNAL_FUNC (cb_update_menu_select),
2922                            GINT_TO_POINTER (GTK_UPDATE_CONTINUOUS));
2923     gtk_menu_append (GTK_MENU (menu), item);
2924   
2925     item = make_menu_item ("Discontinuous",
2926                             GTK_SIGNAL_FUNC (cb_update_menu_select),
2927                             GINT_TO_POINTER (GTK_UPDATE_DISCONTINUOUS));
2928     gtk_menu_append (GTK_MENU (menu), item);
2929   
2930     item = make_menu_item ("Delayed",
2931                            GTK_SIGNAL_FUNC (cb_update_menu_select),
2932                            GINT_TO_POINTER (GTK_UPDATE_DELAYED));
2933     gtk_menu_append (GTK_MENU (menu), item);
2934   
2935     gtk_option_menu_set_menu (GTK_OPTION_MENU (opt), menu);
2936     gtk_box_pack_start (GTK_BOX (caja2), opt, TRUE, TRUE, 0);
2937     gtk_widget_show (opt);
2938   
2939     gtk_box_pack_start (GTK_BOX (caja1), caja2, TRUE, TRUE, 0);
2940     gtk_widget_show (caja2);
2941
2942     caja2 = gtk_hbox_new (FALSE, 10);
2943     gtk_container_border_width (GTK_CONTAINER (caja2), 10);
2944   
2945     /* Un widget GtkHScale para ajustar el número de dígitos en
2946      * la escala. */
2947     etiqueta = gtk_label_new ("Scale Digits:");
2948     gtk_box_pack_start (GTK_BOX (caja2), etiqueta, FALSE, FALSE, 0);
2949     gtk_widget_show (etiqueta);
2950
2951     adj2 = gtk_adjustment_new (1.0, 0.0, 5.0, 1.0, 1.0, 0.0);
2952     gtk_signal_connect (GTK_OBJECT (adj2), "value_changed",
2953                         GTK_SIGNAL_FUNC (cb_digits_scale), NULL);
2954     scale = gtk_hscale_new (GTK_ADJUSTMENT (adj2));
2955     gtk_scale_set_digits (GTK_SCALE (scale), 0);
2956     gtk_box_pack_start (GTK_BOX (caja2), scale, TRUE, TRUE, 0);
2957     gtk_widget_show (scale);
2958
2959     gtk_box_pack_start (GTK_BOX (caja1), caja2, TRUE, TRUE, 0);
2960     gtk_widget_show (caja2);
2961   
2962     caja2 = gtk_hbox_new (FALSE, 10);
2963     gtk_container_border_width (GTK_CONTAINER (caja2), 10);
2964   
2965     /* Y un último widget GtkHScale para ajustar el tamaño de la
2966      * página de la barra de desplazamiento. */
2967     etiqueta = gtk_label_new ("Scrollbar Page Size:");
2968     gtk_box_pack_start (GTK_BOX (caja2), etiqueta, FALSE, FALSE, 0);
2969     gtk_widget_show (etiqueta);
2970
2971     adj2 = gtk_adjustment_new (1.0, 1.0, 101.0, 1.0, 1.0, 0.0);
2972     gtk_signal_connect (GTK_OBJECT (adj2), "value_changed",
2973                         GTK_SIGNAL_FUNC (cb_page_size), adj1);
2974     scale = gtk_hscale_new (GTK_ADJUSTMENT (adj2));
2975     gtk_scale_set_digits (GTK_SCALE (scale), 0);
2976     gtk_box_pack_start (GTK_BOX (caja2), scale, TRUE, TRUE, 0);
2977     gtk_widget_show (scale);
2978
2979     gtk_box_pack_start (GTK_BOX (caja1), caja2, TRUE, TRUE, 0);
2980     gtk_widget_show (caja2);
2981
2982     separator = gtk_hseparator_new ();
2983     gtk_box_pack_start (GTK_BOX (caja1), separator, FALSE, TRUE, 0);
2984     gtk_widget_show (separator);
2985
2986     caja2 = gtk_vbox_new (FALSE, 10);
2987     gtk_container_border_width (GTK_CONTAINER (caja2), 10);
2988     gtk_box_pack_start (GTK_BOX (caja1), caja2, FALSE, TRUE, 0);
2989     gtk_widget_show (caja2);
2990
2991     boton = gtk_button_new_with_label ("Quit");
2992     gtk_signal_connect_object (GTK_OBJECT (boton), "clicked",
2993                                GTK_SIGNAL_FUNC(gtk_main_quit),
2994                                NULL);
2995     gtk_box_pack_start (GTK_BOX (caja2), boton, TRUE, TRUE, 0);
2996     GTK_WIDGET_SET_FLAGS (boton, GTK_CAN_DEFAULT);
2997     gtk_widget_grab_default (boton);
2998     gtk_widget_show (boton);
2999
3000     gtk_widget_show (ventana);
3001 }
3002
3003 int main( int   argc,
3004           char *argv[] )
3005 {
3006     gtk_init(&amp;argc, &amp;argv);
3007
3008     create_range_controls();
3009
3010     gtk_main();
3011
3012     return(0);
3013 }
3014
3015 /* fin del ejemplo */
3016 </verb></tscreen>
3017
3018 Observe que el programa no llama a <tt/gtk_signal_connect/ para
3019 conectar el «delete_event», y que sólo conecta la señal
3020 «destroy». Con esto seguimos realizando la función deseada, ya que
3021 un «delete_event» no manejado desenboca en una señal «destroy»
3022 para la ventana. 
3023 </sect1>
3024 </sect>
3025
3026 <!-- ***************************************************************** -->
3027 <sect><em/Widgets/ varios
3028 <!-- ***************************************************************** -->
3029
3030 <!-- ----------------------------------------------------------------- -->
3031 <sect1> Etiquetas
3032 <p>
3033 Las etiquetas se usan mucho en GTK y son bastante simples de manejar.
3034 No pueden emitir señales ya que no tienen ventanas X window
3035 asociadas. Si se desea capturar señales se debe usar el <em/widget/
3036 EventBox o un <em/widget/ botón.
3037
3038 Para crear una nueva etiqueta se usa:
3039
3040 <tscreen><verb>
3041 GtkWidget *gtk_label_new( char *str );
3042 </verb></tscreen>
3043
3044 El único argumento es la cadena de texto que se quiere mostrar.
3045
3046 Para cambiarla después de que haya sido creada se usa:
3047
3048 <tscreen><verb>
3049 void gtk_label_set( GtkLabel *etiqueta,
3050                     char     *str );
3051 </verb></tscreen>
3052
3053 En este caso el primer argumento es la etiqueta ya creada (cambiado su
3054 tipo mediante la macro <tt/GTK_LABEL()/) y el segundo es la nueva cadena.
3055 El espacio que necesite la nueva etiqueta se ajustará
3056 automáticamente, si es necesario.
3057
3058 Para obtener el estado de la cadena en un momento dado existe la
3059 función:
3060
3061 <tscreen><verb>
3062 void gtk_label_get( GtkLabel  *etiqueta,
3063                     char     **str );
3064 </verb></tscreen>
3065 El primer argumento es la etiqueta, mientras que el segundo es el
3066 valor devuelto para la cadena. No libere la memoria de la cadena
3067 devuelta, ya que se utiliza internamente por GTK.
3068
3069 El texto de la etiqueta se puede justificar utilizando:
3070
3071 <tscreen><verb>
3072 void gtk_label_set_justify( GtkLabel         *etiqueta,
3073                             GtkJustification  jtype );
3074 </verb></tscreen>
3075
3076 Los valores posibles para <tt/jtype/ son:
3077 <itemize>
3078 <item> GTK_JUSTIFY_LEFT
3079 <item> GTK_JUSTIFY_RIGHT
3080 <item> GTK_JUSTIFY_CENTER (the default)
3081 <item> GTK_JUSTIFY_FILL
3082 </itemize>
3083
3084 El <em/widget/ etiqueta también es capaz de separar el texto de forma
3085 automática cuando se llega al final de una linea. Esto se puede
3086 conseguir utilizando: 
3087
3088 <tscreen><verb>
3089 void gtk_label_set_line_wrap (GtkLabel *etiqueta,
3090                               gboolean  wrap);
3091 </verb></tscreen>
3092
3093 El argumento <tt/wrap/ toma el valor TRUE o FALSE.
3094
3095 Si quiere que su etiqueta salga subrayada, puede especificar un motivo
3096 para el subrayado con: 
3097
3098 <tscreen><verb>
3099 void       gtk_label_set_pattern   (GtkLabel          *etiqueta,
3100                                     const gchar       *pattern);
3101 </verb></tscreen>
3102
3103 El argumento <tt/pattern/ indica cual debe ser el aspecto del
3104 subrayado. Consiste en una cadena de espacios en blanco y carácteres
3105 de subrayado. Por ejemplo, la cadena <tt/"__     __"/ debe hacer que
3106 se subrayen los dos primeros y el octavo y el noveno carácter.
3107
3108 A continuación tenemos un pequeño ejemplo que ilustra el uso de estas
3109 funciones. Este ejemplo utiliza el <em/widget/ marco (<em/frame/) para
3110 hacer una mejor demostración de los estilos de la etiqueta. Por ahora
3111 puede ignorarlo, ya que el <em/widget/ <ref id="sec_Frames"
3112 name="Frame"> se explicará más tarde. 
3113
3114 <tscreen><verb>
3115 /* principio del ejemplo label label.c */
3116
3117 #include <gtk/gtk.h>
3118
3119 int main( int   argc,
3120           char *argv[] )
3121 {
3122   static GtkWidget *ventana = NULL;
3123   GtkWidget *hbox;
3124   GtkWidget *vbox;
3125   GtkWidget *frame;
3126   GtkWidget *etiqueta;
3127
3128   /* Inicializa GTK */
3129   gtk_init(&amp;argc, &amp;argv);
3130
3131   ventana = gtk_window_new (GTK_WINDOW_TOPLEVEL);
3132   gtk_signal_connect (GTK_OBJECT (ventana), "destroy",
3133                       GTK_SIGNAL_FUNC(gtk_main_quit),
3134                       NULL);
3135
3136   gtk_window_set_title (GTK_WINDOW (ventana), "Etiqueta");
3137   vbox = gtk_vbox_new (FALSE, 5);
3138   hbox = gtk_hbox_new (FALSE, 5);
3139   gtk_container_add (GTK_CONTAINER (ventana), hbox);
3140   gtk_box_pack_start (GTK_BOX (hbox), vbox, FALSE, FALSE, 0);
3141   gtk_container_set_border_width (GTK_CONTAINER (ventana), 5);
3142   
3143   frame = gtk_frame_new ("Normal Label");
3144   etiqueta = gtk_label_new ("This is a Normal label");
3145   gtk_container_add (GTK_CONTAINER (frame), etiqueta);
3146   gtk_box_pack_start (GTK_BOX (vbox), frame, FALSE, FALSE, 0);
3147   
3148   frame = gtk_frame_new ("Multi-line Label");
3149   etiqueta = gtk_label_new ("This is a Multi-line label.\nSecond line\n" \
3150                          "Third line");
3151   gtk_container_add (GTK_CONTAINER (frame), etiqueta);
3152   gtk_box_pack_start (GTK_BOX (vbox), frame, FALSE, FALSE, 0);
3153   
3154   frame = gtk_frame_new ("Left Justified Label");
3155   etiqueta = gtk_label_new ("This is a Left-Justified\n" \
3156                          "Multi-line label.\nThird      line");
3157   gtk_label_set_justify (GTK_LABEL (etiqueta), GTK_JUSTIFY_LEFT);
3158   gtk_container_add (GTK_CONTAINER (frame), etiqueta);
3159   gtk_box_pack_start (GTK_BOX (vbox), frame, FALSE, FALSE, 0);
3160   
3161   frame = gtk_frame_new ("Right Justified Label");
3162   etiqueta = gtk_label_new ("This is a Right-Justified\nMulti-line label.\n" \
3163                          "Fourth line, (j/k)");
3164   gtk_label_set_justify (GTK_LABEL (etiqueta), GTK_JUSTIFY_RIGHT);
3165   gtk_container_add (GTK_CONTAINER (frame), etiqueta);
3166   gtk_box_pack_start (GTK_BOX (vbox), frame, FALSE, FALSE, 0);
3167
3168   vbox = gtk_vbox_new (FALSE, 5);
3169   gtk_box_pack_start (GTK_BOX (hbox), vbox, FALSE, FALSE, 0);
3170   frame = gtk_frame_new ("Line wrapped label");
3171   etiqueta = gtk_label_new ("This is an example of a line-wrapped label.  It " \
3172                          "should not be taking up the entire             " /* big space to test spacing */\
3173                          "width allocated to it, but automatically " \
3174                          "wraps the words to fit.  " \
3175                          "The time has come, for all good men, to come to " \
3176                          "the aid of their party.  " \
3177                          "The sixth sheik's six sheep's sick.\n" \
3178                          "     It supports multiple paragraphs correctly, " \
3179                          "and  correctly   adds "\
3180                          "many          extra  spaces. ");
3181   gtk_label_set_line_wrap (GTK_LABEL (etiqueta), TRUE);
3182   gtk_container_add (GTK_CONTAINER (frame), etiqueta);
3183   gtk_box_pack_start (GTK_BOX (vbox), frame, FALSE, FALSE, 0);
3184   
3185   frame = gtk_frame_new ("Filled, wrapped label");
3186   etiqueta = gtk_label_new ("This is an example of a line-wrapped, filled label.  " \
3187                          "It should be taking "\
3188                          "up the entire              width allocated to it.  " \
3189                          "Here is a seneance to prove "\
3190                          "my point.  Here is another sentence. "\
3191                          "Here comes the sun, do de do de do.\n"\
3192                          "    This is a new paragraph.\n"\
3193                          "    This is another newer, longer, better " \
3194                          "paragraph.  It is coming to an end, "\
3195                          "unfortunately.");
3196   gtk_label_set_justify (GTK_LABEL (etiqueta), GTK_JUSTIFY_FILL);
3197   gtk_label_set_line_wrap (GTK_LABEL (etiqueta), TRUE);
3198   gtk_container_add (GTK_CONTAINER (frame), etiqueta);
3199   gtk_box_pack_start (GTK_BOX (vbox), frame, FALSE, FALSE, 0);
3200   
3201   frame = gtk_frame_new ("Underlined label");
3202   etiqueta = gtk_label_new ("This label is underlined!\n"
3203                          "This one is underlined in quite a funky fashion");
3204   gtk_label_set_justify (GTK_LABEL (etiqueta), GTK_JUSTIFY_LEFT);
3205   gtk_label_set_pattern (GTK_LABEL (etiqueta),
3206                          "_________________________ _ _________ _ ______     __ _______ ___");
3207   gtk_container_add (GTK_CONTAINER (frame), etiqueta);
3208   gtk_box_pack_start (GTK_BOX (vbox), frame, FALSE, FALSE, 0);
3209   
3210   gtk_widget_show_all (ventana);
3211
3212   gtk_main ();
3213   
3214   return(0);
3215 }
3216 /* fin del ejemplo */
3217 </verb></tscreen>
3218
3219 <!-- ----------------------------------------------------------------- -->
3220 <sect1> Flechas
3221 <p>
3222 En <em/widget/ flecha (<em/arrow/) dibuja la punta de una flecha,
3223 con un estilo y hacia una dirección a escoger. Puede ser muy útil
3224 en muchas aplicaciones cuando se coloca en un botón.
3225
3226 Sólo hay dos funciones para manipular el <em/widget/ flecha: 
3227
3228 <tscreen><verb>
3229 GtkWidget *gtk_arrow_new( GtkArrowType   arrow_type,
3230                           GtkShadowType  shadow_type );
3231
3232 void gtk_arrow_set( GtkArrow      *arrow,
3233                     GtkArrowType   arrow_type,
3234                     GtkShadowType  shadow_type );
3235 </verb></tscreen>
3236
3237 La primera crea un nuevo <em/widget/ flecha del tipo y apariencia
3238 indicados. La segunda permite alterar posteriormente estos valores. El
3239 argumento <tt/arrow_type/ puede tomar uno de los valores siguientes: 
3240
3241 <itemize>
3242 <item> GTK_ARROW_UP
3243 <item> GTK_ARROW_DOWN
3244 <item> GTK_ARROW_LEFT
3245 <item> GTK_ARROW_RIGHT
3246 </itemize>
3247
3248 Naturalmente, estos valores indican la dirección a la que debe apuntar
3249 la flecha. El argumento <tt/shadow_type/ puede tomar uno de los
3250 valores siguientes: 
3251
3252 <itemize>
3253 <item> GTK_SHADOW_IN
3254 <item> GTK_SHADOW_OUT (por defecto)
3255 <item> GTK_SHADOW_ETCHED_IN
3256 <item> GTK_SHADOW_ETCHED_OUT
3257 </itemize>
3258
3259 Aquí tenemos un pequeño ejemplo para ilustrar la utilización de la
3260 flecha. 
3261
3262 <tscreen><verb>
3263 /* principio del ejemplo arrow arrow.c */
3264
3265 #include <gtk/gtk.h>
3266
3267 /* Crea un widget flecha con los parámetros especificados
3268  * y lo empaqueta en un botón */
3269 GtkWidget *create_arrow_button( GtkArrowType  arrow_type,
3270                                 GtkShadowType shadow_type )
3271 {
3272   GtkWidget *boton;
3273   GtkWidget *arrow;
3274
3275   boton = gtk_button_new();
3276   arrow = gtk_arrow_new (arrow_type, shadow_type);
3277
3278   gtk_container_add (GTK_CONTAINER (boton), arrow);
3279   
3280   gtk_widget_show(boton);
3281   gtk_widget_show(arrow);
3282
3283   return(boton);
3284 }
3285
3286 int main( int   argc,
3287           char *argv[] )
3288 {
3289   /* GtkWidget es el tipo utilizado para los widgets */
3290   GtkWidget *ventana;
3291   GtkWidget *boton;
3292   GtkWidget *box;
3293
3294   /* Inicializa el toolkit */
3295   gtk_init (&amp;argc, &amp;argv);
3296
3297   /* Crea una nueva ventana */
3298   ventana = gtk_window_new (GTK_WINDOW_TOPLEVEL);
3299
3300   gtk_window_set_title (GTK_WINDOW (ventana), "Arrow Buttons");
3301
3302   /* Es una buena idea hacer esto con todas las ventanas. */
3303   gtk_signal_connect (GTK_OBJECT (ventana), "destroy",
3304                       GTK_SIGNAL_FUNC (gtk_main_quit), NULL);
3305
3306   /* Establece el ancho del borde de la ventana. */
3307   gtk_container_set_border_width (GTK_CONTAINER (ventana), 10);
3308
3309   /* Crea una caja para almacenar las flechas/botones */
3310   box = gtk_hbox_new (FALSE, 0);
3311   gtk_container_set_border_width (GTK_CONTAINER (box), 2);
3312   gtk_container_add (GTK_CONTAINER (ventana), box);
3313
3314   /* Empaqueta y muestra todos nuestros widgets */
3315   gtk_widget_show(box);
3316
3317   boton = create_arrow_button(GTK_ARROW_UP, GTK_SHADOW_IN);
3318   gtk_box_pack_start (GTK_BOX (box), boton, FALSE, FALSE, 3);
3319
3320   boton = create_arrow_button(GTK_ARROW_DOWN, GTK_SHADOW_OUT);
3321   gtk_box_pack_start (GTK_BOX (box), boton, FALSE, FALSE, 3);
3322   
3323   boton = create_arrow_button(GTK_ARROW_LEFT, GTK_SHADOW_ETCHED_IN);
3324   gtk_box_pack_start (GTK_BOX (box), boton, FALSE, FALSE, 3);
3325   
3326   boton = create_arrow_button(GTK_ARROW_RIGHT, GTK_SHADOW_ETCHED_OUT);
3327   gtk_box_pack_start (GTK_BOX (box), boton, FALSE, FALSE, 3);
3328   
3329   gtk_widget_show (ventana);
3330   
3331   /* Nos quedamos en gtk_main y ¡esperamos que empiece la diversión! */
3332   gtk_main ();
3333   
3334   return(0);
3335 }
3336 /* fin del ejemplo */
3337 </verb></tscreen>
3338
3339 <!-- ----------------------------------------------------------------- -->
3340 <sect1>El <em/widget/ de información rápida (<em/tooltip/)
3341 <p>
3342 Estos <em/widgets/ son las pequeñas etiquetas que texto que
3343 aparecen cuando se sitúa el puntero del ratón sobre un botón
3344 u otro <em/widget/ durante algunos segundos. Son bastante fáciles
3345 de usar, así que no se dará ningún ejemplo. Si quiere ver
3346 algún ejemplo se recomienda leer el programa testgtk.c que
3347 acompaña a GTK.
3348
3349 Algunos <em/widgets/ (como la etiqueta) no pueden llevar asociado un
3350 <em/tooltip/.
3351
3352 Para cada función sólo hay que hacer una llamada para conseguir
3353 un <em/tooltip/. El objeto <tt/GtkTooltip/ que devuelve la siguiente
3354 función puede ser usado para crear múltiples <em/widgets/.
3355
3356 <tscreen><verb>
3357 GtkTooltips *gtk_tooltips_new( void );
3358 </verb></tscreen>
3359
3360 Una vez que el <em/tooltip/ ha sido creado (y el <em/widget/ sobre el
3361 que se quiere usar) simplemente hay que usar la siguiente llamada para
3362 pegarlo:
3363
3364 <tscreen><verb>
3365 void gtk_tooltips_set_tip( GtkTooltips *tooltips,
3366                            GtkWidget   *widget,
3367                            const gchar *tip_text,
3368                            const gchar *tip_private );
3369 </verb></tscreen>
3370
3371 El primer argumento es el <em/tooltip/ que ya ha creado, seguido del
3372 <em/widget/ al que se desea asociar el <em/tooltip/, el tercero es el
3373 texto que se quiere que aparezca y el último es una cadena de texto
3374 que puede ser usada como un identificador cuando se usa GtkTipsQuery
3375 para desarollar ayuda sensible al contexto. Por ahora conviene dejarlo
3376 como NULL.
3377
3378 <!-- TODO: sort out what how to do the context sensitive help -->
3379
3380 Veamos un ejemplo:
3381
3382 <tscreen><verb>
3383 GtkTooltips *tooltips;
3384 GtkWidget *boton;
3385 ...
3386 tooltips = gtk_tooltips_new ();
3387 boton = gtk_button_new_with_label ("botón 1");
3388 ...
3389 gtk_tooltips_set_tip (tooltips, boton, "Este es el botón 1", NULL);
3390 </verb></tscreen>
3391
3392 Existen otras funciones que pueden ser usadas con los <em/tooltips/. 
3393 Solamente vamos a enumerlarlas añadiendo una pequeña descripción
3394 de que hace cada una.
3395
3396 <tscreen><verb>
3397 void gtk_tooltips_enable( GtkTooltips *tooltips );
3398 </verb></tscreen>
3399
3400 Permite que funcionen un conjunto de <em/tooltips/
3401
3402 <tscreen><verb>
3403 void gtk_tooltips_disable( GtkTooltips *tooltips );
3404 </verb></tscreen>
3405
3406 Oculta un conjunto de <em/tooltips/ para que no pueda ser mostrado.
3407
3408 <tscreen><verb>
3409 void gtk_tooltips_set_delay( GtkTooltips *tooltips,
3410                              gint         delay );
3411
3412 </verb></tscreen>
3413
3414 Establece cuantos milisegundos tiene que estar el puntero sobre el
3415 <em/widget/ para que aparezca el <em/tooltip/. Por defecto se usan 1000
3416 milisegundos (1 segundo).
3417
3418 <tscreen><verb>
3419 void gtk_tooltips_set_colors( GtkTooltips *tooltips,
3420                               GdkColor    *background,
3421                               GdkColor    *foreground );
3422 </verb></tscreen>
3423
3424 Establece el color del texto y del fondo del <em/tooltip/. No se como
3425 se especifica el color.
3426
3427 <!-- ----------------------------------------------------------------- -->
3428 <sect1> Barras de progreso <label id="sec_ProgressBar">
3429 <p>
3430 Estas barras se usan para mostrar el estado de una operación. Son
3431 bastante sencillas de utilizar, tal y como se verá en los ejemplos
3432 siguientes. Pero primero vamos a ver cuales son las funciones que hay
3433 que utilizar para crear una nueva barra de progreso.
3434
3435 Hay dos formas de crear una nueva barra de progreso, la sencilla no
3436 necesita de argumentos, y la otra recibe un objeto GtkAdjustment. Si
3437 se utiliza la primera forma, la barra de progreso creará su propio
3438 GtkAdjustment. 
3439
3440 <tscreen><verb>
3441 GtkWidget *gtk_progress_bar_new( void );
3442
3443 GtkWidget *gtk_progress_bar_new_with_adjustment( GtkAdjustment *adjustment );
3444 </verb></tscreen>
3445
3446 El segundo método tiene la ventaja de que podemos utilizar el objeto
3447 adjustment para especificar nuestro propio rango de parámetros para la
3448 barra de progreso.
3449
3450 El ajuste de una barra de progreso se puede cambiar de forma dinámica
3451 utilizando: 
3452
3453 <tscreen><verb>
3454 void gtk_progress_set_adjustment( GtkProgress   *progress,
3455                                   GtkAdjustment *adjustment );
3456 </verb></tscreen>
3457
3458 Ahora que hemos creado la barra de progreso ya podemos utilizarla.
3459
3460 <tscreen><verb>
3461 void gtk_progress_bar_update( GtkProgressBar *pbar,
3462                               gfloat          percentage );
3463 </verb></tscreen>
3464
3465 El primer argumento es la barra que se quiere manejar, el segundo es
3466 tanto por ciento que ha sido `completado' (indica cuanto ha sido
3467 llenada la barra y oscila entre 0-100%). El valor que se le tiene que
3468 pasar oscila entre 0 y 1.
3469
3470 GTK+ v1.2 ha añadido una nueva característica a la barra de progreso,
3471 y es que ahora permite mostrar su valor de varias maneras distintas, e
3472 informar al usuario del valor y rango actual.
3473
3474 Una barra de progreso puede mostrarse con distintas orientaciones
3475 utilizando la función 
3476
3477 <tscreen><verb>
3478 void gtk_progress_bar_set_orientation( GtkProgressBar *pbar,
3479                                        GtkProgressBarOrientation orientation );
3480 </verb></tscreen>
3481
3482 Donde el argumento <tt/orientación/ puede tomar uno de los valores que
3483 vienen a continuación para indicar la dirección en la que se mueve la
3484 barra de progreso: 
3485
3486 <itemize>
3487 <item> GTK_PROGRESS_LEFT_TO_RIGHT
3488 <item> GTK_PROGRESS_RIGHT_TO_LEFT
3489 <item> GTK_PROGRESS_BOTTOM_TO_TOP
3490 <item> GTK_PROGRESS_TOP_TO_BOTTOM
3491 </itemize>
3492
3493 Cuando se utiliza como una medida de cuanto se ha completado de un
3494 proceso, la barra de progreso puede configurarse para que muestre su
3495 valor de una forma continua o discreta. En modo continuo, la barra de
3496 progreso se actualiza mediante un número discreto de bloques, el
3497 número de bloques también es configurable. 
3498
3499 Se puede configurar el estilo de la barra de progreso utilizando la
3500 siguiente función:
3501
3502 <tscreen><verb>
3503 void gtk_progress_bar_set_bar_style( GtkProgressBar      *pbar,
3504                                      GtkProgressBarStyle  style );
3505 </verb></tscreen>
3506
3507 El parámetro <tt/style/ puede tomar uno de los dos valores siguientes:
3508
3509 <itemize>
3510 <item>GTK_PROGRESS_CONTINUOUS
3511 <item>GTK_PROGRESS_DISCRETE
3512 </itemize>
3513
3514 El número de bloques se puede establecer utilizando 
3515
3516 <tscreen><verb>
3517 void gtk_progress_bar_set_discrete_blocks( GtkProgressBar *pbar,
3518                                            guint           blocks );
3519 </verb></tscreen>
3520
3521 La barra de progreso también se puede utilizar, a parte de para
3522 indicar lo «avanzado» de una tarea, para indicar que hay algún tipo
3523 de actividad. Esto puede ser útil en situaciones donde no se pueda
3524 medir el progreso de una tarea con un rango de valores. Para el modo
3525 actividad, no sirve el estilo de barra que se ha descrito más
3526 arriba. Este modo hay que seleccionarlo utilizando la siguiente
3527 función: 
3528
3529 <tscreen><verb>
3530 void gtk_progress_set_activity_mode( GtkProgress *progress,
3531                                      guint        activity_mode );
3532 </verb></tscreen>
3533
3534 El tamaño del paso del indicador de actividad, y el número de bloques
3535 se indican usando las siguientes funciones:
3536
3537 <tscreen><verb>
3538 void gtk_progress_bar_set_activity_step( GtkProgressBar *pbar,
3539                                          guint           step );
3540
3541 void gtk_progress_bar_set_activity_blocks( GtkProgressBar *pbar,
3542                                            guint           blocks );
3543 </verb></tscreen>
3544
3545 Cuando estamos en modo continuo, la barra de progreso puede mostrar un
3546 texto configurable dentro la barra misma, utilizando la función
3547 siguiente: 
3548
3549 <tscreen><verb>
3550 void gtk_progress_set_format_string( GtkProgress *progress,
3551                                      gchar       *format);
3552 </verb></tscreen>
3553
3554 El argumento <tt/format/ es parecido al que se utiliza en una orden
3555 <tt/printf/ de C. Se pueden utilizar las siguientes opciones para el
3556 formateado de la cadena: 
3557
3558 <itemize>
3559 <item> %p - porcentaje
3560 <item> %v - valor
3561 <item> %l - valor inferior del rango
3562 <item> %u - valor superior del rango
3563 </itemize>
3564
3565 Puede activar o desactivar el texto utilizando:
3566
3567 <tscreen><verb>
3568 void gtk_progress_set_show_text( GtkProgress *progress,
3569                                  gint         show_text );
3570 </verb></tscreen>
3571
3572 El argumento <tt/show_text/ es un valor booleano TRUE/FALSE. La
3573 apariencia del texto puede modificarse utilizando: 
3574
3575 <tscreen><verb>
3576 void gtk_progress_set_text_alignment( GtkProgress   *progress,
3577                                       gfloat         x_align,
3578                                       gfloat         y_align );
3579 </verb></tscreen>
3580
3581 Los argumentos <tt/x_align/ y <tt/y_align/ toman un valor entre 0.0 y
3582 1.0. Este valor indica la posición de la cadena de texto dentro de la
3583 barra. Si ponemos 0.0 en los dos sitios la cadena de texto aparecerá
3584 en la esquina superior izquierda; un valor de 0.5 (el que se utiliza
3585 por defecto) centra el texto, y un valor de 1.0 coloca el texto en la
3586 esquina inferior derecha.
3587
3588 Se pueden leer los parámetros actuales del texto de un objeto barra
3589 de progreso utilizando las dos funciones que se muestran a
3590 continuación. La cadena de carácteres devuelta por estas funciones
3591 debe liberarse en la aplicación (utilizando la función
3592 g_free()). Estas funciones devuelven el texto formateado que se
3593 mostrará en la barra.
3594
3595 <tscreen><verb>
3596 gchar *gtk_progress_get_current_text( GtkProgress   *progress );
3597
3598 gchar *gtk_progress_get_text_from_value( GtkProgress *progress,
3599                                          gfloat       value );
3600 </verb></tscreen>
3601
3602 Hay otra forma de cambiar el rango y el valor de un objeto barra de
3603 progreso utilizando la función: 
3604
3605 <tscreen><verb>
3606 void gtk_progress_configure( GtkProgress  *progress,
3607                              gfloat        value,
3608                              gfloat        min,
3609                              gfloat        max );
3610 </verb></tscreen>
3611
3612 Esta función proporciona una interfaz sencilla al rango y valor de una
3613 barra de progreso.
3614
3615 Las funciones restantes se pueden utilizar para obtener y establecer
3616 el valor actual de una barra de progreso utilizando distintos tipos y
3617 formatos para el valor.
3618
3619 <tscreen><verb>
3620 void gtk_progress_set_percentage( GtkProgress *progress,
3621                                   gfloat       percentage );
3622
3623 void gtk_progress_set_value( GtkProgress *progress,
3624                              gfloat       value );
3625
3626 gfloat gtk_progress_get_value( GtkProgress *progress );
3627
3628 gfloat gtk_progress_get_current_percentage( GtkProgress *progress );
3629
3630 gfloat gtk_progress_get_percentage_from_value( GtkProgress *progress,
3631                                                gfloat       value );
3632 </verb></tscreen>
3633
3634 Estas funciones son autoexplicatorias. La última función utiliza el
3635 ajuste de la barra de progreso especificada para calcular el
3636 porcentaje dentro del rango de valores de la barra. 
3637
3638 Las barras de progreso se usan con otras funciones como los tiempos de
3639 espera (<em/timeouts/), sección <ref id="sec_timeouts"
3640 name="Tiempos de espera, E/S (I/O) y funciones ociosas (idle)">) para
3641 crear la ilusión de la multitarea. Todas usan la función
3642 gtk_progress_bar_update de la misma manera.
3643
3644 Estudiemos un ejemplo de barras de progreso actualizada usando
3645 tiempos de espera. También se muestra como se debe reestablecer una
3646 barra.
3647
3648 <tscreen><verb>
3649 /* comienzo del programa-ejemplo progressbar.c */
3650
3651 #include <gtk/gtk.h>
3652
3653 #include <gtk/gtk.h>
3654
3655 typedef struct _ProgressData {
3656     GtkWidget *ventana;
3657     GtkWidget *pbar;
3658     int timer;
3659 } ProgressData;
3660
3661 /* Actualiza el valor de la barra de progreso para que
3662  * podamos ver algún movimiento */
3663 gint progress_timeout( gpointer data )
3664 {
3665     gfloat new_val;
3666     GtkAdjustment *adj;
3667
3668     /* Calcula el valor de la barra de progreso utilizando
3669      * el rango de valores establecido en el ajuste de la
3670      * barra */
3671
3672     new_val = gtk_progress_get_value( GTK_PROGRESS(data) ) + 1;
3673
3674     adj = GTK_PROGRESS (data)->adjustment;
3675     if (new_val > adj->upper)
3676       new_val = adj->lower;
3677
3678     /* Establece el nuevo valor */
3679
3680     gtk_progress_set_value (GTK_PROGRESS (data), new_val);
3681
3682     /* Como esta es una función de espera, devolvemos TRUE
3683      * para que continue siendo llamada */
3684
3685     return(TRUE);
3686
3687
3688 /* Función de llamada que activa/desactiva el texto de dentro
3689  * de la barra de progreso */
3690 void toggle_show_text( GtkWidget    *widget,
3691                        ProgressData *pdata )
3692 {
3693     gtk_progress_set_show_text (GTK_PROGRESS (pdata->pbar),
3694                                 GTK_TOGGLE_BUTTON (widget)->active);
3695 }
3696
3697 /* Función de llamada que activa/desactiva el modo actividad
3698  * de la barra de progreso */
3699 void toggle_activity_mode( GtkWidget    *widget,
3700                            ProgressData *pdata )
3701 {
3702     gtk_progress_set_activity_mode (GTK_PROGRESS (pdata->pbar),
3703                                     GTK_TOGGLE_BUTTON (widget)->active);
3704 }
3705
3706 /* Función de llamada que activa/desactiva el modo continuo
3707  * de la barra de progreso */
3708 void set_continuous_mode( GtkWidget    *widget,
3709                           ProgressData *pdata )
3710 {
3711     gtk_progress_bar_set_bar_style (GTK_PROGRESS_BAR (pdata->pbar),
3712                                     GTK_PROGRESS_CONTINUOUS);
3713 }
3714
3715 /* Función de llamada que activa/desactiva el modo discreto
3716  * de la barra de progreso */
3717 void set_discrete_mode( GtkWidget    *widget,
3718                         ProgressData *pdata )
3719 {
3720     gtk_progress_bar_set_bar_style (GTK_PROGRESS_BAR (pdata->pbar),
3721                                     GTK_PROGRESS_DISCRETE);
3722 }
3723  
3724 /* Libera la memoria y elimina el temporizador */
3725 void destroy_progress( GtkWidget     *widget,
3726                        ProgressData *pdata)
3727 {
3728     gtk_timeout_remove (pdata->timer);
3729     pdata->timer = 0;
3730     pdata->ventana = NULL;
3731     g_free(pdata);
3732     gtk_main_quit();
3733 }
3734
3735 int main( int   argc,
3736           char *argv[])
3737 {
3738     ProgressData *pdata;
3739     GtkWidget *align;
3740     GtkWidget *separator;
3741     GtkWidget *table;
3742     GtkAdjustment *adj;
3743     GtkWidget *boton;
3744     GtkWidget *check;
3745     GtkWidget *vbox;
3746
3747     gtk_init (&amp;argc, &amp;argv);
3748
3749     /* Reserva memoria para los datos que se le pasan a las funciones
3750      * de llamada */
3751     pdata = g_malloc( sizeof(ProgressData) );
3752   
3753     pdata->ventana = gtk_window_new (GTK_WINDOW_TOPLEVEL);
3754     gtk_window_set_policy (GTK_WINDOW (pdata->ventana), FALSE, FALSE, TRUE);
3755
3756     gtk_signal_connect (GTK_OBJECT (pdata->ventana), "destroy",
3757                         GTK_SIGNAL_FUNC (destroy_progress),
3758                         pdata);
3759     gtk_window_set_title (GTK_WINDOW (pdata->ventana), "GtkProgressBar");
3760     gtk_container_set_border_width (GTK_CONTAINER (pdata->ventana), 0);
3761
3762     vbox = gtk_vbox_new (FALSE, 5);
3763     gtk_container_set_border_width (GTK_CONTAINER (vbox), 10);
3764     gtk_container_add (GTK_CONTAINER (pdata->ventana), vbox);
3765     gtk_widget_show(vbox);
3766   
3767     /* Crea un objeto de alineamiento centrado */
3768     align = gtk_alignment_new (0.5, 0.5, 0, 0);
3769     gtk_box_pack_start (GTK_BOX (vbox), align, FALSE, FALSE, 5);
3770     gtk_widget_show(align);
3771
3772     /* Crea un objeto GtkAdjusment para albergar el rango de la barra
3773      * de progreso */
3774     adj = (GtkAdjustment *) gtk_adjustment_new (0, 1, 150, 0, 0, 0);
3775
3776     /* Crea la GtkProgressBar utilizando el ajuste */
3777     pdata->pbar = gtk_progress_bar_new_with_adjustment (adj);
3778
3779     /* Establece el formato de la cadena de texto que puede mostrarse
3780      * en la barra de progreso:
3781      * %p - porcentaje
3782      * %v - valor
3783      * %l - valor inferior del rango
3784      * %u - valor superior del rango */
3785     gtk_progress_set_format_string (GTK_PROGRESS (pdata->pbar),
3786                                     "%v from [%l-%u] (=%p%%)");
3787     gtk_container_add (GTK_CONTAINER (align), pdata->pbar);
3788     gtk_widget_show(pdata->pbar);
3789
3790     /* Añade un temporizador para la actualización del valor de la
3791      * barra de progreso */
3792     pdata->timer = gtk_timeout_add (100, progress_timeout, pdata->pbar);
3793
3794     separator = gtk_hseparator_new ();
3795     gtk_box_pack_start (GTK_BOX (vbox), separator, FALSE, FALSE, 0);
3796     gtk_widget_show(separator);
3797
3798     /* filas, columnas, homogéneo */
3799     table = gtk_table_new (2, 3, FALSE);
3800     gtk_box_pack_start (GTK_BOX (vbox), table, FALSE, TRUE, 0);
3801     gtk_widget_show(table);
3802
3803     /* Añade un botón de comprobación para seleccionar si se debe
3804      * mostrar el texto dentro de la barra */
3805     check = gtk_check_button_new_with_label ("Show text");
3806     gtk_table_attach (GTK_TABLE (table), check, 0, 1, 0, 1,
3807                       GTK_EXPAND | GTK_FILL, GTK_EXPAND | GTK_FILL,
3808                       5, 5);
3809     gtk_signal_connect (GTK_OBJECT (check), "clicked",
3810                         GTK_SIGNAL_FUNC (toggle_show_text),
3811                         pdata);
3812     gtk_widget_show(check);
3813
3814     /* Añade un botón de comprobación para activar/desactivar el modo
3815      * actividad */
3816     check = gtk_check_button_new_with_label ("Activity mode");
3817     gtk_table_attach (GTK_TABLE (table), check, 0, 1, 1, 2,
3818                       GTK_EXPAND | GTK_FILL, GTK_EXPAND | GTK_FILL,
3819                       5, 5);
3820     gtk_signal_connect (GTK_OBJECT (check), "clicked",
3821                         GTK_SIGNAL_FUNC (toggle_activity_mode),
3822                         pdata);
3823     gtk_widget_show(check);
3824
3825     separator = gtk_vseparator_new ();
3826     gtk_table_attach (GTK_TABLE (table), separator, 1, 2, 0, 2,
3827                       GTK_EXPAND | GTK_FILL, GTK_EXPAND | GTK_FILL,
3828                       5, 5);
3829     gtk_widget_show(separator);
3830
3831     /* Añade un botón circular para seleccionar el modo continuo */
3832     boton = gtk_radio_button_new_with_label (NULL, "Continuous");
3833     gtk_table_attach (GTK_TABLE (table), boton, 2, 3, 0, 1,
3834                       GTK_EXPAND | GTK_FILL, GTK_EXPAND | GTK_FILL,
3835                       5, 5);
3836     gtk_signal_connect (GTK_OBJECT (boton), "clicked",
3837                         GTK_SIGNAL_FUNC (set_continuous_mode),
3838                         pdata);
3839     gtk_widget_show (boton);
3840
3841     /* Añade un botón circular para seleccionar el modo discreto */
3842     boton = gtk_radio_button_new_with_label(
3843                gtk_radio_button_group (GTK_RADIO_BUTTON (boton)),
3844                "Discrete");
3845     gtk_table_attach (GTK_TABLE (table), boton, 2, 3, 1, 2,
3846                       GTK_EXPAND | GTK_FILL, GTK_EXPAND | GTK_FILL,
3847                       5, 5);
3848     gtk_signal_connect (GTK_OBJECT (boton), "clicked",
3849                         GTK_SIGNAL_FUNC (set_discrete_mode),
3850                         pdata);
3851     gtk_widget_show (boton);
3852
3853     separator = gtk_hseparator_new ();
3854     gtk_box_pack_start (GTK_BOX (vbox), separator, FALSE, FALSE, 0);
3855     gtk_widget_show(separator);
3856
3857     /* Añade un botón para salir del programa */
3858     boton = gtk_button_new_with_label ("close");
3859     gtk_signal_connect_object (GTK_OBJECT (boton), "clicked",
3860                                (GtkSignalFunc) gtk_widget_destroy,
3861                                GTK_OBJECT (pdata->ventana));
3862     gtk_box_pack_start (GTK_BOX (vbox), boton, FALSE, FALSE, 0);
3863
3864     /* Esto hace que este botón sea el botón pueda utilizarse por
3865      * defecto defecto. */
3866     GTK_WIDGET_SET_FLAGS (boton, GTK_CAN_DEFAULT);
3867
3868     /* Esto marca este botón para que sea el botón por
3869      * defecto. Simplemente utilizando la tecla "Intro" haremos que se
3870      * active este botón. */
3871     gtk_widget_grab_default (boton);
3872     gtk_widget_show(boton);
3873
3874     gtk_widget_show (pdata->ventana);
3875
3876     gtk_main ();
3877     
3878     return(0);
3879 }
3880 /* final del ejemplo */
3881 </verb></tscreen>
3882
3883 <!-- ----------------------------------------------------------------- -->
3884 <sect1>Cuadros de diálogo
3885 <p>
3886 El <em/widget/ del cuadro de diálogo es bastante simple, sólo es una
3887 ventana con algunas cosas ya preempaquetadas. Su estructura es la
3888 siguiente:
3889
3890 <tscreen><verb>
3891 struct GtkDialog
3892 {
3893       GtkWindow ventana;
3894     
3895       GtkWidget *vbox;
3896       GtkWidget *action_area;
3897 };
3898 </verb></tscreen>
3899
3900 Simplemente se crea una  ventana en la cual se empaqueta una vbox, un
3901 separador y una hbox llamada «action_area».
3902
3903 Este tipo de <em/widgets/ pueden ser usados como mensages <em/pop-up/
3904 (pequeñas ventanas con texto en su interior que aparecen cuando el
3905 usuario hace algo y queremos informarle de alguna cosa) y otras cosas
3906 parecidas. Su manejo desde el punto de vista del programador
3907 es bastante fácil, sólo hay que usar una función: 
3908
3909 <tscreen><verb>
3910 GtkWidget *gtk_dialog_new( void );
3911 </verb></tscreen>
3912
3913 Para crear un nuevo cuadro de diálogo hay que llamar a:
3914
3915 <tscreen><verb>
3916 GtkWidget *ventana;
3917 ventana = gtk_dialog_new ();
3918 </verb></tscreen>
3919
3920 Una vez que el cuadro ha sido creado sólo hay que usarlo. Por
3921 ejemplo para empaquetar un botón en la action_area escribiríamos
3922 algo así:
3923
3924 <tscreen><verb>
3925 boton = ...
3926 gtk_box_pack_start (GTK_BOX (GTK_DIALOG (ventana)->action_area), boton,
3927                     TRUE, TRUE, 0);
3928 gtk_widget_show (boton);
3929 </verb></tscreen>
3930
3931 Otra cosa que nos puede interesar es empaquetar una etiqueta en la
3932 vbox:
3933
3934 <tscreen><verb>
3935 etiqueta = gtk_label_new ("Dialogs are groovy");
3936 gtk_box_pack_start (GTK_BOX (GTK_DIALOG (ventana)->vbox), etiqueta, TRUE,
3937                     TRUE, 0);
3938 gtk_widget_show (etiqueta);
3939 </verb></tscreen>
3940
3941 Otros ejemplo posible es poner dos botones en el action_area (uno 
3942 para cancelar y el otro para permitir algo) junto con una etiqueta en
3943 la vbox el usuario puede seleccionar lo que quiera.
3944
3945 Si se precisa algo más complejo siempre se puede empaquetar otro
3946 <em/widget/ en cualquiera de las cajas (p.j. una tabla en una vbox).
3947
3948 <!-- ----------------------------------------------------------------- -->
3949 <sect1> <em/Pixmaps/ <label id="sec_Pixmaps">
3950 <p>
3951 Los <em/pixmaps/ son estructuras de datos que contienen dibujos. Estos
3952 pueden ser usados en diferentes lugares, pero los iconos y los
3953 cursores son los más comunes.
3954
3955 Un <em/bitmap/ es un <em/pixmap/ que sólo tiene dos colores, y hay
3956 unas cuantas rutinas especiales para controlar este caso particular.
3957
3958 Para comprender los <em/pixmaps/, puede ayudar entender como funciona
3959 X-windows. Bajo X-windows, las aplicaciones no tienen porque estar
3960 ejecutándose en el ordenador que está interactuando con el
3961 usuario. Las distintas aplicaciones, llamadas «clientes», comunican
3962 con un programa que muestra los gráficos y que controla el tecledo y
3963 el ratón. Este programa que interactua directamente con el usuario se
3964 llama un «<em/display server/» o «servidor X». Como la
3965 comunicación entre el servidor y el cliente puede llevarse a cabo
3966 mediante una red, es importante mantener alguna información en el
3967 servidor X. Los <em/pixmaps/ por ejemplo, se almacenan en la memoria
3968 del servidor X. Esto significa que una vez que se establecen los
3969 valores del <em/pixmap/, no tienen que estar transmitiéndose por la
3970 red; en su lugar lo único que hay que enviar es una orden del estilo
3971 «mostrar <em/pixmap/ número XYZ aquí». Incluso si no está utilizando
3972 X-windows con GTK, al utilizar construcciones como los <em/pixmaps/
3973 conseguirá que sus programas funciones de forma aceptable bajo
3974 X-windows. 
3975
3976 Para usar un <em/pixmap/ en GTK primero tiene que construir una
3977 estructura del tipo GdkPixmap usando rutinas de GDK. Los <em/pixmaps/
3978 se pueden crear usando datos que se encuentren en la memoria o en un
3979 archivo. Veremos con detalle cada una de las dos posibilidades.
3980
3981 <tscreen><verb>
3982 GdkPixmap *gdk_bitmap_create_from_data( GdkWindow *ventana,
3983                                         gchar     *data,
3984                                         gint       width,
3985                                         gint       height );
3986 </verb></tscreen>
3987
3988 Esta rutina se utiliza para crear un <em/bitmap/ a partir de datos
3989 almacenados en la memoria. Cada bit de información indica si el
3990 <em/pixel/ luce o no. Tanto la altura como la anchura estan expresadas
3991 en <em/pixels/. El puntero del tipo GdkWindow indica la ventana en
3992 cuestión, ya que los <em/pixmaps/ sólo tienen sentido dentro de
3993 la pantalla en la que van a ser mostrados.
3994
3995 <tscreen><verb>
3996 GdkPixmap *gdk_pixmap_create_from_data( GdkWindow *ventana,
3997                                         gchar     *data,
3998                                         gint       width,
3999                                         gint       height,
4000                                         gint       depth,
4001                                         GdkColor  *fg,
4002                                         GdkColor  *bg );
4003 </verb></tscreen>
4004
4005 Con esto creamos un <em/pixmap/ con la profundidad (número de
4006 colores) especificada en los datos del <em/bitmap/. Los valores
4007 <tt/fg/ y <tt/bg/ son los colores del frente y del fondo
4008 respectivamente.
4009
4010 <tscreen><verb>
4011 GdkPixmap *gdk_pixmap_create_from_xpm( GdkWindow   *ventana,
4012                                        GdkBitmap  **mask,
4013                                        GdkColor    *transparent_color,
4014                                        const gchar *filename );
4015 </verb></tscreen>
4016
4017 El formato XPM es una representacion de los <em/pixmaps/ para el
4018 sistema X Window. Es bastante popular y existen muchos programas para
4019 crear imágenes en este formato. El archivo especificado mediante
4020 <tt/filename/ debe contener una imagen en ese formato para que sea
4021 cargada en la estructura. La máscara especifica que bits son
4022 opacos. Todos los demás bits se colorean usando el color
4023 especificado en <tt/transparent_color/. Más adelante veremos un
4024 ejemplo.
4025
4026 <tscreen><verb>
4027 GdkPixmap *gdk_pixmap_create_from_xpm_d( GdkWindow  *ventana,
4028                                          GdkBitmap **mask,
4029                                          GdkColor   *transparent_color,
4030                                          gchar     **data );
4031 </verb></tscreen>
4032
4033 Se pueden incorporar imágenes pequeñas dentro de un programa en
4034 formato XPM. Un <em/pixmap/ se crea usando esta información, en
4035 lugar de leerla de un archivo. Un ejemplo sería:
4036
4037 <tscreen><verb>
4038 /* XPM */
4039 static const char * xpm_data[] = {
4040 "16 16 3 1",
4041 "       c None",
4042 ".      c #000000000000",
4043 "X      c #FFFFFFFFFFFF",
4044 "                ",
4045 "   ......       ",
4046 "   .XXX.X.      ",
4047 "   .XXX.XX.     ",
4048 "   .XXX.XXX.    ",
4049 "   .XXX.....    ",
4050 "   .XXXXXXX.    ",
4051 "   .XXXXXXX.    ",
4052 "   .XXXXXXX.    ",
4053 "   .XXXXXXX.    ",
4054 "   .XXXXXXX.    ",
4055 "   .XXXXXXX.    ",
4056 "   .XXXXXXX.    ",
4057 "   .........    ",
4058 "                ",
4059 "                "};
4060 </verb></tscreen>
4061
4062 Cuando hayamos acabado de usar un <em/pixmap/ y no lo vayamos a usar
4063 durante un tiempo suele ser conveniente liberar el recurso mediante
4064 gdk_pixmap_unref(). (Los <em/pixmaps/ deben ser considerados recursos
4065 preciosos).
4066
4067 Una vez que hemos creado el <em/pixmap/ lo podemos mostrar como un
4068 <em/widget/ GTK. Primero tenemos que crear un <em/widget pixmap/ que
4069 contenga un <em/pixmap/ GDK. Esto se hace usando: 
4070
4071 <tscreen><verb>
4072 GtkWidget *gtk_pixmap_new( GdkPixmap *pixmap,
4073                            GdkBitmap *mask );
4074 </verb></tscreen>
4075
4076 Las otras funciones del <em/widget pixmap/ son: 
4077
4078 <tscreen><verb>
4079 guint gtk_pixmap_get_type( void );
4080
4081 void  gtk_pixmap_set( GtkPixmap  *pixmap,
4082                       GdkPixmap  *val,
4083                       GdkBitmap  *mask );
4084
4085 void  gtk_pixmap_get( GtkPixmap  *pixmap,
4086                       GdkPixmap **val,
4087                       GdkBitmap **mask);
4088 </verb></tscreen>
4089
4090 La función gtk_pixmap_set se usa para cambiar los datos del
4091 <em/pixmap/ que el <em/widget/ está manejando en ese
4092 momento. <tt/val/ es el <em/pixmap/ creado usando GDK.
4093
4094 El ejemplo siguiente usa un <em/pixmap/ en un botón:
4095
4096 <tscreen><verb>
4097 /* comienzo del ejemplo pixmap.c */
4098
4099 #include <gtk/gtk.h>
4100
4101
4102 /* Datos en formato XPM del icono de apertura de archivo */
4103 static const char * xpm_data[] = {
4104 "16 16 3 1",
4105 "       c None",
4106 ".      c #000000000000",
4107 "X      c #FFFFFFFFFFFF",
4108 "                ",
4109 "   ......       ",
4110 "   .XXX.X.      ",
4111 "   .XXX.XX.     ",
4112 "   .XXX.XXX.    ",
4113 "   .XXX.....    ",
4114 "   .XXXXXXX.    ",
4115 "   .XXXXXXX.    ",
4116 "   .XXXXXXX.    ",
4117 "   .XXXXXXX.    ",
4118 "   .XXXXXXX.    ",
4119 "   .XXXXXXX.    ",
4120 "   .XXXXXXX.    ",
4121 "   .........    ",
4122 "                ",
4123 "                "};
4124
4125 /* Cuando se llama a esta función (usando signal delete_event) se
4126  * termina la aplicación*/
4127
4128 void close_application( GtkWidget *widget, GdkEvent *event, gpointer data ) {
4129     gtk_main_quit();
4130 }
4131
4132
4133 /* Al presionar el botón aparece el mensaje */
4134 void button_clicked( GtkWidget *widget, gpointer data ) {
4135     printf( "botón pulsado\n" );
4136 }
4137
4138 int main( int argc, char *argv[] )
4139 {
4140     
4141     GtkWidget *ventana, *pixmapwid, *boton;
4142     GdkPixmap *pixmap;
4143     GdkBitmap *mask;
4144     GtkStyle *style;
4145     
4146     /* Creamos la ventana principal y relacionamos la señal
4147      * delete_event con acabar el programa.*/
4148     gtk_init( &amp;argc, &amp;argv );
4149     ventana = gtk_window_new( GTK_WINDOW_TOPLEVEL );
4150     gtk_signal_connect( GTK_OBJECT (ventana), "delete_event",
4151                         GTK_SIGNAL_FUNC (close_application), NULL );
4152     gtk_container_border_width( GTK_CONTAINER (ventana), 10 );
4153     gtk_widget_show( ventana );
4154
4155     /* Ahora para el pixmap de gdk */
4156     style = gtk_widget_get_style( ventana );
4157     pixmap = gdk_pixmap_create_from_xpm_d( ventana->window,  &amp;mask,
4158                                            &amp;style->bg[GTK_STATE_NORMAL],
4159                                            (gchar **)xpm_data );
4160
4161     /* Un pixmap widget que contendrá al pixmap */
4162     pixmapwid = gtk_pixmap_new( pixmap, mask );
4163     gtk_widget_show( pixmapwid );
4164
4165     /* Un botón para contener al pixmap */
4166     boton = gtk_button_new();
4167     gtk_container_add( GTK_CONTAINER(boton), pixmapwid );
4168     gtk_container_add( GTK_CONTAINER(ventana), boton );
4169     gtk_widget_show( boton );
4170
4171     gtk_signal_connect( GTK_OBJECT(boton), "clicked",
4172                         GTK_SIGNAL_FUNC(button_clicked), NULL );
4173
4174     /* mostramos la ventana */
4175     gtk_main ();
4176           
4177     return 0;
4178 }
4179 /* final del ejemplo */
4180 </verb></tscreen>
4181
4182 Para cargar un archivo llamado icon0.xpm con la información XPM (que
4183 se encuentra en en directorio actual) habríamos usado:
4184
4185 <tscreen><verb>
4186     /* cargar un pixmap desde un fichero */
4187     pixmap = gdk_pixmap_create_from_xpm( ventana->window, &amp;mask,
4188                                          &amp;style->bg[GTK_STATE_NORMAL],
4189                                          "./icon0.xpm" );
4190     pixmapwid = gtk_pixmap_new( pixmap, mask );
4191     gtk_widget_show( pixmapwid );
4192     gtk_container_add( GTK_CONTAINER(ventana), pixmapwid );
4193 </verb></tscreen>
4194
4195 Una desventaja de los <em/pixmaps/ es que la imagen mostrada siempre
4196 es rectangular (independientemente de como sea la imagen en sí). Si
4197 queremos usar imágenes con otras formas debemos usar ventanas con
4198 forma (<em/shaped windows/).
4199
4200 Este tipo de ventanas son pixmaps en los que el fondo es
4201 transparente. Así cuando la imagen del fondo tiene muchos colores
4202 no los sobreescribimos con el borde de nuestro icono. El ejemplo
4203 siguiente muestra la imagen de una carretilla en el escritorio.
4204
4205 <tscreen><verb>
4206 /* comienzo del ejemplo carretilla wheelbarrow.c */
4207
4208 #include <gtk/gtk.h>
4209
4210 /* XPM */
4211 static char * WheelbarrowFull_xpm[] = {
4212 "48 48 64 1",
4213 "       c None",
4214 ".      c #DF7DCF3CC71B",
4215 "X      c #965875D669A6",
4216 "o      c #71C671C671C6",
4217 "O      c #A699A289A699",
4218 "+      c #965892489658",
4219 "@      c #8E38410330C2",
4220 "#      c #D75C7DF769A6",
4221 "$      c #F7DECF3CC71B",
4222 "%      c #96588A288E38",
4223 "&amp;      c #A69992489E79",
4224 "*      c #8E3886178E38",
4225 "=      c #104008200820",
4226 "-      c #596510401040",
4227 ";      c #C71B30C230C2",
4228 ":      c #C71B9A699658",
4229 ">      c #618561856185",
4230 ",      c #20811C712081",
4231 "<      c #104000000000",
4232 "1      c #861720812081",
4233 "2      c #DF7D4D344103",
4234 "3      c #79E769A671C6",
4235 "4      c #861782078617",
4236 "5      c #41033CF34103",
4237 "6      c #000000000000",
4238 "7      c #49241C711040",
4239 "8      c #492445144924",
4240 "9      c #082008200820",
4241 "0      c #69A618611861",
4242 "q      c #B6DA71C65144",
4243 "w      c #410330C238E3",
4244 "e      c #CF3CBAEAB6DA",
4245 "r      c #71C6451430C2",
4246 "t      c #EFBEDB6CD75C",
4247 "y      c #28A208200820",
4248 "u      c #186110401040",
4249 "i      c #596528A21861",
4250 "p      c #71C661855965",
4251 "a      c #A69996589658",
4252 "s      c #30C228A230C2",
4253 "d      c #BEFBA289AEBA",
4254 "f      c #596545145144",
4255 "g      c #30C230C230C2",
4256 "h      c #8E3882078617",
4257 "j      c #208118612081",
4258 "k      c #38E30C300820",
4259 "l      c #30C2208128A2",
4260 "z      c #38E328A238E3",
4261 "x      c #514438E34924",
4262 "c      c #618555555965",
4263 "v      c #30C2208130C2",
4264 "b      c #38E328A230C2",
4265 "n      c #28A228A228A2",
4266 "m      c #41032CB228A2",
4267 "M      c #104010401040",
4268 "N      c #492438E34103",
4269 "B      c #28A2208128A2",
4270 "V      c #A699596538E3",
4271 "C      c #30C21C711040",
4272 "Z      c #30C218611040",
4273 "A      c #965865955965",
4274 "S      c #618534D32081",
4275 "D      c #38E31C711040",
4276 "F      c #082000000820",
4277 "                                                ",
4278 "          .XoO                                  ",
4279 "         +@#$%o&amp;                                ",
4280 "         *=-;#::o+                              ",
4281 "           >,<12#:34                            ",
4282 "             45671#:X3                          ",
4283 "               +89<02qwo                        ",
4284 "e*                >,67;ro                       ",
4285 "ty>                 459@>+&amp;&amp;                    ",
4286 "$2u+                  ><ipas8*                  ",
4287 "%$;=*                *3:.Xa.dfg>                ",
4288 "Oh$;ya             *3d.a8j,Xe.d3g8+             ",
4289 " Oh$;ka          *3d$a8lz,,xxc:.e3g54           ",
4290 "  Oh$;kO       *pd$%svbzz,sxxxxfX..&amp;wn>         ",
4291 "   Oh$@mO    *3dthwlsslszjzxxxxxxx3:td8M4       ",
4292 "    Oh$@g&amp; *3d$XNlvvvlllm,mNwxxxxxxxfa.:,B*     ",
4293 "     Oh$@,Od.czlllllzlmmqV@V#V@fxxxxxxxf:%j5&amp;   ",
4294 "      Oh$1hd5lllslllCCZrV#r#:#2AxxxxxxxxxcdwM*  ",
4295 "       OXq6c.%8vvvllZZiqqApA:mq:Xxcpcxxxxxfdc9* ",
4296 "        2r<6gde3bllZZrVi7S@SV77A::qApxxxxxxfdcM ",
4297 "        :,q-6MN.dfmZZrrSS:#riirDSAX@Af5xxxxxfevo",
4298 "         +A26jguXtAZZZC7iDiCCrVVii7Cmmmxxxxxx%3g",
4299 "          *#16jszN..3DZZZZrCVSA2rZrV7Dmmwxxxx&amp;en",
4300 "           p2yFvzssXe:fCZZCiiD7iiZDiDSSZwwxx8e*>",
4301 "           OA1<jzxwwc:$d%NDZZZZCCCZCCZZCmxxfd.B ",
4302 "            3206Bwxxszx%et.eaAp77m77mmmf3&amp;eeeg* ",
4303 "             @26MvzxNzvlbwfpdettttttttttt.c,n&amp;  ",
4304 "             *;16=lsNwwNwgsvslbwwvccc3pcfu<o    ",
4305 "              p;<69BvwwsszslllbBlllllllu<5+     ",
4306 "              OS0y6FBlvvvzvzss,u=Blllj=54       ",
4307 "               c1-699Blvlllllu7k96MMMg4         ",
4308 "               *10y8n6FjvllllB<166668           ",
4309 "                S-kg+>666<M<996-y6n<8*          ",
4310 "                p71=4 m69996kD8Z-66698&amp;&amp;        ",
4311 "                &amp;i0ycm6n4 ogk17,0<6666g         ",
4312 "                 N-k-<>     >=01-kuu666>        ",
4313 "                 ,6ky&amp;      &amp;46-10ul,66,        ",
4314 "                 Ou0<>       o66y<ulw<66&amp;       ",
4315 "                  *kk5       >66By7=xu664       ",
4316 "                   <<M4      466lj<Mxu66o       ",
4317 "                   *>>       +66uv,zN666*       ",
4318 "                              566,xxj669        ",
4319 "                              4666FF666>        ",
4320 "                               >966666M         ",
4321 "                                oM6668+         ",
4322 "                                  *4            ",
4323 "                                                ",
4324 "                                                "};
4325
4326
4327
4328 void close_application( GtkWidget *widget, GdkEvent *event, gpointer data ) {
4329     gtk_main_quit();
4330 }
4331
4332 int main (int argc, char *argv[])
4333 {
4334     
4335     GtkWidget *ventana, *pixmap, *fixed;
4336     GdkPixmap *gdk_pixmap;
4337     GdkBitmap *mask;
4338     GtkStyle *style;
4339     GdkGC *gc;
4340     
4341     /* Creamos la ventana principal y relacionamos la señal
4342      * delete_event para terminar la aplicación. Conviene destacar
4343      * que la ventana no tendrá título puesto que es popup.*/
4344     gtk_init (&amp;argc, &amp;argv);
4345     ventana = gtk_window_new( GTK_WINDOW_POPUP );
4346     gtk_signal_connect (GTK_OBJECT (ventana), "delete_event",
4347                         GTK_SIGNAL_FUNC (close_application), NULL);
4348     gtk_widget_show (ventana);
4349
4350     style = gtk_widget_get_default_style();
4351     gc = style->black_gc;
4352     gdk_pixmap = gdk_pixmap_create_from_xpm_d( ventana->window, &amp;mask,
4353                                              &amp;style->bg[GTK_STATE_NORMAL],
4354                                              WheelbarrowFull_xpm );
4355     pixmap = gtk_pixmap_new( gdk_pixmap, mask );
4356     gtk_widget_show( pixmap );
4357
4358     
4359     fixed = gtk_fixed_new();
4360     gtk_widget_set_usize( fixed, 200, 200 );
4361     gtk_fixed_put( GTK_FIXED(fixed), pixmap, 0, 0 );
4362     gtk_container_add( GTK_CONTAINER(ventana), fixed );
4363     gtk_widget_show( fixed );
4364
4365     /* Con esto cubrimos todo menos la imagen */
4366     gtk_widget_shape_combine_mask( ventana, mask, 0, 0 );
4367     
4368     /* mostramos la ventana */
4369     gtk_widget_set_uposition( ventana, 20, 400 );
4370     gtk_widget_show( ventana );
4371     gtk_main ();
4372           
4373     return 0;
4374 }
4375 /* final del ejemplo */
4376 </verb></tscreen>
4377
4378 Para que la carretilla sea más realista podríamos relacionar la
4379 pulsación del botón con que haga algo. Con las líneas
4380 siguientes la pulsación del botón hace que se acabe el programa. 
4381
4382 <tscreen><verb>
4383 gtk_widget_set_events( ventana,
4384                        gtk_widget_get_events( ventana ) |
4385                        GDK_BUTTON_PRESS_MASK );
4386
4387 gtk_signal_connect( GTK_OBJECT(ventana), "button_press_event",
4388                     GTK_SIGNAL_FUNC(close_application), NULL );
4389 </verb></tscreen>
4390
4391 <!-- ----------------------------------------------------------------- -->
4392 <sect1>Reglas
4393 <p>
4394
4395 Las reglas son usadas para indicar la posición del puntero del
4396 ratón en una ventana dada. Una ventana puede tener una regla
4397 vertical a lo largo de su alto y una horizontal a lo largo de su
4398 ancho. Un pequeño indicador triangular muestra la relación entre
4399 el puntero del ratón y la regla.
4400
4401 Las reglas (horizontales y verticales) se crean usando:
4402
4403 <tscreen><verb>
4404 GtkWidget *gtk_hruler_new( void );    /* horizontal  */
4405 GtkWidget *gtk_vruler_new( void );    /* vertical  */
4406 </verb></tscreen>
4407
4408 Las unidades de la regla pueden ser pixels, pulgadas o centímetros
4409 (GKD_PIXELS, GDK_INCHES, GDK_CENTIMETRES). Esto se hace usando:
4410
4411 <tscreen><verb>
4412 void gtk_ruler_set_metric( GtkRuler      *ruler,
4413                            GtkMetricType  metric );
4414 </verb></tscreen>
4415
4416 El valor por defecto es GTK_PIXELS.
4417
4418 <tscreen><verb>
4419 gtk_ruler_set_metric( GTK_RULER(ruler), GTK_PIXELS );
4420 </verb></tscreen>
4421
4422 Otra característica importante de las reglas es cómo mostrar las
4423 unidades de escala y la posicion inicial dónde se situa el indicador.
4424 Todo esto se consigue mediante:
4425
4426 <tscreen><verb>
4427 void gtk_ruler_set_range( GtkRuler *ruler,
4428                           gfloat    lower,
4429                           gfloat    upper,
4430                           gfloat    posicion,
4431                           gfloat    max_size );
4432 </verb></tscreen>
4433
4434 Los argumentos <tt/lower/ (valor más bajo) y <tt/upper/ (más
4435 alto) delimitan la extensión de la regla. El argumento
4436 <tt/max_size/ es el número más alto que será mostrado. Como
4437 es lógico <tt/posicion/ define la posición inicial del indicador
4438 dentro de la regla.
4439
4440 Una regla vertical puede puede llegar a ser de 800 pixels:
4441
4442 <tscreen><verb>
4443 gtk_ruler_set_range( GTK_RULER(vruler), 0, 800, 0, 800);
4444 </verb></tscreen>
4445
4446 Las marcas dentro de la regla oscilarán entre 0 y 800 con una
4447 periodicidad de 100. Si queremos que varíe entre 7 y 16
4448 debemos usar:
4449
4450 <tscreen><verb>
4451 gtk_ruler_set_range( GTK_RULER(vruler), 7, 16, 0, 20);
4452 </verb></tscreen>
4453
4454 El indicador de la regla es un pequeño triángulo que señala la
4455 posición del puntero con relación a la regla. Si la regla debe
4456 seguir al puntero del ratón la señal motion_notify_event debe estar
4457 conectada con el motion_notify_event de la regla. Para seguir todos
4458 los movimientos dentro de una ventana conviene usar:
4459
4460 <tscreen><verb>
4461 #define EVENT_METHOD(i, x) GTK_WIDGET_CLASS(GTK_OBJECT(i)->klass)->x
4462
4463 gtk_signal_connect_object( GTK_OBJECT(area), "motion_notify_event",
4464          (GtkSignalFunc)EVENT_METHOD(ruler, motion_notify_event),
4465          GTK_OBJECT(ruler) );
4466 </verb></tscreen>
4467
4468 El siguiente ejemplo crea una zona de dibujo con una regla horizontal
4469 y otra vertical. El tamaño de la zona de dibujo es de 600 x 400
4470 <em/pixels/. La regla horizontal oscila entre 7 y 13 con marcas cada
4471 100 <em/pixels/, mientras que la vertical va desde 0 a 400 con
4472 separaciones cada 100. La zona de dibujo y las reglas se sitúan
4473 usando una tabla.
4474
4475 <tscreen><verb>
4476 /* comienzo del ejemplo rulers.c */
4477
4478 #include <gtk/gtk.h>
4479
4480 #define EVENT_METHOD(i, x) GTK_WIDGET_CLASS(GTK_OBJECT(i)->klass)->x
4481
4482 #define XSIZE  600
4483 #define YSIZE  400
4484
4485 /* Esta rutina toma el control cuando se pulsa el botón close
4486  */
4487 void close_application( GtkWidget *widget, GdkEvent *event, gpointer data ) {
4488     gtk_main_quit();
4489 }
4490
4491 int main( int argc, char *argv[] ) {
4492     GtkWidget *ventana, *table, *area, *hrule, *vrule;
4493
4494     
4495     gtk_init( &amp;argc, &amp;argv );
4496
4497     ventana = gtk_window_new( GTK_WINDOW_TOPLEVEL );
4498     gtk_signal_connect (GTK_OBJECT (ventana), "delete_event",
4499             GTK_SIGNAL_FUNC( close_application ), NULL);
4500     gtk_container_border_width (GTK_CONTAINER (ventana), 10);
4501
4502     /* creación de la tabla donde pondremos las reglas y la zona de
4503      * dibujo */
4504     table = gtk_table_new( 3, 2, FALSE );
4505     gtk_container_add( GTK_CONTAINER(ventana), table );
4506
4507     area = gtk_drawing_area_new();
4508     gtk_drawing_area_size( (GtkDrawingArea *)area, XSIZE, YSIZE );
4509     gtk_table_attach( GTK_TABLE(table), area, 1, 2, 1, 2,
4510                       GTK_EXPAND|GTK_FILL, GTK_FILL, 0, 0 );
4511     gtk_widget_set_events( area, GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK );
4512
4513     /* La regla horizontal está arriba. Cuando el ratón se mueve
4514      * a lo largo de la zona de dibujo el controlador de eventos de la
4515      * regla recibe motion_notify_event. */
4516     hrule = gtk_hruler_new();
4517     gtk_ruler_set_metric( GTK_RULER(hrule), GTK_PIXELS );
4518     gtk_ruler_set_range( GTK_RULER(hrule), 7, 13, 0, 20 );
4519     gtk_signal_connect_object( GTK_OBJECT(area), "motion_notify_event",
4520                                (GtkSignalFunc)EVENT_METHOD(hrule,
4521                                                         motion_notify_event),
4522                                GTK_OBJECT(hrule) );
4523     /* GTK_WIDGET_CLASS(GTK_OBJECT(hrule)->klass)->motion_notify_event, */
4524     gtk_table_attach( GTK_TABLE(table), hrule, 1, 2, 0, 1,
4525                       GTK_EXPAND|GTK_SHRINK|GTK_FILL, GTK_FILL, 0, 0 );
4526     
4527
4528     /* la zona de dibujo el controlador de eventos de la regla recibe
4529      * motion_notify_event. */
4530     vrule = gtk_vruler_new();
4531     gtk_ruler_set_metric( GTK_RULER(vrule), GTK_PIXELS );
4532     gtk_ruler_set_range( GTK_RULER(vrule), 0, YSIZE, 10, YSIZE );
4533     gtk_signal_connect_object( GTK_OBJECT(area), "motion_notify_event",
4534                                (GtkSignalFunc)
4535                                   GTK_WIDGET_CLASS(GTK_OBJECT(vrule)->klass)->
4536                                                          motion_notify_event,
4537                                GTK_OBJECT(vrule) );
4538     gtk_table_attach( GTK_TABLE(table), vrule, 0, 1, 1, 2,
4539                       GTK_FILL, GTK_EXPAND|GTK_SHRINK|GTK_FILL, 0, 0 );
4540
4541     
4542    /* mostramos todo */
4543     gtk_widget_show( area );
4544     gtk_widget_show( hrule );
4545     gtk_widget_show( vrule );
4546     gtk_widget_show( table );
4547     gtk_widget_show( ventana );
4548     gtk_main();
4549
4550     return 0;
4551 }
4552 /* final del ejemplo */
4553 </verb></tscreen>
4554
4555 <!-- ----------------------------------------------------------------- -->
4556 <sect1>Barras de estado
4557 <p>
4558 Las  barras de estado son widgets usados para mostrar un mensaje. Todo 
4559 aquello que haya sido mostrado se guarda en una pila, con lo que es
4560 muy fácil repetir el último mensaje.
4561
4562 Para permitir que diferentes partes del programa usen la misma barra
4563 de estado éstas usan Identificadores por Contexto (Context
4564 Identifiers) para identificar a los `usuarios'. El mensaje que está
4565 en lo alto de la pila será el siguiente en mostrarse, sin importar
4566 el contexto en el que se esté. Los mensajes se almacenan en el
4567 orden el último en entrar es el primero en salir, y el
4568 Identificador por Contexto no influye en este orden.
4569
4570 Las barras de estado se crean con una llamada a:
4571
4572 <tscreen><verb>
4573 GtkWidget *gtk_statusbar_new( void );
4574 </verb></tscreen>
4575
4576 Se pide un nuevo Identificador por Contexto con una pequeña
4577 descripción textual del contexto y una llamada a la función:
4578
4579 <tscreen><verb>
4580 guint gtk_statusbar_get_context_id( GtkStatusbar *statusbar,
4581                                     const gchar  *context_description );
4582 </verb></tscreen>
4583
4584 Hay tres funciones que pueden manipular las barras de estado:
4585
4586 <tscreen><verb>
4587 guint gtk_statusbar_push( GtkStatusbar *statusbar,
4588                           guint         context_id,
4589                           gchar        *text );
4590
4591 void gtk_statusbar_pop( GtkStatusbar *statusbar)
4592                         guint         context_id );
4593
4594 void gtk_statusbar_remove( GtkStatusbar *statusbar,
4595                            guint         context_id,
4596                            guint         message_id ); 
4597 </verb></tscreen>
4598
4599 La primera, gtk_statusbar_push, se utiliza para añadir un nuevo
4600 mensaje a la barra de estado. Devuelve un Identificador de Mensaje,
4601 que podemos pasarle más tarde a la función gtk_statusbar_remove para
4602 eliminar el mensaje con los Identificadores de Contexto y de Mensaje
4603 que hay en la pila de barras de estado.
4604
4605 La función gtk_statusbar_pop elimina el mensaje que se encuentra
4606 más alto en pila y que contiene el Identificador por Contexto
4607 especificado. 
4608
4609 El ejemplo siguiente crea una barra de estado y dos botones, uno para
4610 meter un elemento en la barra y el otro para sacar el último elemento
4611 introducido.
4612
4613 <tscreen><verb>
4614 /* Principio del ejemplo de barras de estado statusbar.c */
4615
4616 #include <gtk/gtk.h>
4617 #include <glib.h>
4618
4619 GtkWidget *status_bar;
4620
4621 void push_item (GtkWidget *widget, gpointer data)
4622 {
4623   static int count = 1;
4624   char buff[20];
4625
4626   g_snprintf(buff, 20, "Item %d", count++);
4627   gtk_statusbar_push( GTK_STATUSBAR(status_bar), GPOINTER_TO_INT(data), buff);
4628
4629   return;
4630 }
4631
4632 void pop_item (GtkWidget *widget, gpointer data)
4633 {
4634   gtk_statusbar_pop( GTK_STATUSBAR(status_bar), GPOINTER_TO_INT(data) );
4635   return;
4636 }
4637
4638 int main (int argc, char *argv[])
4639 {
4640
4641     GtkWidget *ventana;
4642     GtkWidget *vbox;
4643     GtkWidget *boton;
4644
4645     int context_id;
4646
4647     gtk_init (&amp;argc, &amp;argv);
4648
4649     /* crear una nueva ventana */
4650     ventana = gtk_window_new(GTK_WINDOW_TOPLEVEL);
4651     gtk_widget_set_usize( GTK_WIDGET (ventana), 200, 100);
4652     gtk_window_set_title(GTK_WINDOW (ventana), "GTK Statusbar Example");
4653     gtk_signal_connect(GTK_OBJECT (ventana), "delete_event",
4654                        (GtkSignalFunc) gtk_exit, NULL);
4655  
4656     vbox = gtk_vbox_new(FALSE, 1);
4657     gtk_container_add(GTK_CONTAINER(ventana), vbox);
4658     gtk_widget_show(vbox);
4659           
4660     status_bar = gtk_statusbar_new();      
4661     gtk_box_pack_start (GTK_BOX (vbox), status_bar, TRUE, TRUE, 0);
4662     gtk_widget_show (status_bar);
4663
4664     context_id = gtk_statusbar_get_context_id(
4665                           GTK_STATUSBAR(status_bar), "Statusbar example");
4666
4667     boton = gtk_button_new_with_label("push item");
4668     gtk_signal_connect(GTK_OBJECT(boton), "clicked",
4669         GTK_SIGNAL_FUNC (push_item), &amp;context_id);
4670     gtk_box_pack_start(GTK_BOX(vbox), boton, TRUE, TRUE, 2);
4671     gtk_widget_show(boton);              
4672
4673     boton = gtk_button_new_with_label("pop last item");
4674     gtk_signal_connect(GTK_OBJECT(boton), "clicked",
4675         GTK_SIGNAL_FUNC (pop_item), &amp;context_id);
4676     gtk_box_pack_start(GTK_BOX(vbox), boton, TRUE, TRUE, 2);
4677     gtk_widget_show(boton);              
4678
4679     /* siempre mostramos la ventana en el último paso para que todo se
4680      * dibuje en la pantalla de un golpe. */
4681     gtk_widget_show(ventana);
4682
4683     gtk_main ();
4684
4685     return 0;
4686 }
4687 /* Final del ejemplo */
4688 </verb></tscreen>
4689
4690 <!-- ----------------------------------------------------------------- -->
4691 <sect1>Entrada de texto
4692 <p>
4693 El <em/widget/ Entry permite mostrar e introducir texto en una línea
4694 de un cuadro de diálogo. El texto se puede poner con llamadas a funciones
4695 que permiten reemplazar, preañadir o añadir  el texto al contenido
4696 actual del <em/widget/ Entry.
4697
4698 Hay dos funciones para crear un <em/widget/ Entry:
4699
4700 <tscreen><verb>
4701 GtkWidget *gtk_entry_new( void );
4702
4703 GtkWidget *gtk_entry_new_with_max_length( guint16 max );
4704 </verb></tscreen>
4705
4706 La primera sirve para crear un nuevo <em/widget/ Entry, mientras que la
4707 segunda crea el <em/widget/ y además establece un límite en la longitud
4708 del texto que irá en el mismo.
4709
4710 hay varias funciones que sirven para alterar el que texto que se está
4711 en el <em/widget/ Entry.
4712
4713 <tscreen><verb>
4714 void gtk_entry_set_text( GtkEntry    *entry,
4715                          const gchar *text );
4716
4717 void gtk_entry_append_text( GtkEntry    *entry,
4718                             const gchar *text );
4719
4720 void gtk_entry_prepend_text( GtkEntry    *entry,
4721                              const gchar *text );
4722 </verb></tscreen>
4723
4724 La función <tt/gtk_entry_set_text/ cambia el contenido actual del
4725 <em/widget/ Entry. Las funciones <tt/gtk_entry_append_text/ y
4726 <tt/gtk_entry_prepend_text/ permiten añadir o preañadir texto.
4727
4728 Las función siguientes permiten decir donde poner el punto de inserción.
4729
4730 <tscreen><verb>
4731 void gtk_entry_set_position( GtkEntry *entry,
4732                              gint      posicion );
4733 </verb></tscreen>
4734
4735 Se pueden obtener los contenidos del <em/widget/ llamando a la función
4736 que se describe a continuación. Obtener los contenidos del <em/widget/
4737 puede ser útil en las funciones de llamada descritas más adelante.
4738
4739 <tscreen><verb>
4740 gchar *gtk_entry_get_text( GtkEntry *entry );
4741 </verb></tscreen>
4742
4743 Si quiere impedir que alguien cambie el contenido del <em/widget/ escribiendo
4744 en él, utilice la función
4745
4746 <tscreen><verb>
4747 void gtk_entry_set_editable( GtkEntry *entry,
4748                              gboolean  editable );
4749 </verb></tscreen>
4750
4751 Esta función permite camiar el estado de edición de un <em/widget/ Entry,
4752 siendo el argumento <tt/editable/ TRUE o FALSE.
4753
4754 Si estamos utilizando el <em/widget/ Entry en un sitio donde no queremos
4755 que el texto que se introduce sea visible, como por ejemplo cuando estamos
4756 introduciendo una clave, podemos utilizar la función siguiente, que también
4757 admite como argumento una bandera booleana.
4758
4759 <tscreen><verb>
4760 void gtk_entry_set_visibility( GtkEntry *entry,
4761                                gboolean  visible );
4762 </verb></tscreen>
4763
4764 Se puede seleccionar una región del texto utilizando la siguiente función.
4765 Esta función se puede utilizar después de poner algún texto por defecto en
4766 el <em/widget/, haciéndole fácil al usuario eliminar este texto.
4767
4768 <tscreen><verb>
4769 void gtk_entry_select_region( GtkEntry *entry,
4770                               gint      start,
4771                               gint      end );
4772 </verb></tscreen>
4773
4774 Si queremos saber el momento en el que el usuario ha introducido el texto,
4775 podemos conectar con las señales <tt/activate/ o <tt/changed/. <tt/activate/
4776 se activa cuando el usuario aprieta la tecla enter en el <em/widget/.
4777 <tt/changed/ se activa cuando cambia algo del texto, p.e. cuando se introduce
4778 o se elimina algún carácter.
4779
4780 <tscreen><verb>
4781 /* Principio del ejemplo entry entry.c */
4782
4783 #include <gtk/gtk.h>
4784
4785 void enter_callback(GtkWidget *widget, GtkWidget *entry)
4786 {
4787   gchar *entry_text;
4788   entry_text = gtk_entry_get_text(GTK_ENTRY(entry));
4789   printf("Entry contents: %s\n", entry_text);
4790 }
4791
4792 void entry_toggle_editable (GtkWidget *checkbutton,
4793                                    GtkWidget *entry)
4794 {
4795   gtk_entry_set_editable(GTK_ENTRY(entry),
4796                          GTK_TOGGLE_BUTTON(checkbutton)->active);
4797 }
4798
4799 void entry_toggle_visibility (GtkWidget *checkbutton,
4800                                    GtkWidget *entry)
4801 {
4802   gtk_entry_set_visibility(GTK_ENTRY(entry),
4803                          GTK_TOGGLE_BUTTON(checkbutton)->active);
4804 }
4805
4806 int main (int argc, char *argv[])
4807 {
4808
4809     GtkWidget *ventana;
4810     GtkWidget *vbox, *hbox;
4811     GtkWidget *entry;
4812     GtkWidget *boton;
4813     GtkWidget *check;
4814
4815     gtk_init (&amp;argc, &amp;argv);
4816
4817     /* crear una nueva ventana */
4818     ventana = gtk_window_new(GTK_WINDOW_TOPLEVEL);
4819     gtk_widget_set_usize( GTK_WIDGET (ventana), 200, 100);
4820     gtk_window_set_title(GTK_WINDOW (ventana), "GTK Entry");
4821     gtk_signal_connect(GTK_OBJECT (ventana), "delete_event",
4822                        (GtkSignalFunc) gtk_exit, NULL);
4823
4824     vbox = gtk_vbox_new (FALSE, 0);
4825     gtk_container_add (GTK_CONTAINER (ventana), vbox);
4826     gtk_widget_show (vbox);
4827
4828     entry = gtk_entry_new_with_max_length (50);
4829     gtk_signal_connect(GTK_OBJECT(entry), "activate",
4830                        GTK_SIGNAL_FUNC(enter_callback),
4831                        entry);
4832     gtk_entry_set_text (GTK_ENTRY (entry), "hello");
4833     gtk_entry_append_text (GTK_ENTRY (entry), " world");
4834     gtk_entry_select_region (GTK_ENTRY (entry),
4835                              0, GTK_ENTRY(entry)->text_length);
4836     gtk_box_pack_start (GTK_BOX (vbox), entry, TRUE, TRUE, 0);
4837     gtk_widget_show (entry);
4838
4839     hbox = gtk_hbox_new (FALSE, 0);
4840     gtk_container_add (GTK_CONTAINER (vbox), hbox);
4841     gtk_widget_show (hbox);
4842                                   
4843     check = gtk_check_button_new_with_label("Editable");
4844     gtk_box_pack_start (GTK_BOX (hbox), check, TRUE, TRUE, 0);
4845     gtk_signal_connect (GTK_OBJECT(check), "toggled",
4846                         GTK_SIGNAL_FUNC(entry_toggle_editable), entry);
4847     gtk_toggle_button_set_state(GTK_TOGGLE_BUTTON(check), TRUE);
4848     gtk_widget_show (check);
4849     
4850     check = gtk_check_button_new_with_label("Visible");
4851     gtk_box_pack_start (GTK_BOX (hbox), check, TRUE, TRUE, 0);
4852     gtk_signal_connect (GTK_OBJECT(check), "toggled",
4853                         GTK_SIGNAL_FUNC(entry_toggle_visibility), entry);
4854     gtk_toggle_button_set_state(GTK_TOGGLE_BUTTON(check), TRUE);
4855     gtk_widget_show (check);
4856                                    
4857     boton = gtk_button_new_with_label ("Close");
4858     gtk_signal_connect_object (GTK_OBJECT (boton), "clicked",
4859                                GTK_SIGNAL_FUNC(gtk_exit),
4860                                GTK_OBJECT (ventana));
4861     gtk_box_pack_start (GTK_BOX (vbox), boton, TRUE, TRUE, 0);
4862     GTK_WIDGET_SET_FLAGS (boton, GTK_CAN_DEFAULT);
4863     gtk_widget_grab_default (boton);
4864     gtk_widget_show (boton);
4865     
4866     gtk_widget_show(ventana);
4867
4868     gtk_main();
4869     return(0);
4870 }
4871 /* fin del ejemplo */
4872 </verb></tscreen>
4873
4874 <!-- ----------------------------------------------------------------- -->
4875 <sect1>Botones <em/spin/
4876 <p>
4877 El <em/widget/ botón <em/spin/ se utiliza normalmente para permitir
4878 que el usuario elija un valor de un rango de valores. Consiste en una
4879 caja para la entrada de texto con una flecha para arriba y otra para
4880 abajo justo al lado de la caja. Si utilizamos alguna de las flechas
4881 haremos que el valor suba o baje dentro del rango de los valores
4882 posibles. También podemos introducir directamente un valor específico
4883 (utilizando la caja de texto).
4884
4885 El <em/widget/ botón <em/spin/ permite tener valores con un número de
4886 cifras decimales (o sin cifras decimales) y la posibilidad de
4887 incrementarlo/decrementarlo en pasos configurables. La acción de
4888 matener pulsado uno de los botones puede resultar (es opcional) en una
4889 aceleración del cambio en el valor de acuerdo con el tiempo que se
4890 mantenga pulsado.
4891
4892 El botón <em/spin/ utiliza un objeto <ref id="sec_Adjustment"
4893 name="Ajuste"> para conservar la información referente al rango de
4894 valores que puede tomar el botón <em/spin/. Esto hace que el
4895 <em/widget/ botón <em/spin/ sea muy poderoso.
4896
4897 Recuerde que un <em/widget/ ajuste puede crearse con la siguiente
4898 función, que ilustra la información que se guarda:
4899
4900 <tscreen><verb>
4901 GtkObject *gtk_adjustment_new( gfloat valor,
4902                                gfloat inferior,
4903                                gfloat superior,
4904                                gfloat paso,
4905                                gfloat incremento_pagina,
4906                                gfloat tamano_pagina );
4907 </verb></tscreen>
4908
4909 Estos atributos de un ajuste se utilizan en un botón <em/spin/ de la
4910 forma siguiente:
4911
4912 <itemize>
4913 <item> <tt/valor/: valor inicial del botón <em/spin/
4914 <item> <tt/inferior/: valor inferior del rango
4915 <item> <tt/superior/: valor superior del rango
4916 <item> <tt/paso/: valor a incrementar/decrementar cuando pulsemos el
4917 botón 1 en una flecha
4918 <item> <tt/incremento_pagina/: valor a incrementar/decrementar cuando
4919 pulsemos el botón 2 en una flecha
4920 <item> <tt/tamano_pagina/: no se utiliza
4921 </itemize>
4922
4923 Además, se puede utilizar el botón 3 para saltar directamente a los
4924 valores <tt/superior/ o <tt/inferior/ cuando se pulsa en una de las
4925 flechas. Veamos como crear un botón <em/spin/:
4926
4927 <tscreen><verb>
4928 GtkWidget *gtk_spin_button_new( GtkAdjustment *ajuste,
4929                                 gfloat         aceleracion,
4930                                 guint          digitos );
4931 </verb></tscreen>
4932
4933 El argumento <tt/aceleracion/ toma un valor entre 0.0 y 1.0 e indica
4934 la aceleración que tendrá el botón <em/spin/. El argumento
4935 <tt/digitos/ especifica el número de cifras decimales con que se
4936 mostrará el valor.
4937
4938 Se puede reconfigurar un botón <em/spin/ después de su creación
4939 utilizando la función:
4940
4941 <tscreen><verb>
4942 void gtk_spin_button_configure( GtkSpinButton *boton_spin,
4943                                 GtkAdjustment *ajuste,
4944                                 gfloat         aceleracion,
4945                                 guint          digitos );
4946 </verb></tscreen>
4947
4948 El argumento <tt/boton_spin/ especifica el botón <em/spin/ que va a
4949 reconfigurarse. El resto de argumentos son los que acabamos de
4950 explicar.
4951
4952 Podemos establecer y obtener el ajuste utilizando las dos funciones
4953 siguientes:
4954
4955 <tscreen><verb>
4956 void gtk_spin_button_set_adjustment( GtkSpinButton  *boton_spin,
4957                                      GtkAdjustment  *ajuste );
4958
4959 GtkAdjustment *gtk_spin_button_get_adjustment( GtkSpinButton *boton_spin );
4960 </verb></tscreen>
4961
4962 El número de cifras decimales también puede alterarse utilizando:
4963
4964 <tscreen><verb>
4965 void gtk_spin_button_set_digits( GtkSpinButton *boton_spin,
4966                                  guint          digitos) ;
4967 </verb></tscreen>
4968
4969 El valor que un botón <em/spin/ está mostrando actualmente puede
4970 cambiarse utilizando las siguientes funciones:
4971
4972 <tscreen><verb>
4973 void gtk_spin_button_set_value( GtkSpinButton *boton_spin,
4974                                 gfloat         valor );
4975 </verb></tscreen>
4976
4977 El valor actual de un botón <em/spin/ puede obtenerse como un entero o
4978 como un flotante con las funciones siguientes:
4979
4980 <tscreen><verb>
4981 gfloat gtk_spin_button_get_value_as_float( GtkSpinButton *boton_spin );
4982
4983 gint gtk_spin_button_get_value_as_int( GtkSpinButton *boton_spin );
4984 </verb></tscreen>
4985
4986 Si quiere alterar el valor de un <em/spin/ de forma relativa a su
4987 valor actual, puede utilizar la siguiente función:
4988
4989 <tscreen><verb>
4990 void gtk_spin_button_spin( GtkSpinButton *boton_spin,
4991                            GtkSpinType    direccion,
4992                            gfloat         incremento );
4993 </verb></tscreen>
4994
4995 El parámetro <tt/direccion/ puede tomar uno de los valores siguientes:
4996
4997 <itemize>
4998 <item> GTK_SPIN_STEP_FORWARD
4999 <item> GTK_SPIN_STEP_BACKWARD
5000 <item> GTK_SPIN_PAGE_FORWARD
5001 <item> GTK_SPIN_PAGE_BACKWARD
5002 <item> GTK_SPIN_HOME
5003 <item> GTK_SPIN_END
5004 <item> GTK_SPIN_USER_DEFINED
5005 </itemize>
5006
5007 Trataré de explicar todas las posibilidades que ofrece esta
5008 función. Algunos de los valores que puede utilizar <tt/direccion/
5009 hacen que se utilicen valores que están almacenados en el objeto
5010 Ajuste que está asociado con el botón <em/spin/.
5011
5012 GTK_SPIN_STEP_FORWARD y GTK_SPIN_STEP_BACKWARD aumentan o disminuyen
5013 (respectivamente) el valor del botón <em/spin/ por la cantidad
5014 especificada por <tt/incremento/, a menos que <tt/incremento/ sea
5015 igual a 0, en cuyo caso el valor se aumentará o disminuirá por el
5016 valor especificado en <tt/paso/ dentro del Ajuste.
5017
5018 GTK_SPIN_PAGE_FORWARD y GTK_SPIN_PAGE_BACKWARD sencillamente alteran
5019 el valor del botón <em/spin/ por la cantidad <tt/incremento/.
5020
5021 GTK_SPIN_HOME hace que el botón <em/spin/ tenga el mismo valor que el
5022 valor inferior del rango Ajuste.
5023
5024 GTK_SPIN_END hace que el botón <em/spin/ tenga el mismo valor que el
5025 valor superior del rango Ajuste.
5026
5027 GTK_SPIN_USER_DEFINED cambia el valor del botón <em/spin/ por la
5028 cantidad especificada.
5029
5030 Ahora vamos a dejar de lado las funciones para establecer y obtener el
5031 rango de los atributos del botón <em/spin/, y vamos a pasar a las
5032 funciones que afectan a la apariencia y al comportamiento del
5033 <em/widget/ botón <em/spin/ en sí mismo.
5034
5035 La primera de estas funciones se utiliza para restringir el contenido
5036 de la caja de texto de un botón <em/spin/ a un valor numérico. Esto
5037 evita que un usuario introduzca cualquier valor no númerico.
5038
5039 <tscreen><verb>
5040 void gtk_spin_button_set_numeric( GtkSpinButton *boton_spin,
5041                                   gboolean       numerico );
5042 </verb></tscreen>
5043
5044 Puede indicar si un botón <em/spin/ pasará del límite superior al
5045 inferior utilizando la siguiente función:
5046
5047 <tscreen><verb>
5048 void gtk_spin_button_set_wrap( GtkSpinButton *boton_spin,
5049                                gboolean       wrap );
5050 </verb></tscreen>
5051
5052 Puede hacer que un botón <em/spin/ redondee su valor al <tt/paso/ más
5053 cercano, que se indica cuando creamos el Ajuste que se utiliza con el
5054 botón <em/spin/. Para hacer que redondee tenemos que utilizar la
5055 función siguiente:
5056
5057 <tscreen><verb>
5058 void gtk_spin_button_set_snap_to_ticks( GtkSpinButton  *boton_spin,
5059                                         gboolean        redondear );
5060 </verb></tscreen>
5061
5062 Para política de actualización de un botón <em/spin/ puede cambiarse
5063 con la siguiente función:
5064
5065 <tscreen><verb>
5066 void gtk_spin_button_set_update_policy( GtkSpinButton  *boton_spin,
5067                                     GtkSpinButtonUpdatePolicy politica );
5068 </verb></tscreen>
5069
5070 <!-- TODO: find out what this does - TRG -->
5071
5072 Los valores posibles de <tt/politica/ son o GTK_UPDATE_ALWAYS o
5073 GTK_UPDATE_IF_VALID.
5074
5075 Estas políticas afectan al comportamiento de un botón <em/spin/ cuando
5076 se lee el texto insertado en la caja de texto y se sincroniza con los
5077 valores del Ajuste.
5078
5079 En el caso de GTK_UPDATE_IF_VALID el valor de un botón <em/spin/
5080 cambiará si el texto introducido es un valor numérico contenido dentro
5081 del rango especificado por el Ajuste. En caso contrario el texto
5082 introducido se convierte al valor del botón <em/spin/.
5083
5084 En caso de utilizar GTK_UPDATE_ALWAYS se ignorarán los errores que
5085 puedan ocurrir en la conversión del texto en un valor numérico.
5086
5087 El aspecto de los botones utilizados en un botón <em/spin/ pueden
5088 cambiarse utilizando las siguientes funciones:
5089
5090 <tscreen><verb>
5091 void gtk_spin_button_set_shadow_type( GtkSpinButton *boton_spin,
5092                                       GtkShadowType  tipo_sombra );
5093 </verb></tscreen>
5094
5095 Como siempre, el <tt/tipo_sombra/ puede ser uno de los siguientes:
5096
5097 <itemize>
5098 <item> GTK_SHADOW_IN
5099 <item> GTK_SHADOW_OUT
5100 <item> GTK_SHADOW_ETCHED_IN
5101 <item> GTK_SHADOW_ETCHED_OUT
5102 </itemize>
5103
5104 Finalmente, puede pedir de forma explícita que un botón <em/spin/ se
5105 actualice a sí mismo:
5106
5107 <tscreen><verb>
5108 void gtk_spin_button_update( GtkSpinButton  *boton_spin );
5109 </verb></tscreen>
5110
5111 Es hora de un nuevo ejemplo.
5112
5113 <tscreen><verb>
5114 /* principio del ejemplo spinbutton spinbutton.c */
5115
5116 #include <gtk/gtk.h>
5117
5118 static GtkWidget *spinner1;
5119
5120 void toggle_snap( GtkWidget     *widget,
5121                   GtkSpinButton *spin )
5122 {
5123   gtk_spin_button_set_snap_to_ticks (spin, GTK_TOGGLE_BUTTON (widget)->active);
5124 }
5125
5126 void toggle_numeric( GtkWidget *widget,
5127                      GtkSpinButton *spin )
5128 {
5129   gtk_spin_button_set_numeric (spin, GTK_TOGGLE_BUTTON (widget)->active);
5130 }
5131
5132 void change_digits( GtkWidget *widget,
5133                     GtkSpinButton *spin )
5134 {
5135   gtk_spin_button_set_digits (GTK_SPIN_BUTTON (spinner1),
5136                               gtk_spin_button_get_value_as_int (spin));
5137 }
5138
5139 void get_value( GtkWidget *widget,
5140                 gpointer data )
5141 {
5142   gchar buf[32];
5143   GtkLabel *etiqueta;
5144   GtkSpinButton *spin;
5145
5146   spin = GTK_SPIN_BUTTON (spinner1);
5147   etiqueta = GTK_LABEL (gtk_object_get_user_data (GTK_OBJECT (widget)));
5148   if (GPOINTER_TO_INT (data) == 1)
5149     sprintf (buf, "%d", gtk_spin_button_get_value_as_int (spin));
5150   else
5151     sprintf (buf, "%0.*f", spin->digits,
5152              gtk_spin_button_get_value_as_float (spin));
5153   gtk_label_set_text (etiqueta, buf);
5154 }
5155
5156
5157 int main( int   argc,
5158           char *argv[] )
5159 {
5160   GtkWidget *ventana;
5161   GtkWidget *frame;
5162   GtkWidget *hbox;
5163   GtkWidget *main_vbox;
5164   GtkWidget *vbox;
5165   GtkWidget *vbox2;
5166   GtkWidget *spinner2;
5167   GtkWidget *spinner;
5168   GtkWidget *boton;
5169   GtkWidget *etiqueta;
5170   GtkWidget *val_label;
5171   GtkAdjustment *adj;
5172
5173   /* Inicializar GTK */
5174   gtk_init(&amp;argc, &amp;argv);
5175
5176   ventana = gtk_window_new (GTK_WINDOW_TOPLEVEL);
5177
5178   gtk_signal_connect (GTK_OBJECT (ventana), "destroy",
5179                       GTK_SIGNAL_FUNC (gtk_main_quit),
5180                       NULL);
5181
5182   gtk_window_set_title (GTK_WINDOW (ventana), "Spin Button");
5183
5184   main_vbox = gtk_vbox_new (FALSE, 5);
5185   gtk_container_set_border_width (GTK_CONTAINER (main_vbox), 10);
5186   gtk_container_add (GTK_CONTAINER (ventana), main_vbox);
5187   
5188   frame = gtk_frame_new ("Not accelerated");
5189   gtk_box_pack_start (GTK_BOX (main_vbox), frame, TRUE, TRUE, 0);
5190   
5191   vbox = gtk_vbox_new (FALSE, 0);
5192   gtk_container_set_border_width (GTK_CONTAINER (vbox), 5);
5193   gtk_container_add (GTK_CONTAINER (frame), vbox);
5194   
5195   /* spin del día, mes y año */
5196   
5197   hbox = gtk_hbox_new (FALSE, 0);
5198   gtk_box_pack_start (GTK_BOX (vbox), hbox, TRUE, TRUE, 5);
5199   
5200   vbox2 = gtk_vbox_new (FALSE, 0);
5201   gtk_box_pack_start (GTK_BOX (hbox), vbox2, TRUE, TRUE, 5);
5202   
5203   etiqueta = gtk_label_new ("Day :");
5204   gtk_misc_set_alignment (GTK_MISC (etiqueta), 0, 0.5);
5205   gtk_box_pack_start (GTK_BOX (vbox2), etiqueta, FALSE, TRUE, 0);
5206   
5207   adj = (GtkAdjustment *) gtk_adjustment_new (1.0, 1.0, 31.0, 1.0,
5208                                               5.0, 0.0);
5209   spinner = gtk_spin_button_new (adj, 0, 0);
5210   gtk_spin_button_set_wrap (GTK_SPIN_BUTTON (spinner), TRUE);
5211   gtk_spin_button_set_shadow_type (GTK_SPIN_BUTTON (spinner),
5212                                    GTK_SHADOW_OUT);
5213   gtk_box_pack_start (GTK_BOX (vbox2), spinner, FALSE, TRUE, 0);
5214   
5215   vbox2 = gtk_vbox_new (FALSE, 0);
5216   gtk_box_pack_start (GTK_BOX (hbox), vbox2, TRUE, TRUE, 5);
5217   
5218   etiqueta = gtk_label_new ("Month :");
5219   gtk_misc_set_alignment (GTK_MISC (etiqueta), 0, 0.5);
5220   gtk_box_pack_start (GTK_BOX (vbox2), etiqueta, FALSE, TRUE, 0);
5221   
5222   adj = (GtkAdjustment *) gtk_adjustment_new (1.0, 1.0, 12.0, 1.0,
5223                                               5.0, 0.0);
5224   spinner = gtk_spin_button_new (adj, 0, 0);
5225   gtk_spin_button_set_wrap (GTK_SPIN_BUTTON (spinner), TRUE);
5226   gtk_spin_button_set_shadow_type (GTK_SPIN_BUTTON (spinner),
5227                                    GTK_SHADOW_ETCHED_IN);
5228   gtk_box_pack_start (GTK_BOX (vbox2), spinner, FALSE, TRUE, 0);
5229   
5230   vbox2 = gtk_vbox_new (FALSE, 0);
5231   gtk_box_pack_start (GTK_BOX (hbox), vbox2, TRUE, TRUE, 5);
5232   
5233   etiqueta = gtk_label_new ("Year :");
5234   gtk_misc_set_alignment (GTK_MISC (etiqueta), 0, 0.5);
5235   gtk_box_pack_start (GTK_BOX (vbox2), etiqueta, FALSE, TRUE, 0);
5236   
5237   adj = (GtkAdjustment *) gtk_adjustment_new (1998.0, 0.0, 2100.0,
5238                                               1.0, 100.0, 0.0);
5239   spinner = gtk_spin_button_new (adj, 0, 0);
5240   gtk_spin_button_set_wrap (GTK_SPIN_BUTTON (spinner), FALSE);
5241   gtk_spin_button_set_shadow_type (GTK_SPIN_BUTTON (spinner),
5242                                    GTK_SHADOW_IN);
5243   gtk_widget_set_usize (spinner, 55, 0);
5244   gtk_box_pack_start (GTK_BOX (vbox2), spinner, FALSE, TRUE, 0);
5245   
5246   frame = gtk_frame_new ("Accelerated");
5247   gtk_box_pack_start (GTK_BOX (main_vbox), frame, TRUE, TRUE, 0);
5248   
5249   vbox = gtk_vbox_new (FALSE, 0);
5250   gtk_container_set_border_width (GTK_CONTAINER (vbox), 5);
5251   gtk_container_add (GTK_CONTAINER (frame), vbox);
5252   
5253   hbox = gtk_hbox_new (FALSE, 0);
5254   gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, TRUE, 5);
5255   
5256   vbox2 = gtk_vbox_new (FALSE, 0);
5257   gtk_box_pack_start (GTK_BOX (hbox), vbox2, TRUE, TRUE, 5);
5258   
5259   etiqueta = gtk_label_new ("Value :");
5260   gtk_misc_set_alignment (GTK_MISC (etiqueta), 0, 0.5);
5261   gtk_box_pack_start (GTK_BOX (vbox2), etiqueta, FALSE, TRUE, 0);
5262   
5263   adj = (GtkAdjustment *) gtk_adjustment_new (0.0, -10000.0, 10000.0,
5264                                               0.5, 100.0, 0.0);
5265   spinner1 = gtk_spin_button_new (adj, 1.0, 2);
5266   gtk_spin_button_set_wrap (GTK_SPIN_BUTTON (spinner1), TRUE);
5267   gtk_widget_set_usize (spinner1, 100, 0);
5268   gtk_box_pack_start (GTK_BOX (vbox2), spinner1, FALSE, TRUE, 0);
5269   
5270   vbox2 = gtk_vbox_new (FALSE, 0);
5271   gtk_box_pack_start (GTK_BOX (hbox), vbox2, TRUE, TRUE, 5);
5272   
5273   etiqueta = gtk_label_new ("Digits :");
5274   gtk_misc_set_alignment (GTK_MISC (etiqueta), 0, 0.5);
5275   gtk_box_pack_start (GTK_BOX (vbox2), etiqueta, FALSE, TRUE, 0);
5276   
5277   adj = (GtkAdjustment *) gtk_adjustment_new (2, 1, 5, 1, 1, 0);
5278   spinner2 = gtk_spin_button_new (adj, 0.0, 0);
5279   gtk_spin_button_set_wrap (GTK_SPIN_BUTTON (spinner2), TRUE);
5280   gtk_signal_connect (GTK_OBJECT (adj), "value_changed",
5281                       GTK_SIGNAL_FUNC (change_digits),
5282                       (gpointer) spinner2);
5283   gtk_box_pack_start (GTK_BOX (vbox2), spinner2, FALSE, TRUE, 0);
5284   
5285   hbox = gtk_hbox_new (FALSE, 0);
5286   gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, TRUE, 5);
5287   
5288   boton = gtk_check_button_new_with_label ("Snap to 0.5-ticks");
5289   gtk_signal_connect (GTK_OBJECT (boton), "clicked",
5290                       GTK_SIGNAL_FUNC (toggle_snap),
5291                       spinner1);
5292   gtk_box_pack_start (GTK_BOX (vbox), boton, TRUE, TRUE, 0);
5293   gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (boton), TRUE);
5294   
5295   boton = gtk_check_button_new_with_label ("Numeric only input mode");
5296   gtk_signal_connect (GTK_OBJECT (boton), "clicked",
5297                       GTK_SIGNAL_FUNC (toggle_numeric),
5298                       spinner1);
5299   gtk_box_pack_start (GTK_BOX (vbox), boton, TRUE, TRUE, 0);
5300   gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (boton), TRUE);
5301   
5302   val_label = gtk_label_new ("");
5303   
5304   hbox = gtk_hbox_new (FALSE, 0);
5305   gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, TRUE, 5);
5306   boton = gtk_button_new_with_label ("Value as Int");
5307   gtk_object_set_user_data (GTK_OBJECT (boton), val_label);
5308   gtk_signal_connect (GTK_OBJECT (boton), "clicked",
5309                       GTK_SIGNAL_FUNC (get_value),
5310                       GINT_TO_POINTER (1));
5311   gtk_box_pack_start (GTK_BOX (hbox), boton, TRUE, TRUE, 5);
5312   
5313   boton = gtk_button_new_with_label ("Value as Float");
5314   gtk_object_set_user_data (GTK_OBJECT (boton), val_label);
5315   gtk_signal_connect (GTK_OBJECT (boton), "clicked",
5316                       GTK_SIGNAL_FUNC (get_value),
5317                       GINT_TO_POINTER (2));
5318   gtk_box_pack_start (GTK_BOX (hbox), boton, TRUE, TRUE, 5);
5319   
5320   gtk_box_pack_start (GTK_BOX (vbox), val_label, TRUE, TRUE, 0);
5321   gtk_label_set_text (GTK_LABEL (val_label), "0");
5322   
5323   hbox = gtk_hbox_new (FALSE, 0);
5324   gtk_box_pack_start (GTK_BOX (main_vbox), hbox, FALSE, TRUE, 0);
5325   
5326   boton = gtk_button_new_with_label ("Close");
5327   gtk_signal_connect_object (GTK_OBJECT (boton), "clicked",
5328                              GTK_SIGNAL_FUNC (gtk_widget_destroy),
5329                              GTK_OBJECT (ventana));
5330   gtk_box_pack_start (GTK_BOX (hbox), boton, TRUE, TRUE, 5);
5331
5332   gtk_widget_show_all (ventana);
5333
5334   /* Entramos dentro del bucle de eventos */
5335   gtk_main ();
5336     
5337   return(0);
5338 }
5339 /* fin del ejemplo */
5340 </verb></tscreen>
5341
5342 <!-- ----------------------------------------------------------------- -->
5343 <sect1>Caja combinada (<em/Combo Box/)
5344 <p>
5345 La caja combinada o <em/combo box/ es otro sencillo <em/widget/
5346 exclusivamente compuesto por otros <em/widgets/. Desde el punto de
5347 vista del usuario, el <em/widget/ consiste en una caja para la
5348 introducción de texto y un menú desplegable desde el que el usuario
5349 puede seleccionar una de un conjunto predefinido de entradas. De forma
5350 alternativa, el usuario puede introducir una opción diferente en la
5351 caja de texto.
5352
5353 El siguiente extracto de la estructura que define un Combo Box
5354 identifica algunos de sus componentes:
5355
5356 <tscreen><verb>
5357 struct _GtkCombo { 
5358         GtkHBox hbox; 
5359         GtkWidget *entry; 
5360         GtkWidget *boton;
5361         GtkWidget *popup; 
5362         GtkWidget *popwin; 
5363         GtkWidget *list;
5364         ...  };
5365 </verb></tscreen>
5366
5367 Como puede ver, el Combo Box tiene dos partes principales que tiene
5368 que conocer: un <em/widget entry/ y un <em/widget list/ (lista).
5369
5370 Lo primero, para crear un combo box, utilice:
5371
5372 <tscreen><verb>
5373 GtkWidget *gtk_combo_new( void );
5374 </verb></tscreen>
5375
5376 Ahora, si quiere indicar la cadena que debe aparecer en la sección
5377 entry del combo box, podrá hacerlo manipulando directamente el
5378 <em/widget/ <tt/entry/:
5379
5380 <tscreen><verb>
5381     gtk_entry_set_text(GTK_ENTRY(GTK_COMBO(combo)->entry), "Mi cadena.");
5382 </verb></tscreen>
5383
5384 Para introducir valores en la lista desplegable, puede utilizar la
5385 función:
5386
5387 <tscreen><verb>
5388 void gtk_combo_set_popdown_strings( GtkCombo *combo,
5389                                     GList    *cadenas );
5390 </verb></tscreen>
5391
5392 Antes de llamar a esta función, tiene que ensamblar una GList con las
5393 cadenas que quiere. GList es una implementación de una lista enlazada
5394 que forma parte de <ref id="sec_glib" name="glib">, una biblioteca
5395 base de GTK. Por el momento, la explicación fea y rápida es que tiene
5396 que crear un puntero GList, hacerlo igual a NULL, y añadirle cadenas
5397 de texto con la función
5398
5399 <tscreen><verb>
5400 GList *g_list_append( GList *glist, 
5401                       gpointer datos );
5402 </verb></tscreen>
5403
5404 Es importante que inicialice el puntero GList a NULL antes de
5405 utilizarlo. El valor devuelto por la función g_list_append debe
5406 utilizarse como el nuevo puntero a la GList.
5407
5408 Aquí tenemos un trozo de código típico para crear un conjunto de
5409 opciones:
5410
5411 <tscreen><verb>
5412     GList *glist=NULL;
5413
5414     glist = g_list_append(glist, "Cadena 1");
5415     glist = g_list_append(glist, "Cadena 2");
5416     glist = g_list_append(glist, "Cadena 3"); 
5417     glist = g_list_append(glist, "Cadena 4");
5418
5419     gtk_combo_set_popdown_strings( GTK_COMBO(combo), glist) ;
5420 </verb></tscreen>
5421
5422 A partir de este momento tendrá un combo box completo funcionando. Hay
5423 unos cuantos aspectos de su funcionamiento que puede cambiar. Para
5424 hacerlo tiene las funciones siguientes:
5425
5426 <tscreen><verb>
5427 void gtk_combo_set_use_arrows( GtkCombo *combo,
5428                                gint      valor );
5429
5430 void gtk_combo_set_use_arrows_always( GtkCombo *combo,
5431                                       gint      valor );
5432
5433 void gtk_combo_set_case_sensitive( GtkCombo *combo,
5434                                    gint      valor );
5435 </verb></tscreen>
5436
5437 <tt/gtk_combo_set_use_arrows()/ le deja al usuario cambiar el valor
5438 del combo box utilizando las flechas de arriba/abajo. Utilizando estas
5439 teclas no haremos salir la lista, pero se reemplazará el texto actual
5440 del combo box con el siguiente elemento de la lista (superior o
5441 inferior, según la tecla que se pulse). Esto se consigue buscando en
5442 la lista el elemento correspondiente al valor actual del combo box y
5443 seleccionando el anterior o el posterior (según corresponda).
5444 Normalmente en una caja de entrada de texto las flechas se utilizan
5445 para cambiar el foco (ie. el <em/widget/ que recibe la entrada del
5446 teclado), pero en este caso será el TAB quien se ocupe. Cuando el
5447 elemento actual sea el último de la lista y presione la flecha abajo
5448 se cambiará el foco (lo mismo se aplica cuando estamos sobre el primer
5449 elemento y pulsamos la tecla arriba).
5450
5451 Si el valor actual en la caja de entrada de texto no está en la lista,
5452 entonces se desactiva la función de <tt/gtk_combo_set_use_arrows()/.
5453
5454 <tt/gtk_combo_set_use_arrows_always()/ igualmente permite la
5455 utilización de las flechas arriba/abajo para cambiar el elemento
5456 seleccionado por el siguiente/anterior de la lista, pero además trata
5457 la lista como si fuese circular (ie. pasa del último al primer
5458 elemento), desactivando completamente la utilidad de las teclas arriba
5459 y abajo para cambiar el foco.
5460
5461 <tt/gtk_combo_set_case_sensitive()/ cambia entre una búsqueda por la
5462 lista que discrimine entre mayúsculas y minúsculas y una búsqueda que
5463 no discrimine. Se utiliza cuando se quiere que el <em/widget/ combo
5464 complete el valor que se está introduciendo con un valor de la
5465 lista. Dependiendo de esta función, se completará distinguiendo entre
5466 mayúsculas y minúsculas o no. El <em/widget/ combo completará la
5467 entrada actual si el usuario presiona la combinación de teclas MOD-1 y
5468 `Tab'. MOD-1 normalmente es la tecla `Alt'. Hay algunos
5469 administradores de ventanas que también utilizan esta combinación de
5470 teclas, con lo que perderemos su posible utilización por parte de GTK.
5471
5472 Ahora que tenemos un combo box que actua como queremos que actue, todo
5473 lo que nos queda es saber como hay que hacer para obtener los datos
5474 que nos puede proporcionar. Esto es relativamente sencillo. La mayoría
5475 del tiempo, de lo único que tiene que preocuparse es de obtener datos
5476 de la caja de texto. Podemos acceder a la caja de texto mediante
5477 GTK_ENTRY(GTK_COMBO(combo)->entry). Las dos cosas que son interesantes
5478 hacer con esta caja son: enlazarla con la señal <tt/activate/, que
5479 indica que el usuario ha presionado la tecla «Intro», y leer el
5480 texto. Lo primero podemos hacerlo utilizando algo así:
5481
5482 <tscreen><verb>
5483     gtk_signal_connect(GTK_OBJECT(GTK_COMB(combo)->entry), "activate",
5484                        GTK_SIGNAL_FUNC (mi_funcion_respuesta), mis_datos);
5485 </verb></tscreen>
5486
5487 Para conseguir el texto que hay en la caja en cualquier momento sólo
5488 tenemos que utilizar la función siguiente:
5489
5490 <tscreen><verb>
5491 gchar *gtk_entry_get_text(GtkEntry *entry);
5492 </verb></tscreen>
5493
5494 De esta forma:
5495
5496 <tscreen><verb>
5497     char *cadena;
5498
5499     cadena = gtk_entry_get_text(GTK_ENTRY(GTK_COMBO(combo)->entry));
5500 </verb></tscreen>
5501
5502 Esto es todo lo interesante. Existe otra función,
5503
5504 <tscreen><verb>
5505 void gtk_combo_disable_activate(GtkCombo *combo);
5506 </verb></tscreen>
5507
5508 que permite desactivar la señal <tt/activate/ en el <em/widget/ entry
5509 dentro del combo box. Personalmente no se me ocurre ningún motivo para
5510 utilizarla, pero existir existe.
5511
5512 <!-- There are also a function to set the string on a particular item, void
5513 gtk_combo_set_item_string(GtkCombo *combo, GtkItem *item, const gchar
5514 *item_value), but this requires that you have a pointer to the
5515 appropriate GtkItem.  Frankly, I have no idea how to do that.
5516 -->
5517
5518 <!-- ************************************** -->
5519
5520 <!-- ----------------------------------------------------------------- -->
5521 <sect1> Selección de Color
5522 <p>
5523 El <em/widget/ selección de color, nos permite (¡sorpresa!) la selección
5524 interactiva de colores. Este <em/widget/ compuesto le permite al usuario
5525 seleccionar un color manipulando los tripletes RGB (rojo, verde y azul) y
5526 HSV (tono, saturación, valor). Para conseguirlo puede ajustar cada variable
5527 mediante las regletas o introduciendo directamente el valor deseado.
5528 También puede pinchar en la rueda de colores y seleccionar así el color
5529 deseado. También se puede establecer, opcionalmente, la transparencia
5530 del color.
5531
5532 El <em/widget/ de selección de color emite (por ahora) sólo una señal,
5533 <tt/color_changed/, que se emite cuando cambia el color seleccionado,
5534 ya sea mediante un cambio que haga el usuario o median el resultado
5535 de una llamada a la función <tt/gtk_color_selection_set_color()/.
5536
5537 Echémosle un vistazo a lo que nos ofrece el <em/widget/ de selección de color.
5538 El <em/widget/ tiene dos «sabores» diferentes; <tt/gtk_color_selection/
5539 y <tt/gtk_color_selection_dialog/:
5540
5541 <tscreen><verb>
5542 GtkWidget *gtk_color_selection_new( void );
5543 </verb></tscreen>
5544         
5545 Probablemente no utilizará este constructor directamente. Crea un <em/widget/
5546 GtkColorSelection huérfano al que le tendrá que asignarle un padre. El
5547 <em/widget/ GtkColorSelection está heredado del <em/widget/ GtkVBox.
5548
5549 <tscreen><verb> 
5550 GtkWidget *gtk_color_selection_dialog_new( const gchar *title );
5551 </verb></tscreen>
5552
5553 Éste es el constructor del cuadro de selección de color más común. Crea un
5554 <tt/GtkColorSelectionDialog/, heredado de un <tt/GtkDialog/. Consiste en un
5555 <tt/GtkFrame/ con un <tt/GtkColorSelection/, un <tt/GtkHSeparator/ y un
5556 <tt/GtkHBox/ con tres botones, «Aceptar», «Cancelar» y «Ayuda».
5557 Puede utilizar estos botones accediendo a los <em/widgets/ <tt/ok_button/,
5558 <tt/cancel_button/ y <tt/help_button/ de la estructura GtkColorSelectionDialog,
5559 (es decir GTK_COLOR_SELECTION_DIALOG(colorseldialog)->ok_button).
5560
5561 <tscreen><verb>
5562 void gtk_color_selection_set_update_policy( GtkColorSelection *colorsel, 
5563                                             GtkUpdateType      policy );
5564 </verb></tscreen>
5565
5566 Esta función se utiliza para indicar la política de actuación. La política
5567 por defecto es <tt/GTK_UPDATE_CONTINUOUS/ que significa que el color
5568 seleccionado se actualiza continuamente cuando el usuario arrastra la barra
5569 o selecciona con el ratón un color de la rueda de colores. Si tiene problemas
5570 de rendimiento, puede poner la política <tt/GTK_UPDATE_DISCONTINUOUS/ o
5571 <tt/GTK_UPDATE_DELAYED/.
5572
5573 <tscreen><verb>
5574 void gtk_color_selection_set_opacity( GtkColorSelection *colorsel,
5575                                       gint               use_opacity );
5576 </verb></tscreen>
5577
5578 El <em/widget/ de selección de color admite el ajuste de la transparencia
5579 de un color (también conocido como el canal alfa). Esta opción está
5580 desactivada por defecto. Si se llama a esta función con <tt/use_opacity/
5581 como TRUE se activa la transparencia. Si se utiliza <tt/use_opacity/ como
5582 FALSE se desactiva la transparencia.
5583
5584 <tscreen><verb>
5585 void gtk_color_selection_set_color( GtkColorSelection *colorsel,
5586                                     gdouble           *color );
5587 </verb></tscreen>
5588
5589 Puede poner el color actual explicitamente haciendo uso de esta función con
5590 un puntero a un vector de colores (de tipo <tt/gdouble/). La longitud del
5591 vector depende de si está activada la transparencia. La posición 0 contiene
5592 la componente roja del color, la 1 contiene la verde, la 2 la azul y la
5593 transparencia está en la posición 3 (solamente si está activada la
5594 transparencia, ver <tt/gtk_color_selection_set_opacity()/). Todos los
5595 valores se encuentran entre 0.0 y 1.0.
5596
5597 <tscreen><verb>
5598 void gtk_color_selection_get_color( GtkColorSelection *colorsel,
5599                                     gdouble           *color );
5600 </verb></tscreen>
5601
5602 Cuando necesite preguntar por el color actual, normalmente cuando haya
5603 recibido una señal <tt/color_changed/, utilice esta función. <tt/color/
5604 es un puntero al vector de colores que se rellenará. Ver la descripción
5605 de la función <tt/gtk_color_selection_set_color()/ para conocer la
5606 estructura de este vector.
5607
5608 <!-- Need to do a whole section on DnD - TRG
5609 Drag and drop
5610 -------------
5611
5612 The color sample areas (right under the hue-saturation wheel) supports
5613 drag and drop. The type of drag and drop is "application/x-color". The
5614 message data consists of an array of 4 (or 5 if opacity is enabled)
5615 gdouble values, where the value at position 0 is 0.0 (opacity on) or
5616 1.0 (opacity off) followed by the red, green and blue values at
5617 positions 1,2 and 3 respectively. If opacity is enabled, the opacity
5618 is passed in the value at position 4.
5619 -->
5620
5621 Aquí tenemos un pequeño ejemplo que muestra el uso de
5622 <tt/GtkColorSelectionDialog/. El programa muestra una ventana con una
5623 zona de dibujo. Pulsando en ella se abre un cuadro de diálogo de
5624 selección del color, y cambiando el color en el cuadro de diálogo se
5625 cambia el color de fondo de la zona de dibujo.
5626
5627 <tscreen><verb>
5628 /* principio del ejemplo colorsel colorsel.c */
5629
5630 #include <glib.h>
5631 #include <gdk/gdk.h>
5632 #include <gtk/gtk.h>
5633
5634 GtkWidget *colorseldlg = NULL;
5635 GtkWidget *drawingarea = NULL;
5636
5637 /* Manejador del cambio de color */
5638
5639 void color_changed_cb (GtkWidget *widget, GtkColorSelection *colorsel)
5640 {
5641   gdouble color[3];
5642   GdkColor gdk_color;
5643   GdkColormap *colormap;
5644
5645   /* Obtener el mapa de colores de la zona de dibujo */
5646
5647   colormap = gdk_window_get_colormap (drawingarea->window);
5648
5649   /* Obtener el color actual */
5650
5651   gtk_color_selection_get_color (colorsel,color);
5652
5653   /* Meterlo en un entero sin signo de 16 bits (0..65535) e insertarlo
5654      en la estructura GdkColor */
5655
5656   gdk_color.red = (guint16)(color[0]*65535.0);
5657   gdk_color.green = (guint16)(color[1]*65535.0);
5658   gdk_color.blue = (guint16)(color[2]*65535.0);
5659
5660   /* Pedir memoria para el color */
5661
5662   gdk_color_alloc (colormap, &amp;gdk_color);
5663
5664   /* Poner el color de fondo de la ventana */
5665
5666   gdk_window_set_background (drawingarea->window, &amp;gdk_color);
5667
5668   /* Limpiar la ventana */
5669
5670   gdk_window_clear (drawingarea->window);
5671 }
5672
5673 /* Manejador del evento Drawingarea */
5674
5675 gint area_event (GtkWidget *widget, GdkEvent *event, gpointer client_data)
5676 {
5677   gint handled = FALSE;
5678   GtkWidget *colorsel;
5679
5680   /* Comprobar si hemos recibido un evento de pulsación de botón */
5681
5682   if (event->type == GDK_BUTTON_PRESS &amp;&amp; colorseldlg == NULL)
5683     {
5684       /* Sí, ¡tenemos un evento y todavía no está el colorseldlg! */
5685
5686       handled = TRUE;
5687
5688       /* Crear el cuadro de diálogo de selección del color */
5689
5690       colorseldlg = gtk_color_selection_dialog_new("Select background color");
5691
5692       /* Obtener el widget GtkColorSelection */
5693
5694       colorsel = GTK_COLOR_SELECTION_DIALOG(colorseldlg)->colorsel;
5695
5696       /* Conectar con la señal «color_changed», darle al dato del
5697          cliente el valor del widget colorsel */
5698
5699       gtk_signal_connect(GTK_OBJECT(colorsel), "color_changed",
5700         (GtkSignalFunc)color_changed_cb, (gpointer)colorsel);
5701
5702       /* Mostrar el cuadro de diálogo */
5703
5704       gtk_widget_show(colorseldlg);
5705     }
5706
5707   return handled;
5708 }
5709
5710 /* Manipulador de los eventos cerrar y salir */
5711
5712 void destroy_window (GtkWidget *widget, gpointer client_data)
5713 {
5714   gtk_main_quit ();
5715 }
5716
5717 /* Principal */
5718
5719 gint main (gint argc, gchar *argv[])
5720 {
5721   GtkWidget *ventana;
5722
5723   /* Inicializa el toolkit, y elimina las opciones relacionadas con
5724      gtk incluidas en la línea de órdenes */
5725
5726   gtk_init (&amp;argc,&amp;argv);
5727
5728   /* Crea la ventana de más alto nivel, le da título y la política */
5729
5730   ventana = gtk_window_new (GTK_WINDOW_TOPLEVEL);
5731   gtk_window_set_title (GTK_WINDOW(ventana), "Color selection test");
5732   gtk_window_set_policy (GTK_WINDOW(ventana), TRUE, TRUE, TRUE);
5733
5734   /* Enlaza con los eventos «delete» y «destroy», para que podamos
5735      salir */
5736
5737   gtk_signal_connect (GTK_OBJECT(ventana), "delete_event",
5738     (GtkSignalFunc)destroy_window, (gpointer)ventana);
5739
5740   gtk_signal_connect (GTK_OBJECT(ventana), "destroy",
5741     (GtkSignalFunc)destroy_window, (gpointer)ventana);
5742   
5743   /* Crea la zona de dibujo, pone el tamaño y caza los eventos de los
5744      botones */
5745
5746   drawingarea = gtk_drawing_area_new ();
5747
5748   gtk_drawing_area_size (GTK_DRAWING_AREA(drawingarea), 200, 200);
5749
5750   gtk_widget_set_events (drawingarea, GDK_BUTTON_PRESS_MASK);
5751
5752   gtk_signal_connect (GTK_OBJECT(drawingarea), "event", 
5753     (GtkSignalFunc)area_event, (gpointer)drawingarea);
5754   
5755   /* Add drawingarea to window, then show them both */
5756
5757   gtk_container_add (GTK_CONTAINER(ventana), drawingarea);
5758
5759   gtk_widget_show (drawingarea);
5760   gtk_widget_show (ventana);
5761   
5762   /* Entrar en el bucle principal de gtk (nunca sale de aquí) */
5763
5764   gtk_main ();
5765
5766   /* Para satisfacer a los compiladores pijos */
5767
5768   return 0;
5769 }
5770 /* final del ejemplo */
5771 </verb></tscreen>
5772
5773 <!-- ----------------------------------------------------------------- -->
5774 <sect1> Selección de ficheros
5775 <p>
5776 El <em/widget/ de selección de ficheros nos proporciona una forma
5777 rápida y sencilla de mostrar un cuadro de diálogo para la selección de
5778 un fichero. Ya viene con los botones Aceptar, Cancelar y Ayuda. Una
5779 magnifica ayuda para acortar el tiempo de programación.
5780
5781 Para crear un nuevo cuadro de diálogo de selección de ficheros
5782 utilice:
5783
5784 <tscreen><verb>
5785 GtkWidget *gtk_file_selection_new( gchar *title );
5786 </verb></tscreen>
5787
5788 Para poner el nombre del fichero en el cuadro de diálogo, por
5789 ejemplo para poder utilizar un directorio o un fichero por defecto,
5790 utilice la función:
5791
5792 <tscreen><verb>
5793 void gtk_file_selection_set_filename( GtkFileSelection *filesel,
5794                                       gchar            *filename );
5795 </verb></tscreen>
5796
5797 Para obtener el texto que el usuario ha introducido, utilice la función:
5798
5799 <tscreen><verb>
5800 gchar *gtk_file_selection_get_filename( GtkFileSelection *filesel );
5801 </verb></tscreen>
5802
5803 También hay punteros a los <em/widgets/ que contiene el cuadro de
5804 diálogo. Son los siguientes:
5805
5806 <itemize>
5807 <item>dir_list
5808 <item>file_list
5809 <item>selection_entry
5810 <item>selection_text
5811 <item>main_vbox
5812 <item>ok_button
5813 <item>cancel_button
5814 <item>help_button
5815 </itemize>
5816
5817 Lo más probable es que sólo utilice los punteros <tt/ok_button/,
5818 <tt/cancel_button/, y <tt/help_button/ para controlar cuando se pulsan.
5819
5820 Aquí incluímos un ejemplo robado de <tt/testgtk.c/, modificado
5821 para que se puede ejecutar independientemente. Como puede ver, no es
5822 muy complicado crear un <em/widget/ para la selección de
5823 ficheros. Aunque aparezca el botón de ayuda en la pantalla, no hace
5824 nada y no tiene ninguna señal conectada.
5825
5826 <tscreen><verb>
5827 /* principio del ejemplo filesel filesel.c */
5828
5829 #include <gtk/gtk.h>
5830
5831 /* Obtener el nombre del fichero e imprimirlo en la consola */
5832 void file_ok_sel (GtkWidget *w, GtkFileSelection *fs)
5833 {
5834     g_print ("%s\n", gtk_file_selection_get_filename (GTK_FILE_SELECTION (fs)));
5835 }
5836
5837 void destroy (GtkWidget *widget, gpointer data)
5838 {
5839     gtk_main_quit ();
5840 }
5841
5842 int main (int argc, char *argv[])
5843 {
5844     GtkWidget *filew;
5845     
5846     gtk_init (&amp;argc, &amp;argv);
5847     
5848     /* Crear un nuevo widget de selección de ficheros */
5849     filew = gtk_file_selection_new ("File selection");
5850     
5851     gtk_signal_connect (GTK_OBJECT (filew), "destroy",
5852                         (GtkSignalFunc) destroy, &amp;filew);
5853     /* Conectar el ok_button con la función file_ok_sel */
5854     gtk_signal_connect (GTK_OBJECT (GTK_FILE_SELECTION (filew)->ok_button),
5855                         "clicked", (GtkSignalFunc) file_ok_sel, filew );
5856     
5857     /* Conectar el cancel_button con la destrucción del widget */
5858     gtk_signal_connect_object (GTK_OBJECT (GTK_FILE_SELECTION (filew)->cancel_button),
5859                                "clicked", (GtkSignalFunc) gtk_widget_destroy,
5860                                GTK_OBJECT (filew));
5861     
5862     /* Damos el nombre del fichero, como si fuese un cuadro de diálogo para
5863        grabar ficheros y estuviesemos dando un nombre por defecto */
5864     gtk_file_selection_set_filename (GTK_FILE_SELECTION(filew), 
5865                                      "penguin.png");
5866     
5867     gtk_widget_show(filew);
5868     gtk_main ();
5869     return 0;
5870 }
5871 /* fin del ejemplo */
5872 </verb></tscreen>
5873
5874 <!-- ***************************************************************** -->
5875 <sect> El <em/widget/ contenedor
5876 <!-- ***************************************************************** -->
5877
5878 <!-- ----------------------------------------------------------------- -->
5879 <sect1> El <em/widget/ EventBox<label id="sec_EventBox"> 
5880 <label id="sec_The_EventBox_Widget">
5881 <p> 
5882 Algunos <em/widget/ gtk no tienen asociada una ventana X, por lo que
5883 sólo pueden dibujar en la de su padre. Debido a esto, no pueden
5884 recibir ningún evento y si tienen un tamaño incorrecto, no se
5885 recortarán correctamente por lo que puede que se sobreescriban ciertas
5886 zonas, etc... Si necesita este tipo de <em/widgets/, el EventBox es
5887 para usted.
5888
5889 Cuando se ve por primera vez, el <em/widget/ EventBox puede parecer
5890 completamente inútil. No dibuja nada en la pantalla y no responde
5891 a ningún evento. Sin embargo, tiene una utilidad - proporciona una
5892 ventana X para su <em/widget/ hijo. Esto es importante ya que
5893 muchos <em/widgets/ GTK no tienen una ventana X asociada. No tener una
5894 ventana X ahorra memoria y mejora el rendimiento, pero tiene sus
5895 desventajas. Un <em/widget/ sin una ventana X no puede recibir
5896 eventos, y no realizará ningún recorte en sus contenidos. Aunque el
5897 nombre <em/EventBox/ enfatiza su función de manejador de eventos, el
5898 <em/widget/ también puede utilizarse para hacer los recortes.
5899 (Y más... ver el ejemplo más abajo.)
5900
5901 Para crear un nuevo <em/widget/ EventBox, utilice:
5902
5903 <tscreen><verb>
5904 GtkWidget *gtk_event_box_new( void );
5905 </verb></tscreen>
5906
5907 Un <em/widget/ hijo puede añadirse a su EventBox así:
5908
5909 <tscreen><verb>
5910 gtk_container_add( GTK_CONTAINER(event_box), widget );
5911 </verb></tscreen>
5912
5913 El siguiente ejemplo demuestra los dos usos de EventBox - se crea
5914 una etiqueta que se recorta dentro de una pequeña caja, y hace
5915 que una pulsación del ratón en la misma finalice el programa.
5916
5917 <tscreen><verb>
5918 /* principio del ejemplo eventbox eventbox.c */
5919
5920 #include <gtk/gtk.h>
5921
5922 int 
5923 main (int argc, char *argv[])
5924 {
5925     GtkWidget *ventana;
5926     GtkWidget *event_box;
5927     GtkWidget *etiqueta;
5928     
5929     gtk_init (&amp;argc, &amp;argv);
5930     
5931     ventana = gtk_window_new (GTK_WINDOW_TOPLEVEL);
5932     
5933     gtk_window_set_title (GTK_WINDOW (ventana), "Event Box");
5934     
5935     gtk_signal_connect (GTK_OBJECT (ventana), "destroy",
5936                         GTK_SIGNAL_FUNC (gtk_exit), NULL);
5937     
5938     gtk_container_border_width (GTK_CONTAINER (ventana), 10);
5939     
5940     /* Crea un EventBox y lo añade a nuestra ventana superior */
5941
5942     event_box = gtk_event_box_new ();
5943     gtk_container_add (GTK_CONTAINER(ventana), event_box);
5944     gtk_widget_show (event_box);
5945     
5946     /* Crea una larga etiqueta */
5947     
5948     etiqueta = gtk_label_new ("Click here to quit, quit, quit, quit, quit");
5949     gtk_container_add (GTK_CONTAINER (event_box), etiqueta);
5950     gtk_widget_show (etiqueta);
5951     
5952     /* La recortamos. */
5953     gtk_widget_set_usize (etiqueta, 110, 20);
5954     
5955     /* Y enlazamos una acción con la etiqueta */
5956     gtk_widget_set_events (event_box, GDK_BUTTON_PRESS_MASK);
5957     gtk_signal_connect (GTK_OBJECT(event_box), "button_press_event",
5958                         GTK_SIGNAL_FUNC (gtk_exit), NULL);
5959     
5960     /* Otra cosa más que necesita una ventana X ... */
5961     
5962     gtk_widget_realize (event_box);
5963     gdk_window_set_cursor (event_box->window, gdk_cursor_new (GDK_HAND1));
5964     
5965     gtk_widget_show (ventana);
5966     
5967     gtk_main ();
5968     
5969     return 0;
5970 }
5971 /* Final del ejemplo */
5972 </verb></tscreen>
5973
5974 <!-- ----------------------------------------------------------------- -->
5975 <sect1>El <em/widget/ alineamiento <label id="sec_Alignment">
5976 <p>
5977 El <em/widget/ alineamiento (<em/alignment/) le permitirá colocar un
5978 <em/widget/ dentro de su ventana utilizando una posición y un tamaño
5979 relativos al mismo <em/widget/ de alineamiento. Por ejemplo, puede ser
5980 muy útil para centrar un <em/widget/ en la ventana.
5981
5982 Sólo hay dos funciones asociadas con el <em/widget/ alineamiento:
5983
5984 <tscreen><verb>
5985 GtkWidget* gtk_alignment_new( gfloat xalign,
5986                               gfloat yalign,
5987                               gfloat xscale,
5988                               gfloat yscale );
5989
5990 void gtk_alignment_set( GtkAlignment *alignment,
5991                         gfloat        xalign,
5992                         gfloat        yalign,
5993                         gfloat        xscale,
5994                         gfloat        yscale );
5995 </verb></tscreen>
5996
5997 La primera función crea un nuevo <em/widget/ alineamiento con los
5998 parámetros especificados. La segunda función permite alterar los
5999 parámetros de un <em/widget/ alineamiento ya existente.
6000
6001 Los cuatro parámetros de alineamiento son números en coma flotante que
6002 pueden tener variar entre 0.0 y 1.0. Los argumentos <tt/xalign/ e
6003 <tt/yalign/ afectan a la posición del <em/widget/ colocado dentro del
6004 <em/widget/ de alineamiento. Los argumentos <tt/xscale/ e <tt/yscale/
6005 afectan a la cantidad de espacio que ocupa el <em/widget/. 
6006
6007 Se le puede añadir un <em/widget/ hijo a un alineamiento utilizando:
6008
6009 <tscreen><verb>
6010     gtk_container_add( GTK_CONTAINER(alignment), child_widget );
6011 </verb></tscreen>
6012
6013 Para ver un ejemplo de utilización del <em/widget/ alineamiento,
6014 diríjase al ejemplo del <em/widget/ <ref id="sec_ProgressBar"
6015 name="Barra de progreso">.
6016
6017
6018 <!-- ----------------------------------------------------------------- -->
6019 <sect1> Contenedor fijo
6020 <p>
6021 El contenedor fijo le permite situar <em/widgets/ en una posición fija
6022 dentro de su ventana, relativa a la esquina superior izquierda. La
6023 posición de los <em/widgets/ puede cambiarse dinámicamente.
6024
6025 Sólo hay tres funciones asociadas al <em/widget/ contenedor fijo:
6026
6027 <tscreen><verb>
6028 GtkWidget* gtk_fixed_new( void );
6029
6030 void gtk_fixed_put( GtkFixed  *fixed,
6031                     GtkWidget *widget,
6032                     gint16     x,
6033                     gint16     y );
6034
6035 void gtk_fixed_move( GtkFixed  *fixed,
6036                      GtkWidget *widget,
6037                      gint16     x,
6038                      gint16     y );
6039 </verb></tscreen>
6040
6041 La función <tt/gtk_fixed_new/ permite la creación de un nuevo
6042 contenedor fijo.
6043
6044 <tt/gtk_fixed_put/ situa <tt/widget/ dentro del contenedor <tt/fixed/
6045 en la posición especificada por <tt/x/ e <tt/y/.
6046
6047 <tt/gtk_fixed_move/ permite que mover hacia una nuevo posición el
6048 <em/widget/ especificado.
6049
6050 El ejemplo siguiente muestra como utilizar el contenedor fijo.
6051
6052 <tscreen><verb>
6053 /* principio del ejemplo fixed fixed.c */
6054
6055 #include <gtk/gtk.h>
6056
6057 /* Voy a ser un poco torpe y utilizar algunas variables
6058  * globales para almacenar la posición del widget que
6059  * hay dentro del contenedor */
6060 gint x=50;
6061 gint y=50;
6062
6063 /* Esta función de llamada mueve el botón a una nueva
6064  * posición dentro del contenedor fijo. */
6065 void move_button( GtkWidget *widget,
6066                   GtkWidget *fixed )
6067 {
6068   x = (x+30)%300;
6069   y = (y+50)%300;
6070   gtk_fixed_move( GTK_FIXED(fixed), widget, x, y); 
6071 }
6072
6073 int main( int   argc,
6074           char *argv[] )
6075 {
6076   /* GtkWidget es el tipo de almacenamiento para los widgets */
6077   GtkWidget *ventana;
6078   GtkWidget *fixed;
6079   GtkWidget *boton;
6080   gint i;
6081
6082   /* Inicializa GTK */
6083   gtk_init(&amp;argc, &amp;argv);
6084     
6085   /* Crear una nueva ventana */
6086   ventana = gtk_window_new (GTK_WINDOW_TOPLEVEL);
6087   gtk_window_set_title(GTK_WINDOW(ventana), "Fixed Container");
6088
6089   /* Aquí conectamos el evento "destroy" al manejador de la señal */
6090   gtk_signal_connect (GTK_OBJECT (ventana), "destroy",
6091                       GTK_SIGNAL_FUNC (gtk_main_quit), NULL);
6092  
6093   /* Establecemos el ancho del borde la ventana */
6094   gtk_container_set_border_width (GTK_CONTAINER (ventana), 10);
6095
6096   /* Creamos un contenedor fijo */
6097   fixed = gtk_fixed_new();
6098   gtk_container_add(GTK_CONTAINER(ventana), fixed);
6099   gtk_widget_show(fixed);
6100   
6101   for (i = 1 ; i <= 3 ; i++) {
6102     /* Crea un nuevo botón con la etiqueta "Press me" */
6103     boton = gtk_button_new_with_label ("Press me");
6104   
6105     /* Cuando el botón reciba la señal "pulsado", llamará a la función
6106      * move_button() pasándole el contenedor fijo como argumento. */
6107     gtk_signal_connect (GTK_OBJECT (boton), "clicked",
6108                         GTK_SIGNAL_FUNC (move_button), fixed);
6109   
6110     /* Esto mete el botón dentro de la ventana del window contenedor
6111      * fijo. */
6112     gtk_fixed_put (GTK_FIXED (fixed), boton, i*50, i*50);
6113   
6114     /* El paso final es mostrar el widget recien creado */
6115     gtk_widget_show (boton);
6116   }
6117
6118   /* Mostrar la ventana */
6119   gtk_widget_show (ventana);
6120     
6121   /* Entrar en el bucle principal */
6122   gtk_main ();
6123     
6124   return(0);
6125 }
6126 /* fin del ejemplo */
6127 </verb></tscreen>
6128
6129 <!-- ----------------------------------------------------------------- -->
6130 <sect1> Contenedor capa
6131 <p>
6132 El contenedor capa es similar al contenedor fijo, excepto que permite
6133 implementar una zona de <em/scroll/ infinita (donde infinito significa
6134 menor de 2^32). Xwindows tiene una limitación en la que las ventanas
6135 pueden tener un máximo de 32767 <em/pixels/ de alto o de ancho. El
6136 contenedor capa sortea esta limitación con una exótica combinación de
6137 ventanas y <em/bits/ de gravedad, <!-- Si alguien entiende que
6138 significa esto: e98cuenc@criens.u-psud.fr --> para que puede tener un
6139 suave <em/scroll/ aún cuando utilice una gran cantidad de <em/widgets/
6140 hijos dentro de su zona de <em/scroll/.
6141
6142 Podrá crear un contenedor capa utilizando:
6143
6144 <tscreen><verb>
6145 GtkWidget *gtk_layout_new( GtkAdjustment *hadjustment,
6146                            GtkAdjustment *vadjustment );
6147 </verb></tscreen>
6148
6149 Como puede observar, podrá especificar (de forma opcional) los objetos
6150 de ajuste que utilizará el <em/widget/ capa para hacer su <em/scroll/.
6151
6152 Puede añadir y mover <em/widgets/ dentro del contenedor capa
6153 utilizando las dos funciones siguientes:
6154
6155 <tscreen><verb>
6156 void gtk_layout_put( GtkLayout *layout,
6157                      GtkWidget *widget,
6158                      gint       x,
6159                      gint       y );
6160
6161 void gtk_layout_move( GtkLayout *layout,
6162                       GtkWidget *widget,
6163                       gint       x,
6164                       gint       y );
6165 </verb></tscreen>
6166
6167 El tamaño del contenedor capa se puede establecer utilizando la
6168 siguiente función:
6169
6170 <tscreen><verb>
6171 void gtk_layout_set_size( GtkLayout *layout,
6172                           guint      width,
6173                           guint      height );
6174 </verb></tscreen>
6175
6176 Los contenedores capa son uno de los poquísimos <em/widgets/ dentro de
6177 GTK que se repintan ellos mismos en la pantalla cuando se cambian
6178 utilizando las funciones anteriores (la inmensa mayoria de los
6179 <em/widgets/ mandan una petición a la cola que será procesada cuando
6180 se devuelva el control a la función <tt/gtk_main()/).
6181
6182 Cuando quiera hacer una gran cantidad de cambios dentro del contenedor
6183 capa, podrá utilizar las dos funciones siguientes para desactivar y
6184 reactivar la característica de repintado:
6185
6186 <tscreen><verb>
6187 void gtk_layout_freeze( GtkLayout *layout );
6188
6189 void gtk_layout_thaw( GtkLayout *layout );
6190 </verb></tscreen>
6191
6192 Las cuatro funciones finales a utilizar con los <em/widgets/capa son
6193 para la manipulación de los <em/widgets/ de ajuste horizontal y
6194 vertical:
6195
6196 <tscreen><verb>
6197 GtkAdjustment* gtk_layout_get_hadjustment( GtkLayout *layout );
6198
6199 GtkAdjustment* gtk_layout_get_vadjustment( GtkLayout *layout );
6200
6201 void gtk_layout_set_hadjustment( GtkLayout     *layout,
6202                                  GtkAdjustment *adjustment );
6203
6204 void gtk_layout_set_vadjustment( GtkLayout     *layout,
6205                                  GtkAdjustment *adjustment);
6206 </verb></tscreen>
6207
6208 <!-- ----------------------------------------------------------------- -->
6209 <sect1> Marcos <label id="sec_Frames">
6210 <p>
6211 Los marcos pueden utilizarse para meter uno o un grupo de
6212 <em/widgets/dentro de una caja puede ser (de forma opcional)
6213 etiquetada. La posición de la etiqueta y el estilo de la caja pueden
6214 modificarse.
6215
6216 Se puede crear un marco con la siguiente función:
6217
6218 <tscreen><verb>
6219 GtkWidget *gtk_frame_new( const gchar *etiqueta );
6220 </verb></tscreen>
6221
6222 La etiqueta se coloca por defecto en la esquina superior izquierda del
6223 marco. Si el argumento <tt/etiqueta/ es NULL no se mostrará ninguna
6224 etiqueta. Puede cambiarse el texto de la etiqueta utilizando la
6225 función siguiente.
6226
6227 <tscreen><verb>
6228 void gtk_frame_set_label( GtkFrame    *frame,
6229                           const gchar *etiqueta );
6230 </verb></tscreen>
6231
6232 La posición de la etiqueta se puede cambiar utilizado la función:
6233
6234 <tscreen><verb>
6235 void gtk_frame_set_label_align( GtkFrame *frame,
6236                                 gfloat    xalign,
6237                                 gfloat    yalign );
6238 </verb></tscreen>
6239
6240 <tt/xalign/ e <tt/yalign/ toman valores entre 0.0 y 1.0. <tt/yalign/
6241 no se actualmente no se utiliza. El valor por defecto de <tt/xalign/
6242 es 0.0, lo que coloca la etiqueta a la izquierda del marco.
6243
6244 La siguiente función altera el estilo de la caja que se utiliza para
6245 señalar el marco.
6246
6247 <tscreen><verb>
6248 void gtk_frame_set_shadow_type( GtkFrame      *frame,
6249                                 GtkShadowType  type);
6250 </verb></tscreen>
6251
6252 El argumento <tt/type/ puede tomar uno de los valores siguientes:
6253
6254 <itemize>
6255 <item> GTK_SHADOW_NONE
6256 <item> GTK_SHADOW_IN
6257 <item> GTK_SHADOW_OUT
6258 <item> GTK_SHADOW_ETCHED_IN (the default)
6259 <item> GTK_SHADOW_ETCHED_OUT
6260 </itemize>
6261
6262 El código siguiente ilustra la utilización del <em/widget/ marco.
6263
6264 <tscreen><verb>
6265 /* principio del ejemplo frame frame.c */
6266
6267 #include <gtk/gtk.h>
6268
6269 int main( int   argc,
6270           char *argv[] )
6271 {
6272   /* GtkWidget es el tipo de almacenamiento para los widgets */
6273   GtkWidget *ventana;
6274   GtkWidget *frame;
6275   GtkWidget *boton;
6276   gint i;
6277
6278   /* Inicializa GTK */
6279   gtk_init(&amp;argc, &amp;argv);
6280     
6281   /* Crea una nueva ventana */
6282   ventana = gtk_window_new (GTK_WINDOW_TOPLEVEL);
6283   gtk_window_set_title(GTK_WINDOW(ventana), "Frame Example");
6284
6285   /* Aquí conectamos el evento "destroy"al manejador de señal */
6286   gtk_signal_connect (GTK_OBJECT (ventana), "destroy",
6287                       GTK_SIGNAL_FUNC (gtk_main_quit), NULL);
6288
6289   gtk_widget_set_usize(ventana, 300, 300);
6290
6291   /* Establecemos el ancho del borde de la ventana */
6292   gtk_container_set_border_width (GTK_CONTAINER (ventana), 10);
6293
6294   /* Crea un marco */
6295   frame = gtk_frame_new(NULL);
6296   gtk_container_add(GTK_CONTAINER(ventana), frame);
6297
6298   /* Establece la etiqueta del marco */
6299   gtk_frame_set_label( GTK_FRAME(frame), "GTK Frame Widget" );
6300
6301   /* Alinea la etiqueta a la derecha del marco */
6302   gtk_frame_set_label_align( GTK_FRAME(frame), 1.0, 0.0);
6303
6304   /* Establece el estilo del marco */
6305   gtk_frame_set_shadow_type( GTK_FRAME(frame), GTK_SHADOW_ETCHED_OUT);
6306
6307   gtk_widget_show(frame);
6308   
6309   /* Muestra la ventana */
6310   gtk_widget_show (ventana);
6311     
6312   /* Entra dentro del bucle principal */
6313   gtk_main ();
6314     
6315   return(0);
6316 }
6317 /* fin del ejemplo */
6318
6319 </verb></tscreen>
6320
6321 <!-- ----------------------------------------------------------------- -->   
6322 <sect1> Marcos con proporciones fijas
6323 <p>
6324 El <em/widget aspect frame/ (marco proporcional) es como el <em/widget
6325 frame/ (marco), excepto que conserva las proporciones (esto es, la
6326 relación entre el ancho y el alto) del <em/widget/ hijo, añadiendo
6327 espacio extra en caso de ser necesario. Esto es útil, por ejemplo, si
6328 quiere hacer una vista previa de una gran imagen. El tamaño de la
6329 vista previa debería variar cuando el usuario redimensione la ventana,
6330 pero la proporción tiene que coincidir con la de la imagen original.
6331    
6332 Para crear un nuevo marco proporcional utilice:
6333    
6334 <tscreen><verb>
6335 GtkWidget *gtk_aspect_frame_new( const gchar *etiqueta,
6336                                  gfloat       xalign,
6337                                  gfloat       yalign,
6338                                  gfloat       ratio,
6339                                  gint         obey_child);
6340 </verb></tscreen>
6341    
6342 <tt/xalign/ e <tt/yalign/ indican la alineación exactamente igual que
6343 con los <em/widgets Alignment/. Si <tt/obey_child/ es TRUE, la
6344 proporción de un <em/widget/ hijo será la misma que la proporción del
6345 tamaño ideal que éste pida. En caso contrario, vendrá dada por
6346 <tt/ratio/.
6347    
6348 Para cambiar las opciones de un marco proporcional ya existente, puede
6349 utilizar:
6350    
6351 <tscreen><verb>
6352 void gtk_aspect_frame_set( GtkAspectFrame *aspect_frame,
6353                            gfloat          xalign,
6354                            gfloat          yalign,
6355                            gfloat          ratio,
6356                            gint            obey_child);
6357 </verb></tscreen>
6358    
6359 Como por ejemplo, el siguiente programa utiliza un marco proporcional
6360 para mostrar una zona de dibujo cuyas proporciones siempre será de
6361 2:1, no importa como el usuario redimensione la ventana.
6362    
6363 <tscreen><verb>
6364 /* principio del ejemplo aspectframe aspectframe.c */
6365
6366 #include <gtk/gtk.h>
6367    
6368 int
6369 main (int argc, char *argv[])
6370 {
6371     GtkWidget *ventana;
6372     GtkWidget *aspect_frame;
6373     GtkWidget *drawing_area;
6374     gtk_init (&amp;argc, &amp;argv);
6375    
6376     ventana = gtk_window_new (GTK_WINDOW_TOPLEVEL);
6377     gtk_window_set_title (GTK_WINDOW (ventana), "Aspect Frame");
6378     gtk_signal_connect (GTK_OBJECT (ventana), "destroy",
6379                         GTK_SIGNAL_FUNC (gtk_main_quit), NULL);
6380     gtk_container_border_width (GTK_CONTAINER (ventana), 10);
6381    
6382     /* Crear un aspect_frame y añadirlo a nuestra ventana superior */
6383    
6384     aspect_frame = gtk_aspect_frame_new ("2x1", /* etiqueta */
6385                                          0.5, /* centro x */
6386                                          0.5, /* centro y */
6387                                          2, /* tamañox/tamañoy = 2 */
6388                                          FALSE /* ignorar el aspecto del hijo */);
6389    
6390     gtk_container_add (GTK_CONTAINER(ventana), aspect_frame);
6391     gtk_widget_show (aspect_frame);
6392    
6393     /* Añadir un widget hijo al marco proporcional */
6394    
6395     drawing_area = gtk_drawing_area_new ();
6396    
6397     /* Pediremos una ventana de 200x200, pero el marco proporcional
6398      * sólo no dejará una ventana de 200x100, ya que tenemos una
6399      * relación de 2x1 */
6400     gtk_widget_set_usize (drawing_area, 200, 200);
6401     gtk_container_add (GTK_CONTAINER(aspect_frame), drawing_area);
6402     gtk_widget_show (drawing_area);
6403    
6404     gtk_widget_show (ventana);
6405     gtk_main ();
6406     return 0;
6407 }
6408 /* fin del ejemplo */
6409 </verb></tscreen>
6410
6411 <!-- ----------------------------------------------------------------- -->
6412
6413 <sect1> El <em/widget/ ventana dividida (<em/Paned Window/)
6414 <p>
6415 El <em/widget/ ventana dividida es útil para cuando se quiere dividir
6416 una zona en dos partes, con un tamaño relativo controlado por el
6417 usuario. Entre las dos porciones de la ventana se dibuja un separador
6418 con un botoncito que el usuario puede arrastrar para cambiar el tamaño
6419 de cada zona. La división puede ser horizontal (HPaned) o vertical
6420 (VPaned).
6421    
6422 Para crear una nueva ventana dividida, utilice una de las siguientes
6423 funciones:
6424    
6425 <tscreen><verb>
6426 GtkWidget *gtk_hpaned_new (void);
6427
6428 GtkWidget *gtk_vpaned_new (void);
6429 </verb></tscreen>
6430
6431 Después de crear el <em/widget/ ventana dividida, tiene que añadirle
6432 un <em/widget/ hijo a cada mitad. Para hacerlo, utilice:
6433    
6434 <tscreen><verb>
6435 void gtk_paned_add1 (GtkPaned *paned, GtkWidget *hijo);
6436
6437 void gtk_paned_add2 (GtkPaned *paned, GtkWidget *hijo);
6438 </verb></tscreen>
6439    
6440 <tt/gtk_paned_add1()/ añade el <em/widget/ hijo a la mitad que se
6441 encuentra en la parte izquierda o superior de la ventana
6442 dividida. <tt/gtk_paned_add2()/ añade el <em/widget/ a la mitad que
6443 hay en la parte derecha o inferior de la ventana.
6444    
6445 Por ejemplo, si queremos crear una parte del interface de usuario de
6446 un programa de correo-e imaginario. Dividiremos verticalmente una
6447 ventana en dos partes, teniendo en la parte superior una lista de los
6448 mensajes de correo-e y en la parte inferior el texto de uno de estos
6449 mensajes. El programa es bastante fácil de entender. Solo un par de
6450 cosillas: no se puede añadir texto en un <em/widget/ de texto (Text)
6451 si no se ha hecho antes <tt/gtk_widget_realize()/, pero como
6452 demostración de una técnica alternativa, para añadir el texto
6453 conectaremos un manipulador a la señal «realize». Y tenemos que
6454 añadir la opción <tt/GTK_SHRINK/ a algunos de los elementos que hay en
6455 la tabla con la ventana de texto y sus barras de desplazamiento, así
6456 cuando la porción de abajo se haga más pequeña, se encogerá
6457 correctamente en lugar de desaparecer por la parte de abajo de la
6458 ventana.
6459
6460 <tscreen><verb>
6461 /* principio del ejemplo paned paned.c */
6462
6463 #include <gtk/gtk.h>
6464    
6465 /* Crear la lista de "messages" */
6466 GtkWidget *
6467 create_list (void)
6468 {
6469
6470     GtkWidget *scrolled_window;
6471     GtkWidget *list;
6472     GtkWidget *list_item;
6473    
6474     int i;
6475     char buffer[16];
6476    
6477     /* Crear una nueva ventana con barras de desplazamiento si hacen
6478        falta */
6479     scrolled_window = gtk_scrolled_window_new (NULL, NULL);
6480     gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled_window),
6481                                     GTK_POLICY_AUTOMATIC, 
6482                                     GTK_POLICY_AUTOMATIC);
6483    
6484     /* Crear una nueva lista y poner en ella la ventana con barras */
6485     list = gtk_list_new ();
6486     gtk_container_add (GTK_CONTAINER(scrolled_window), list);
6487     gtk_widget_show (list);
6488    
6489     /* Añadir algunos mensajes a la ventana */
6490     for (i=0; i<10; i++) {
6491
6492         sprintf(buffer,"Message #%d",i);
6493         list_item = gtk_list_item_new_with_label (buffer);
6494         gtk_container_add (GTK_CONTAINER(list), list_item);
6495         gtk_widget_show (list_item);
6496
6497     }
6498    
6499     return scrolled_window;
6500 }
6501    
6502 /* Añadir algún texto a nuestro widget de texto - esta función se
6503    invoca cada vez que se produce una señal realize en la
6504    ventana. Podemos forzar esta señal mediante gtk_widget_realize, pero
6505    primero tiene que formar parte de una jerarquía */
6506
6507 void
6508 realize_text (GtkWidget *text, gpointer data)
6509 {
6510     gtk_text_freeze (GTK_TEXT (text));
6511     gtk_text_insert (GTK_TEXT (text), NULL, &amp;text->style->black, NULL,
6512     "From: pathfinder@nasa.gov\n"
6513     "To: mom@nasa.gov\n"
6514     "Subject: Made it!\n"
6515     "\n"
6516     "We just got in this morning. The weather has been\n"
6517     "great - clear but cold, and there are lots of fun sights.\n"
6518     "Sojourner says hi. See you soon.\n"
6519     " -Path\n", -1);
6520    
6521     gtk_text_thaw (GTK_TEXT (text));
6522 }
6523    
6524 /* Creamos una zona con texto que muestra un "message" */
6525 GtkWidget *
6526 create_text (void)
6527 {
6528     GtkWidget *table;
6529     GtkWidget *text;
6530     GtkWidget *hscrollbar;
6531     GtkWidget *vscrollbar;
6532    
6533     /* Crea una tabla para contener el widget de texto y las barras de
6534        desplazamiento */
6535     table = gtk_table_new (2, 2, FALSE);
6536    
6537     /* Pone un widget de texto en la esquina superior izquierda.
6538        Observe la utilización de GTK_SHRINK en la dirección y */
6539     text = gtk_text_new (NULL, NULL);
6540     gtk_table_attach (GTK_TABLE (table), text, 0, 1, 0, 1,
6541                       GTK_FILL | GTK_EXPAND,
6542                       GTK_FILL | GTK_EXPAND | GTK_SHRINK, 0, 0);
6543     gtk_widget_show (text);
6544    
6545     /* Pone una HScrollbar en la esquina inferior izquierda */
6546     hscrollbar = gtk_hscrollbar_new (GTK_TEXT (text)->hadj);
6547     gtk_table_attach (GTK_TABLE (table), hscrollbar, 0, 1, 1, 2,
6548                       GTK_EXPAND | GTK_FILL, GTK_FILL, 0, 0);
6549     gtk_widget_show (hscrollbar);
6550    
6551     /* Y una VScrollbar en la esquina superior derecha */
6552     vscrollbar = gtk_vscrollbar_new (GTK_TEXT (text)->vadj);
6553     gtk_table_attach (GTK_TABLE (table), vscrollbar, 1, 2, 0, 1,
6554                       GTK_FILL, GTK_EXPAND | GTK_FILL | GTK_SHRINK, 0, 0);
6555     gtk_widget_show (vscrollbar);
6556    
6557     /* Y un manejador para poner un mensaje en el widget de texto
6558        cuando reciba realize */
6559     gtk_signal_connect (GTK_OBJECT (text), "realize",
6560                         GTK_SIGNAL_FUNC (realize_text), NULL);
6561    
6562     return table;
6563 }
6564    
6565 int
6566 main (int argc, char *argv[])
6567 {
6568     GtkWidget *ventana;
6569     GtkWidget *vpaned;
6570     GtkWidget *list;
6571     GtkWidget *text;
6572
6573     gtk_init (&amp;argc, &amp;argv);
6574    
6575     ventana = gtk_window_new (GTK_WINDOW_TOPLEVEL);
6576     gtk_window_set_title (GTK_WINDOW (ventana), "Paned Windows");
6577     gtk_signal_connect (GTK_OBJECT (ventana), "destroy",
6578                         GTK_SIGNAL_FUNC (gtk_main_quit), NULL);
6579     gtk_container_border_width (GTK_CONTAINER (ventana), 10);
6580    
6581     /* crea un widget vpaned y lo añade a nuestra ventana superior */
6582    
6583     vpaned = gtk_vpaned_new ();
6584     gtk_container_add (GTK_CONTAINER(ventana), vpaned);
6585     gtk_widget_show (vpaned);
6586    
6587     /* Ahora crea los contenidos de las dos mitades de la ventana */
6588    
6589     list = create_list ();
6590     gtk_paned_add1 (GTK_PANED(vpaned), list);
6591     gtk_widget_show (list);
6592    
6593     text = create_text ();
6594     gtk_paned_add2 (GTK_PANED(vpaned), text);
6595     gtk_widget_show (text);
6596     gtk_widget_show (ventana);
6597     gtk_main ();
6598     return 0;
6599 }
6600 /* fin del ejemplo */
6601 </verb></tscreen>
6602
6603 <!-- XXX -->
6604 <!-- ----------------------------------------------------------------- -->
6605 <sect1> <em/Viewports/ <label id="sec_Viewports">
6606 <p>
6607 Probablemente nunca le llegue a hacer falta utilizar el <em/widget/
6608 Viewport directamente. Será mucho más probable que tenga que utilizar
6609 el <em/widget/ <ref id="sec_ScrolledWindows" name="Ventanas con barras
6610 de desplazamiento"> que a su vez hace uso de <em/viewport/.
6611
6612 Un <em/widget viewport/ le permite meter dentro un gran <em/widget/,
6613 de forma que sólo verá una parte del mismo. Utiliza 
6614 <ref id="sec_Adjustment" name="ajustes"> para definir la zona que se
6615 está viendo actualmente.
6616
6617 Para crear un <em/viewport/ hay que utilizar la función:
6618
6619 <tscreen><verb>
6620 GtkWidget *gtk_viewport_new( GtkAdjustment *hadjustment,
6621                              GtkAdjustment *vadjustment );
6622 </verb></tscreen>
6623
6624 Como puede observar, se pueden especificar los ajustes horizontal y
6625 vertical que el <em/widget/ va a utilizar en el mismo momento de su
6626 creación. El <em/widget/ creará sus propios ajustes en caso de que
6627 reciba como argumento un valor NULL.
6628
6629 Puede obtener y establecer los ajustes después de que se haya
6630 creado el <em/widget/ utilizado las cuatro funciones siguientes:
6631
6632 <tscreen><verb>
6633 GtkAdjustment *gtk_viewport_get_hadjustment (GtkViewport *viewport );
6634
6635 GtkAdjustment *gtk_viewport_get_vadjustment (GtkViewport *viewport );
6636
6637 void gtk_viewport_set_hadjustment( GtkViewport   *viewport,
6638                                    GtkAdjustment *adjustment );
6639
6640 void gtk_viewport_set_vadjustment( GtkViewport   *viewport,
6641                                    GtkAdjustment *adjustment );
6642 </verb></tscreen>
6643
6644 La única función relativa al <em/viewport/ que queda que altera su
6645 apariencia es:
6646
6647 <tscreen><verb>
6648 void gtk_viewport_set_shadow_type( GtkViewport   *viewport,
6649                                    GtkShadowType  type );
6650 </verb></tscreen>
6651
6652 Los valores posibles para el argumento <tt/type/ son:
6653 <itemize>
6654 <item> GTK_SHADOW_NONE,
6655 <item> GTK_SHADOW_IN,
6656 <item> GTK_SHADOW_OUT,
6657 <item> GTK_SHADOW_ETCHED_IN,
6658 <item> GTK_SHADOW_ETCHED_OUT
6659 </itemize>
6660
6661 <!-- ----------------------------------------------------------------- -->
6662 <sect1>Ventanas con barras de desplazamiento <label id="sec_ScrolledWindows">
6663 <p>
6664
6665 Las ventanas con barras de desplazamiento se utilizan para crear una zona
6666 con barras de desplazamiento dentro de una ventana real. Puede insertar
6667 cualquier tipo de <em/widget/ en una ventana con barras de
6668 desplazamiento, y podrá utilizarlo sin importar su tamaño gracias a
6669 las barras de desplazamiento.
6670
6671 La función siguiente se utiliza para crear una nueva ventana con
6672 barras de desplazamiento.
6673
6674 <tscreen><verb>
6675 GtkWidget *gtk_scrolled_window_new( GtkAdjustment *hadjustment,
6676                                     GtkAdjustment *vadjustment );
6677 </verb></tscreen>
6678
6679 Donde el primer argumento es el ajuste para la dirección horizontal, y
6680 el segundo es el ajuste para la dirección vertical. Casi siempre valen
6681 NULL.
6682
6683 <tscreen><verb>
6684 void gtk_scrolled_window_set_policy( GtkScrolledWindow *scrolled_window,
6685                                      GtkPolicyType      hscrollbar_policy,
6686                                      GtkPolicyType      vscrollbar_policy );
6687 </verb></tscreen>
6688
6689 Esta función establece la política que se utilizará con respecto a las
6690 barras de desplazamiento. El primer argumento es la ventana con barras
6691 de desplazamiento sobre la que queremos actuar. El segundo establece
6692 la política para la barra de desplazamiento horizontal, y el tercero
6693 la política para la barra de desplazamiento vertical.
6694
6695 La política puede ser GTK_POLICY_AUTOMATIC, o
6696 GTK_POLICY_ALWAYS. GTK_POLICY_AUTOMATIC decidirá automáticamente si
6697 necesita barras de desplazamiento, mientras que GTK_POLICY_ALWAYS pondrá
6698 siempre las barras de desplazamiento.
6699
6700 Aquí tenemos un ejemplo sencillo que empaqueta 100 botones de
6701 selección en una ventana con barras de desplazamiento. Solamente he
6702 comentado las partes que debería ser nuevas para usted.
6703
6704 <tscreen><verb>
6705 /* principio del ejemplo scrolledwin scrolledwin.c */
6706
6707 #include <gtk/gtk.h>
6708
6709 void destroy(GtkWidget *widget, gpointer data)
6710 {
6711     gtk_main_quit();
6712 }
6713
6714 int main (int argc, char *argv[])
6715 {
6716     static GtkWidget *ventana;
6717     GtkWidget *scrolled_window;
6718     GtkWidget *table;
6719     GtkWidget *boton;
6720     char buffer[32];
6721     int i, j;
6722     
6723     gtk_init (&amp;argc, &amp;argv);
6724     
6725     /* Crea un nuevo cuadro de diálogo para que la ventana con barras de
6726      * desplazamiento se meta dentro. Un cuadro de diálogo es como una
6727      * ventana normal excepto que tiene dentro una vbox y un separador
6728      * horizontal. Es sólo un atajo para crear cuadros de diálogo */
6729     ventana = gtk_dialog_new ();
6730     gtk_signal_connect (GTK_OBJECT (ventana), "destroy",
6731                         (GtkSignalFunc) destroy, NULL);
6732     gtk_window_set_title (GTK_WINDOW (ventana), "dialog");
6733     gtk_container_border_width (GTK_CONTAINER (ventana), 0);
6734     gtk_widget_set_usize(ventana, 300, 300);
6735     
6736     /* crea una nueva ventana con barras de desplazamiento. */
6737     scrolled_window = gtk_scrolled_window_new (NULL, NULL);
6738     
6739     gtk_container_border_width (GTK_CONTAINER (scrolled_window), 10);
6740
6741     /* la política es GTK_POLICY_AUTOMATIC, o GTK_POLICY_ALWAYS.
6742      * GTK_POLICY_AUTOMATIC decidirá automáticamente si necesita
6743      * barras de desplazamiento, mientras que GTK_POLICY_ALWAYS pondrá
6744      * siempre las barras de desplazamiento. El primer argumento se
6745      * refiere a la barra horizontal, el segundo a la vertical. */
6746     gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled_window),
6747                                     GTK_POLICY_AUTOMATIC, GTK_POLICY_ALWAYS);
6748     /* El cuadro de diálogo se crea con una vbox dentro de él. */
6749     gtk_box_pack_start (GTK_BOX (GTK_DIALOG(ventana)->vbox), scrolled_window, 
6750                         TRUE, TRUE, 0);
6751     gtk_widget_show (scrolled_window);
6752     
6753     /* crea una tabla de 10 por 10 casillas. */
6754     table = gtk_table_new (10, 10, FALSE);
6755     
6756     /* pone el espacio en x y en y a 10 */
6757     gtk_table_set_row_spacings (GTK_TABLE (table), 10);
6758     gtk_table_set_col_spacings (GTK_TABLE (table), 10);
6759     
6760     /* empaqueta la tabla en la ventana con barras de desplazamiento */
6761     gtk_container_add (GTK_CONTAINER (scrolled_window), table);
6762     gtk_widget_show (table);
6763     
6764     /* crea una rejilla de botones de selección en la tabla para
6765      * demostrar la ventana con barras de desplazamiento. */
6766     for (i = 0; i < 10; i++)
6767        for (j = 0; j < 10; j++) {
6768           sprintf (buffer, "botón (%d,%d)\n", i, j);
6769           boton = gtk_toggle_button_new_with_label (buffer);
6770           gtk_table_attach_defaults (GTK_TABLE (table), boton,
6771                                      i, i+1, j, j+1);
6772           gtk_widget_show (boton);
6773        }
6774     
6775     /* Añade un botón "close" en la parte de abajo del cuadro de
6776      * diálogo */
6777     boton = gtk_button_new_with_label ("close");
6778     gtk_signal_connect_object (GTK_OBJECT (boton), "clicked",
6779                                (GtkSignalFunc) gtk_widget_destroy,
6780                                GTK_OBJECT (ventana));
6781     
6782     /* hace que el botón puede ser elegido por defecto. */
6783     
6784     GTK_WIDGET_SET_FLAGS (boton, GTK_CAN_DEFAULT);
6785     gtk_box_pack_start (GTK_BOX (GTK_DIALOG (ventana)->action_area), boton, TRUE, TRUE, 0);
6786     
6787     /* Hace que el botón sea el elegido por defecto. Con pulsar la
6788      * tecla "Enter" se activará este botón. */
6789     gtk_widget_grab_default (boton);
6790     gtk_widget_show (boton);
6791     
6792     gtk_widget_show (ventana);
6793     
6794     gtk_main();
6795     
6796     return(0);
6797 }
6798 /* fin del ejemplo */
6799 </verb></tscreen>
6800
6801 Juegue un poco redimensionando la ventana. Vea como actuan las barras
6802 de desplazamiento. También puede utilizar la función
6803 <tt/gtk_widget_set_usize()/ para poner el tamaño por defecto de la
6804 ventana o de cualquier otro <em/widget/.
6805
6806 <!-- XXX -->
6807 <!-- ----------------------------------------------------------------- -->   
6808 <sect1>Cajas de botones
6809 <p>
6810 Las cajas de botones son útiles para crear grupos de botones. Hay
6811 cajas horizontales y verticales. Puede crear una nueva caja de botones
6812 utilizando alguna de las funciones siguientes, que crean
6813 respectivamente una caja horizontal y otra vertical:
6814
6815 <tscreen><verb>
6816 GtkWidget *gtk_hbutton_box_new( void );
6817
6818 GtkWidget *gtk_vbutton_box_new( void );
6819 </verb></tscreen>
6820
6821 Los únicos atributos pertenecientes a las cajas de botones son los
6822 que definen como se distribuyen los botones. Puede cambiar el
6823 espaciado que hay entre los botones con:
6824
6825 <tscreen><verb>
6826 void gtk_hbutton_box_set_spacing_default( gint spacing );
6827
6828 void gtk_vbutton_box_set_spacing_default( gint spacing );
6829 </verb></tscreen>
6830
6831 Igualmente, se pueden obtener los actuales valores para el espaciado
6832 utilizando:
6833
6834 <tscreen><verb>
6835 gint gtk_hbutton_box_get_spacing_default( void );
6836
6837 gint gtk_vbutton_box_get_spacing_default( void );
6838 </verb></tscreen>
6839
6840 El segundo atributo al que podemos acceder afecta al esquema de los
6841 botones dentro de la caja. Se establece utilizando:
6842
6843 <tscreen><verb>
6844 void gtk_hbutton_box_set_layout_default( GtkButtonBoxStyle layout );
6845
6846 void gtk_vbutton_box_set_layout_default( GtkButtonBoxStyle layout );
6847 </verb></tscreen>
6848
6849 El argumento <tt/layout/ puede tomar uno de los siguientes valores:
6850
6851 <itemize>
6852 <item> GTK_BUTTONBOX_DEFAULT_STYLE
6853 <item> GTK_BUTTONBOX_SPREAD
6854 <item> GTK_BUTTONBOX_EDGE
6855 <item> GTK_BUTTONBOX_START
6856 <item> GTK_BUTTONBOX_END
6857 </itemize>
6858
6859 Puede obtenerse el esquema actual utilizando:
6860
6861 <tscreen><verb>
6862 GtkButtonBoxStyle gtk_hbutton_box_get_layout_default( void );
6863
6864 GtkButtonBoxStyle gtk_vbutton_box_get_layout_default( void );
6865 </verb></tscreen>
6866
6867 Podemos añadir botones a una caja de botones utilizando (como
6868 siempre) la función:
6869
6870 <tscreen><verb>
6871     gtk_container_add( GTK_CONTAINER(button_box), child_widget );
6872 </verb></tscreen>
6873
6874 Aquí hay un ejemplo que ilustra todos los diferentes esquemas que
6875 podemos utilizar con las cajas de botones.
6876
6877 <tscreen><verb>
6878 /* principio del ejemplo buttonbox buttonbox.c */
6879
6880 #include <gtk/gtk.h>
6881
6882 /* Crear una Caja de Botones con los parámetros
6883  * especificados */
6884 GtkWidget *create_bbox (gint  horizontal,
6885                         char* title,
6886                         gint  spacing,
6887                         gint  child_w,
6888                         gint  child_h,
6889                         gint  layout)
6890 {
6891   GtkWidget *frame;
6892   GtkWidget *bbox;
6893   GtkWidget *boton;
6894
6895   frame = gtk_frame_new (title);
6896
6897   if (horizontal)
6898     bbox = gtk_hbutton_box_new ();
6899   else
6900     bbox = gtk_vbutton_box_new ();
6901
6902   gtk_container_set_border_width (GTK_CONTAINER (bbox), 5);
6903   gtk_container_add (GTK_CONTAINER (frame), bbox);
6904
6905   /* Establece la apariencia de la Caja de Botones */
6906   gtk_button_box_set_layout (GTK_BUTTON_BOX (bbox), layout);
6907   gtk_button_box_set_spacing (GTK_BUTTON_BOX (bbox), spacing);
6908   gtk_button_box_set_child_size (GTK_BUTTON_BOX (bbox), child_w, child_h);
6909
6910   boton = gtk_button_new_with_label ("OK");
6911   gtk_container_add (GTK_CONTAINER (bbox), boton);
6912
6913   boton = gtk_button_new_with_label ("Cancel");
6914   gtk_container_add (GTK_CONTAINER (bbox), boton);
6915
6916   boton = gtk_button_new_with_label ("Help");
6917   gtk_container_add (GTK_CONTAINER (bbox), boton);
6918
6919   return(frame);
6920 }
6921
6922 int main( int   argc,
6923           char *argv[] )
6924 {
6925   static GtkWidget* ventana = NULL;
6926   GtkWidget *main_vbox;
6927   GtkWidget *vbox;
6928   GtkWidget *hbox;
6929   GtkWidget *frame_horz;
6930   GtkWidget *frame_vert;
6931
6932   /* Inicializa GTK */
6933   gtk_init( &amp;argc, &amp;argv );
6934
6935   ventana = gtk_window_new (GTK_WINDOW_TOPLEVEL);
6936   gtk_window_set_title (GTK_WINDOW (ventana), "Button Boxes");
6937
6938   gtk_signal_connect (GTK_OBJECT (ventana), "destroy",
6939                       GTK_SIGNAL_FUNC(gtk_main_quit),
6940                       NULL);
6941
6942   gtk_container_set_border_width (GTK_CONTAINER (ventana), 10);
6943
6944   main_vbox = gtk_vbox_new (FALSE, 0);
6945   gtk_container_add (GTK_CONTAINER (ventana), main_vbox);
6946
6947   frame_horz = gtk_frame_new ("Horizontal Button Boxes");
6948   gtk_box_pack_start (GTK_BOX (main_vbox), frame_horz, TRUE, TRUE, 10);
6949
6950   vbox = gtk_vbox_new (FALSE, 0);
6951   gtk_container_set_border_width (GTK_CONTAINER (vbox), 10);
6952   gtk_container_add (GTK_CONTAINER (frame_horz), vbox);
6953
6954   gtk_box_pack_start (GTK_BOX (vbox),
6955            create_bbox (TRUE, "Spread (spacing 40)", 40, 85, 20, GTK_BUTTONBOX_SPREAD),
6956                       TRUE, TRUE, 0);
6957
6958   gtk_box_pack_start (GTK_BOX (vbox),
6959            create_bbox (TRUE, "Edge (spacing 30)", 30, 85, 20, GTK_BUTTONBOX_EDGE),
6960                       TRUE, TRUE, 5);
6961
6962   gtk_box_pack_start (GTK_BOX (vbox),
6963            create_bbox (TRUE, "Start (spacing 20)", 20, 85, 20, GTK_BUTTONBOX_START),
6964                       TRUE, TRUE, 5);
6965
6966   gtk_box_pack_start (GTK_BOX (vbox),
6967            create_bbox (TRUE, "End (spacing 10)", 10, 85, 20, GTK_BUTTONBOX_END),
6968                       TRUE, TRUE, 5);
6969
6970   frame_vert = gtk_frame_new ("Vertical Button Boxes");
6971   gtk_box_pack_start (GTK_BOX (main_vbox), frame_vert, TRUE, TRUE, 10);
6972
6973   hbox = gtk_hbox_new (FALSE, 0);
6974   gtk_container_set_border_width (GTK_CONTAINER (hbox), 10);
6975   gtk_container_add (GTK_CONTAINER (frame_vert), hbox);
6976
6977   gtk_box_pack_start (GTK_BOX (hbox),
6978            create_bbox (FALSE, "Spread (spacing 5)", 5, 85, 20, GTK_BUTTONBOX_SPREAD),
6979                       TRUE, TRUE, 0);
6980
6981   gtk_box_pack_start (GTK_BOX (hbox),
6982            create_bbox (FALSE, "Edge (spacing 30)", 30, 85, 20, GTK_BUTTONBOX_EDGE),
6983                       TRUE, TRUE, 5);
6984
6985   gtk_box_pack_start (GTK_BOX (hbox),
6986            create_bbox (FALSE, "Start (spacing 20)", 20, 85, 20, GTK_BUTTONBOX_START),
6987                       TRUE, TRUE, 5);
6988
6989   gtk_box_pack_start (GTK_BOX (hbox),
6990            create_bbox (FALSE, "End (spacing 20)", 20, 85, 20, GTK_BUTTONBOX_END),
6991                       TRUE, TRUE, 5);
6992
6993   gtk_widget_show_all (ventana);
6994
6995   /* Entra dentro del bucle de eventos */
6996   gtk_main ();
6997     
6998   return(0);
6999 }
7000 /* fin del ejemplo */
7001 </verb></tscreen>
7002
7003 <!-- ----------------------------------------------------------------- -->   
7004 <sect1>Barras de herramientas
7005 <p>
7006 Las barras de herramientas acostumbran a agrupar un conjunto de
7007 <em>widgets</em> para hacer más sencilla la personalización
7008 de su aspecto y composición. Típicamente una barra de herramientas
7009 consiste en botones con iconos, etiquetas y <em/tips/ para los iconos
7010 (pequeño texto descriptivo que aparece cuando se mantiene el ratón
7011 sobre el icono), pero en realidad en una barra se puede poner
7012 cualquier tipo de <em>widget</em>. Finalmente, los elementos se pueden
7013 disponer de forma horizontal o vertical, y los botones pueden mostrar
7014 iconos, etiquetas o ambos.
7015
7016 La creación de una barra de herramientas se hace (como puede que ya
7017 haya sospechado) mediante la función siguiente:
7018
7019 <tscreen><verb>
7020 GtkWidget *gtk_toolbar_new( GtkOrientation orientation,
7021                             GtkToolbarStyle  style );
7022 </verb></tscreen>
7023
7024 donde <tt/orientation/ puede ser:
7025
7026 <tscreen><verb>
7027   GTK_ORIENTATION_HORIZONTAL    
7028   GTK_ORIENTATION_VERTICAL
7029 </verb></tscreen>
7030
7031 y <tt/style/:
7032
7033 <tscreen><verb>
7034   GTK_TOOLBAR_TEXT
7035   GTK_TOOLBAR_ICONS
7036   GTK_TOOLBAR_BOTH
7037 </verb></tscreen>
7038
7039 La variable <tt/style/ se aplica a todos los botones que se crean con las
7040 funciones `item' (pero no a los botones insertados en la barra de
7041 herramientas como <em>widgets</em> separados).
7042
7043 Después de crear una barra de herramientas, se pueden añadir,
7044 preañadir e insertar elementos (o sea, botones) en la misma. Los
7045 campos que describen un elemento son el texto de la etiqueta, el texto
7046 del <em/tip/, un texto para el <em/tip/ privado, un icono para el
7047 botón y una función de llamada para el mismo. Por ejemplo, para añadir
7048 un elemento puede utilizar la siguiente función:
7049
7050 <tscreen><verb>
7051 GtkWidget *gtk_toolbar_append_item( GtkToolbar    *toolbar,
7052                                     const char    *text,
7053                                     const char    *tooltip_text,
7054                                     const char    *tooltip_private_text,
7055                                     GtkWidget     *icon,
7056                                     GtkSignalFunc  callback,
7057                                     gpointer       user_data );
7058 </verb></tscreen>
7059
7060 Si quiere utilizar <tt/gtk_toolbar_insert_item/, el único parámetro
7061 adicional que debería especificar es la posición en la que quiere que
7062 se introduzca el elemento.
7063
7064 Para añadir un espacio en blanco entre los elementos de la barra de
7065 herramientas, puede utilizar la función siguiente:
7066
7067 <tscreen><verb>
7068 void gtk_toolbar_append_space( GtkToolbar *toolbar );
7069
7070 void gtk_toolbar_prepend_space( GtkToolbar *toolbar );
7071
7072 void gtk_toolbar_insert_space( GtkToolbar *toolbar,
7073                                gint        posicion );
7074  
7075 </verb></tscreen>
7076
7077 Y el tamaño del espacio en blanco puede establecerse globalmente
7078 para toda una barra de herramientas con la función:
7079
7080 <tscreen><verb>
7081 void gtk_toolbar_set_space_size( GtkToolbar *toolbar,
7082                                  gint        space_size) ;
7083 </verb></tscreen>
7084
7085 Si tiene que establecer la orientación de una barra de herramientas y
7086 su estilo, puede hacerlo `al vuelo' con las funciones siguientes:
7087
7088 <tscreen><verb>
7089 void gtk_toolbar_set_orientation( GtkToolbar     *toolbar,
7090                                   GtkOrientation  orientation );
7091
7092 void gtk_toolbar_set_style( GtkToolbar      *toolbar,
7093                             GtkToolbarStyle  style );
7094
7095 void gtk_toolbar_set_tooltips( GtkToolbar *toolbar,
7096                                gint        enable );
7097 </verb></tscreen>
7098
7099 Para mostrar algunas otras cosas que pueden hacerse con una barra de
7100 herramientas, vamos a ver el siguiente programa (interrumpiremos el
7101 listado con alguna explicación adicional):
7102
7103 <tscreen><verb>
7104 #include <gtk/gtk.h>
7105
7106 #include "gtk.xpm"
7107
7108 /* Esta función está conectada al botón Close o a la acción de cerrar
7109  * la ventana desde el WM */
7110 void delete_event (GtkWidget *widget, GdkEvent *event, gpointer data)
7111 {
7112   gtk_main_quit ();
7113 }
7114 </verb></tscreen>
7115
7116 Este principio ya debería de sonarle familiar, a no ser que éste sea
7117 su primer programa GTK. En nuestro programa no habrá ninguna novedad,
7118 salvo un bonito dibujo XPM que utilizaremos como icono para todos los
7119 botones.
7120
7121 <tscreen><verb>
7122 GtkWidget* close_button; // este botón emitirá la señal de cerrar el programa
7123 GtkWidget* tooltips_button; // para activar/desactivar los tooltips
7124 GtkWidget* text_button,
7125          * icon_button,
7126          * both_button; // botones circulares para el estilo de la barra
7127 GtkWidget* entry; // un widget para meter texto para mostrar como
7128                   // empaquetar widgets en la barra de herramientas
7129 </verb></tscreen>
7130
7131 En realidad no necesitamos todos los <em>widgets</em> que acabo de
7132 poner, pero para aclarar las cosas un poco más los he puesto todos.
7133
7134 <tscreen><verb>
7135 /* Esto es fácil... cuando uno de los botones cambia, sólo
7136  * tenemos que comprobar quien está activo y hacer que el estilo
7137  * de la barra de herramientas esté acorde con la elección
7138  * ATENCIÓN: ¡nuestra barra de herramientas es data !
7139 void radio_event (GtkWidget *widget, gpointer data)
7140 {
7141   if (GTK_TOGGLE_BUTTON (text_button)->active) 
7142     gtk_toolbar_set_style(GTK_TOOLBAR ( data ), GTK_TOOLBAR_TEXT);
7143   else if (GTK_TOGGLE_BUTTON (icon_button)->active)
7144     gtk_toolbar_set_style(GTK_TOOLBAR ( data ), GTK_TOOLBAR_ICONS);
7145   else if (GTK_TOGGLE_BUTTON (both_button)->active)
7146     gtk_toolbar_set_style(GTK_TOOLBAR ( data ), GTK_TOOLBAR_BOTH);
7147 }
7148
7149 /* todavía más fácil, sólo hay que comprobar el botón de selección
7150  * y activar/desactivar los tooltips */
7151 void toggle_event (GtkWidget *widget, gpointer data)
7152 {
7153   gtk_toolbar_set_tooltips (GTK_TOOLBAR ( data ),
7154                             GTK_TOGGLE_BUTTON (widget)->active );
7155 }
7156 </verb></tscreen>
7157
7158 Lo de arriba son sólo dos funciones de llamada que se invocarán cuando
7159 se presione uno de los botones de la barra de herramientas. Todo esto
7160 ya debería resultarle familiar si ha utilizado alguna vez los botones
7161 de selección (o los botones circulares)
7162
7163 <tscreen><verb>
7164 int main (int argc, char *argv[])
7165 {
7166   /* Aquí está nuestra ventana principal (un cuadro de diálogo) y una
7167    * caja flotante */
7168   GtkWidget* dialog;
7169   GtkWidget* handlebox;
7170
7171   /* De acuerdo, necesitamos una barra de herramientas, un icono con
7172    * una máscara (una para todos los botones) y un widget icono donde
7173    * meter el icono (crearemos un widget diferente para cada botón) */
7174   GtkWidget * toolbar;
7175   GdkPixmap * icon;
7176   GdkBitmap * mask;
7177   GtkWidget * iconw;
7178
7179   /* a esta función se le llama en todas las aplicación GTK */
7180   gtk_init (&amp;argc, &amp;argv);
7181   
7182   /* crear una ventana nueva con un título y el tamaño adecuado */
7183   dialog = gtk_dialog_new ();
7184   gtk_window_set_title ( GTK_WINDOW ( dialog ) , "GTKToolbar Tutorial");
7185   gtk_widget_set_usize( GTK_WIDGET ( dialog ) , 600 , 300 );
7186   GTK_WINDOW ( dialog ) ->allow_shrink = TRUE;
7187
7188   /* salimos si alguien intenta cerrarnos */
7189   gtk_signal_connect ( GTK_OBJECT ( dialog ), "delete_event",
7190                        GTK_SIGNAL_FUNC ( delete_event ), NULL);
7191
7192   /* tenemos que mandar la señalo realize porque utilizamos pixmaps
7193    * para los elementos que hay en la barra de herramientas */
7194   gtk_widget_realize ( dialog );
7195
7196   /* para hacerlo más bonito ponemos la barra de herramientas en la
7197    * caja flotante, para que así se pueda desatar de la ventana
7198    * principal */
7199   handlebox = gtk_handle_box_new ();
7200   gtk_box_pack_start ( GTK_BOX ( GTK_DIALOG(dialog)->vbox ),
7201                        handlebox, FALSE, FALSE, 5 );
7202 </verb></tscreen>
7203
7204 Lo de arriba debería ser parecido en cualquier aplicación GTK. Sólo
7205 está la inicialización de GTK, la creación de la ventana, etc...
7206 Solamente hay una cosa que probablemente necesite una explicación:
7207 una barra de herramientas flotante. Una barra de herramientas flotante
7208 sólo es otra barra donde pueden empaquetarse <em>widgets</em>. La
7209 diferencia que tiene con una barra típica es que puede desatarse de la
7210 ventana padre (o, de hecho, la barra de herramientas flotante permanece
7211 en el padre, pero reducida a un rectángulo muy pequeño, mientras que
7212 todos sus contenidos se pasan a una nueva ventana flotante). Es bonito
7213 tener una barra de herramientas flotante, por lo que estos dos
7214 <em>widgets</em> suelen aparecer juntos.
7215
7216 <tscreen><verb>
7217   /* la barra de herramientas será horizontal, con iconos y texto, y
7218    * con un espacio de 5pxl entre elementos y finalmente, la ponemos en
7219    * nuestra caja flotante */
7220   toolbar = gtk_toolbar_new ( GTK_ORIENTATION_HORIZONTAL,
7221                               GTK_TOOLBAR_BOTH );
7222   gtk_container_border_width ( GTK_CONTAINER ( toolbar ) , 5 );
7223   gtk_toolbar_set_space_size ( GTK_TOOLBAR ( toolbar ), 5 );
7224   gtk_container_add ( GTK_CONTAINER ( handlebox ) , toolbar );
7225
7226   /* ahora creamos el icono con la máscara: utilizaremos el widget
7227    * icon con todos los elementos de la barra de herramientas */
7228   icon = gdk_pixmap_create_from_xpm_d ( dialog->window, &amp;mask,
7229       &amp;dialog->style->white, gtk_xpm );
7230 </verb></tscreen>
7231
7232 Bien, lo que acabamos de escribir es la inicialización del
7233 <em>widget</em> de la barra de herramientas y la creación de un
7234 <em>pixmap</em> GDK con su máscara. Si quiere saber algo más sobre la
7235 utilización de <em>pixmaps</em>, vea la documentación de GDK o la
7236 sección <ref id="sec_Pixmaps" name="Pixmaps"> en este tutorial.
7237
7238 <tscreen><verb>
7239   /* nuestro primer elemento es el botón <close> */
7240   iconw = gtk_pixmap_new ( icon, mask ); // icon widget
7241   close_button = 
7242     gtk_toolbar_append_item ( GTK_TOOLBAR (toolbar), // nuestra barra
7243                               "Close",               // etiqueta del botón
7244                               "Closes this app",     // tooltip para el botón
7245                               "Private",             // cadena privada del tooltip
7246                               iconw,                 // widget del icono
7247                               GTK_SIGNAL_FUNC (delete_event), // una señal
7248                               NULL );
7249   gtk_toolbar_append_space ( GTK_TOOLBAR ( toolbar ) ); // espacio después del elemento
7250 </verb></tscreen>
7251
7252 En el trozo de código de arriba puede ver como se hace la acción más
7253 simple: añadir un botón a la barra de herramientas. Justo antes de
7254 añadir un nuevo elemento, tenemos que construir un <em>widget
7255 pixmap</em> para que sirva como icono para este elemento; este paso
7256 tendrá que repetirse para cada nuevo elemento. Después del elemento
7257 añadiremos un espacio en blanco en la barra de herramientas, para que
7258 los elementos que añadamos a continuación no se toquen los unos a los
7259 otros. Como puede ver, <tt/gtk_toolbar_append_item/ devuelve un
7260 puntero al <em>widget</em> de nuestro nuevo botón recien creado, por
7261 lo que podremos trabajar con él como siempre.
7262
7263 <tscreen><verb>
7264   /* ahora, vamos a hacer nuestro grupo de botones circulares... */
7265   iconw = gtk_pixmap_new ( icon, mask );
7266   icon_button = 
7267     gtk_toolbar_append_element(GTK_TOOLBAR(toolbar),
7268                                GTK_TOOLBAR_CHILD_RADIOBUTTON, // un tipo de elemento
7269                                NULL,                          // puntero al widget
7270                                "Icon",                        // etiqueta
7271                                "Only icons in toolbar",       // tooltip
7272                                "Private",                     // cadena privada del tooltip
7273                                iconw,                         // icono
7274                                GTK_SIGNAL_FUNC (radio_event), // señal
7275                                toolbar);                      // dato para la señal
7276   gtk_toolbar_append_space ( GTK_TOOLBAR ( toolbar ) );
7277 </verb></tscreen>
7278
7279 Aquí empezamos creando un grupo de botones circulares. Para hacerlo
7280 hemos utilizado <tt/gtk_toolbar_append_element/. De hecho, utilizando
7281 esta función se pueden añadir tanto elementos simples como espacios en
7282 blanco (tipo = GTK_TOOLBAR_CHILD_SPACE o GTK_TOOLBAR_CHILD_BUTTON). En
7283 el caso de arriba, hemos empezado creando un grupo de botones circulares.
7284 Para crear más botones circulares para este grupo
7285 necesitaremos un puntero al botón anterior del grupo, mediante el que
7286 podremos construir fácilmente una lista de botones (ver la sección
7287 <ref id="sec_Radio_Buttons" name="Botones circulares"> que se encuentra
7288 más adelante en este tutorial).
7289
7290 <tscreen><verb>
7291   /* los botones circulares que vienen a continuación están
7292      relacionados con los anteriores */
7293   iconw = gtk_pixmap_new ( icon, mask );
7294   text_button = 
7295     gtk_toolbar_append_element(GTK_TOOLBAR(toolbar),
7296                                GTK_TOOLBAR_CHILD_RADIOBUTTON,
7297                                icon_button,
7298                                "Text",
7299                                "Only texts in toolbar",
7300                                "Private",
7301                                iconw,
7302                                GTK_SIGNAL_FUNC (radio_event),
7303                                toolbar);
7304   gtk_toolbar_append_space ( GTK_TOOLBAR ( toolbar ) );
7305                                           
7306   iconw = gtk_pixmap_new ( icon, mask );
7307   both_button = 
7308     gtk_toolbar_append_element(GTK_TOOLBAR(toolbar),
7309                                GTK_TOOLBAR_CHILD_RADIOBUTTON,
7310                                text_button,
7311                                "Both",
7312                                "Icons and text in toolbar",
7313                                "Private",
7314                                iconw,
7315                                GTK_SIGNAL_FUNC (radio_event),
7316                                toolbar);
7317   gtk_toolbar_append_space ( GTK_TOOLBAR ( toolbar ) );
7318   gtk_toggle_button_set_state(GTK_TOGGLE_BUTTON(both_button),TRUE);
7319 </verb></tscreen>
7320
7321 Al final hemos activado manualmente uno de los botones (en caso
7322 contrario los botones permanecerían todos en estado activo,
7323 impidiéndonos poder cambiar de uno a otro).
7324
7325 <tscreen><verb>
7326   /* aquí tenemos un sencillo botón de selección */
7327   iconw = gtk_pixmap_new ( icon, mask );
7328   tooltips_button = 
7329     gtk_toolbar_append_element(GTK_TOOLBAR(toolbar),
7330                                GTK_TOOLBAR_CHILD_TOGGLEBUTTON,
7331                                NULL,
7332                                "Tooltips",
7333                                "Toolbar with or without tips",
7334                                "Private",
7335                                iconw,
7336                                GTK_SIGNAL_FUNC (toggle_event),
7337                                toolbar);
7338   gtk_toolbar_append_space ( GTK_TOOLBAR ( toolbar ) );
7339   gtk_toggle_button_set_state(GTK_TOGGLE_BUTTON(tooltips_button),TRUE);
7340 </verb></tscreen>
7341
7342 Un botón de selección puede crearse de una forma obvia (si ya sabe como
7343 crear botones circulares).
7344
7345 <tscreen><verb>
7346   /* para empaquetar un widget en la barra de herramientas, sólo
7347    * tenemos que crearlo y añadirlo en la barra con el tooltip
7348    * apropiado */
7349   entry = gtk_entry_new ();
7350   gtk_toolbar_append_widget( GTK_TOOLBAR (toolbar), 
7351                              entry, 
7352                              "This is just an entry", 
7353                              "Private" );
7354
7355   /* bien, no se ha creado con la barra, así que debemos mostrarlo
7356    * explicitamente */
7357   gtk_widget_show ( entry );
7358 </verb></tscreen>
7359
7360 Como puede ver, añadir cualquier tipo de <em>widget</em> a la barra
7361 de herramientas es fácil. Lo único que debe recordar es que este
7362 <em>widget</em> debe mostrarse manualmente (al contrario que los demás
7363 elementos que se mostrarán junto con la barra de herramientas).
7364
7365 <tscreen><verb>
7366   /* ¡ Eso es ! mostremos algo. */
7367   gtk_widget_show ( toolbar );
7368   gtk_widget_show (handlebox);
7369   gtk_widget_show ( dialog );
7370
7371   /* quedémonos en gtk_main y ¡esperemos a que empiece la diversión! */
7372   gtk_main ();
7373   
7374   return 0;
7375 }
7376 </verb></tscreen>
7377
7378 Y ya estamos en el final del tutorial sobre la barra de herramientas.
7379 Por supuesto, para apreciar completamente el ejemplo, necesita además
7380 del código este precioso icono XPM que le mostramos a continuación:
7381
7382 <tscreen><verb>
7383 /* XPM */
7384 static char * gtk_xpm[] = {
7385 "32 39 5 1",
7386 ".      c none",
7387 "+      c black",
7388 "@      c #3070E0",
7389 "#      c #F05050",
7390 "$      c #35E035",
7391 "................+...............",
7392 "..............+++++.............",
7393 "............+++++@@++...........",
7394 "..........+++++@@@@@@++.........",
7395 "........++++@@@@@@@@@@++........",
7396 "......++++@@++++++++@@@++.......",
7397 ".....+++@@@+++++++++++@@@++.....",
7398 "...+++@@@@+++@@@@@@++++@@@@+....",
7399 "..+++@@@@+++@@@@@@@@+++@@@@@++..",
7400 ".++@@@@@@+++@@@@@@@@@@@@@@@@@@++",
7401 ".+#+@@@@@@++@@@@+++@@@@@@@@@@@@+",
7402 ".+##++@@@@+++@@@+++++@@@@@@@@$@.",
7403 ".+###++@@@@+++@@@+++@@@@@++$$$@.",
7404 ".+####+++@@@+++++++@@@@@+@$$$$@.",
7405 ".+#####+++@@@@+++@@@@++@$$$$$$+.",
7406 ".+######++++@@@@@@@++@$$$$$$$$+.",
7407 ".+#######+##+@@@@+++$$$$$$@@$$+.",
7408 ".+###+++##+##+@@++@$$$$$$++$$$+.",
7409 ".+###++++##+##+@@$$$$$$$@+@$$@+.",
7410 ".+###++++++#+++@$$@+@$$@++$$$@+.",
7411 ".+####+++++++#++$$@+@$$++$$$$+..",
7412 ".++####++++++#++$$@+@$++@$$$$+..",
7413 ".+#####+++++##++$$++@+++$$$$$+..",
7414 ".++####+++##+#++$$+++++@$$$$$+..",
7415 ".++####+++####++$$++++++@$$$@+..",
7416 ".+#####++#####++$$+++@++++@$@+..",
7417 ".+#####++#####++$$++@$$@+++$@@..",
7418 ".++####++#####++$$++$$$$$+@$@++.",
7419 ".++####++#####++$$++$$$$$$$$+++.",
7420 ".+++####+#####++$$++$$$$$$$@+++.",
7421 "..+++#########+@$$+@$$$$$$+++...",
7422 "...+++########+@$$$$$$$$@+++....",
7423 ".....+++######+@$$$$$$$+++......",
7424 "......+++#####+@$$$$$@++........",
7425 ".......+++####+@$$$$+++.........",
7426 ".........++###+$$$@++...........",
7427 "..........++##+$@+++............",
7428 "...........+++++++..............",
7429 ".............++++..............."};
7430 </verb></tscreen>
7431
7432 <!-- ----------------------------------------------------------------- -->
7433 <sect1> Libros de notas (<em/Notebooks/)
7434 <p>
7435 El <em/widget/ Notebook es una colección de `páginas' que se solapan
7436 las unas a las otras, cada una con un contenido diferente. Este
7437 <em/widget/ se ha vuelto cada vez más común últimamente en la
7438 programación de interfaces gráficos de usuario (GUI en inglés), y es
7439 una buena forma de mostrar bloques de información similar que
7440 necesitan aparecer de forma separada.
7441
7442 La primera función que necesita conocer, como probablemente ya habrá
7443 adivinado, se utiliza para crear un nuevo <em/widget/ notebook.
7444
7445 <tscreen><verb>
7446 GtkWidget *gtk_notebook_new( void );
7447 </verb></tscreen>
7448
7449 Una vez haya crear el libro de notas, hay 12 funciones que se pueden
7450 utilizar para trabajar con él. Echémosles un vistazo una a una.
7451
7452 La primera que estudiaremos será la que nos permita establecer la
7453 posición de los indicadores de la página. Estos indicadores se pueden
7454 poner en cuatro lugares diferentes: arriba, abajo, a la derecha o a la
7455 izquierda.
7456
7457 <tscreen><verb>
7458 void gtk_notebook_set_tab_pos( GtkNotebook     *notebook,
7459                                GtkPositionType  pos );
7460 </verb></tscreen>
7461
7462 <tt/GtkPositionType/ debe tener uno de los valores siguientes (su significado
7463 está bastante claro):
7464
7465 <itemize>
7466 <item> GTK_POS_LEFT
7467 <item> GTK_POS_RIGHT
7468 <item> GTK_POS_TOP
7469 <item> GTK_POS_BOTTOM
7470 </itemize>
7471
7472 GTK_POS_TOP es el valor por defecto.
7473
7474 Lo siguiente que estudiaremos es como añadir páginas al libro de notas.
7475 Hay tres formas de añadirle páginas al <em/widget/. Veamos las dos primeras
7476 formas (son muy parecidas).
7477
7478 <tscreen><verb>
7479 void gtk_notebook_append_page( GtkNotebook *notebook,
7480                                GtkWidget   *hijo,
7481                                GtkWidget   *tab_label );
7482
7483 void gtk_notebook_prepend_page( GtkNotebook *notebook,
7484                                 GtkWidget   *hijo,
7485                                 GtkWidget   *tab_label );
7486 </verb></tscreen>
7487
7488 Estas funciones le añaden páginas al libro de notas insertándolas desde
7489 el fondo del libro (añadiéndolas), o desde parte superior del libro
7490 (preañadiéndolas). <tt/hijo/ es el <em/widget/ que se mete en la página
7491 del libro de notas, y <tt/tab_label/ es la etiqueta para la página que
7492 estamos añadiendo.
7493
7494 La función que queda que sirve para añadir una página contiene todas las
7495 propiedades de las anteriores, pero además permite especificar en que
7496 posición quiere que esté la página dentro del libro de notas.
7497
7498 <tscreen><verb>
7499 void gtk_notebook_insert_page( GtkNotebook *notebook,
7500                                GtkWidget   *hijo,
7501                                GtkWidget   *tab_label,
7502                                gint         posicion );
7503 </verb></tscreen>
7504
7505 Los parámetros son los mismos que habían en las funciones _append_ y
7506 _prepend_ excepto que hay uno más que antes, <tt/posicion/. Este
7507 parámetro se utiliza para especificar en que lugar debe introducirse
7508 la página.
7509
7510 Ahora que sabemos como añadir un página, veamos como podemos eliminar
7511 una página del libro de notas.
7512
7513 <tscreen><verb>
7514 void gtk_notebook_remove_page( GtkNotebook *notebook,
7515                                gint         page_num );
7516 </verb></tscreen>
7517
7518 Esta función coge la página especificada por <tt/page_num/ y la
7519 elimina del <em/widget/ al que apunta <tt/notebook/.
7520
7521 Para saber cual es la página actual del libro de notas utilice la
7522 función:
7523
7524 <tscreen><verb>
7525 gint gtk_notebook_current_page( GtkNotebook *notebook );
7526 </verb></tscreen>
7527
7528 Las dos funciones siguientes sirven para ir a la página siguiente o a
7529 la anterior del libro de notas. Para utilizarlas sólo hay que
7530 proporcionar el <em/widget/ notebook que queremos manipular. Nota:
7531 cuando el libro de notas está en la última página y se llama a
7532 <tt/gtk_notebook_next_page/, se pasará a la primera página. Sin
7533 embargo, si el libro de notas está en la primera página, y se llama a
7534 <tt/gtk_notebook_prev_page/, no se pasará a la última página.
7535
7536 <tscreen><verb>
7537 void gtk_notebook_next_page( GtkNoteBook *notebook );
7538
7539 void gtk_notebook_prev_page( GtkNoteBook *notebook );
7540 </verb></tscreen>
7541
7542 La siguiente función establece la página `activa'. Si quiere que se
7543 abra el libro de notas por la página 5, por ejemplo, debe utilizar
7544 esta función. Si no utiliza esta función el libro de notas empezará
7545 por defecto en la primera página.
7546
7547 <tscreen><verb>
7548 void gtk_notebook_set_page( GtkNotebook *notebook,
7549                             gint         page_num );
7550 </verb></tscreen>
7551
7552 Las dos funciones siguientes añaden o eliminan los indicadores de las
7553 páginas o el borde del libro, respectivamente.
7554
7555 <tscreen><verb>
7556 void gtk_notebook_set_show_tabs( GtkNotebook *notebook,
7557                                  gint         show_tabs);
7558
7559 void gtk_notebook_set_show_border( GtkNotebook *notebook,
7560                                    gint         show_border );
7561 </verb></tscreen>
7562
7563 <tt/show_tabs/ y <tt/show_border/ puede ser TRUE o FALSE.
7564
7565 Ahora echémosle un vistaza a un ejemplo, sacado del código de
7566 <tt/testgtk.c/ que viene con la distribución de GTK, y que muestra
7567 la utilización de las 13 funciones. Este pequeño programa crea una
7568 ventana con un libro de notas y seis botones. El libro de notas
7569 contiene 11 páginas, incluidas de tres formas diferentes, añadidas,
7570 insertadas, y preañadidas. Los botones le permiten rotar las
7571 posiciones de los indicadores, añadir y eliminar los indicadores y el
7572 borde, eliminar una página, cambiar páginas hacia delante y hacia
7573 detrás, y salir del programa.
7574
7575 <tscreen><verb>
7576 /* principio del ejemplo notebook notebook.c */
7577
7578 #include <gtk/gtk.h>
7579
7580 /* Esta función rota la posición de los indicadores */
7581 void rotate_book (GtkButton *boton, GtkNotebook *notebook)
7582 {
7583     gtk_notebook_set_tab_pos (notebook, (notebook->tab_pos +1) %4);
7584 }
7585
7586 /* Añade/Elimina los indicadores de la página y los bordes */
7587 void tabsborder_book (GtkButton *boton, GtkNotebook *notebook)
7588 {
7589     gint tval = FALSE;
7590     gint bval = FALSE;
7591     if (notebook->show_tabs == 0)
7592             tval = TRUE; 
7593     if (notebook->show_border == 0)
7594             bval = TRUE;
7595     
7596     gtk_notebook_set_show_tabs (notebook, tval);
7597     gtk_notebook_set_show_border (notebook, bval);
7598 }
7599
7600 /* Elimina una página del libro de notas */
7601 void remove_book (GtkButton *boton, GtkNotebook *notebook)
7602 {
7603     gint page;
7604     
7605     page = gtk_notebook_current_page(notebook);
7606     gtk_notebook_remove_page (notebook, page);
7607     /* Hay que redibujar el widget --
7608      Esto fuerza que el widget se autoredibuje */
7609     gtk_widget_draw(GTK_WIDGET(notebook), NULL);
7610 }
7611
7612 void delete (GtkWidget *widget, GtkWidget *event, gpointer data)
7613 {
7614     gtk_main_quit ();
7615 }
7616
7617 int main (int argc, char *argv[])
7618 {
7619     GtkWidget *ventana;
7620     GtkWidget *boton;
7621     GtkWidget *table;
7622     GtkWidget *notebook;
7623     GtkWidget *frame;
7624     GtkWidget *etiqueta;
7625     GtkWidget *checkbutton;
7626     int i;
7627     char bufferf[32];
7628     char bufferl[32];
7629     
7630     gtk_init (&amp;argc, &amp;argv);
7631     
7632     ventana = gtk_window_new (GTK_WINDOW_TOPLEVEL);
7633     
7634     gtk_signal_connect (GTK_OBJECT (ventana), "delete_event",
7635                         GTK_SIGNAL_FUNC (delete), NULL);
7636     
7637     gtk_container_border_width (GTK_CONTAINER (ventana), 10);
7638     
7639     table = gtk_table_new(2,6,TRUE);
7640     gtk_container_add (GTK_CONTAINER (ventana), table);
7641     
7642     /* Crea un nuevo libro de notas, indicando la posición de los
7643        indicadores */
7644     notebook = gtk_notebook_new ();
7645     gtk_notebook_set_tab_pos (GTK_NOTEBOOK (notebook), GTK_POS_TOP);
7646     gtk_table_attach_defaults(GTK_TABLE(table), notebook, 0,6,0,1);
7647     gtk_widget_show(notebook);
7648     
7649     /* le añadimos un montón de páginas al libro de notas */
7650     for (i=0; i < 5; i++) {
7651         sprintf(bufferf, "Append Frame %d", i+1);
7652         sprintf(bufferl, "Page %d", i+1);
7653         
7654         frame = gtk_frame_new (bufferf);
7655         gtk_container_border_width (GTK_CONTAINER (frame), 10);
7656         gtk_widget_set_usize (frame, 100, 75);
7657         gtk_widget_show (frame);
7658         
7659         etiqueta = gtk_label_new (bufferf);
7660         gtk_container_add (GTK_CONTAINER (frame), etiqueta);
7661         gtk_widget_show (etiqueta);
7662         
7663         etiqueta = gtk_label_new (bufferl);
7664         gtk_notebook_append_page (GTK_NOTEBOOK (notebook), frame, etiqueta);
7665     }
7666     
7667     
7668     /* Ahora añadimos una página en punto específico */
7669     checkbutton = gtk_check_button_new_with_label ("Check me please!");
7670     gtk_widget_set_usize(checkbutton, 100, 75);
7671     gtk_widget_show (checkbutton);
7672     
7673     etiqueta = gtk_label_new ("Add spot");
7674     gtk_container_add (GTK_CONTAINER (checkbutton), etiqueta);
7675     gtk_widget_show (etiqueta);
7676     etiqueta = gtk_label_new ("Add page");
7677     gtk_notebook_insert_page (GTK_NOTEBOOK (notebook), checkbutton, etiqueta, 2);
7678     
7679     /* Y finalmente preañadimos páginas en el libro de notas */
7680     for (i=0; i < 5; i++) {
7681         sprintf(bufferf, "Prepend Frame %d", i+1);
7682         sprintf(bufferl, "PPage %d", i+1);
7683         
7684         frame = gtk_frame_new (bufferf);
7685         gtk_container_border_width (GTK_CONTAINER (frame), 10);
7686         gtk_widget_set_usize (frame, 100, 75);
7687         gtk_widget_show (frame);
7688         
7689         etiqueta = gtk_label_new (bufferf);
7690         gtk_container_add (GTK_CONTAINER (frame), etiqueta);
7691         gtk_widget_show (etiqueta);
7692         
7693         etiqueta = gtk_label_new (bufferl);
7694         gtk_notebook_prepend_page (GTK_NOTEBOOK(notebook), frame, etiqueta);
7695     }
7696     
7697     /* Decimos en que página empezar (página 4) */
7698     gtk_notebook_set_page (GTK_NOTEBOOK(notebook), 3);
7699     
7700     
7701     /* creamos un montón de botones */
7702     boton = gtk_button_new_with_label ("close");
7703     gtk_signal_connect_object (GTK_OBJECT (boton), "clicked",
7704                                GTK_SIGNAL_FUNC (delete), NULL);
7705     gtk_table_attach_defaults(GTK_TABLE(table), boton, 0,1,1,2);
7706     gtk_widget_show(boton);
7707     
7708     boton = gtk_button_new_with_label ("next page");
7709     gtk_signal_connect_object (GTK_OBJECT (boton), "clicked",
7710                                (GtkSignalFunc) gtk_notebook_next_page,
7711                                GTK_OBJECT (notebook));
7712     gtk_table_attach_defaults(GTK_TABLE(table), boton, 1,2,1,2);
7713     gtk_widget_show(boton);
7714     
7715     boton = gtk_button_new_with_label ("prev page");
7716     gtk_signal_connect_object (GTK_OBJECT (boton), "clicked",
7717                                (GtkSignalFunc) gtk_notebook_prev_page,
7718                                GTK_OBJECT (notebook));
7719     gtk_table_attach_defaults(GTK_TABLE(table), boton, 2,3,1,2);
7720     gtk_widget_show(boton);
7721     
7722     boton = gtk_button_new_with_label ("tab position");
7723     gtk_signal_connect_object (GTK_OBJECT (boton), "clicked",
7724                                (GtkSignalFunc) rotate_book, GTK_OBJECT(notebook));
7725     gtk_table_attach_defaults(GTK_TABLE(table), boton, 3,4,1,2);
7726     gtk_widget_show(boton);
7727     
7728     boton = gtk_button_new_with_label ("tabs/border on/off");
7729     gtk_signal_connect_object (GTK_OBJECT (boton), "clicked",
7730                                (GtkSignalFunc) tabsborder_book,
7731                                GTK_OBJECT (notebook));
7732     gtk_table_attach_defaults(GTK_TABLE(table), boton, 4,5,1,2);
7733     gtk_widget_show(boton);
7734     
7735     boton = gtk_button_new_with_label ("remove page");
7736     gtk_signal_connect_object (GTK_OBJECT (boton), "clicked",
7737                                (GtkSignalFunc) remove_book,
7738                                GTK_OBJECT(notebook));
7739     gtk_table_attach_defaults(GTK_TABLE(table), boton, 5,6,1,2);
7740     gtk_widget_show(boton);
7741     
7742     gtk_widget_show(table);
7743     gtk_widget_show(ventana);
7744     
7745     gtk_main ();
7746     
7747     return 0;
7748 }
7749 /* fin del ejemplo */
7750 </verb></tscreen>
7751
7752 Espero que la explicación le ayude de alguna manera a crear libros de
7753 notas en sus aplicaciones GTK.
7754
7755 <!-- ***************************************************************** -->
7756 <sect> El <em/widget/ GtkCList
7757 <!-- ***************************************************************** -->
7758 <!-- ----------------------------------------------------------------- -->
7759 <p>
7760 El <em>widget</em> GtkCList ha reemplazado al <em>widget</em> GtkList
7761 (que sigue estando disponible).
7762
7763 El <em>widget</em> GtkCList es un <em>widget</em> de una lista
7764 multicolumna que es capaz de manejar, literalmente, miles de filas de
7765 información. Cada columna puede tener (opcionalmente) un título, que
7766 puede estar activado (opcionalmente), permitiéndonos enlazar una
7767 función con la selección.
7768
7769 <!-- ----------------------------------------------------------------- -->
7770 <sect1>Creando un <em>widget</em> GtkCList
7771 <p>
7772 Crear un GtkCList es algo bastante sencillo, una vez que sabe como
7773 crear un <em>widget</em> en general. Se proporcionan al menos dos
7774 formas estándar de crearlo, la forma fácil y la forma difícil. Pero
7775 antes de crear una GtkCList, hay una cosa que debemos saber: ¿Cuántas
7776 columnas va a tener?
7777
7778 No todas las columnas tienen que ser visibles y pueden utilizarse para
7779 almacenar datos que estén relacionados con una cierta celda de la
7780 lista.
7781
7782 <tscreen><verb>
7783 GtkWidget *gtk_clist_new ( gint columns );
7784
7785 GtkWidget *gtk_clist_new_with_titles( gint   columns,
7786                                       gchar *titles[] );
7787 </verb></tscreen>
7788
7789 Esta primera aproximación al problema es muy sencilla, pero la segunda
7790 requerirá alguna explicación adicional. Cada columna puede tener un
7791 título asociado. Si utilizamos la segunda forma, deberemos proporcionar
7792 punteros al texto del título, y el número de punteros debe ser igual
7793 al número de columnas especificadas. Por supuesto, siempre podemos
7794 utilizar la primera forma de creación y añadir más tarde los títulos
7795 de forma manual.
7796
7797 <!-- ----------------------------------------------------------------- -->
7798 <sect1>Modos de operación
7799 <p>
7800 Hay varios atributos que pueden utilizarse para alterar el aspecto
7801 de un GtkCList. Primero tenemos
7802
7803 <tscreen><verb>
7804 void gtk_clist_set_selection_mode( GtkCList         *clist,
7805                                    GtkSelectionMode  mode );
7806 </verb></tscreen>
7807
7808 que, como el propio nombre indica, establece el modo de selección de la
7809 lista GtkCList. El primer argumento es el <em>widget</em> GtkCList, y el
7810 segundo especifica el modo de selección de la celda (están definidos
7811 en <tt/gtkenums.h/). En el momento de escribir esto, estaban
7812 disponibles los siguientes modos:
7813
7814 <itemize>
7815 <item> GTK_SELECTION_SINGLE - La selección o es NULL o contiene un
7816 puntero GList a un elemento seleccionado.
7817
7818 <item> GTK_SELECTION_BROWSE -  La selección es NULL si la lista no
7819 contiene <em>widgets</em> o si los que contiene son insensibles, en
7820 caso contrario contendrá un puntero GList hacia una estructura GList,
7821 y por tanto con exactamente un elemento.
7822
7823 <item> GTK_SELECTION_MULTIPLE -  La selección es NULL si no hay
7824 seleccionados una lista de elementos o un puntero GList para el primer
7825 elemento seleccionado.<!-- FIXME: Todo esto no se si tiene sentido -->
7826 Éste apunta de nuevo a una estructura GList para el segundo elemento
7827 seleccionado y continua así. Éste es, actualmente, el modo por
7828 <bf>defecto</bf> para el <em>widget</em> GtkCList.
7829
7830 <item> GTK_SELECTION_EXTENDED - La selección siempre es NULL.
7831 </itemize>
7832
7833 Puede que se añadan otros modos en versiones posteriores de GTK.
7834
7835 También tenemos
7836
7837 <tscreen><verb>
7838 void gtk_clist_set_policy (GtkCList *clist,
7839                            GtkPolicyType vscrollbar_policy,
7840                            GtkPolicyType hscrollbar_policy);
7841 </verb></tscreen>
7842
7843 que define que es lo que ocurre con las barras de desplazamiento. Los
7844 siguientes valores son los posibles para las barras de desplazamiento
7845 horizontal y vertical:
7846
7847 <itemize>
7848 <item> GTK_POLICY_ALWAYS - La barra de desplazamiento siempre está ahí.
7849
7850 <item> GTK_POLICY_AUTOMATIC - La barra de desplazamiento estará ahí sólo
7851 cuando el número de elementos en la GtkCList supere el número que puede
7852 mostrarse en el <em>widget</em>.
7853 </itemize>
7854
7855 También podemos definir como debería ser el aspecto del borde del
7856 <em>widget</em> GtkCList. Esto lo podemos hacer mediante
7857
7858 <tscreen><verb>
7859 void gtk_clist_set_border( GtkCList      *clist,
7860                            GtkShadowType  border );
7861 </verb></tscreen>
7862
7863 Y los posibles valores para el segundo argumento son
7864
7865 <itemize>
7866 <item> GTK_SHADOW_NONE
7867
7868 <item> GTK_SHADOW_IN
7869
7870 <item> GTK_SHADOW_OUT
7871
7872 <item> GTK_SHADOW_ETCHED_IN
7873
7874 <item> GTK_SHADOW_ETCHED_OUT
7875 </itemize>
7876
7877 <!-- ----------------------------------------------------------------- -->
7878 <sect1>Trabajando con los títulos
7879 <p>
7880 Cuando cree un <em>widget</em> GtkCList, también obtendrá
7881 automáticamente un conjunto de botones título. Vivirán en lo alto de
7882 una ventana CList, y pueden actuar como botones normales que responden
7883 cuando se pulsa sobre ellos, o bien pueden ser pasivos, en cuyo caso
7884 no serán nada más que un título. Hay cuatro llamadas diferentes que
7885 nos ayudarán a establecer el estado de los botones título.
7886
7887 <tscreen><verb>
7888 void gtk_clist_column_title_active( GtkCList *clist,
7889                                      gint     column );
7890
7891 void gtk_clist_column_title_passive( GtkCList *clist,
7892                                      gint      column );
7893
7894 void gtk_clist_column_titles_active( GtkCList *clist );
7895
7896 void gtk_clist_column_titles_passive( GtkCList *clist );
7897 </verb></tscreen>
7898
7899 Un título activo es aquel que actua como un botón normal, y uno pasivo
7900 es sólo una etiqueta. Las primeras dos llamadas de arriba
7901 activarán/desactivarán el botón título correspondiente a la columna
7902 <tt/column/, mientras que las dos llamadas siguientes
7903 activarán/desactivarán todos los botones título que hayan en el
7904 <em>widget</em> <tt/clist/ que se le proporcione a la función.
7905
7906 Pero, por supuesto, habrá casos en el que no querremos utilizar los
7907 botones título, así que también tenemos la posibilidad de ocultarlos y
7908 de volverlos a mostrar utilizando las dos llamadas siguientes:
7909
7910 <tscreen><verb>
7911 void gtk_clist_column_titles_show( GtkCList *clist );
7912
7913 void gtk_clist_column_titles_hide( GtkCList *clist );
7914 </verb></tscreen>
7915
7916 Para que los títulos sean realmente útiles necesitamos un mecanismo
7917 que nos permita darles el valor que nosotros queramos y cambiar ese
7918 valor, y podremos hacerlo mediante
7919
7920 <tscreen><verb>
7921 void gtk_clist_set_column_title( GtkCList *clist,
7922                                  gint      column,
7923                                  gchar    *title );
7924 </verb></tscreen>
7925
7926 Debe llevar cuidado, ya que sólo se puede especificar el título de una
7927 columna a la vez, por lo que si conoce todos los títulos desde el
7928 principio, le sugiero que utilice <tt/gtk_clist_new_with_titles/ (como
7929 se describe arriba) para establecerlos adecuadamente. Le ahorrará
7930 tiempo de programación, y hará su programa más pequeño. Hay algunos
7931 casos donde es mejor utilizar la forma manual, y uno de ellos es
7932 cuando no todos los títulos son texto. GtkCList nos proporciona
7933 botones título que pueden, de hecho, incorporar un <em>widget</em>
7934 entero, por ejemplo un <em>pixmap</em>. Todo esto se hace mediante
7935
7936 <tscreen><verb>
7937 void gtk_clist_set_column_widget( GtkCList  *clist,
7938                                   gint       column,
7939                                   GtkWidget *widget );
7940 </verb></tscreen>
7941
7942 que no debería necesitar de explicaciones adicionales.
7943
7944 <!-- ----------------------------------------------------------------- -->
7945 <sect1>Manipulando la lista en sí.
7946 <p>
7947 Es posible cambiar la justificación de una columna, y esto se hace
7948 mediante
7949
7950 <tscreen><verb>
7951 void gtk_clist_set_column_justification( GtkCList         *clist,
7952                                          gint              column,
7953                                          GtkJustification  justification );
7954 </verb></tscreen>
7955
7956 El tipo GtkJustification puede tomar los valores siguientes:
7957
7958 <itemize>
7959 <item>GTK_JUSTIFY_LEFT - El texto en la columna empezará desde el lado
7960 izquierdo.
7961
7962 <item>GTK_JUSTIFY_RIGHT - El texto en la columna empezará desde el
7963 lado derecho.
7964
7965 <item>GTK_JUSTIFY_CENTER - El texto se colocará en el centro de la
7966 columna.
7967
7968 <item>GTK_JUSTIFY_FILL - El texto utilizará todo el espacio disponible
7969 en la columna. Normalmente se hace añadiendo espacios en blanco entre
7970 las palabras (o entre letras por separado, si se trata de una sola
7971 palabra). Más o menos de la misma forma en la que lo hace un
7972 procesador de textos WYSIWYG.
7973 </itemize>
7974
7975 La siguiente función es muy importante, y debería ser un estándar
7976 para inicializar todos los <em>widgets</em> GtkCList. Cuando se crea
7977 la lista, los anchos de las distintas columnas se eligen para que
7978 coincidan con sus títulos, y éste es el ancho adecuado que tenemos que
7979 poner, utilizando
7980
7981 <tscreen><verb>
7982 void gtk_clist_set_column_width( GtkCList *clist,
7983                                  gint      column,
7984                                  gint      width );
7985 </verb></tscreen>
7986
7987 Observe que el ancho viene dado en pixeles y no en letras. Lo mismo
7988 vale para el alto de la celda en las columnas, pero como el valor por
7989 defecto es la altura del tipo de letra actual, no es algo tan crítico
7990 para la aplicación. De todas formas, la altura se cambia mediante
7991
7992 <tscreen><verb>
7993 void gtk_clist_set_row_height( GtkCList *clist,
7994                                gint      height );
7995 </verb></tscreen>
7996
7997 De nuevo, hay que advertir que el ancho viene dado en pixeles.
7998
7999 También podemos ir hacia un elemento sin la intervención del usuario,
8000 sin embargo hace falta que sepamos hacia donde queremos ir. O en otras
8001 palabras, necesitamos la fila y la columna del elemento al que queremos
8002 pasar.
8003
8004 <tscreen><verb>
8005 void gtk_clist_moveto( GtkCList *clist,
8006                        gint      row,
8007                        gint      column,
8008                        gfloat    row_align,
8009                        gfloat    col_align );
8010 </verb></tscreen>
8011
8012 Es importante comprender bien el significado de <tt/gfloat
8013 row_align/. Tiene un valor entre 0.0 y 1.0, donde 0.0 significa que
8014 debemos hacer que la fila seleccionada aparezca en la alto de la
8015 lista, mientras que 1.0 significa que la fila aparecerá en la parte de
8016 abajo. El resto de valores entre 0.0 y 1.0 son válidos y harán que la
8017 fila aparezca entre la parte superior y la inferior. El último
8018 argumento, <tt/gfloat col_align/ funciona igual, siendo 0.0 la
8019 izquierda y 1.0 la derecha.
8020
8021 Dependiendo de las necesidades de la aplicación, puede que no tengamos
8022 que hacer un desplazamiento hacia un elemento que ya sea visible. Por
8023 tanto, ¿cómo podemos saber si ya es visible? Como siempre, hay una función
8024 que sirve para averiguarlo
8025
8026 <tscreen><verb>
8027 GtkVisibility gtk_clist_row_is_visible( GtkCList *clist,
8028                                         gint      row );
8029 </verb></tscreen>
8030
8031 El valor devuelto es uno de los siguientes:
8032
8033 <itemize>
8034 <item>GTK_VISIBILITY_NONE
8035
8036 <item>GTK_VISIBILITY_PARTIAL
8037
8038 <item>GTK_VISIBILITY_FULL
8039 </itemize>
8040
8041 Como puede ver, sólo nos dice si una fila es visible. Actualmente no hay
8042 ninguna forma de obtener el mismo dato para una columna. Sin embargo
8043 podemos obtener información parcial, porque si el valor devuelto es
8044 GTK_VISIBILITY_PARTIAL, entonces es que alguna parte está oculta,
8045 pero no sabemos si es la fila que está cortada por la parte de abajo
8046 de la lista, o si la fila tiene columnas que están fuera.
8047
8048 También podemos cambiar el color del primer y del segundo plano de una
8049 fila en particular. Esto es útil para marcar la fila seleccionada por
8050 el usuario, y las dos funciones que hay que utilizar son
8051
8052 <tscreen><verb>
8053 void gtk_clist_set_foreground( GtkCList *clist,
8054                                gint      row,
8055                                GdkColor *color );
8056
8057 void gtk_clist_set_background( GtkCList *clist,
8058                                gint      row,
8059                                GdkColor *color );
8060 </verb></tscreen>
8061
8062 Cuidado, ya que los colores deben estar asignados previamente en la
8063 memoria.
8064
8065 <!-- ----------------------------------------------------------------- -->
8066 <sect1>Añadiendo filas a la lista
8067 <p>
8068 Podemos añadir filas de dos formas. Se pueden añadir al final de la lista
8069 utilizando
8070
8071 <tscreen><verb>
8072 gint gtk_clist_append( GtkCList *clist,
8073                        gchar    *text[] );
8074 </verb></tscreen>
8075
8076 o podemos insertar una fila en un lugar determinado utilizando
8077
8078 <tscreen><verb>
8079 void gtk_clist_insert( GtkCList *clist,
8080                        gint      row,
8081                        gchar    *text[] );
8082 </verb></tscreen>
8083
8084 En ambas llamadas podemos proporcionar un conjunto de punteros que
8085 serán los textos que queremos poner en las columnas. El número de
8086 punteros debe ser igual al número de columnas en la lista. Si el
8087 argumento <tt/text[]/ es NULL, entonces no habrá texto en las columnas
8088 de la fila. Esto sería útil, por ejemplo, si queremos añadir
8089 <em>pixmaps</em> en lugar de texto (en general para cualquier cosa que
8090 haya que hacer manualmente).
8091
8092 De nuevo, cuidado ya que el número de filas y de columnas comienza en
8093 0.
8094
8095 Para eliminar una fila individual podemos utilizar
8096
8097 <tscreen><verb>
8098 void gtk_clist_remove( GtkCList *clist,
8099                        gint      row );
8100 </verb></tscreen>
8101
8102 Hay también una llamada que elimina todas las filas en la lista.
8103 Es mucho más rápido que llamar a <tt/gtk_clist_remove/ una vez por
8104 cada fila, que sería la única alternativa.
8105
8106 <tscreen><verb>
8107 void gtk_clist_clear( GtkCList *clist );
8108 </verb></tscreen>
8109
8110 También hay dos funciones que es conveniente utilizarlas cuando hay
8111 que hacerle muchos cambios a una lista. Son para evitar que la lista
8112 parpadee mientras es actualizada repetidamente, que puede ser muy
8113 molesto para el usuario. Por tanto es una buena idea congelar la
8114 lista, hacer los cambios, y descongelarla, que hará que la lista se
8115 actualice en la pantalla.
8116
8117 <tscreen><verb>
8118 void gtk_clist_freeze( GtkCList * clist );
8119
8120 void gtk_clist_thaw( GtkCList * clist );
8121 </verb></tscreen>
8122
8123 <!-- ----------------------------------------------------------------- -->
8124 <sect1>Poniendo texto y <em>pixmaps</em> en las celdas
8125 <p>
8126 Una celda puede contener un <em>pixmap</em>, texto o ambos. Para ponerlos
8127 en las celdas, podemos utilizar las siguientes funciones.
8128
8129 <tscreen><verb>
8130 void gtk_clist_set_text( GtkCList *clist,
8131                          gint      row,
8132                          gint      column,
8133                          gchar    *text );
8134
8135 void gtk_clist_set_pixmap( GtkCList  *clist,
8136                            gint       row,
8137                            gint       column,
8138                            GdkPixmap *pixmap,
8139                            GdkBitmap *mask );
8140
8141 void gtk_clist_set_pixtext( GtkCList  *clist,
8142                             gint       row,
8143                             gint       column,
8144                             gchar     *text,
8145                             guint8     spacing,
8146                             GdkPixmap *pixmap,
8147                             GdkBitmap *mask );
8148 </verb></tscreen>
8149
8150 Son bastante sencillas de entender. Todas las llamadas tienen la
8151 GtkCList como primer argumento, seguidas por la fila y la columna
8152 de la celda, y seguidas por el dato que debe ponerse en la celda. El
8153 argumento <tt/gint8 spacing/ en <tt/gtk_clist_set_pixtext/ es el
8154 número de <em>pixels</em> entre el <em>pixmap</em> y el principio del
8155 texto.
8156
8157 Para leer los datos que hay en una celda, podemos utilizar
8158
8159 <tscreen><verb>
8160 gint gtk_clist_get_text( GtkCList  *clist,
8161                          gint       row,
8162                          gint       column,
8163                          gchar    **text );
8164
8165 gint gtk_clist_get_pixmap( GtkCList   *clist,
8166                            gint        row,
8167                            gint        column,
8168                            GdkPixmap **pixmap,
8169                            GdkBitmap **mask );
8170
8171 gint gtk_clist_get_pixtext( GtkCList   *clist,
8172                             gint        row,
8173                             gint        column,
8174                             gchar     **text,
8175                             guint8     *spacing,
8176                             GdkPixmap **pixmap,
8177                             GdkBitmap **mask );
8178 </verb></tscreen>
8179
8180 No es necesario leer todos los datos en caso de que no estemos
8181 interesados. Cualquiera de los punteros que se supone contendrán los
8182 valores a devolver (cualquiera excepto el <tt/clist/) pueden ser
8183 NULL. Por lo que si sólo queremos leer el texto de una celda que es de
8184 tipo <tt/pixtext/, deberíamos hacer lo siguiente, suponiendo que
8185 <tt/clist/, <tt/row/ y <tt/column/ ya existan:
8186
8187 <tscreen><verb>
8188 gchar *mytext;
8189
8190 gtk_clist_get_pixtext(clist, row, column, &amp;mytext, NULL, NULL, NULL);
8191 </verb></tscreen>
8192
8193 Hay una rutina más que está relacionada con lo que está dentro
8194 de una celda de una <tt/clist/, y es
8195
8196 <tscreen><verb>
8197 GtkCellType gtk_clist_get_cell_type( GtkCList *clist,
8198                                      gint      row,
8199                                      gint      column );
8200 </verb></tscreen>
8201
8202 que devuelve el tipo de datos que hay en la celda. El valor devuelto es
8203 uno de los siguientes
8204
8205 <itemize>
8206 <item>GTK_CELL_EMPTY
8207
8208 <item>GTK_CELL_TEXT
8209
8210 <item>GTK_CELL_PIXMAP
8211
8212 <item>GTK_CELL_PIXTEXT
8213
8214 <item>GTK_CELL_WIDGET
8215 </itemize>
8216
8217 También hay una función que nos permite especificar la indentación de
8218 un celda (horizontal o vertical). El valor de la indentación es del
8219 tipo <tt/gint/, viene dado en <em>pixeles</em>, y puede ser positivo o
8220 negativo.
8221
8222 <tscreen><verb>
8223 void gtk_clist_set_shift( GtkCList *clist,
8224                           gint      row,
8225                           gint      column,
8226                           gint      vertical,
8227                           gint      horizontal );
8228 </verb></tscreen>
8229
8230 <!-- ----------------------------------------------------------------- -->
8231 <sect1>Almacenando punteros a datos
8232 <p>
8233 Con una GtkCList es posible poner un puntero a datos en una
8234 fila. Este puntero no será visible al usuario, pero puede serle útil
8235 al programador.
8236
8237 De nuevo, las funciones son lo suficientemente autoexplicativas
8238
8239 <tscreen><verb>
8240 void gtk_clist_set_row_data( GtkCList *clist,
8241                              gint      row,
8242                              gpointer  data );
8243
8244 void gtk_clist_set_row_data_full( GtkCList         *clist,
8245                                   gint              row,
8246                                   gpointer          data,
8247                                   GtkDestroyNotify  destroy );
8248
8249 gpointer gtk_clist_get_row_data( GtkCList *clist,
8250                                  gint      row );
8251
8252 gint gtk_clist_find_row_from_data( GtkCList *clist,
8253                                    gpointer  data );
8254 </verb></tscreen>
8255
8256 <!-- ----------------------------------------------------------------- -->
8257 <sect1>Trabajando con la selección
8258 <p>
8259 También hay funciones que nos permiten forzar la (de)selección de una
8260 fila. Son
8261
8262 <tscreen><verb>
8263 void gtk_clist_select_row( GtkCList *clist,
8264                            gint      row,
8265                            gint      column );
8266
8267 void gtk_clist_unselect_row( GtkCList *clist,
8268                              gint      row,
8269                              gint      column );
8270 </verb></tscreen>
8271
8272 Y también una función que tomará las coordenadas x e y (por ejemplo,
8273 recibidas del ratón), mirará en la lista y devolverá la fila y la
8274 columna que les corresponden.
8275
8276 <tscreen><verb>
8277 gint gtk_clist_get_selection_info( GtkCList *clist,
8278                                    gint      x,
8279                                    gint      y,
8280                                    gint     *row,
8281                                    gint     *column );
8282 </verb></tscreen>
8283
8284 Cuando detectemos algo interesante, como por ejemplo el movimiento del
8285 ratón, o una pulsación en cualquier lugar de la lista, podemos leer
8286 las coordenadas del ratón y encontrar en que elemento de la lista se
8287 encuentra. ¿Engorroso? Afortunadamente, hay una forma más sencilla de
8288 hacer las cosas...
8289
8290 <!-- ----------------------------------------------------------------- -->
8291 <sect1>Las señales que lo hacen todo
8292 <p>
8293 Como con el resto de <em>widgets</em>, hay unas cuantas señales que
8294 podemos utilizar. El <em>widget</em> GtkCList está derivado del
8295 <em>widget</em> GtkContainer, y por tanto tiene las mismas
8296 señales que éste, pero además añade las siguientes:
8297
8298 <itemize>
8299 <item><tt/select_row/ - Esta señal enviará la siguiente información,
8300 en este orden: GtkCList *clist, gint row, gint column, GtkEventButton
8301 *event
8302
8303 <item><tt/unselect_row/ - Cuando el usuario deselecciona una fila, se
8304 activará esta señal. Envia la misma información que <tt/select_row/
8305
8306 <item><tt/click_column/ - Envia GtkCList *clist, gint column
8307 </itemize>
8308
8309 Por tanto si queremos conectar una llamada a <tt/select_row/, la
8310 llamada se deberá declarar como
8311
8312 <tscreen><verb>
8313 void select_row_callback(GtkWidget *widget,
8314                          gint row,
8315                          gint column,
8316                          GdkEventButton *event,
8317                          gpointer data);
8318 </verb></tscreen>
8319
8320 La llamada se conectará, como siempre, con
8321
8322 <tscreen><verb>
8323 gtk_signal_connect(GTK_OBJECT( clist),
8324                    "select_row"
8325                    GTK_SIGNAL_FUNC(select_row_callback),
8326                    NULL);
8327 </verb></tscreen>
8328
8329 <!-- ----------------------------------------------------------------- -->
8330 <sect1>Un ejemplo GtkCList
8331 <p>
8332
8333 <tscreen><verb>
8334 /* principio del ejemplo clist clist.c */
8335
8336 #include        <gtk/gtk.h>
8337 #include        <glib.h>
8338
8339 /* Aquí tenemos algunos prototipos de las funciones de llamada */
8340 void button_add_clicked( GtkWidget *boton, gpointer data);
8341 void button_clear_clicked( GtkWidget *boton, gpointer data);
8342 void button_hide_show_clicked( GtkWidget *boton, gpointer data);
8343 void selection_made( GtkWidget *clist, gint row, gint column,
8344                      GdkEventButton *event, gpointer data);
8345
8346 gint main (int argc, gchar *argv[])
8347 {                                  
8348     GtkWidget       *ventana;
8349     GtkWidget       *vbox, *hbox;
8350     GtkWidget       *clist;
8351     GtkWidget       *button_add, *button_clear, *button_hide_show;    
8352     gchar           *titles[2] = {"Ingredients","Amount"};
8353
8354     gtk_init(&amp;argc, &amp;argv);
8355     
8356     
8357     ventana=gtk_window_new(GTK_WINDOW_TOPLEVEL);
8358     gtk_widget_set_usize(GTK_WIDGET(ventana), 300, 150);
8359
8360     gtk_window_set_title(GTK_WINDOW(ventana), "GtkCList Example");
8361     gtk_signal_connect(GTK_OBJECT(ventana),
8362                        "destroy",
8363                        GTK_SIGNAL_FUNC(gtk_main_quit),
8364                        NULL);
8365     
8366     vbox=gtk_vbox_new(FALSE, 5);
8367     gtk_container_border_width(GTK_CONTAINER(vbox), 5);
8368     gtk_container_add(GTK_CONTAINER(ventana), vbox);
8369     gtk_widget_show(vbox);
8370     
8371     /* Crear el GtkCList. Para este ejemplo utilizaremos 2 columnas */
8372     clist = gtk_clist_new_with_titles( 2, titles);
8373
8374     /* Cuando se hace una selección, queremos saber algo acerca de
8375      * ella. La función de llamada utilizada es selection_made, y su
8376      * código lo podemos encontrar más abajo */
8377     gtk_signal_connect(GTK_OBJECT(clist), "select_row",
8378                        GTK_SIGNAL_FUNC(selection_made),
8379                        NULL);
8380
8381     /* No es necesario ponerle sombra al borde, pero es bonito :) */
8382     gtk_clist_set_border(GTK_CLIST(clist), GTK_SHADOW_OUT);
8383
8384     /* Lo que sí que es importante, es poner el ancho de las columnas
8385      * ya no tendrán el valor correcto en caso contrario. Recuerde que
8386      * las columnas se numeran desde el 0 en adelante (hasta el 1 en
8387      * este caso).
8388      */
8389     gtk_clist_set_column_width (GTK_CLIST(clist), 0, 150);
8390
8391     /* Scollbars _only when needed_ */
8392     gtk_clist_set_policy(GTK_CLIST(clist), GTK_POLICY_AUTOMATIC,
8393                                            GTK_POLICY_AUTOMATIC);
8394
8395     /* Añade el widget GtkCList a la caja vertical y lo muestra. */
8396     gtk_box_pack_start(GTK_BOX(vbox), clist, TRUE, TRUE, 0);
8397     gtk_widget_show(clist);
8398
8399     /* Crea los botones y los añade a la ventana. Ver la parte del
8400      * tutorial sobre botones para ver más ejemplos y comentarios
8401      * acerca de todo esto.
8402      */
8403     hbox = gtk_hbox_new(FALSE, 0);
8404     gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, TRUE, 0);
8405     gtk_widget_show(hbox);
8406
8407     button_add = gtk_button_new_with_label("Add List");
8408     button_clear = gtk_button_new_with_label("Clear List");
8409     button_hide_show = gtk_button_new_with_label("Hide/Show titles");
8410
8411     gtk_box_pack_start(GTK_BOX(hbox), button_add, TRUE, TRUE, 0);
8412     gtk_box_pack_start(GTK_BOX(hbox), button_clear, TRUE, TRUE, 0);
8413     gtk_box_pack_start(GTK_BOX(hbox), button_hide_show, TRUE, TRUE, 0);
8414
8415     /* Conectar nuestras funciones de llamada a los tres botones */
8416     gtk_signal_connect_object(GTK_OBJECT(button_add), "clicked",
8417                               GTK_SIGNAL_FUNC(button_add_clicked),
8418                               (gpointer) clist);
8419     gtk_signal_connect_object(GTK_OBJECT(button_clear), "clicked",
8420                               GTK_SIGNAL_FUNC(button_clear_clicked),
8421                               (gpointer) clist);
8422     gtk_signal_connect_object(GTK_OBJECT(button_hide_show), "clicked",
8423                               GTK_SIGNAL_FUNC(button_hide_show_clicked),
8424                               (gpointer) clist);
8425
8426     gtk_widget_show(button_add);
8427     gtk_widget_show(button_clear);
8428     gtk_widget_show(button_hide_show);
8429
8430     /* Ahora hemos terminado el interface y sólo nos queda mostrar la
8431      * ventana y entrar en el bucle gtk_main.
8432      */
8433     gtk_widget_show(ventana);
8434     gtk_main();
8435     
8436     return 0;
8437 }
8438
8439 /* El usuario pulsó el botón "Add List". */
8440 void button_add_clicked( GtkWidget *boton, gpointer data)
8441 {
8442     int         indx;
8443
8444     /* Algo tonto que añadir a la lista. 4 filas con 2 columnas cada
8445      * una
8446      */
8447     gchar      *drink[4][2] = {{"Milk", "3 Oz"},
8448                                {"Water", "6 l"},
8449                                {"Carrots", "2"},
8450                                {"Snakes", "55"}};
8451
8452     /* Aquí hacemos la adición del texto. Se hace una vez por cada
8453      * fila.
8454      */
8455     for( indx=0; indx < 4; indx++)
8456         gtk_clist_append( (GtkCList*) data, drink[indx]);
8457
8458     return;
8459 }
8460
8461 /* El usuario pulsó el botón "Clear List" */
8462 void button_clear_clicked( GtkWidget *boton, gpointer data)
8463 {
8464     /* Borrar la lista utilizando gtk_clist_clear. Esto es mucho más
8465      * rápido que llamar a gtk_clist_remove una vez por cada fila.
8466      */
8467     gtk_clist_clear((GtkCList*) data);
8468
8469     return;
8470 }
8471
8472 /* El usuario pulsó el botón "Hide/Show titles". */
8473 void button_hide_show_clicked( GtkWidget *boton, gpointer data)
8474 {
8475     /* Una bandera para recordar el estado. 0 = actualmente visible */
8476     static short int flag = 0;
8477
8478     if (flag == 0)
8479     {
8480         /* Oculta los títulos y pone la bandera a 1 */
8481         gtk_clist_column_titles_hide((GtkCList*) data);
8482         flag++;
8483     }
8484     else
8485     {
8486         /* Muestra los títulos y pone la bandera a 0 */
8487         gtk_clist_column_titles_show((GtkCList*) data);
8488         flag--;
8489     }
8490
8491     return;
8492 }
8493
8494 /* Se llegamos aquí, entonces el usuario ha seleccionado una fila de
8495  * la lista.
8496  */
8497 void selection_made( GtkWidget *clist, gint row, gint column,
8498                      GdkEventButton *event, gpointer data)
8499 {
8500     gchar       *text;
8501
8502     /* Obtiene el texto que se ha almacenado en la fila y columna
8503      *  sobre las que se ha pulsado. Lo recibiremos como un puntero en
8504      * el argumento text.
8505      */
8506     gtk_clist_get_text(GTK_CLIST(clist), row, column, &amp;text);
8507
8508     /* Imprime alguna información sobre la fila seleccionada */
8509     g_print("You selected row %d. More specifically you clicked in column %d, and the text in this cell is %s\n\n", row, column, text);
8510
8511     return;
8512 }
8513 /* final del ejemplo */
8514 </verb></tscreen>
8515
8516 <!-- ***************************************************************** -->
8517 <sect> El <em>widget</em> árbol<label id="sec_Tree_Widgets">
8518 <!-- ***************************************************************** -->
8519 <p>
8520
8521 El propósito del <em>widget</em> GtkTree es mostrar datos organizados
8522 de forma jerárquica. El <em>widget</em> GtkTree en sí es un contenedor
8523 vertical para los <em>widgets</em> del tipo GtkTreeItem. GtkTree en
8524 sí mismo no es muy diferente de GtkList - ambos están derivados
8525 directamente de GtkContainer, y los métodos GtkContainer funcionan
8526 igual en los <em>widgets</em> GtkTree que en los GtkList. La
8527 diferencia es que los <em>widgets</em> GtkTree pueden anidarse
8528 dentro de otros <em>widgets</em> GtkTree. Vamos a verlo de forma
8529 resumida.
8530
8531 El <em>widget</em> GtkTree tiene su propia ventana, y tiene por
8532 defecto un fondo de color blanco, como GtkList. La mayoría de los
8533 métodos de GtkTree funcionan igual que sus correspondientes de
8534 GtkList. Sin embargo, GtkTree no está derivado de GtkList, por lo que
8535 no puede intercambiarlos.
8536
8537 <sect1> Creando un árbol
8538 <p>
8539 Puede crear un GtkTree de la forma usual, utilizando:
8540
8541 <tscreen><verb>
8542 GtkWidget* gtk_tree_new( void );
8543 </verb></tscreen>
8544
8545 Como el <em>widget</em> GtkList, un GtkTree crecerá cuando le añadan
8546 elementos o cuando crezca alguno de sus subárboles. Por esta razón,
8547 suelen venir dentro de una GtkScrolledWindow. Puede que quiera
8548 utilizar <tt/gtk_widget_set_usize()/ con la ventana para asegurarse de
8549 que es lo suficientemente grande como para poder ver todos los
8550 elementos del árbol, ya que el valor por defecto de GtkScrolledWindow
8551 es bastante pequeño.
8552
8553 Ahora que ya sabemos como crear un árbol, probablemente quiera
8554 añadirle algunos elementos. <ref id="sec_Tree_Item_Widget" name="El
8555 widget elemento de árbol"> más adelante explica todos los
8556 detalles de GtkTreeItem. Por ahora, es suficiente con saber como crear
8557 uno, utilizando:
8558
8559 <tscreen><verb>
8560 GtkWidget* gtk_tree_item_new_with_label( gchar *etiqueta );
8561 </verb></tscreen>
8562
8563 Puede añadirlo al árbol utilizando una de las siguientes funciones
8564 (ver <ref id="sec_GtkTree_Functions" name="Funciones y macros">
8565 más adelante para leer más opciones):
8566
8567 <tscreen><verb>
8568 void gtk_tree_append( GtkTree    *arbol,
8569                        GtkWidget *elemento_arbol );
8570
8571 void gtk_tree_prepend( GtkTree   *arbol,
8572                        GtkWidget *elemento_arbol );
8573 </verb></tscreen>
8574
8575 Observe que debe añadir elementos a un GtkTree de uno en uno - no
8576 hay un equivalente a <tt/gtk_list_*_items()/.
8577
8578 <sect1> Añadiendo un Subárbol
8579 <p>
8580 Un subárbol se crea como cualquier otro <em>widget</em> GtkTree. Un
8581 subárbol se añade a otro árbol bajo un elemento del mismo, utilizando:
8582
8583 <tscreen><verb>
8584 void gtk_tree_item_set_subtree( GtkTreeItem *elemento_arbol,
8585                                 GtkWidget   *subarbol );
8586 </verb></tscreen>
8587
8588 No necesita llamar a <tt/gtk_widget_show()/ en un subárbol ni antes ni
8589 después de añadirlo a GtkTreeItem. Sin embargo, <em>deberá</em> haber
8590 añadido el GtkTreeItem en cuestión a un árbol padre antes de llamar a
8591 <em/gtk_tree_item_set_subtree()/. Esto se debe a que, técnicamente,
8592 el padre del subárbol <em>no</em> es el GtkTreeItem «propietario»,
8593 sino el GtkTree que contiene al GtkTreeItem.
8594
8595 Cuando le añade un subárbol a un GtkTreeItem, aparece el signo de un
8596 más o de un menos a su lado, donde puede pinchar el usuario para
8597 «expandirlo» u «contraerlo», o sea, para mostrar u ocultar su
8598 subárbol. Los GtkTreeItems están contraídos por defecto. Observe que
8599 cuando contrae un GtkTreeItem, cualquier elemento seleccionado en el
8600 subárbol permanece seleccionado, que puede no coincidir con lo que el
8601 usuario espera.
8602
8603 <sect1> Manejando la lista de selección
8604 <p>
8605 Como con GtkList, GtkTree tiene un campo <tt>selection</tt>, y
8606 es posible controlar el comportamiento del árbol (de alguna manera)
8607 estableciendo el tipo de selección, utilizando:
8608
8609 <tscreen><verb>
8610 void gtk_tree_set_selection_mode( GtkTree          *arbol,
8611                                   GtkSelectionMode  mode );
8612 </verb></tscreen>
8613
8614 La semántica asociada con los distintos modos de selección está
8615 descrita en la sección del <em>widget</em> GtkList. Como ocurría con
8616 el <em>widget</em> GtkList, se enviarán las señales <tt/select_child/,
8617 <tt/unselect_child/ (realmente no - ver <ref id="sec_GtkTree_Signals"
8618 name="Señales"> más adelante para una explicación), y
8619 <tt/selection_changed/ cuando los elementos de la lista sean
8620 seleccionados o deseleccionados. Sin embargo, para aprovechar estas
8621 señales, necesita conocer por medio <em>de que</em> <em>widget</em>
8622 GtkTree serán emitidas, y donde encontrar una lista con los elementos
8623 seleccionados.
8624
8625 Todo esto es una potencial fuente de confusión. La mejor manera de
8626 entenderlo es imaginarse que aunque todos los <em>widgets</em> GtkTree
8627 son creados iguales, algunos son más iguales que otros. Todos los
8628 <em>widgets</em> GtkTree tienen su propia ventana X, y por tanto
8629 pueden recibir eventos como pulsaciones de ratón (¡si sus hijos o
8630 GtkTreeItems no las capturan primero!). Sin embargo, para hacer
8631 que GTK_SELECTION_SINGLE y GTK_SELECTION_BROWSE funcionen bien, la
8632 lista de elementos seleccionados debe ser específica al <em>widget</em>
8633 GtkTree superior de la jerarquia, conocido como el «árbol raíz».
8634
8635 Por tanto no es una buena idea acceder al campo <tt>selection</tt>
8636 directamente en un <em>widget</em> GtkTree arbitrario, a menos que
8637 <em>sepa</em> que es el árbol raíz. En vez de eso, utilice la
8638 macro GTK_TREE_SELECTION (arbol), que da la lista selección del árbol
8639 raíz como un puntero <tt/GList/. Por supuesto, esta lista puede
8640 incluir elementos que no estén en el subárbol en cuestión si el tipo
8641 de selección es GTK_SELECTION_MULTIPLE.
8642
8643 Para terminar, las señales <tt/select_child/ (y tt/unselect_child/, en
8644 teoría) son emitidas por todos los árboles, pero la señal
8645 <em/selection_changed/ es emitida sólo por el árbol raíz. En
8646 consecuencia, si quiere manipular la señal <tt/select_child/ de un
8647 árbol y todos sus subárboles, tendrá que llamar a
8648 <tt/gtk_signal_connect()/ una vez por cada subárbol.
8649
8650 <sect1> Estructura interna del <em>widget</em> árbol
8651 <p>
8652 La definición de la estructura GtkTree es ls siguiente:
8653
8654 <tscreen><verb>
8655 struct _GtkTree
8656 {
8657   GtkContainer container;
8658
8659   GList *child;
8660   
8661   GtkTree* root_tree; /* propietario de la lista de selección */
8662   GtkWidget* tree_owner;
8663   GList *selection;
8664   guint level;
8665   guint indent_value;
8666   guint current_indent;
8667   guint selection_mode : 2;
8668   guint view_mode : 1;
8669   guint view_line : 1;
8670 };
8671 </verb></tscreen>
8672
8673 Ya se han mencionado los peligros asociados con el acceso directo al
8674 campo <tt>selection</tt>. Se puede acceder a los otros campos
8675 importantes de la estructura mediante macros manipuladoras o
8676 funciones de clase. GTK_TREE_IS_ROOT_TREE (arbol) devuelve un valor
8677 booleano que indica si un árbol es árbol raíz de una jerarquia
8678 GtkTree, mientras que GTK_TREE_ROOT_TREE (arbol) devuelve el árbol
8679 raíz, un objeto de tipo GtkTree (recuerde transformarlo utilizando
8680 GTK_WIDGET (arbol) si quiere utilizar con él alguna de la funciones
8681 <tt/gtk_widget_*()/).
8682
8683 En lugar de acceder directamente al campo hijo de un <em>widget</em>
8684 GtkTree, probablemente sea mejor transformarlo utilizando
8685 GTK_CONTAINER (arbol), y pasárselo a la función
8686 <tt/gtk_container_children()/. Con esto crearemos un duplicado de la
8687 lista original, por lo que deberá eliminarlo de la memoria utilizando
8688 <tt/g_list_free()/ después haber hecho con él lo que tenga que hacer,
8689 o bien crear un bucle que lo vaya destruyendo de elemento en elemento,
8690 como por ejemplo así:
8691
8692 <tscreen><verb>
8693 hijo = gtk_container_children (GTK_CONTAINER (arbol));
8694 while (hijo) {
8695   do_something_nice (GTK_TREE_ITEM (hijo->data));
8696   hijo = g_list_remove_link (hijo, hijo);
8697 }
8698 </verb></tscreen>
8699
8700 El campo <tt>tree_owner</tt> sólo está definido en subárboles, donde
8701 apunta al <em>widget</em> GtkTreeItem que contiene al árbol en
8702 cuestión. El campo <tt>level</tt> indica el nivel de profundidad de un
8703 árbol en particular; los árboles raíz tienen un nivel 0, y cada nivel
8704 sucesivo de subárboles tiene un nivel superior al del padre. Sólo se
8705 puede asegurar que este campo contiene un valor correcto después de
8706 que el <em>widget</em> GtkTree se dibuje en la pantalla.
8707
8708 <sect2> Señales<label id="sec_GtkTree_Signals">
8709 <p>
8710 <tscreen><verb>
8711 void selection_changed( GtkTree *arbol );
8712 </verb></tscreen>
8713
8714 Esta señal se emitirá cuando cambie el campo <tt>selection</tt> de
8715 un GtkTree. Esto ocurre cuando se selecciona o deselecciona un hijo del
8716 GtkTree.
8717
8718 <tscreen><verb>
8719 void select_child( GtkTree   *arbol,
8720                    GtkWidget *hijo );
8721 </verb></tscreen>
8722
8723 Esta señal se emite cuando se está seleccionando un hijo del GtkTree.
8724 Esto ocurre en las llamadas a <tt/gtk_tree_select_item()/,
8725 <tt/gtk_tree_select_child()/, en <em>todas</em> las pulsaciones de
8726 botón y llamadas a <tt/gtk_tree_item_toggle()/ y
8727 <tt/gtk_item_toggle()/. Puede que a veces se invoque indirectamente en
8728 otras ocasiones, cuando el hijo se añada o elimine del GtkTree.
8729
8730 <tscreen><verb>
8731 void unselect_child (GtkTree   *arbol,
8732                      GtkWidget *hijo);
8733 </verb></tscreen>
8734
8735 Esta señal se emite cuando se deselecciona un hijo del GtkTree. Con
8736 GTK+ 1.0.4, esto sólo parece ocurrir en las llamadas a
8737 <tt/gtk_tree_unselect_item()/ o a <tt/gtk_tree_unselect_child()/, y quizás
8738 en otras ocasiones, pero <em>no</em> cuando la pulsación de un botón
8739 deselecciona un hijo, y tampoco por la emisión de la señal «toggle»
8740 por <tt/gtk_item_toggle()/.
8741
8742 <sect2> Funciones y macros<label id="sec_GtkTree_Functions">
8743 <p>
8744 <tscreen><verb>
8745 guint gtk_tree_get_type( void );
8746 </verb></tscreen>
8747
8748 Devuelve el identificador de tipo de `GtkTree'.
8749
8750 <tscreen><verb>
8751 GtkWidget* gtk_tree_new( void );
8752 </verb></tscreen>
8753
8754 Crea un nuevo objeto GtkTree. El nuevo <em>widget</em> se devuelve como
8755 un puntero a un objeto GtkWidget. Se devolverá NULL si se produce algún
8756 error.
8757
8758 <tscreen><verb>
8759 void gtk_tree_append( GtkTree   *arbol,
8760                       GtkWidget *elemento_arbol );
8761 </verb></tscreen>
8762
8763 Añade un árbol a un GtkTree.
8764
8765 <tscreen><verb>
8766 void gtk_tree_prepend( GtkTree   *arbol,
8767                        GtkWidget *elemento_arbol );
8768 </verb></tscreen>
8769
8770 Preañade un árbol a un GtkTree.
8771
8772 <tscreen><verb>
8773 void gtk_tree_insert( GtkTree   *arbol,
8774                       GtkWidget *elemento_arbol,
8775                       gint       posicion );
8776 </verb></tscreen>
8777
8778 Inserta un árbol en un GtkTree en la posición de la lista especificada
8779 por <tt>posicion.</tt>
8780
8781 <tscreen><verb>
8782 void gtk_tree_remove_items( GtkTree *arbol,
8783                             GList   *items );
8784 </verb></tscreen>
8785
8786 Elimina una lista de elementos (en forma de una <tt/GList */) de un
8787 GtkTree. Eliminar un elemento de un árbol lo dereferencia (y por tanto
8788 normalmente) lo destruye (""), a él <em>y</em> a su subárbol, de
8789 haberlo, <em>y</em> a todos los subárboles que contenga ese
8790 subárbol. Si quiere eliminar sólo un elemento, deberá utilizar
8791 <tt/gtk_container_remove()/.
8792
8793 <tscreen><verb>
8794 void gtk_tree_clear_items( GtkTree *arbol,
8795                            gint     start,
8796                            gint     end );
8797 </verb></tscreen>
8798
8799 Elimina los elementos de un GtkTree desde la posición <tt>start</tt>
8800 hasta la posición <tt>end</tt>. De nuevo hay que llevarse cuidado
8801 con donde se aplica la dereferencia, ya que <tt/gtk_tree_clear_items()/
8802 simplemente construye una lista y se la pasa a
8803 <tt/gtk_tree_remove_items()/.
8804
8805 <tscreen><verb>
8806 void gtk_tree_select_item( GtkTree *arbol,
8807                            gint     item );
8808 </verb></tscreen>
8809
8810 Emite la señal <tt/select_item/ para el hijo que se encuentra en la
8811 posición <tt>item</tt>, y por tanto selecciona a ese hijo (a menos que
8812 lo deseleccione en un manejador de señal...)
8813
8814 <tscreen><verb>
8815 void gtk_tree_unselect_item( GtkTree *arbol,
8816                              gint     item );
8817 </verb></tscreen>
8818
8819 Emite la señal <tt/unselect_item/ para el hijo en la posición
8820 <tt>item</tt>, y por tanto deselecciona al hijo.
8821
8822 <tscreen><verb>
8823 void gtk_tree_select_child( GtkTree   *arbol,
8824                             GtkWidget *elemento_arbol );
8825 </verb></tscreen>
8826
8827 Emite la señal <tt/select_item/ para el hijo <tt>elemento_arbol</tt>, y por tanto
8828 lo selecciona.
8829
8830 <tscreen><verb>
8831 void gtk_tree_unselect_child( GtkTree   *arbol,
8832                               GtkWidget *elemento_arbol );
8833 </verb></tscreen>
8834
8835 Emite la señal <tt/unselect_item/ para el hijo <tt>elemento_arbol</tt>, y por
8836 tanto lo deselecciona.
8837
8838 <tscreen><verb>
8839 gint gtk_tree_child_position( GtkTree   *arbol,
8840                               GtkWidget *hijo );
8841 </verb></tscreen>
8842
8843 Devuelve la posición en el árbol de <tt>child</tt>, a menos que
8844 <tt>child</tt> no esté en el árbol, en cuya caso devuelve -1.
8845
8846 <tscreen><verb>
8847 void gtk_tree_set_selection_mode( GtkTree          *arbol,
8848                                   GtkSelectionMode  mode );
8849 </verb></tscreen>
8850
8851 Establece el modo de selección, que puede ser uno de los siguientes
8852 GTK_SELECTION_SINGLE (por defecto), GTK_SELECTION_BROWSE,
8853 GTK_SELECTION_MULTIPLE, o GTK_SELECTION_EXTENDED. Esto sólo está
8854 definido para los árboles raíz, que es donde tiene sentido, ya que el
8855 árbol raíz es el «propietario» de la selección. Establecer este
8856 valor en un subárbol no tiene ningún efecto en absoluto; el valor
8857 simplemente será ignorado.
8858
8859 <tscreen><verb>
8860 void gtk_tree_set_view_mode( GtkTree         *arbol,
8861                              GtkTreeViewMode  mode ); 
8862 </verb></tscreen>
8863
8864 Establece el «modo de visión», que puede ser o GTK_TREE_VIEW_LINE
8865 (por defecto) o GTK_TREE_VIEW_ITEM. El modo de visión se propaga
8866 de un árbol a sus subárboles, y no puede establecerse en exclusiva
8867 para un subárbol (esto no es exacto del todo - vea los comentarios en el
8868 código de ejemplo).
8869
8870 El termino «modo de visión» es algo ambiguo - básicamente, controla
8871 la forma en que se resalta a uno de los hijos del árbol cuando es
8872 seleccionado. Si es GTK_TREE_VIEW_LINE, se resaltará el
8873 <em>widget</em> GtkTreeItem completo, mientras que si es
8874 GTK_TREE_VIEW_ITEM, sólo se resaltará el <em>widget</em> hijo (es
8875 decir, lo que normalmente es la etiqueta).
8876
8877 <tscreen><verb>
8878 void gtk_tree_set_view_lines( GtkTree *arbol,
8879                               guint    flag );
8880 </verb></tscreen>
8881
8882 Controla si se dibujarán las líneas de conexión entre los elementos
8883 del árbol. <tt>flag</tt> es o TRUE, en cuyo caso se dibujarán, o
8884 FALSE, en cuyo caso no se dibujarán.
8885
8886 <tscreen><verb>
8887 GtkTree *GTK_TREE (gpointer obj);
8888 </verb></tscreen>
8889
8890 Convierte un puntero genérico a `GtkTree *'.
8891
8892 <tscreen><verb>
8893 GtkTreeClass *GTK_TREE_CLASS (gpointer class);
8894 </verb></tscreen>
8895
8896 Convierte un puntero genérico a `GtkTreeClass *'.
8897
8898 <tscreen><verb>
8899 gint GTK_IS_TREE (gpointer obj);
8900 </verb></tscreen>
8901
8902 Determina si un puntero genérico se refiere a un objeto `GtkTree'.
8903
8904 <tscreen><verb>
8905 gint GTK_IS_ROOT_TREE (gpointer obj)
8906 </verb></tscreen>
8907
8908 Determina si un puntero genérico se refiere a un objeto `GtkTree'
8909 <em>y</em> es un árbol raíz. Aunque la función acepta cualquier
8910 puntero, los resultados de pasarle un puntero que no se refiera
8911 a un GtkTree no están definidos y probablemente no tengan ningún
8912 sentido.
8913
8914 <tscreen><verb>
8915 GtkTree *GTK_TREE_ROOT_TREE (gpointer obj)
8916 </verb></tscreen>
8917
8918 Devuelve el árbol raíz de un puntero a un objeto `GtkTree'. Seguimos
8919 con el mismo problema que en el caso anterior.
8920
8921 <tscreen><verb>
8922 GList *GTK_TREE_SELECTION(gpointer obj)
8923 </verb></tscreen>
8924
8925 Devuelve la lista de selección del árbol raíz de un objeto
8926 `GtkTree'. Seguimos con el mismo problema que antes.
8927
8928 <sect1> El <em>widget</em> elemento de árbol<label id="sec_Tree_Item_Widget">
8929 <p>
8930 El <em>widget</em> GtkTreeItem, cómo el GtkListItem, está derivado
8931 de GtkItem, que de nuevo, está derivado de GtkBin. Sin embargo, el
8932 elemento en sí mismo es un contenedor genérico que contiene un
8933 <em>widget</em> hijo, que puede ser de cualquier tipo. El <em>widget</em>
8934 GtkTreeItem tiene ciertos campos extra, pero el único que nos
8935 interesa ahora es el campo <em>subárbol</em>.
8936
8937 La definición de la estructura GtkTreeItem es así:
8938
8939 <tscreen><verb>
8940 struct _GtkTreeItem
8941 {
8942   GtkItem item;
8943
8944   GtkWidget *subtree;
8945   GtkWidget *pixmaps_box;
8946   GtkWidget *plus_pix_widget, *minus_pix_widget;
8947
8948   GList *pixmaps    /* nodo pixmap para esta profundidad de color */
8949
8950   guint expanded : 1;
8951 };
8952 </verb></tscreen>
8953
8954 El campo <tt>pixmaps_box</tt> es un GtkEventBox que caza las pulsaciones
8955 en el símbolo más/menos que controla la expansión y contracción. El
8956 campo <tt>pixmaps</tt> apunta a una estructura de datos interna. Ya que
8957 siempre puede obtener el subárbol de un GtkTreeItem de una forma
8958 (relativamente) segura mediante la macro GTK_TREE_ITEM_SUBTREE (Item),
8959 es aconsejable no tocar las tripas de un GtkTreeItem a menos que
8960 <em>realmente</em> sepa que es lo que está haciendo.
8961
8962 Ya que está derivado directamente de un GtkItem, puede tratarse como
8963 tal utilizando la macro GTK_ITEM (ElementoArbol). Un GtkTreeItem normalmente
8964 tiene una etiqueta, por lo que tenemos a nuestra disposición la
8965 función gtk_list_item_new_with_label(). Podemos conseguir el mismo
8966 efecto utilizando código como el siguiente, que por ahora es sólo
8967 una copia de la función gtk_tree_item_new_with_label():
8968
8969 <tscreen><verb>
8970 elemento_arbol = gtk_tree_item_new ();
8971 etiqueta_widget = gtk_label_new (etiqueta);
8972 gtk_misc_set_alignment (GTK_MISC (etiqueta_widget), 0.0, 0.5);
8973
8974 gtk_container_add (GTK_CONTAINER (elemento_arbol), etiqueta_widget);
8975 gtk_widget_show (etiqueta_widget);
8976 </verb></tscreen>
8977
8978 Cómo no es obligatorio añadir una GtkLabel a un GtkTreeItem, puede
8979 también añadirle un GtkHBox o una GtkArrow, o hasta un GtkNotebook
8980 (aunque en esos casos su aplicación no será muy popular).
8981
8982 Si elimina todos los elementos de un subárbol, será destruido
8983 y se eliminará la información sobre su padre, a menos que lo
8984 referencie de antemano, además el GtkTreeItem que sea su propietario
8985 se colapsará. Por lo tanto, si quiere que se mantenga el subárbol
8986 tendrá que hacer algo así:
8987
8988 <tscreen><verb>
8989 gtk_widget_ref (arbol);
8990 propietario = GTK_TREE(arbol)->tree_owner;
8991 gtk_container_remove (GTK_CONTAINER(arbol), item);
8992 if (arbol->parent == NULL){
8993   gtk_tree_item_expand (GTK_TREE_ITEM(propietario));
8994   gtk_tree_item_set_subtree (GTK_TREE_ITEM(propietario), arbol);
8995 }
8996 else
8997   gtk_widget_unref (arbol);
8998 </verb></tscreen>
8999
9000 Finalmente, hay que mencionar que la opción de drag-n-drop (arrastar y
9001 soltar) <em>funciona</em> con los GtkTreeItems. Sólo tiene que
9002 asegurarse de que el GtkTreeItem que quiere convertir en un elemento
9003 de arrastre o en un lugar en el que, además de haber sido añadido a
9004 GtkTree, sino que además cada su <em>widget</em> padre tiene a su vez
9005 un padre, y así hasta llegar al nivel más alto o ventana de diálogo,
9006 cuando llamamos a <tt/gtk_widget_dnd_drag_set()/ o
9007 <tt/gtk_widget_dnd_drop_set()/. En caso contrario, podrían ocurrir
9008 cosas extrañas.
9009
9010 <sect2> Señales
9011 <p>
9012 GtkTreeItem hereda las señales <tt/select/, <tt/deselect/, y
9013 <tt/toggle/ de GtkItem. Además, añade dos señales propias, <tt/expand/
9014 y <tt/collapse/.
9015
9016 <tscreen><verb>
9017 void select( GtkItem *elemento_arbol );
9018 </verb></tscreen>
9019
9020 Esta señal se emite cuando un elemento está siendo seleccionado,
9021 o bien después de que el usuario pinche en él, o bien cuando
9022 el programa llame a <tt/gtk_tree_item_select()/,
9023 <tt/gtk_item_select()/, o a <tt/gtk_tree_select_child()/.
9024
9025 <tscreen><verb>
9026 void deselect( GtkItem *elemento_arbol );
9027 </verb></tscreen>
9028
9029 Esta señal se emite cuando un elemento está siendo deseleccionado,
9030 o bien después de que el usuario pinche en él, o bien cuando
9031 el programa llame a <tt/gtk_tree_item_deselect()/ o a
9032 <tt/gtk_item_deselect()/. En el caso de GtkTreeItems, también se
9033 emitirá por <tt/gtk_tree_unselect_child()/, y a veces por
9034 <tt/gtk_tree_select_child()/.
9035
9036 <tscreen><verb>
9037 void toggle( GtkItem *elemento_arbol );
9038 </verb></tscreen>
9039
9040 Esta señal se emite cuando el programa llama a <tt/gtk_item_toggle()/. El
9041 efecto que tiene cuando se emite en un GtkTreeItem es llamar a
9042 <tt/gtk_tree_select_child()/ (y nunca a
9043 <tt/gtk_tree_unselect_child()/) en el árbol padre del elemento, si el
9044 elemento tiene un árbol padre. Si no lo tiene, entonces se cambiará el
9045 resaltado del elemento.
9046
9047 <tscreen><verb>
9048 void expand( GtkTreeItem *elemento_arbol );
9049 </verb></tscreen>
9050
9051 Esta señal se emite cuando se está expandiendo el subárbol del
9052 elemento, esto es, cuando el usuario pincha en el signo más que
9053 hay al lado del elemento, o cuando el programa llama a
9054 <tt/gtk_tree_item_expand()/.
9055
9056 <tscreen><verb>
9057 void collapse( GtkTreeItem *elemento_arbol );
9058 </verb></tscreen>
9059
9060 Esta señal se emite cuando se está contrayendo el subárbol del
9061 elemento, esto es, cuando el usuario pincha en el signo menos que hay
9062 al lado del elemento, o cuando el programa llama a
9063 <tt/gtk_tree_item_collapse()/.
9064
9065 <sect2> Funciones y Macros
9066 <p>
9067 <tscreen><verb>
9068 guint gtk_tree_item_get_type( void );
9069 </verb></tscreen>
9070
9071 Devuelve el identificador de tipo de `GtkTreeItem'.
9072
9073 <tscreen><verb>
9074 GtkWidget* gtk_tree_item_new( void );
9075 </verb></tscreen>
9076
9077 Crea un nuevo objeto GtkTreeItem. El nuevo <em>widget</em> se devuelve
9078 como un puntero a un objeto GtkWidget. Se devolverá NULL si hay algún
9079 fallo.
9080
9081 <tscreen><verb>
9082 GtkWidget* gtk_tree_item_new_with_label (gchar       *etiqueta);
9083 </verb></tscreen>
9084
9085 Crea un nuevo objeto GtkTreeItem, teniendo una simple GtkLabel
9086 como único hijo. El nuevo <em>widget</em> se devolverá como
9087 un puntero a un objeto GtkWidget. Se devolverá NULL en caso
9088 de haber algún fallo.
9089
9090 <tscreen><verb>
9091 void gtk_tree_item_select( GtkTreeItem *elemento_arbol );
9092 </verb></tscreen>
9093
9094 Esta función es básicamente un recubrimiento de una llamada a
9095 gtk_item_select (GTK_ITEM (elemento_arbol)) que emitirá la
9096 señal select.
9097
9098 <tscreen><verb>
9099 void gtk_tree_item_deselect( GtkTreeItem *elemento_arbol );
9100 </verb></tscreen>
9101
9102 Esta función es básicamente un recubrimiento de una llamada a
9103 gtk_item_deselect (GTK_ITEM (elemento_arbol)) que emitirá la
9104 señal deselect.
9105
9106 <tscreen><verb>
9107 void gtk_tree_item_set_subtree( GtkTreeItem *elemento_arbol,
9108                                 GtkWidget   *subarbol );
9109 </verb></tscreen>
9110
9111 Esta función añade <tt/subarbol/ a <tt/elemento_arbol/, mostrándolo si
9112 <tt/elemento_arbol/ está expandido, u ocultándolo si <tt/elemento_arbol/ está
9113 contraído. De nuevo, recuerde que el <tt/elemento_arbol/ ya debe de haber
9114 sido añadido a un árbol para que esto funcione.
9115
9116 <tscreen><verb>
9117 void gtk_tree_item_remove_subtree( GtkTreeItem *elemento_arbol );
9118 </verb></tscreen>
9119
9120 Esto elimina todos los hijos de los subárboles del <tt/elemento_arbol/
9121 (esto es, dereferencia y destruye a los subárboles hijos, y a los
9122 hijos de los hijos y...), entonces elimina el subárbol en si mismo, y
9123 oculta el signo más/menos.
9124
9125 <tscreen><verb>
9126 void gtk_tree_item_expand( GtkTreeItem *elemento_arbol );
9127 </verb></tscreen>
9128
9129 Esto emite la señal «expand» para el <tt/elemento_arbol/, que lo
9130 expande.
9131
9132 <tscreen><verb>
9133 void gtk_tree_item_collapse( GtkTreeItem *elemento_arbol );
9134 </verb></tscreen>
9135
9136 Esto emite la señal «collapse» en el <tt/elemento_arbol/, que lo
9137 contrae.
9138
9139 <tscreen><verb>
9140 GtkTreeItem *GTK_TREE_ITEM (gpointer obj)
9141 </verb></tscreen>
9142
9143 Convierte un puntero genérico en un `GtkTreeItem *'.
9144
9145 <tscreen><verb>
9146 GtkTreeItemClass *GTK_TREE_ITEM_CLASS (gpointer obj)
9147 </verb></tscreen>
9148
9149 Convierte un puntero genérico en un `GtkTreeItemClass'.
9150
9151 <tscreen><verb>
9152 gint GTK_IS_TREE_ITEM (gpointer obj)
9153 </verb></tscreen>
9154
9155 Determina si un puntero genérico se refiere a un objeto `GtkTreeItem'.
9156  
9157 <tscreen><verb>
9158 GtkWidget GTK_TREE_ITEM_SUBTREE (gpointer obj)
9159 </verb></tscreen>
9160
9161 Devuelve un subárbol del elemento (<tt/obj/ debería apuntar a un
9162 objeto `GtkTreeItem').
9163
9164 <sect1> Árbol ejemplo
9165 <p>
9166 Este ejemplo es muy parecido al árbol ejemplo que hay en
9167 <tt/testgtk.c/, pero mucho menos completo (aunque mucho mejor
9168 comentado). Pone una ventana con un árbol, y conecta todas las señales
9169 de los objetos relevantes, con lo que podrá ver cuando se emiten.
9170
9171 <!-- Hay un comentario en el código que no se traducir -->
9172 <tscreen><verb>
9173 /* principio del ejemplo tree tree.c */
9174
9175 #include <gtk/gtk.h>
9176
9177 /* para todas las señales GtkItem:: y GtkTreeItem:: */
9178 static void cb_itemsignal (GtkWidget *item, gchar *signame)
9179 {
9180   gchar *name;
9181   GtkLabel *etiqueta;
9182
9183   /* Es un GtkBin, por lo que tiene un hijo, que sabemos que es una
9184    * etiqueta, por lo que la cogemos */
9185   etiqueta = GTK_LABEL (GTK_BIN (item)->child);
9186   /* Conseguimos el texto de la etiqueta */
9187   gtk_label_get (etiqueta, &amp;name);
9188   /* Conseguimos el nivel del árbol en el que se encuentra el elemento */
9189   g_print ("%s called for item %s->%p, level %d\n", signame, name,
9190            item, GTK_TREE (item->parent)->level);
9191 }
9192
9193 /* nunca se llamará a esta función */
9194 static void cb_unselect_child (GtkWidget *arbol_raiz, GtkWidget *hijo,
9195                                GtkWidget *subarbol)
9196 {
9197   g_print ("unselect_child called for root tree %p, subtree %p, child %p\n",
9198            arbol_raiz, subarbol, hijo);
9199 }
9200
9201 /* Se llamará a esta función cada vez que el usuario pulse en un
9202  * elemento, esté o no seleccionado. */
9203    whether it is already selected or not. */
9204 static void cb_select_child (GtkWidget *arbol_raiz, GtkWidget *hijo,
9205                              GtkWidget *subarbol)
9206 {
9207   g_print ("select_child called for root tree %p, subtree %p, child %p\n",
9208            arbol_raiz, subarbol, hijo);
9209 }
9210
9211 static void cb_selection_changed (GtkWidget *arbol)
9212 {
9213   GList *i;
9214   
9215   g_print ("selection_change called for tree %p\n", arbol);
9216   g_print ("selected objects are:\n");
9217
9218   i = GTK_TREE_SELECTION(arbol);
9219   while (i){
9220     gchar *name;
9221     GtkLabel *etiqueta;
9222     GtkWidget *item;
9223
9224     /* Get a GtkWidget pointer from the list node */
9225     item = GTK_WIDGET (i->data);
9226     etiqueta = GTK_LABEL (GTK_BIN (item)->child);
9227     gtk_label_get (etiqueta, &amp;name);
9228     g_print ("\t%s on level %d\n", name, GTK_TREE
9229              (item->parent)->level);
9230     i = i->next;
9231   }
9232 }
9233
9234 int main (int argc, char *argv[])
9235 {
9236   GtkWidget *ventana, *scrolled_win, *arbol;
9237   static gchar *itemnames[] = {"Foo", "Bar", "Baz", "Quux",
9238                                "Maurice"};
9239   gint i;
9240
9241   gtk_init (&amp;argc, &amp;argv);
9242
9243   /* una ventana general */
9244   ventana = gtk_window_new (GTK_WINDOW_TOPLEVEL);
9245   gtk_signal_connect (GTK_OBJECT(ventana), "delete_event",
9246                       GTK_SIGNAL_FUNC (gtk_main_quit), NULL);
9247   gtk_container_border_width (GTK_CONTAINER(ventana), 5);
9248
9249   /* una ventana con barras de desplazamiento */
9250   scrolled_win = gtk_scrolled_window_new (NULL, NULL);
9251   gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled_win),
9252                                   GTK_POLICY_AUTOMATIC,
9253                                   GTK_POLICY_AUTOMATIC);
9254   gtk_widget_set_usize (scrolled_win, 150, 200);
9255   gtk_container_add (GTK_CONTAINER(ventana), scrolled_win);
9256   gtk_widget_show (scrolled_win);
9257   
9258   /* Crear el árbol raíz */
9259   arbol = gtk_tree_new();
9260   g_print ("root tree is %p\n", arbol);
9261   /* connect all GtkTree:: signals */
9262   gtk_signal_connect (GTK_OBJECT(arbol), "select_child",
9263                       GTK_SIGNAL_FUNC(cb_select_child), arbol);
9264   gtk_signal_connect (GTK_OBJECT(arbol), "unselect_child",
9265                       GTK_SIGNAL_FUNC(cb_unselect_child), arbol);
9266   gtk_signal_connect (GTK_OBJECT(arbol), "selection_changed",
9267                       GTK_SIGNAL_FUNC(cb_selection_changed), arbol);
9268   /* Añadirlo a la ventana con barras de desplazamiento */
9269   gtk_container_add (GTK_CONTAINER(scrolled_win), arbol);
9270   /* Poner el modo de selección */
9271   gtk_tree_set_selection_mode (GTK_TREE(arbol),
9272                                GTK_SELECTION_MULTIPLE);
9273   /* mostrar el árbol */
9274   gtk_widget_show (arbol);
9275
9276   for (i = 0; i < 5; i++){
9277     GtkWidget *subarbol, *item;
9278     gint j;
9279
9280     /* Crear un elemento del árbol */
9281     item = gtk_tree_item_new_with_label (itemnames[i]);
9282     /* Conectar todas las señales GtkItem:: y GtkTreeItem:: */
9283     gtk_signal_connect (GTK_OBJECT(item), "select",
9284                         GTK_SIGNAL_FUNC(cb_itemsignal), "select");
9285     gtk_signal_connect (GTK_OBJECT(item), "deselect",
9286                         GTK_SIGNAL_FUNC(cb_itemsignal), "deselect");
9287     gtk_signal_connect (GTK_OBJECT(item), "toggle",
9288                         GTK_SIGNAL_FUNC(cb_itemsignal), "toggle");
9289     gtk_signal_connect (GTK_OBJECT(item), "expand",
9290                         GTK_SIGNAL_FUNC(cb_itemsignal), "expand");
9291     gtk_signal_connect (GTK_OBJECT(item), "collapse",
9292                         GTK_SIGNAL_FUNC(cb_itemsignal), "collapse");
9293     /* Añadirlo al árbol padre */
9294     gtk_tree_append (GTK_TREE(arbol), item);
9295     /* Mostrarlo - esto se puede hacer en cualquier momento */
9296     gtk_widget_show (item);
9297     /* Crear el subárbol de este elemento */
9298     subarbol = gtk_tree_new();
9299     g_print ("-> item %s->%p, subtree %p\n", itemnames[i], item,
9300              subarbol);
9301
9302     /* Esto todavía es necesario si quiere que se llamen a están
9303      * señales en el subárbol hijo.  Note that selection_change will
9304      * be signalled for the root tree regardless. */
9305     gtk_signal_connect (GTK_OBJECT(subarbol), "select_child",
9306                         GTK_SIGNAL_FUNC(cb_select_child), subarbol);
9307     gtk_signal_connect (GTK_OBJECT(subarbol), "unselect_child",
9308                         GTK_SIGNAL_FUNC(cb_unselect_child), subarbol);
9309     /* Esto no tiene absolutamente ningún efecto, ya que se ignora
9310      * completamente en los subárboles */
9311     gtk_tree_set_selection_mode (GTK_TREE(subarbol),
9312                                  GTK_SELECTION_SINGLE);
9313     /* Esto tampoco hace nada, pero por una razón diferente - los
9314      * valores view_mode y view_line de un árbol se propagan a los
9315      * subárboles cuando son mapeados. Por tanto, establecer los
9316      * valores después actualmente tendría (algún impredecible) efecto
9317      */
9318     gtk_tree_set_view_mode (GTK_TREE(subarbol), GTK_TREE_VIEW_ITEM);
9319     /* Establecer este subárbol del elemento - ¡Recuerde que no puede
9320      * hacerlo hasta que se haya añadido a su árbol padre! */
9321     gtk_tree_item_set_subtree (GTK_TREE_ITEM(item), subarbol);
9322
9323     for (j = 0; j < 5; j++){
9324       GtkWidget *subitem;
9325
9326       /* Crea un elemento subárbol, más o menos lo mismo de antes */
9327       subitem = gtk_tree_item_new_with_label (itemnames[j]);
9328       /* Conectar todas las señales GtkItem:: y GtkTreeItem:: */
9329       gtk_signal_connect (GTK_OBJECT(subitem), "select",
9330                           GTK_SIGNAL_FUNC(cb_itemsignal), "select");
9331       gtk_signal_connect (GTK_OBJECT(subitem), "deselect",
9332                           GTK_SIGNAL_FUNC(cb_itemsignal), "deselect");
9333       gtk_signal_connect (GTK_OBJECT(subitem), "toggle",
9334                           GTK_SIGNAL_FUNC(cb_itemsignal), "toggle");
9335       gtk_signal_connect (GTK_OBJECT(subitem), "expand",
9336                           GTK_SIGNAL_FUNC(cb_itemsignal), "expand");
9337       gtk_signal_connect (GTK_OBJECT(subitem), "collapse",
9338                           GTK_SIGNAL_FUNC(cb_itemsignal), "collapse");
9339       g_print ("-> -> item %s->%p\n", itemnames[j], subitem);
9340       /* Añadirlo a su árbol padre */
9341       gtk_tree_append (GTK_TREE(subarbol), subitem);
9342       /* Mostrarlo */
9343       gtk_widget_show (subitem);
9344     }
9345   }
9346
9347   /* Mostrar la ventana y entrar en el bucle final */
9348   gtk_widget_show (ventana);
9349   gtk_main();
9350   return 0;
9351 }
9352 /* fin del ejemplo */
9353 </verb></tscreen>
9354
9355 <!-- ***************************************************************** -->
9356 <sect> El <em>widget</em> menú
9357 <!-- ***************************************************************** -->
9358 <p>
9359 Hay dos formas de crear menús, la fácil, y la difícil. Ambas tienen su
9360 utilidad, aunque lo más probable es que normalmente utilice la
9361 menufactory (la forma fácil). La forma «difícil» consiste en crear
9362 todos los menús utilizando las llamadas directamente. La forma fácil
9363 consiste en utilizar las llamadas de <tt/gtk_item_factory/. Es mucho
9364 más fácil, pero aun así cada aproximación tiene sus ventajas y sus
9365 inconvenientes.
9366
9367 La menufactory es mucho más fácil de utilizar, y tambíen es más fácil
9368 añadir nuevos menús, aunque a larga, escribiendo unas cuántas
9369 funciones de recubrimiento para crear menús utilizando el método
9370 manual puede acabar siendo más útil. Con la itemfactory, no es posible
9371 añadir imágenes o el carácter `/' a los menús.
9372
9373 <!-- ----------------------------------------------------------------- -->
9374 <sect1>Creación manual de menús
9375 <p>
9376 Siguiendo la auténtica tradición de la enseñanza, vamos a enseñarle
9377 primero la forma difícil. <tt>:)</tt>
9378
9379 Se utilizan tres <em>widgets</em> para hacer una barra de menús y
9380 submenús:
9381 <itemize>
9382 <item>un elemento del menú, que es lo que el usuario quiere seleccionar,
9383 p.e. 'Guardar'
9384 <item>un menú, que actua como un contenedor para los elementos del menú, y
9385 <item>una barra de menú, que es un contenedor para cada uno de los menús,
9386 </itemize>
9387
9388 Todo esto se complica ligeramente por el hecho de que los
9389 <em>widgets</em> de los elementos del menú se utilizan para dos cosas
9390 diferentes. Están los <em>widgets</em> que se empaquetan en el menú, y
9391 los que se empaquetan en una barra de menús, que cuando se selecciona,
9392 activa el menú.
9393
9394 Vamos a ver las funciones que se utilizan para crear menús y barras
9395 de menús. ésta primera función se utiliza para crear una barra de menús.
9396
9397 <tscreen><verb>
9398 GtkWidget *gtk_menu_bar_new( void );
9399 </verb></tscreen>
9400
9401 Como el propio nombre indica, esta función crea una nueva barra de
9402 menús. Utilice <tt/gtk_container_add/ para empaquetarla en una
9403 ventana, o las funciones <tt/box_pack/ para empaquetarla en una caja -
9404 exactamente igual que si fuesen botones.
9405
9406 <tscreen><verb>
9407 GtkWidget *gtk_menu_new( void );
9408 </verb></tscreen>
9409
9410 Esta función devuelve un puntero a un nuevo menú, que no se debe
9411 mostrar nunca (no hace falta utilizar <tt/gtk_widget_show/), es sólo
9412 un contenedor para los elementos del menú. Espero que todo esto se
9413 aclare un poco cuando vea en el ejemplo que hay más abajo.
9414
9415 Las siguientes dos llamadas se utilizan para crear elementos de menú
9416 que se empaquetarán en el menú (y en la barra de menú).
9417
9418 <tscreen><verb>
9419 GtkWidget *gtk_menu_item_new( void );
9420 </verb></tscreen>
9421
9422 y
9423
9424 <tscreen><verb>
9425 GtkWidget *gtk_menu_item_new_with_label( const char *etiqueta );
9426 </verb></tscreen>
9427
9428 Estas llamadas se utilizan para crear los elementos del menú que
9429 van a mostrarse. Recuerde que hay que distinguir entre un «menú»
9430 creado con <tt/gtk_menu_new/ y un «elemento del menú» creado con las
9431 funciones <tt/gtk_menu_item_new/. El elemento de menú será un botón
9432 con una acción asociada, y un menú será un contenedor con los
9433 elementos del menú.
9434
9435 Las funciones <tt/gtk_menu_new_with_label/ y <tt/gtk_menu_new/ son
9436 sólo lo que espera que sean después de leer lo de los botones. Una
9437 crea un nuevo elemento del menú con una etiqueta ya dentro, y la otra
9438 crea un elemento del menú en blanco.
9439
9440 Una vez ha creado un elemento del menú tiene que ponerlo en un menú.
9441 Esto se hace utilizando la función <tt/gtk_menu_append/. Para capturar
9442 el momento en el que el elemento se selecciona por el usuario,
9443 necesitamos conectar con la señal <tt/activate/ de la forma usual. Por
9444 tanto, si quiere crear un menú estándar <tt/File/, con las opciones
9445 <tt/Open/, <tt/Save/ y <tt/Quit/ el código debería ser algo como
9446
9447 <tscreen><verb>
9448 file_menu = gtk_menu_new();    /* No hay que mostrar menús */
9449
9450 /* Crear los elementos del menú */
9451 open_item = gtk_menu_item_new_with_label("Open");
9452 save_item = gtk_menu_item_new_with_label("Save");
9453 quit_item = gtk_menu_item_new_with_label("Quit");
9454
9455 /* Añadirlos al menú */
9456 gtk_menu_append( GTK_MENU(file_menu), open_item);
9457 gtk_menu_append( GTK_MENU(file_menu), save_item);
9458 gtk_menu_append( GTK_MENU(file_menu), quit_item);
9459
9460 /* Enlazar las función de llamada a la señal "activate" */
9461 gtk_signal_connect_object( GTK_OBJECT(open_items), "activate",
9462                            GTK_SIGNAL_FUNC(menuitem_response), (gpointer) "file.open");
9463 gtk_signal_connect_object( GTK_OBJECT(save_items), "activate",
9464                            GTK_SIGNAL_FUNC(menuitem_response), (gpointer) "file.save");
9465
9466 /* Podemos enlazar el elemento de menú Quit con nuestra función de
9467  * salida */
9468 gtk_signal_connect_object( GTK_OBJECT(quit_items), "activate",
9469                            GTK_SIGNAL_FUNC(destroy), (gpointer) "file.quit");
9470
9471 /* Tenemos que mostrar los elementos del menú */We do need to show menu items */
9472 gtk_widget_show( open_item );
9473 gtk_widget_show( save_item );
9474 gtk_widget_show( quit_item );
9475 </verb></tscreen>
9476
9477 En este momento tendremos nuestro menú. Ahora necesitamos crear una
9478 barra de menús y un elemento de menú para el elemento <tt/File/, que
9479 vamos a añadir a nuestro menú. El código es el siguiente
9480
9481 <tscreen><verb>
9482 menu_bar = gtk_menu_bar_new();
9483 gtk_container_add( GTK_CONTAINER(ventana), menu_bar);
9484 gtk_widget_show( menu_bar );
9485
9486 file_item = gtk_menu_item_new_with_label("File");
9487 gtk_widget_show(file_item);
9488 </verb></tscreen>
9489
9490 Ahora necesitamos asociar el menú con <tt/file_item/. Esto se hace con
9491 la función
9492
9493 <tscreen>
9494 void gtk_menu_item_set_submenu( GtkMenuItem *menu_item,
9495                                 GtkWidget   *submenu );
9496 </tscreen>
9497
9498 Por lo que nuestro ejemplo continua con
9499
9500 <tscreen><verb>
9501 gtk_menu_item_set_submenu( GTK_MENU_ITEM(file_item), file_menu );
9502 </verb></tscreen>
9503
9504 Todo lo que queda por hacer es añadir el menú a la barra de menús, que
9505 se hace mediante la función
9506
9507 <tscreen>
9508 void gtk_menu_bar_append( GtkMenuBar *menu_bar, GtkWidget *menu_item);
9509 </tscreen>
9510
9511 que en nuestro caso habrá que utilizar así:
9512
9513 <tscreen><verb>
9514 gtk_menu_bar_append( GTK_MENU_BAR (menu_bar), file_item );
9515 </verb></tscreen>
9516
9517 Si queremos que el menú esté alineado a la derecha en la barra de
9518 menús, como suele estar la opción de ayuda, podemos utilizar la
9519 función siguiente (otra vez en <tt/file_item/ en el ejemplo actual)
9520 antes de enlazarla en la barra de menú.
9521
9522 <tscreen><verb>
9523 void gtk_menu_item_right_justify( GtkMenuItem *menu_item );
9524 </verb></tscreen>
9525
9526 Aquí hay un resumen de los pasos que son necesarios para crear una
9527 barra de menús con los menús correspondientes ya enlazados:
9528
9529 <itemize>
9530 <item> Crear un nuevo menú utilizando <tt/gtk_menu_new()/
9531 <item> Utilizar multiples llamadas a <tt/gtk_menu_item_new()/ para
9532 cada elemento que desee tener en su menú. Y utilizar
9533 <tt/gtk_menu_append()/ para poner cada uno de esos nuevos elementos en
9534 el menú.
9535 <item> Crear un elemento de menú utilizando
9536 <tt/gtk_menu_item_new()/. Ésta será la raíz del menú, el texto que
9537 aparezca aquí estará en la barra de menús.
9538 <item> Utilizar <tt/gtk_menu_item_set_submenu()/ para enlazar el menú
9539 al elemento del menú raíz (el creado en el paso anterior).
9540 <item> Crear una nueva barra de menús utilizando
9541 <tt/gtk_menu_bar_new/. Este paso solo necesita hacerse una vez cuando
9542 se crea una serie de menús en una barra de menús.
9543 <item> Utilizar <tt/gtk_menu_bar_append/ para poner el menú raíz en la
9544 barra de menús.
9545 </itemize>
9546
9547 Para hacer un menú desplegable hay que seguir prácticamente los mismos
9548 pasos. La única diferencia es que el menú no estará conectado
9549 `automáticamente' a una barra de menú, sino que para que aparezca
9550 deberá llamarse explícitamente a la función <tt/gtk_menu_popup()/
9551 utilizando, por ejemplo, un evento de pulsación de botón. Siga los
9552 pasos siguientes:
9553
9554 <itemize>
9555 <item>Cree una función manejadora de eventos. Tiene que tener el
9556 siguiente prototipo
9557 <tscreen>
9558 static gint handler( GtkWidget *widget,
9559                      GdkEvent  *event );
9560 </tscreen>
9561
9562 y utilice el evento para encontrar donde debe aparecer el menú.
9563
9564 <item>En el manejador de eventos, si el evento es una pulsación de un
9565 botón del ratón, tratar <tt>event</tt> como un evento de botón
9566 (que lo es) y utilizarlo como se indica en el código ejemplo para
9567 pasarle información a <tt/gtk_menu_popup()/.
9568 <item>Enlazar este manejador de eventos con el <em>widget</em> con
9569 <tscreen>
9570 gtk_signal_connect_object(GTK_OBJECT(widget), "event",
9571                           GTK_SIGNAL_FUNC (handler), GTK_OBJECT(menu));
9572 </tscreen>
9573 donde <tt>widget</tt> es el <em>widget</em> con el que esta conectando,
9574 <tt>handler</tt> es la función manejadora, y <tt>menu</tt> es un menú
9575 creado con <tt/gtk_menu_new()/. Éste puede ser un menú que esté
9576 contenido en una barra de menús, como se puede ver en el código de
9577 ejemplo.
9578 </itemize>
9579
9580 <!-- ----------------------------------------------------------------- -->
9581 <sect1>Ejemplo de la creación manual de un menú
9582 <p>
9583 Esto debería funcionar. Échele un vistazo al ejemplo para aclarar los
9584 conceptos.
9585
9586 <tscreen><verb>
9587 /* principio del ejemplo menu menu.c */
9588
9589 #include <gtk/gtk.h>
9590
9591 static gint button_press (GtkWidget *, GdkEvent *);
9592 static void menuitem_response (gchar *);
9593
9594 int main (int argc, char *argv[])
9595 {
9596
9597     GtkWidget *ventana;
9598     GtkWidget *menu;
9599     GtkWidget *menu_bar;
9600     GtkWidget *root_menu;
9601     GtkWidget *menu_items;
9602     GtkWidget *vbox;
9603     GtkWidget *boton;
9604     char buf[128];
9605     int i;
9606
9607     gtk_init (&amp;argc, &amp;argv);
9608
9609     /* crear una nueva ventana */
9610     ventana = gtk_window_new(GTK_WINDOW_TOPLEVEL);
9611     gtk_widget_set_usize( GTK_WIDGET (ventana), 200, 100);
9612     gtk_window_set_title(GTK_WINDOW (ventana), "GTK Menu Test");
9613     gtk_signal_connect(GTK_OBJECT (ventana), "delete_event",
9614                        (GtkSignalFunc) gtk_main_quit, NULL);
9615
9616     /* Inicializar el widget-menu, y recuerde -- ¡¡Nunca haga
9617      * gtk_show_widget() con el widget menu!!
9618      * Éste es el menú que contiene todos los elementos del menú, el
9619      * que se desplegará cuando pulse en el "Root Menu" en la
9620      * aplicación
9621      */
9622     menu = gtk_menu_new();
9623
9624     /* Ahora hacemos un pequeño bucle que crea tres elementos de menú
9625      * para "test-menu". Recuerde llamar a gtk_menu_append. Aquí
9626      * estamos añadiendo una lista de elementos de menú a nuestro
9627      * menú. Normalmente tendríamos que cazar aquí la señal "clicked"
9628      * de cada uno de los elementos del menú y le deberíamos dar una
9629      * función de llamada a cada uno, pero lo vamos a omitimos para
9630      * ahorrar espacio. */
9631
9632     for(i = 0; i < 3; i++)
9633         {
9634             /* Copia los nombres al búfer. */
9635             sprintf(buf, "Test-undermenu - %d", i);
9636
9637             /* Crea un nuevo elemento de menú con un nombre... */
9638             menu_items = gtk_menu_item_new_with_label(buf);
9639
9640             /* ...y lo añade al menú. */
9641             gtk_menu_append(GTK_MENU (menu), menu_items);
9642
9643             /* Hace algo interesante cuando se selecciona el menuitem */
9644             gtk_signal_connect_object(GTK_OBJECT(menu_items), "activate",
9645                 GTK_SIGNAL_FUNC(menuitem_response), (gpointer) g_strdup(buf));
9646
9647             /* Muestra el widget */
9648             gtk_widget_show(menu_items);
9649         }
9650
9651     /* Ésta es el menú raíz, y será la etiqueta mostrada en la
9652      * barra de menús. No habrá ningún manejador de señal conectado, ya que
9653      * lo único que hace es desplegar el resto del menú. */
9654     root_menu = gtk_menu_item_new_with_label("Root Menu");
9655
9656     gtk_widget_show(root_menu);
9657
9658     /* Ahora especificamos que queremos que el recien creado "menu"
9659      * sea el menú para el "root menu" */
9660     gtk_menu_item_set_submenu(GTK_MENU_ITEM (root_menu), menu);
9661
9662     /* Un vbox para poner dentro un menú y un botón */
9663     vbox = gtk_vbox_new(FALSE, 0);
9664     gtk_container_add(GTK_CONTAINER(ventana), vbox);
9665     gtk_widget_show(vbox);
9666
9667     /* Crear una barra de menú para que contenga al menú y la añadamos
9668      * a nuestra ventana principal */
9669     menu_bar = gtk_menu_bar_new();
9670     gtk_box_pack_start(GTK_BOX(vbox), menu_bar, FALSE, FALSE, 2);
9671     gtk_widget_show(menu_bar);
9672
9673     /* Crear un botón al que atar los menús como un popup */
9674     boton = gtk_button_new_with_label("press me");
9675     gtk_signal_connect_object(GTK_OBJECT(boton), "event",
9676         GTK_SIGNAL_FUNC (button_press), GTK_OBJECT(menu));
9677     gtk_box_pack_end(GTK_BOX(vbox), boton, TRUE, TRUE, 2);
9678     gtk_widget_show(boton);
9679
9680     /* Y finalmente añadimos el elemento de menú y la barra de menú --
9681      * éste es el elemento de menú "raíz" sobre el que he estado
9682      * delirando =) */
9683     gtk_menu_bar_append(GTK_MENU_BAR (menu_bar), root_menu);
9684
9685     /* siempre mostramos la ventana como último paso para que todo se
9686      * pongo en pantalla a la vez. */
9687     gtk_widget_show(ventana);
9688
9689     gtk_main ();
9690
9691     return 0;
9692 }
9693
9694 /* Responde a una pulsación del botón enviando un menú como un widget
9695  * Recuerde que el argumento "widget" es el menú que se está enviando,
9696  * NO el botón que se ha pulsado.
9697  */
9698
9699 static gint button_press (GtkWidget *widget, GdkEvent *event)
9700 {
9701
9702     if (event->type == GDK_BUTTON_PRESS) {
9703         GdkEventButton *bevent = (GdkEventButton *) event; 
9704         gtk_menu_popup (GTK_MENU(widget), NULL, NULL, NULL, NULL,
9705                         bevent->button, bevent->time);
9706         /* Le dice al que llamó a la rutina que hemos manejado el
9707          * evento; la historia termina aquí. */
9708         return TRUE;
9709     }
9710
9711     /* Le dice al que llamó a la rutina que no hemos manejado el
9712      * evento. */
9713     return FALSE;
9714 }
9715
9716
9717 /* Imprime una cadena cuando se selecciona un elemento del menú */
9718
9719 static void menuitem_response (gchar *string)
9720 {
9721     printf("%s\n", string);
9722 }
9723 /* final del ejemplo */
9724 </verb></tscreen>
9725
9726 También puede hacer que un elemento del menú sea insensible y, utilizando
9727 una tabla de teclas aceleradoras, conectar las teclas con las funciones
9728 del menú.
9729
9730 <!-- XXX Las dos sect1 que vienen han cambiado -->
9731 <!-- ----------------------------------------------------------------- -->
9732 <sect1>Utilizando GtkItemFactory
9733 <p>
9734 Ahora que le hemos enseñado la forma difícil, le mostraremos como
9735 utilizar las llamadas <tt/gtk_item_factory/.
9736
9737 <!-- ----------------------------------------------------------------- -->
9738 <sect1>Ejemplo de la fábrica de elementos
9739 <p>
9740 Aquí hay un ejemplo de cómo utilizar la fábrica de elementos
9741 GTK.
9742
9743 <tscreen><verb>
9744 /* principio del ejemplo menu itemfactory.h */
9745
9746 #include <gtk/gtk.h>
9747 #include <strings.h>
9748
9749 /* La obligatoria función de llamada */
9750 static void print_hello( GtkWidget *w,
9751                          gpointer   data )
9752 {
9753   g_message ("Hello, World!\n");
9754 }
9755
9756 /* Esta es la estructura GtkItemFactoryEntry utilizada para crear
9757    nuevos menúes.
9758
9759    This is the GtkItemFactoryEntry structure used to generate new menus.
9760    Elemento 1: La dirección del menú. La letra que hay
9761                después del subrayado indica una tecla aceleradora
9762                una vez que el menú esté abierto.
9763    Elemento 2: La tecla aceleradora para la entrada del menú.
9764    Elemento 3: La función de llamada.
9765    Elemento 4: La acción de llamada. Cambia los parámetros que
9766                se le pasan a la función de llamada. El valor por
9767                defecto es 0.
9768    Elemento 5: El tipo de elemento, se utiliza para definir de que
9769                tipo de elemento se trata. Los valores posibles son:
9770
9771            NULL               -> "<Item>"
9772            ""                 -> "<Item>"
9773            "<Title>"          -> crea un elemento título
9774            "<Item>"           -> crea un simple elemento
9775            "<CheckItem>"      -> crea un elemento de comprobación
9776            "<ToggleItem>"     -> crea un elemento de selección
9777            "<RadioItem>"      -> crea un elemento circular
9778            <path>             -> dirección de un elemento circular
9779                                  con el que enlazar
9780            "<Separator>"      -> crea un separador
9781            "<Branch>"         -> crea un elemento para contener
9782                                  subelementos (de forma opcional)
9783            "<LastBranch>"     -> crea una rama justificada a la
9784                                  derecha
9785 */
9786
9787 static GtkItemFactoryEntry menu_items[] = {
9788   { "/_File",         NULL,         NULL, 0, "<Branch>" },
9789   { "/File/_New",     "<control>N", print_hello, 0, NULL },
9790   { "/File/_Open",    "<control>O", print_hello, 0, NULL },
9791   { "/File/_Save",    "<control>S", print_hello, 0, NULL },
9792   { "/File/Save _As", NULL,         NULL, 0, NULL },
9793   { "/File/sep1",     NULL,         NULL, 0, "<Separator>" },
9794   { "/File/Quit",     "<control>Q", gtk_main_quit, 0, NULL },
9795   { "/_Options",      NULL,         NULL, 0, "<Branch>" },
9796   { "/Options/Test",  NULL,         NULL, 0, NULL },
9797   { "/_Help",         NULL,         NULL, 0, "<LastBranch>" },
9798   { "/_Help/About",   NULL,         NULL, 0, NULL },
9799 };
9800
9801
9802 void get_main_menu( GtkWidget  *ventana,
9803                     GtkWidget **menubar )
9804 {
9805   GtkItemFactory *item_factory;
9806   GtkAccelGroup *accel_group;
9807   gint nmenu_items = sizeof (menu_items) / sizeof (menu_items[0]);
9808
9809   accel_group = gtk_accel_group_new ();
9810
9811   /* Esta función inicializa la fábrica de elementos
9812      Param 1: El tipo de menú - puede ser GTK_TYPE_MENU_BAR,
9813               GTK_TYPE_MENU, o GTK_TYPE_OPTION_MENU.
9814      Param 2: La dirección del menú.
9815      Param 3: Un puntero a un gtk_accel_group. La fábrica de
9816               elementos actualiza la tabla de teclas aceleradoras
9817               mientras genera los menúes.
9818   */
9819
9820   item_factory = gtk_item_factory_new (GTK_TYPE_MENU_BAR, "<main>", 
9821                                        accel_group);
9822
9823   /* Esta función genera los elementos de menú. Pasa la
9824      fábrica de elementos (item_factory), el número de elementos
9825      del vector, el vector en sí, y cualquier dato de llamada para
9826      los elementos de menú. */
9827   gtk_item_factory_create_items (item_factory, nmenu_items, menu_items, NULL);
9828
9829   /* Enlaza el nuevo grupo acelerador a la ventana. */
9830   gtk_accel_group_attach (accel_group, GTK_OBJECT (ventana));
9831
9832   if (menubar)
9833     /* Finalmente, devuelve la barra de menú creada por la
9834      * fábrica de elementos. */
9835     *menubar = gtk_item_factory_get_widget (item_factory, "<main>");
9836 }
9837
9838 int main( int argc,
9839           char *argv[] )
9840 {
9841   GtkWidget *ventana;
9842   GtkWidget *main_vbox;
9843   GtkWidget *menubar;
9844   
9845   gtk_init (&amp;argc, &amp;argv);
9846   
9847   ventana = gtk_window_new (GTK_WINDOW_TOPLEVEL);
9848   gtk_signal_connect (GTK_OBJECT (ventana), "destroy", 
9849                       GTK_SIGNAL_FUNC (gtk_main_quit), 
9850                       "WM destroy");
9851   gtk_window_set_title (GTK_WINDOW(ventana), "Item Factory");
9852   gtk_widget_set_usize (GTK_WIDGET(ventana), 300, 200);
9853   
9854   main_vbox = gtk_vbox_new (FALSE, 1);
9855   gtk_container_border_width (GTK_CONTAINER (main_vbox), 1);
9856   gtk_container_add (GTK_CONTAINER (ventana), main_vbox);
9857   gtk_widget_show (main_vbox);
9858   
9859   get_main_menu (ventana, &amp;menubar);
9860   gtk_box_pack_start (GTK_BOX (main_vbox), menubar, FALSE, TRUE, 0);
9861   gtk_widget_show (menubar);
9862   
9863   gtk_widget_show (ventana);
9864   gtk_main ();
9865   
9866   return(0);
9867 }
9868 /* fin del ejemplo */
9869 </verb></tscreen>
9870
9871 Por ahora, sólo está este ejemplo. Ya llegará una
9872 explicación del mismo y más comentarios.
9873
9874 <!-- ***************************************************************** -->
9875 <sect> El <em>widget</em> texto
9876 <!-- ***************************************************************** -->
9877 <p>
9878 El <em>widget</em> texto permite mostrar y editar multiples líneas de
9879 texto. Admite texto en varios colores y con varios tipos de letra,
9880 permitiendo mezclarlos de cualquier forma que desee. También hay un
9881 gran número de teclas para la edición de textos, que son compatibles
9882 con Emacs.
9883
9884 El <em>widget</em> texto admite copiar-y-pegar, incluyendo la
9885 utilización de doble y triple-click para seleccionar una palabra y una
9886 línea completa, respectivamente.
9887
9888 <!-- ----------------------------------------------------------------- -->
9889 <sect1>Creando y configurando un cuadro de texto
9890 <p>
9891 Sólo hay una función para crear un nuevo <em>widget</em> texto.
9892 <tscreen><verb>
9893 GtkWidget *gtk_text_new( GtkAdjustment *hadj,
9894                          GtkAdjustment *vadj );
9895 </verb></tscreen>
9896
9897 Los argumentos nos permitirán dar al <em>widget</em> texto punteros a
9898 <tt/GtkAdjustement/ que pueden ser utilizados para controlar la visión
9899 de la posición del <em>widget</em>. Si le ponemos un valor NULL en
9900 cualquiera de los dos argumentos (o en los dos), la función
9901 <tt/gtk_text_new/ creará su propio ajuste.
9902
9903 <tscreen><verb>
9904 void gtk_text_set_adjustments( GtkText       *text,
9905                                GtkAdjustment *hadj,
9906                                GtkAdjustment *vadj );
9907 </verb></tscreen>
9908
9909 La función de arriba permite cambiar en cualquier momento el ajuste
9910 horizontal y vertical de un <em>widget</em> texto.
9911
9912 El <em>widget</em> texto no crea automáticamente sus propiar barras
9913 de desplazamiento cuando el texto a mostrar es demasiado largo
9914 para la ventana en la que se encuentra. Tenemos que crearlas y
9915 añadirlas a la capa del <em>display</em> nosotros mismos.
9916
9917 <tscreen><verb>
9918   vscrollbar = gtk_vscrollbar_new (GTK_TEXT(text)->vadj);
9919   gtk_box_pack_start(GTK_BOX(hbox), vscrollbar, FALSE, FALSE, 0);
9920   gtk_widget_show (vscrollbar);
9921 </verb></tscreen>
9922
9923 El trozo de código de arriba crea una nueva barra de desplazamiento
9924 vertical, y la conecta con el ajuste vertical del <em>widget</em>
9925 de texto, <tt/text/. Entonces la empaqueta en un cuadro de la forma
9926 usual.
9927
9928 Observe que, actualmente el <em>widget</em> GtkText no admite barras
9929 de desplazamiento horizontal.
9930
9931 Principalmente hay dos maneras de utilizar un <em>widget</em> de
9932 texto: permitiendo al usuario editar el texto, o permitiéndonos
9933 mostrar varias líneas de texto al usuario. Para cambiar entre estos
9934 dos modos de operación, el <em>widget</em> de texto tiene las
9935 siguientes funciones:
9936
9937 <tscreen><verb>
9938 void gtk_text_set_editable( GtkText *text,
9939                             gint     editable );
9940 </verb></tscreen>
9941
9942 El argumento <tt/editable/ es un valor TRUE o FALSE que especifica si se
9943 permite al usuario editar los contenidos del <em>widget</em> texto.
9944 Cuando el <em>widget</em> texto se pueda editar, mostrará un cursor
9945 en la posición actual de inserción.
9946
9947 Sin embargo la utilización del <em>widget</em> en estos dos modos no
9948 es algo permanente, ya que puede cambiar el estado editable del
9949 <em>widget</em> texto e insertar texto en cualquier momento.
9950
9951 El <em>widget</em> texto corta las líneas de texto que son demasiado
9952 largas para que quepan en una sólo línea en la ventana. Su
9953 comportamiento por defecto es cortar las palabras donde se terminan
9954 las líneas. Esto puede cambiarse utilizando la siguiente función:
9955
9956 <tscreen><verb>
9957 void gtk_text_set_word_wrap( GtkText *text,
9958                              gint     word_wrap );
9959 </verb></tscreen>
9960
9961 Utilizando esta función podremos especificar que el <em>widget</em>
9962 texto debería cortar las líneas largas en los límites de las
9963 palabras. El argumento <tt/word_wrap/ es un valor TRUE o FALSE.
9964
9965 <!-- ----------------------------------------------------------------- -->
9966 <sect1>Manipulación de texto
9967 <P>
9968 El punto actual de inserción en un <em>widget</em> texto puede
9969 cambiarse utilizando
9970 <tscreen><verb>
9971 void gtk_text_set_point( GtkText *text,
9972                          guint    index );
9973 </verb></tscreen>
9974
9975 donde <tt/index/ es la posición en la que poner el punto de inserción.
9976
9977 Análogamente tenemos la función para obtener la posición del punto
9978 de inserción:
9979
9980 <tscreen><verb>
9981 guint gtk_text_get_point( GtkText *text );
9982 </verb></tscreen>
9983
9984 Una función que es útil en combinación con las dos anteriores es
9985
9986 <tscreen><verb>
9987 guint gtk_text_get_length( GtkText *text );
9988 </verb></tscreen>
9989
9990 que devuelve la longitud actual del <em>widget</em> texto. La
9991 longitud es el número de caracteres que hay en el bloque de texto,
9992 incluyendo caracteres como el retorno de carro, que marca el final de
9993 las líneas.
9994
9995 Para insertar texto en la posición actual del cursor, tendrá que
9996 utilizar la función <tt/gtk_text_insert/, que nos permitirá
9997 especificar los colores de fondo y de la letra y un tipo de letra para
9998 el texto. 
9999
10000 <tscreen><verb>
10001 void gtk_text_insert( GtkText    *text,
10002                       GdkFont    *font,
10003                       GdkColor   *fore,
10004                       GdkColor   *back,
10005                       const char *chars,
10006                       gint        length );
10007 </verb></tscreen>
10008
10009 Pasar un valor <tt/NULL/ como el color de la letra (<tt/fore/), el
10010 color de fondo (<tt/back/) o el tipo de letra (<tt/font/) hará que
10011 se utilicen los valores que indiquen el estilo del <em>widget</em>.
10012 Utilizar un valor de <tt/-1/ para el parámetro <tt/length/ hará
10013 que se inserte todo el texto.
10014
10015 El <em/widget/ texto es uno de los pocos de GTK que se redibuja
10016 a sí mismo dinámicamente, fuera de la función <tt/gtk_main/. Esto
10017 significa que todos los cambios en el contenido del <em/widget/ texto
10018 se manifestarán inmediatamente. Para permitirnos realizar varias
10019 actualizaciones del <em/widget/ de texto sin que se redibuje
10020 continuamente, podemos congelar el <em/widget/, lo que hará que pare
10021 momentaneamente de redibujarse a sí mismo cada vez que haya algún
10022 cambio. Podemos descongelarlo cuando hayamos acabado con nuestras
10023 actualizaciones.
10024
10025 Las siguientes dos funciones realizarán la acción de congelar y
10026 descongelar el <em/widget/:
10027
10028 <tscreen><verb>
10029 void gtk_text_freeze( GtkText *text );
10030
10031 void gtk_text_thaw( GtkText *text );         
10032 </verb></tscreen>
10033
10034 Se puede borrar el texto que se encuentra en el punto actual de
10035 inserción del <em/widget/ de texto mediante dos funciones. El valor
10036 devuelto es TRUE o FALSE en función del éxito de la operación. 
10037
10038 <tscreen><verb>
10039 gint gtk_text_backward_delete( GtkText *text,
10040                                guint    nchars );
10041
10042 gint gtk_text_forward_delete ( GtkText *text,
10043                                guint    nchars );
10044 </verb></tscreen>
10045
10046 Si quiere recuperar el contenido del <em/widget/ de texto, entonces
10047 la macro <tt/GTK_TEXT_INDEX(t, index)/ le permitirá obtener el
10048 carácter que se encuentra en la posición <tt/index/ del <em/widget/
10049 de texto <tt/t/.
10050
10051 Para obtener mayores bloques de texto, podemos utilizar la función
10052
10053 <tscreen><verb>
10054 gchar *gtk_editable_get_chars( GtkEditable *editable,
10055                                gint         start_pos,
10056                                gint         end_pos );   
10057 </verb></tscreen>
10058
10059 Esta es una función de la clase padre del <em/widget/ texto. Un valor
10060 de -1 en <tt/end_pos/ significa el final del texto. El índice del
10061 texto empieza en 0.
10062
10063 La función reserva un espacio de memoria para el bloque de texto,
10064 por lo que no debe olvidarse de liberarlo con una llamada a
10065 <tt/g_free/ cuando haya acabado el bloque.
10066  
10067 <!-- ----------------------------------------------------------------- -->
10068 <sect1>Atajos por teclado
10069 <p>
10070 El <em/widget/ texto tiene ciertos atajos de teclado preinstalados
10071 para las funciones de edición estándar, movimiento y selección. Pueden
10072 utilizarse mediante combinaciones de las teclas Control y Alt.
10073
10074 Además, si se mantiene apretada la tecla de Control y se utilizan las
10075 teclas de movimiento, el cursor se moverá por palabras en lugar de por
10076 caracteres. Manteniendo apretada la tecla Shift, las teclas de movimiento
10077 harán que se extienda la selección.
10078
10079 <sect2>Atajos para el movimiento
10080 <p>
10081 <itemize>
10082 <item> Ctrl-A   Principio de línea
10083 <item> Ctrl-E   Final de línea
10084 <item> Ctrl-N   Línea siguiente
10085 <item> Ctrl-P   Línea anterior
10086 <item> Ctrl-B   Retrasarse un carácter
10087 <item> Ctrl-F   Adelantarse un carácter
10088 <item> Alt-B    Retrasarse una palabra
10089 <item> Alt-F    Adelantarse una palabra
10090 </itemize>
10091
10092 <sect2>Atajos para la edición
10093 <p>
10094 <itemize>
10095 <item> Ctrl-H   Borrar el carácter anterior (Backspace)
10096 <item> Ctrl-D   Borrar el carácter siguiente (Suprimir)
10097 <item> Ctrl-W   Borrar la palabra anterior
10098 <item> Alt-D    Borrar la palabra siguiente
10099 <item> Ctrl-K   Borrar hasta el fin de la línea
10100 <item> Ctrl-U   Borrar la línea
10101 </itemize>
10102
10103 <sect2>Atajos de selección
10104 <p>
10105 <itemize>
10106 <item> Ctrl-X   Cortar al portapapeles
10107 <item> Ctrl-C   Copiar al portapapeles
10108 <item> Ctrl-V   Pegar desde el portapapeles
10109 </itemize>
10110
10111 <!-- ----------------------------------------------------------------- -->
10112 <sect1>Un ejemplo de GtkText
10113 <p>
10114 <tscreen><verb>
10115 /* principio del ejemplo text text.c */
10116
10117 /* text.c */
10118
10119 #include <stdio.h>
10120 #include <gtk/gtk.h>
10121
10122 void text_toggle_editable (GtkWidget *checkbutton,
10123                            GtkWidget *text)
10124 {
10125   gtk_text_set_editable(GTK_TEXT(text),
10126                         GTK_TOGGLE_BUTTON(checkbutton)->active);
10127 }
10128
10129 void text_toggle_word_wrap (GtkWidget *checkbutton,
10130                             GtkWidget *text)
10131 {
10132   gtk_text_set_word_wrap(GTK_TEXT(text),
10133                          GTK_TOGGLE_BUTTON(checkbutton)->active);
10134 }
10135
10136 void close_application( GtkWidget *widget, gpointer data )
10137 {
10138        gtk_main_quit();
10139 }
10140
10141 int main (int argc, char *argv[])
10142 {
10143   GtkWidget *ventana;
10144   GtkWidget *caja1;
10145   GtkWidget *caja2;
10146   GtkWidget *hbox;
10147   GtkWidget *boton;
10148   GtkWidget *check;
10149   GtkWidget *separator;
10150   GtkWidget *table;
10151   GtkWidget *vscrollbar;
10152   GtkWidget *text;
10153   GdkColormap *cmap;
10154   GdkColor colour;
10155   GdkFont *fixed_font;
10156
10157   FILE *infile;
10158
10159   gtk_init (&amp;argc, &amp;argv);
10160  
10161   ventana = gtk_window_new (GTK_WINDOW_TOPLEVEL);
10162   gtk_widget_set_usize (ventana, 600, 500);
10163   gtk_window_set_policy (GTK_WINDOW(ventana), TRUE, TRUE, FALSE);  
10164   gtk_signal_connect (GTK_OBJECT (ventana), "destroy",
10165                       GTK_SIGNAL_FUNC(close_application),
10166                       NULL);
10167   gtk_window_set_title (GTK_WINDOW (ventana), "Text Widget Example");
10168   gtk_container_border_width (GTK_CONTAINER (ventana), 0);
10169   
10170   
10171   caja1 = gtk_vbox_new (FALSE, 0);
10172   gtk_container_add (GTK_CONTAINER (ventana), caja1);
10173   gtk_widget_show (caja1);
10174   
10175   
10176   caja2 = gtk_vbox_new (FALSE, 10);
10177   gtk_container_border_width (GTK_CONTAINER (caja2), 10);
10178   gtk_box_pack_start (GTK_BOX (caja1), caja2, TRUE, TRUE, 0);
10179   gtk_widget_show (caja2);
10180   
10181   
10182   table = gtk_table_new (2, 2, FALSE);
10183   gtk_table_set_row_spacing (GTK_TABLE (table), 0, 2);
10184   gtk_table_set_col_spacing (GTK_TABLE (table), 0, 2);
10185   gtk_box_pack_start (GTK_BOX (caja2), table, TRUE, TRUE, 0);
10186   gtk_widget_show (table);
10187   
10188   /* Crear el widget GtkText */
10189   text = gtk_text_new (NULL, NULL);
10190   gtk_text_set_editable (GTK_TEXT (text), TRUE);
10191   gtk_table_attach (GTK_TABLE (table), text, 0, 1, 0, 1,
10192                     GTK_EXPAND | GTK_SHRINK | GTK_FILL,
10193                     GTK_EXPAND | GTK_SHRINK | GTK_FILL, 0, 0);
10194   gtk_widget_show (text);
10195
10196   /* Añadir una barra de desplazamiento vertical al widget GtkText */
10197   vscrollbar = gtk_vscrollbar_new (GTK_TEXT (text)->vadj);
10198   gtk_table_attach (GTK_TABLE (table), vscrollbar, 1, 2, 0, 1,
10199                     GTK_FILL, GTK_EXPAND | GTK_SHRINK | GTK_FILL, 0, 0);
10200   gtk_widget_show (vscrollbar);
10201
10202   /* Obtener el mapa de colores del sistema y conseguir el color rojo */
10203   cmap = gdk_colormap_get_system();
10204   colour.red = 0xffff;
10205   colour.green = 0;
10206   colour.blue = 0;
10207   if (!gdk_color_alloc(cmap, &amp;colour)) {
10208     g_error("couldn't allocate colour");
10209   }
10210
10211   /* Cargar un fuente de tamaño fijo */
10212   fixed_font = gdk_font_load ("-misc-fixed-medium-r-*-*-*-140-*-*-*-*-*-*");
10213
10214   /* Al enviar la señal relize a un widget se crea una ventana para el
10215    * mismo, y nos permite insertar texto */
10216   gtk_widget_realize (text);
10217
10218   /* Congela el widget text, lo que nos permite hacer varias
10219    * actualizaciones */
10220   gtk_text_freeze (GTK_TEXT (text));
10221   
10222   /* Insertamos algún texto coloreado */
10223   gtk_text_insert (GTK_TEXT (text), NULL, &amp;text->style->black, NULL,
10224                    "Supports ", -1);
10225   gtk_text_insert (GTK_TEXT (text), NULL, &amp;colour, NULL,
10226                    "colored ", -1);
10227   gtk_text_insert (GTK_TEXT (text), NULL, &amp;text->style->black, NULL,
10228                    "text and different ", -1);
10229   gtk_text_insert (GTK_TEXT (text), fixed_font, &amp;text->style->black, NULL,
10230                    "fonts\n\n", -1);
10231   
10232   /* Cargamos el fichero text.c en la ventana de texto */
10233
10234   infile = fopen("text.c", "r");
10235   
10236   if (infile) {
10237     char buffer[1024];
10238     int nchars;
10239     
10240     while (1)
10241       {
10242         nchars = fread(buffer, 1, 1024, infile);
10243         gtk_text_insert (GTK_TEXT (text), fixed_font, NULL,
10244                          NULL, buffer, nchars);
10245         
10246         if (nchars < 1024)
10247           break;
10248       }
10249     
10250     fclose (infile);
10251   }
10252
10253   /* Descongelamos el widget text, permitiéndonos ver todos los
10254    * cambios */
10255   gtk_text_thaw (GTK_TEXT (text));
10256   
10257   hbox = gtk_hbutton_box_new ();
10258   gtk_box_pack_start (GTK_BOX (caja2), hbox, FALSE, FALSE, 0);
10259   gtk_widget_show (hbox);
10260
10261   check = gtk_check_button_new_with_label("Editable");
10262   gtk_box_pack_start (GTK_BOX (hbox), check, FALSE, FALSE, 0);
10263   gtk_signal_connect (GTK_OBJECT(check), "toggled",
10264                       GTK_SIGNAL_FUNC(text_toggle_editable), text);
10265   gtk_toggle_button_set_state(GTK_TOGGLE_BUTTON(check), TRUE);
10266   gtk_widget_show (check);
10267   check = gtk_check_button_new_with_label("Wrap Words");
10268   gtk_box_pack_start (GTK_BOX (hbox), check, FALSE, TRUE, 0);
10269   gtk_signal_connect (GTK_OBJECT(check), "toggled",
10270                       GTK_SIGNAL_FUNC(text_toggle_word_wrap), text);
10271   gtk_toggle_button_set_state(GTK_TOGGLE_BUTTON(check), FALSE);
10272   gtk_widget_show (check);
10273
10274   separator = gtk_hseparator_new ();
10275   gtk_box_pack_start (GTK_BOX (caja1), separator, FALSE, TRUE, 0);
10276   gtk_widget_show (separator);
10277
10278   caja2 = gtk_vbox_new (FALSE, 10);
10279   gtk_container_border_width (GTK_CONTAINER (caja2), 10);
10280   gtk_box_pack_start (GTK_BOX (caja1), caja2, FALSE, TRUE, 0);
10281   gtk_widget_show (caja2);
10282   
10283   boton = gtk_button_new_with_label ("close");
10284   gtk_signal_connect (GTK_OBJECT (boton), "clicked",
10285                       GTK_SIGNAL_FUNC(close_application),
10286                       NULL);
10287   gtk_box_pack_start (GTK_BOX (caja2), boton, TRUE, TRUE, 0);
10288   GTK_WIDGET_SET_FLAGS (boton, GTK_CAN_DEFAULT);
10289   gtk_widget_grab_default (boton);
10290   gtk_widget_show (boton);
10291
10292   gtk_widget_show (ventana);
10293
10294   gtk_main ();
10295   
10296   return 0;       
10297 }
10298 /* fin del ejemplo */
10299 </verb></tscreen>
10300
10301 <!-- ***************************************************************** -->
10302 <sect> Los <em>widgets</em> no documentados
10303 <!-- ***************************************************************** -->
10304 <p>
10305 ¡Todos ellos necesitan de gente que los documente! :)  Por favor,
10306 considere el contribuir a nuestro tutorial.
10307
10308 Si debe utilizar uno de estos <em/widgets/, que permanecen no
10309 documentados, le sugiero que le eche un vistazo a su fichero de
10310 cabecera respectivo en la distribución GTK. Los nombre de las
10311 funciones GTK son muy descriptivos. Una vez haya comprendido como
10312 funcionan las cosas, no le será difícil ver como hay que utilizar un
10313 <em/widget/ simplemente mirando su declaración de funciones. Con esto,
10314 y unos cuántos ejemplos del código de otros, no debería tener
10315 problemas.
10316
10317 Cuando haya comprendido todas las funciones de un nuevo <em/widget/
10318 no documentado, por favor considere el hecho de escribir un tutorial
10319 para él, para que así otros se puedan beneficiar del tiempo que usted
10320 gastó.
10321
10322
10323 <!-- ----------------------------------------------------------------- -->
10324 <sect1> Calendar
10325 <p>
10326 <!-- ----------------------------------------------------------------- -->
10327 <sect1> CTree
10328 <p>
10329 <!-- ----------------------------------------------------------------- -->
10330 <sect1> Curves
10331 <p>
10332 <!-- ----------------------------------------------------------------- -->
10333 <sect1> Drawing Area
10334 <p>
10335 <!-- ----------------------------------------------------------------- -->
10336 <sect1> Font Selection Dialog
10337 <p>
10338 <!-- ----------------------------------------------------------------- -->
10339 <sect1> Gamma Curve
10340 <p>
10341 <!-- ----------------------------------------------------------------- -->
10342 <sect1> Image
10343 <p>
10344 <!-- ----------------------------------------------------------------- -->
10345 <sect1> Packer
10346 <p>
10347 <!-- ----------------------------------------------------------------- -->
10348 <sect1> Plugs and Sockets
10349 <p>
10350 <!-- ----------------------------------------------------------------- -->
10351 <sect1> Preview
10352 <p>
10353
10354 <!--
10355
10356 (This may need to be rewritten to follow the style of the rest of the tutorial)
10357
10358 <tscreen><verb>
10359
10360 Previews serve a number of purposes in GIMP/GTK. The most important one is
10361 this. High quality images may take up to tens of megabytes of memory - easy!
10362 Any operation on an image that big is bound to take a long time. If it takes
10363 you 5-10 trial-and-errors (i.e. 10-20 steps, since you have to revert after
10364 you make an error) to choose the desired modification, it make take you
10365 literally hours to make the right one - if you don't run out of memory
10366 first. People who have spent hours in color darkrooms know the feeling.
10367 Previews to the rescue!
10368
10369 But the annoyance of the delay is not the only issue. Oftentimes it is
10370 helpful to compare the Before and After versions side-by-side or at least
10371 back-to-back. If you're working with big images and 10 second delays,
10372 obtaining the Before and After impressions is, to say the least, difficult.
10373 For 30M images (4"x6", 600dpi, 24 bit) the side-by-side comparison is right
10374 out for most people, while back-to-back is more like back-to-1001, 1002,
10375 ..., 1010-back! Previews to the rescue!
10376
10377 But there's more. Previews allow for side-by-side pre-previews. In other
10378 words, you write a plug-in (e.g. the filterpack simulation) which would have
10379 a number of here's-what-it-would-look-like-if-you-were-to-do-this previews.
10380 An approach like this acts as a sort of a preview palette and is very
10381 effective for subtle changes. Let's go previews!
10382
10383 There's more. For certain plug-ins real-time image-specific human
10384 intervention maybe necessary. In the SuperNova plug-in, for example, the
10385 user is asked to enter the coordinates of the center of the future
10386 supernova. The easiest way to do this, really, is to present the user with a
10387 preview and ask him to interactively select the spot. Let's go previews!
10388
10389 Finally, a couple of misc uses. One can use previews even when not working
10390 with big images. For example, they are useful when rendering complicated
10391 patterns. (Just check out the venerable Diffraction plug-in + many other
10392 ones!) As another example, take a look at the colormap rotation plug-in
10393 (work in progress). You can also use previews for little logos inside you
10394 plug-ins and even for an image of yourself, The Author. Let's go previews!
10395
10396 When Not to Use Previews
10397
10398 Don't use previews for graphs, drawing etc. GDK is much faster for that. Use
10399 previews only for rendered images!
10400
10401 Let's go previews!
10402
10403 You can stick a preview into just about anything. In a vbox, an hbox, a
10404 table, a button, etc. But they look their best in tight frames around them.
10405 Previews by themselves do not have borders and look flat without them. (Of
10406 course, if the flat look is what you want...) Tight frames provide the
10407 necessary borders.
10408
10409                                [Image][Image]
10410
10411 Previews in many ways are like any other widgets in GTK (whatever that
10412 means) except they possess an additional feature: they need to be filled with
10413 some sort of an image! First, we will deal exclusively with the GTK aspect
10414 of previews and then we'll discuss how to fill them.
10415
10416 GtkWidget *preview!
10417
10418 Without any ado:
10419
10420                               /* Create a preview widget,
10421                               set its size, an show it */
10422 GtkWidget *preview;
10423 preview=gtk_preview_new(GTK_PREVIEW_COLOR)
10424                               /*Other option:
10425                               GTK_PREVIEW_GRAYSCALE);*/
10426 gtk_preview_size (GTK_PREVIEW (preview), WIDTH, HEIGHT);
10427 gtk_widget_show(preview);
10428 my_preview_rendering_function(preview);
10429
10430 Oh yeah, like I said, previews look good inside frames, so how about:
10431
10432 GtkWidget *create_a_preview(int        Width,
10433                             int        Height,
10434                             int        Colorfulness)
10435 {
10436   GtkWidget *preview;
10437   GtkWidget *frame;
10438   
10439   frame = gtk_frame_new(NULL);
10440   gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_IN);
10441   gtk_container_set_border_width (GTK_CONTAINER(frame),0);
10442   gtk_widget_show(frame);
10443
10444   preview=gtk_preview_new (Colorfulness?GTK_PREVIEW_COLOR
10445                                        :GTK_PREVIEW_GRAYSCALE);
10446   gtk_preview_size (GTK_PREVIEW (preview), Width, Height);
10447   gtk_container_add(GTK_CONTAINER(frame),preview);
10448   gtk_widget_show(preview);
10449
10450   my_preview_rendering_function(preview);
10451   return frame;
10452 }
10453
10454 That's my basic preview. This routine returns the "parent" frame so you can
10455 place it somewhere else in your interface. Of course, you can pass the
10456 parent frame to this routine as a parameter. In many situations, however,
10457 the contents of the preview are changed continually by your application. In
10458 this case you may want to pass a pointer to the preview to a
10459 "create_a_preview()" and thus have control of it later.
10460
10461 One more important note that may one day save you a lot of time. Sometimes
10462 it is desirable to label you preview. For example, you may label the preview
10463 containing the original image as "Original" and the one containing the
10464 modified image as "Less Original". It might occur to you to pack the
10465 preview along with the appropriate label into a vbox. The unexpected caveat
10466 is that if the label is wider than the preview (which may happen for a
10467 variety of reasons unforseeable to you, from the dynamic decision on the
10468 size of the preview to the size of the font) the frame expands and no longer
10469 fits tightly over the preview. The same problem can probably arise in other
10470 situations as well.
10471
10472                                    [Image]
10473
10474 The solution is to place the preview and the label into a 2x1 table and by
10475 attaching them with the following parameters (this is one possible variations
10476 of course. The key is no GTK_FILL in the second attachment):
10477
10478 gtk_table_attach(GTK_TABLE(table),label,0,1,0,1,
10479                  0,
10480                  GTK_EXPAND|GTK_FILL,
10481                  0,0);
10482 gtk_table_attach(GTK_TABLE(table),frame,0,1,1,2,
10483                  GTK_EXPAND,
10484                  GTK_EXPAND,
10485                  0,0);
10486
10487
10488 And here's the result:
10489
10490                                    [Image]
10491
10492 Misc
10493
10494 Making a preview clickable is achieved most easily by placing it in a
10495 boton. It also adds a nice border around the preview and you may not even
10496 need to place it in a frame. See the Filter Pack Simulation plug-in for an
10497 example.
10498
10499 This is pretty much it as far as GTK is concerned.
10500
10501 Filling In a Preview
10502
10503 In order to familiarize ourselves with the basics of filling in previews,
10504 let's create the following pattern (contrived by trial and error):
10505
10506                                    [Image]
10507
10508 void
10509 my_preview_rendering_function(GtkWidget     *preview)
10510 {
10511 #define SIZE 100
10512 #define HALF (SIZE/2)
10513
10514   guchar *row=(guchar *) malloc(3*SIZE); /* 3 bits per dot */
10515   gint i, j;                             /* Coordinates    */
10516   double r, alpha, x, y;
10517
10518   if (preview==NULL) return; /* I usually add this when I want */
10519                              /* to avoid silly crashes. You    */
10520                              /* should probably make sure that */
10521                              /* everything has been nicely     */
10522                              /* initialized!                   */
10523   for (j=0; j < ABS(cos(2*alpha)) ) { /* Are we inside the shape?  */
10524                                          /* glib.h contains ABS(x).   */
10525         row[i*3+0] = sqrt(1-r)*255;      /* Define Red                */
10526         row[i*3+1] = 128;                /* Define Green              */
10527         row[i*3+2] = 224;                /* Define Blue               */
10528       }                                  /* "+0" is for alignment!    */
10529       else {
10530         row[i*3+0] = r*255;
10531         row[i*3+1] = ABS(sin((float)i/SIZE*2*PI))*255;
10532         row[i*3+2] = ABS(sin((float)j/SIZE*2*PI))*255;
10533       }
10534     }
10535     gtk_preview_draw_row( GTK_PREVIEW(preview),row,0,j,SIZE);
10536     /* Insert "row" into "preview" starting at the point with  */
10537     /* coordinates (0,j) first column, j_th row extending SIZE */
10538     /* pixels to the right */
10539   }
10540
10541   free(row); /* save some space */
10542   gtk_widget_draw(preview,NULL); /* what does this do? */
10543   gdk_flush(); /* or this? */
10544 }
10545
10546 Non-GIMP users can have probably seen enough to do a lot of things already.
10547 For the GIMP users I have a few pointers to add.
10548
10549 Image Preview
10550
10551 It is probably wise to keep a reduced version of the image around with just
10552 enough pixels to fill the preview. This is done by selecting every n'th
10553 pixel where n is the ratio of the size of the image to the size of the
10554 preview. All further operations (including filling in the previews) are then
10555 performed on the reduced number of pixels only. The following is my
10556 implementation of reducing the image. (Keep in mind that I've had only basic
10557 C!)
10558
10559 (UNTESTED CODE ALERT!!!)
10560
10561 typedef struct {
10562   gint      width;
10563   gint      height;
10564   gint      bbp;
10565   guchar    *rgb;
10566   guchar    *mask;
10567 } ReducedImage;
10568
10569 enum {
10570   SELECTION_ONLY,
10571   SELECTION_IN_CONTEXT,
10572   ENTIRE_IMAGE
10573 };
10574
10575 ReducedImage *Reduce_The_Image(GDrawable *drawable,
10576                                GDrawable *mask,
10577                                gint LongerSize,
10578                                gint Selection)
10579 {
10580   /* This function reduced the image down to the the selected preview size */
10581   /* The preview size is determine by LongerSize, i.e. the greater of the  */
10582   /* two dimensions. Works for RGB images only!                            */
10583   gint RH, RW;          /* Reduced height and reduced width                */
10584   gint width, height;   /* Width and Height of the area being reduced      */
10585   gint bytes=drawable->bpp;
10586   ReducedImage *temp=(ReducedImage *)malloc(sizeof(ReducedImage));
10587
10588   guchar *tempRGB, *src_row, *tempmask, *src_mask_row,R,G,B;
10589   gint i, j, whichcol, whichrow, x1, x2, y1, y2;
10590   GPixelRgn srcPR, srcMask;
10591   gint NoSelectionMade=TRUE; /* Assume that we're dealing with the entire  */
10592                              /* image.                                     */
10593
10594   gimp_drawable_mask_bounds (drawable->id, &amp;x1, &amp;y1, &amp;x2, &amp;y2);
10595   width  = x2-x1;
10596   height = y2-y1;
10597   /* If there's a SELECTION, we got its bounds!)
10598
10599   if (width != drawable->width &amp;&amp; height != drawable->height)
10600     NoSelectionMade=FALSE;
10601   /* Become aware of whether the user has made an active selection   */
10602   /* This will become important later, when creating a reduced mask. */
10603
10604   /* If we want to preview the entire image, overrule the above!  */
10605   /* Of course, if no selection has been made, this does nothing! */
10606   if (Selection==ENTIRE_IMAGE) {
10607     x1=0;
10608     x2=drawable->width;
10609     y1=0;
10610     y2=drawable->height;
10611   }
10612
10613   /* If we want to preview a selection with some surrounding area we */
10614   /* have to expand it a little bit. Consider it a bit of a riddle. */
10615   if (Selection==SELECTION_IN_CONTEXT) {
10616     x1=MAX(0,                x1-width/2.0);
10617     x2=MIN(drawable->width,  x2+width/2.0);
10618     y1=MAX(0,                y1-height/2.0);
10619     y2=MIN(drawable->height, y2+height/2.0);
10620   }
10621
10622   /* How we can determine the width and the height of the area being */
10623   /* reduced.                                                        */
10624   width  = x2-x1;
10625   height = y2-y1;
10626
10627   /* The lines below determine which dimension is to be the longer   */
10628   /* side. The idea borrowed from the supernova plug-in. I suspect I */
10629   /* could've thought of it myself, but the truth must be told.      */
10630   /* Plagiarism stinks!                                               */
10631   if (width>height) {
10632     RW=LongerSize;
10633     RH=(float) height * (float) LongerSize/ (float) width;
10634   }
10635   else {
10636     RH=LongerSize;
10637     RW=(float)width * (float) LongerSize/ (float) height;
10638   }
10639
10640   /* The entire image is stretched into a string! */
10641   tempRGB   = (guchar *) malloc(RW*RH*bytes);
10642   tempmask  = (guchar *) malloc(RW*RH);
10643
10644   gimp_pixel_rgn_init (&amp;srcPR, drawable, x1, y1, width, height,
10645                        FALSE, FALSE);
10646   gimp_pixel_rgn_init (&amp;srcMask, mask, x1, y1, width, height,
10647                        FALSE, FALSE);
10648
10649   /* Grab enough to save a row of image and a row of mask. */
10650   src_row       = (guchar *) malloc (width*bytes);
10651   src_mask_row  = (guchar *) malloc (width);
10652
10653   for (i=0; i < RH; i++) {
10654     whichrow=(float)i*(float)height/(float)RH;
10655     gimp_pixel_rgn_get_row (&amp;srcPR, src_row, x1, y1+whichrow, width);
10656     gimp_pixel_rgn_get_row (&amp;srcMask, src_mask_row, x1, y1+whichrow, width);
10657
10658     for (j=0; j < RW; j++) {
10659       whichcol=(float)j*(float)width/(float)RW;
10660
10661       /* No selection made = each point is completely selected! */
10662       if (NoSelectionMade)
10663         tempmask[i*RW+j]=255;
10664       else
10665         tempmask[i*RW+j]=src_mask_row[whichcol];
10666
10667       /* Add the row to the one long string which now contains the image! */
10668       tempRGB[i*RW*bytes+j*bytes+0]=src_row[whichcol*bytes+0];
10669       tempRGB[i*RW*bytes+j*bytes+1]=src_row[whichcol*bytes+1];
10670       tempRGB[i*RW*bytes+j*bytes+2]=src_row[whichcol*bytes+2];
10671
10672       /* Hold on to the alpha as well */
10673       if (bytes==4)
10674         tempRGB[i*RW*bytes+j*bytes+3]=src_row[whichcol*bytes+3];
10675     }
10676   }
10677   temp->bpp=bytes;
10678   temp->width=RW;
10679   temp->height=RH;
10680   temp->rgb=tempRGB;
10681   temp->mask=tempmask;
10682   return temp;
10683 }
10684
10685 The following is a preview function which used the same ReducedImage type!
10686 Note that it uses fakes transparency (if one is present by means of
10687 fake_transparency which is defined as follows:
10688
10689 gint fake_transparency(gint i, gint j)
10690 {
10691   if ( ((i%20)- 10) * ((j%20)- 10)>0   )
10692     return 64;
10693   else
10694     return 196;
10695 }
10696
10697 Now here's the preview function:
10698
10699 void
10700 my_preview_render_function(GtkWidget     *preview,
10701                            gint          changewhat,
10702                            gint          changewhich)
10703 {
10704   gint Inten, bytes=drawable->bpp;
10705   gint i, j, k;
10706   float partial;
10707   gint RW=reduced->width;
10708   gint RH=reduced->height;
10709   guchar *row=malloc(bytes*RW);;
10710
10711
10712   for (i=0; i < RH; i++) {
10713     for (j=0; j < RW; j++) {
10714
10715       row[j*3+0] = reduced->rgb[i*RW*bytes + j*bytes + 0];
10716       row[j*3+1] = reduced->rgb[i*RW*bytes + j*bytes + 1];
10717       row[j*3+2] = reduced->rgb[i*RW*bytes + j*bytes + 2];
10718
10719       if (bytes==4)
10720         for (k=0; k<3; k++) {
10721           float transp=reduced->rgb[i*RW*bytes+j*bytes+3]/255.0;
10722           row[3*j+k]=transp*a[3*j+k]+(1-transp)*fake_transparency(i,j);
10723         }
10724     }
10725     gtk_preview_draw_row( GTK_PREVIEW(preview),row,0,i,RW);
10726   }
10727
10728   free(a);
10729   gtk_widget_draw(preview,NULL);
10730   gdk_flush();
10731 }
10732
10733 Applicable Routines
10734
10735 guint           gtk_preview_get_type           (void);
10736 /* No idea */
10737 void            gtk_preview_uninit             (void);
10738 /* No idea */
10739 GtkWidget*      gtk_preview_new                (GtkPreviewType   type);
10740 /* Described above */
10741 void            gtk_preview_size               (GtkPreview      *preview,
10742                                                 gint             width,
10743                                                 gint             height);
10744 /* Allows you to resize an existing preview.    */
10745 /* Apparently there's a bug in GTK which makes  */
10746 /* this process messy. A way to clean up a mess */
10747 /* is to manually resize the window containing  */
10748 /* the preview after resizing the preview.      */
10749
10750 void            gtk_preview_put                (GtkPreview      *preview,
10751                                                 GdkWindow       *ventana,
10752                                                 GdkGC           *gc,
10753                                                 gint             srcx,
10754                                                 gint             srcy,
10755                                                 gint             destx,
10756                                                 gint             desty,
10757                                                 gint             width,
10758                                                 gint             height);
10759 /* No idea */
10760
10761 void            gtk_preview_put_row            (GtkPreview      *preview,
10762                                                 guchar          *src,
10763                                                 guchar          *dest,
10764                                                 gint             x,
10765                                                 gint             y,
10766                                                 gint             w);
10767 /* No idea */
10768
10769 void            gtk_preview_draw_row           (GtkPreview      *preview,
10770                                                 guchar          *data,
10771                                                 gint             x,
10772                                                 gint             y,
10773                                                 gint             w);
10774 /* Described in the text */
10775
10776 void            gtk_preview_set_expand         (GtkPreview      *preview,
10777                                                 gint             expand);
10778 /* No idea */
10779
10780 /* No clue for any of the below but    */
10781 /* should be standard for most widgets */
10782 void            gtk_preview_set_gamma          (double           gamma);
10783 void            gtk_preview_set_color_cube     (guint            nred_shades,
10784                                                 guint            ngreen_shades,
10785                                                 guint            nblue_shades,
10786                                                 guint            ngray_shades);
10787 void            gtk_preview_set_install_cmap   (gint             install_cmap);
10788 void            gtk_preview_set_reserved       (gint             nreserved);
10789 GdkVisual*      gtk_preview_get_visual         (void);
10790 GdkColormap*    gtk_preview_get_cmap           (void);
10791 GtkPreviewInfo* gtk_preview_get_info           (void);
10792
10793 That's all, folks!
10794
10795 </verb></tscreen>
10796
10797 -->
10798
10799 <!-- ***************************************************************** -->
10800 <sect>Estableciendo los atributos de un <em/widget/<label id="sec_setting_widget_attributes">
10801 <!-- ***************************************************************** -->
10802 <p>
10803 En este capítulo se describen las funciones utilizadas para manejar los
10804 <em/widgets/. Pueden utilizarse para establecer el estilo, relleno,
10805 tamaño, etc...
10806
10807 (Puede que deba hacer una sección completa para los aceleradores.)
10808
10809 <tscreen><verb>
10810 void gtk_widget_install_accelerator( GtkWidget           *widget,
10811                                      GtkAcceleratorTable *table,
10812                                      gchar               *signal_name,
10813                                      gchar                key,
10814                                      guint8               modifiers );
10815
10816 void gtk_widget_remove_accelerator ( GtkWidget           *widget,
10817                                      GtkAcceleratorTable *table,
10818                                      gchar               *signal_name);
10819
10820 void gtk_widget_activate( GtkWidget *widget );
10821
10822 void gtk_widget_set_name( GtkWidget *widget,
10823                           gchar     *name );
10824
10825 gchar *gtk_widget_get_name( GtkWidget *widget );
10826
10827 void gtk_widget_set_sensitive( GtkWidget *widget,
10828                                gint       sensitive );
10829
10830 void gtk_widget_set_style( GtkWidget *widget,
10831                            GtkStyle  *style );
10832                                            
10833 GtkStyle *gtk_widget_get_style( GtkWidget *widget );
10834
10835 GtkStyle *gtk_widget_get_default_style( void );
10836
10837 void gtk_widget_set_uposition( GtkWidget *widget,
10838                                gint       x,
10839                                gint       y );
10840
10841 void gtk_widget_set_usize( GtkWidget *widget,
10842                            gint       width,
10843                            gint       height );
10844
10845 void gtk_widget_grab_focus( GtkWidget *widget );
10846
10847 void gtk_widget_show( GtkWidget *widget );
10848
10849 void gtk_widget_hide( GtkWidget *widget );
10850 </verb></tscreen>
10851
10852 <!-- ***************************************************************** -->
10853 <sect>Tiempos de espera, ES (<em/IO/) y funciones ociosas (<em/idle/)<label id="sec_timeouts">
10854 <!-- ***************************************************************** -->
10855
10856 <!-- ----------------------------------------------------------------- -->
10857 <sect1>Tiempos de espera
10858 <p>
10859 Puede que se esté preguntando como hacer que GTK haga algo útil
10860 cuando se encuentra en <tt/gtk_main/. Bien, tiene varias
10861 opciones. Utilizando las rutinas siguientes puede crear una función
10862 a la que se llamará cada <tt/interval/ milisegundos.
10863
10864 <tscreen><verb>
10865 gint gtk_timeout_add( guint32     interval,
10866                       GtkFunction function,
10867                       gpointer    data );
10868 </verb></tscreen>
10869
10870 El primer argumento es el número de milisegundos que habrá entre dos
10871 llamadas a su función. El segundo argumento es la función a la que
10872 desea llamar, y el tercero, los datos que le pasará a ésta función.
10873 El valor devuelto es un «identificador» (un valor entero) que puede
10874 utilizar para detener las llamadas haciendo:
10875
10876 <tscreen><verb>
10877 void gtk_timeout_remove( gint tag );
10878 </verb></tscreen>
10879
10880 También puede hacer que cesen las llamadas a la función haciendo que
10881 la misma devuelva cero o FALSE. Obviamente esto significa que si
10882 quiere que se continue llamando a su función, deberá devolver un valor
10883 distinto de cero, es decir TRUE.
10884
10885 La declaración de su función debería ser algo como:
10886
10887 <tscreen><verb>
10888 gint timeout_callback( gpointer data );
10889 </verb></tscreen>
10890
10891 <!-- ----------------------------------------------------------------- -->
10892 <sect1>Monitorizando la ES
10893 <p>
10894 Otra característica divertida de GTK, es la habilidad que tiene de
10895 comprobar datos por usted en un descriptor de fichero (tal y como
10896 se devuelven por <tt/open(2)/ o <tt/socket(2)/). Esto es especialmente
10897 útil para las aplicaciones de red. La función:
10898
10899 <tscreen><verb>
10900 gint gdk_input_add( gint              source,
10901                     GdkInputCondition condition,
10902                     GdkInputFunction  function,
10903                     gpointer          data );
10904 </verb></tscreen>
10905
10906 Donde el primer argumento es el descriptor de fichero que desea vigilar,
10907 y el segundo especifica que es lo que quiere que GDK busque. Puede ser uno
10908 de los siguientes:
10909
10910 <itemize>
10911 <item>GDK_INPUT_READ - Llama a su función cuando hay datos listos para
10912 leerse del fichero.
10913
10914 <item>GDK_INPUT_WRITE - Llama a su función cuando el descriptor del
10915 fichero está listo para la escritura.
10916 </itemize>
10917
10918 Tal y como se habrá imaginado, el tercer argumento es la función a la
10919 que desea que se llame cuando se den las condiciones anteriores, y el
10920 cuarto son los datos que se le pasarán a ésta función.
10921
10922 El valor devuelto es un identificador que puede utilizarse para que GDK
10923 pare de vigilar ese fichero, utilizando la función
10924
10925 <tscreen><verb>
10926 void gdk_input_remove( gint tag );
10927 </verb></tscreen>
10928
10929 La función a la que quiere que se llame deberá declararse así:
10930
10931 <tscreen><verb>
10932 void input_callback( gpointer          data,
10933                      gint              source, 
10934                      GdkInputCondition condition );
10935 </verb></tscreen>
10936
10937 Donde <tt/source/ y <tt/condition/ están especificados más arriba.
10938
10939 <!-- ----------------------------------------------------------------- -->
10940 <sect1>Funciones ociosas
10941 <p>
10942 <!-- Need to check on idle priorities - TRG -->
10943 ¿Qué le parece si tuviese una función a la que se llamase cuando
10944 no ocurriese nada?
10945
10946 <tscreen><verb>
10947 gint gtk_idle_add( GtkFunction function,
10948                    gpointer    data );
10949 </verb></tscreen>
10950
10951 Esto hace que GTK llame a la función especificada cuando no ocurra
10952 nada más.
10953
10954 <tscreen><verb>
10955 void gtk_idle_remove( gint tag );
10956 </verb></tscreen>
10957
10958 No voy a explicar el significado de los argumentos ya que se parece
10959 mucho a los que he explicado más arriba. La función a la que se apunta
10960 mediante el primer argumento de <tt/gtk_idle_add/ será a la que se
10961 llame cuando llegue el momento. Como antes, si devuelve FALSE hará que
10962 cese de llamarse a la función.
10963
10964 <!-- ***************************************************************** -->
10965 <sect>Manejo avanzado de eventos y señales<label id="sec_Adv_Events_and_Signals">
10966 <!-- ***************************************************************** -->
10967
10968 <!-- ----------------------------------------------------------------- -->
10969 <sect1>Funciones señal
10970
10971 <!-- ----------------------------------------------------------------- -->
10972 <sect2>Conectando y desconectando los manejadores de señal
10973 <p>
10974
10975 <tscreen><verb>
10976 guint gtk_signal_connect( GtkObject     *object,
10977                           const gchar   *name,
10978                           GtkSignalFunc  func,
10979                           gpointer       func_data );
10980
10981 guint gtk_signal_connect_after( GtkObject     *object,
10982                                 const gchar   *name,
10983                                 GtkSignalFunc  func,
10984                                 gpointer       func_data );
10985
10986 guint gtk_signal_connect_object( GtkObject     *object,
10987                                  const gchar   *name,
10988                                  GtkSignalFunc  func,
10989                                  GtkObject     *slot_object );
10990
10991 guint gtk_signal_connect_object_after( GtkObject     *object,
10992                                        const gchar   *name,
10993                                        GtkSignalFunc  func,
10994                                        GtkObject     *slot_object );
10995
10996 guint gtk_signal_connect_full( GtkObject          *object,
10997                                const gchar        *name,
10998                                GtkSignalFunc       func,
10999                                GtkCallbackMarshal  marshal,
11000                                gpointer            data,
11001                                GtkDestroyNotify    destroy_func,
11002                                gint                object_signal,
11003                                gint                after );
11004
11005 guint gtk_signal_connect_interp( GtkObject          *object,
11006                                  const gchar        *name,
11007                                  GtkCallbackMarshal  func,
11008                                  gpointer            data,
11009                                  GtkDestroyNotify    destroy_func,
11010                                  gint                after );
11011
11012 void gtk_signal_connect_object_while_alive( GtkObject     *object,
11013                                             const gchar   *signal,
11014                                             GtkSignalFunc  func,
11015                                             GtkObject     *alive_object );
11016
11017 void gtk_signal_connect_while_alive( GtkObject     *object,
11018                                      const gchar   *signal,
11019                                      GtkSignalFunc  func,
11020                                      gpointer       func_data,
11021                                      GtkObject     *alive_object );
11022
11023 void gtk_signal_disconnect( GtkObject *object,
11024                             guint      handler_id );
11025
11026 void gtk_signal_disconnect_by_func( GtkObject     *object,
11027                                     GtkSignalFunc  func,
11028                                     gpointer       data );
11029 </verb></tscreen>
11030
11031 <!-- ----------------------------------------------------------------- -->
11032 <sect2>Bloqueando y desbloqueando los manejadores de señal
11033 <p>
11034 <tscreen><verb>
11035 void gtk_signal_handler_block( GtkObject *object,
11036                                guint      handler_id);
11037
11038 void gtk_signal_handler_block_by_func( GtkObject     *object,
11039                                        GtkSignalFunc  func,
11040                                        gpointer       data );
11041
11042 void gtk_signal_handler_block_by_data( GtkObject *object,
11043                                        gpointer   data );
11044
11045 void gtk_signal_handler_unblock( GtkObject *object,
11046                                  guint      handler_id );
11047
11048 void gtk_signal_handler_unblock_by_func( GtkObject     *object,
11049                                          GtkSignalFunc  func,
11050                                          gpointer       data );
11051
11052 void gtk_signal_handler_unblock_by_data( GtkObject *object,
11053                                          gpointer   data );
11054 </verb></tscreen>
11055
11056 <!-- ----------------------------------------------------------------- -->
11057 <sect2>Emitiendo y deteniendo señales
11058 <p>
11059 <tscreen><verb>
11060 void gtk_signal_emit( GtkObject *object,
11061                       guint      signal_id,
11062                       ... );
11063
11064 void gtk_signal_emit_by_name( GtkObject   *object,
11065                               const gchar *name,
11066                               ... );
11067
11068 void gtk_signal_emitv( GtkObject *object,
11069                        guint      signal_id,
11070                        GtkArg    *params );
11071
11072 void gtk_signal_emitv_by_name( GtkObject   *object,
11073                                const gchar *name,
11074                                GtkArg      *params );
11075
11076 guint gtk_signal_n_emissions( GtkObject *object,
11077                               guint      signal_id );
11078
11079 guint gtk_signal_n_emissions_by_name( GtkObject   *object,
11080                                       const gchar *name );
11081
11082 void gtk_signal_emit_stop( GtkObject *object,
11083                            guint      signal_id );
11084
11085 void gtk_signal_emit_stop_by_name( GtkObject   *object,
11086                                    const gchar *name );
11087 </verb></tscreen>
11088
11089 <!-- ----------------------------------------------------------------- -->
11090 <sect1>Emisión y propagación de señales
11091 <p>
11092 La emisión de señales es el proceso mediante el cual GTK+ ejecuta
11093 todos los manejadores de un objeto y una señal en especial.
11094
11095 Primero, observe que el valor devuelto por la emisión de una
11096 señal es el mismo que el valor devuelto por el <em>último</em>
11097 manipulador ejecutado. Ya que las señales de los eventos son todas
11098 del tipo GTK_RUN_LAST, el manejador por defecto (proporcionado por
11099 GTK+) será de este tipo, a menos que lo conecte con
11100 <tt/gtk_signal_connect_after()/.
11101
11102 La forma en que se maneja un evento (digamos GTK_BUTTON_PRESS), es la
11103 siguiente:
11104
11105 <itemize>
11106 <item>Empieza con el <em>widget</em> donde ocurrió el evento.
11107
11108 <item>Emite la señal genérica <tt/event/. Si esta señal devuelve un
11109 valor TRUE, detiene todo el proceso.
11110
11111 <item>En caso contrario, emite una señal especifica,
11112 «button_press_event» en nuestro caso. Si ésta devuelve TRUE, detiene
11113 todo el proceso.
11114
11115 <item>En caso contrario, va al <em>widget</em> padre y repite los
11116 pasos anteriores.
11117
11118 <item>Continua hasta que algún manejador de señal devuelva TRUE, o
11119 hasta que se llegue al <em>widget</em> de más alto nivel.
11120 </itemize>
11121
11122 Algunas consecuencias son:
11123 <itemize>
11124 <item>El valor que devuelva su manejador no tendrá ningún efecto si
11125 hay un manejador por defecto, a menos que lo conecte mediante
11126 <tt/gtk_signal_connect_after()/.
11127
11128 <item>Para evitar que el manejador por defecto se ejecute, necesita
11129 conectar mediante <tt/gtk_signal_connect()/ y utilizar
11130 <tt/gtk_signal_emit_stop_by_name()/ - el valor devuelto sólo se ve
11131 afectado si la señal se propaga, y no sólo por el hecho de emitirse.
11132 </itemize>
11133
11134 <!-- ***************************************************************** -->
11135 <sect>Manejando selecciones
11136 <!-- ***************************************************************** -->
11137
11138 <!-- ----------------------------------------------------------------- -->
11139 <sect1> Contenido
11140 <p>
11141 Un tipo de comunicación entre procesos que se puede utilizar con GTK
11142 son las <em/selecciones/. Una selección identifica un conjunto de
11143 datos, por ejemplo, un trozo de texto, seleccionado por el usuario de
11144 alguna manera, por ejemplo, cogiéndolo con el ratón. Sólo una
11145 aplicación en un <em/display/ (la <em>propietaria</em>) puede tener
11146 una selección en particular en un momento dado, por lo que cuando una
11147 aplicación pide una selección, el propietario previo debe indicar al
11148 usuario que la selección ya no es válida. Otras aplicaciones pueden
11149 pedir el contenido de la selección de diferentes formas, llamadas
11150 <em/objetivos/. Puede haber cualquier número de selecciones, pero la
11151 mayoría de las aplicacion X sólo pueden manejar una, la <em/selección
11152 primaria/.
11153
11154 En muchos casos, no es necesario para una aplicación GTK tratar por
11155 sí misma con las selecciones. Los <em/widgets/ estándar, como el
11156 <em/widget/ Entry, ya tienen la posibilidad de crear la selección
11157 cuando sea necesario (p.e., cuando el usuario pase el ratón sobre el
11158 texto manteniendo el botón derecho del ratón pulsado), y de recoger
11159 los contenidos de la selección propiedad de otro <em/widget/, o de
11160 otra aplicación (p.e., cuando el usuario pulsa el segundo botón del
11161 ratón). Sin embargo, pueden haber casos en los que quiera darle a
11162 otros <em/widgets/ la posibilidad de proporcionar la selección, o
11163 puede que quiera recuperar objetivos que no estén admitidos por
11164 defecto.
11165
11166 Un concepto fundamental que es necesario para comprender el manejo de
11167 la selección es el de <em>átomo</em>. Un átomo es un entero que
11168 identifica de una manera unívoca una cadena (en un cierto
11169 <em/display/). Ciertos átomos están predefinidos por el servidor X, y
11170 en algunos casos hay constantes en <tt>gtk.h</tt> que corresponden a
11171 estos átomos. Por ejemplo la constante <tt>GDK_PRIMARY_SELECTION</tt>
11172 corresponde a la cadena «PRIMARY». En otros casos, debería utilizar
11173 las funciones <tt>gdk_atom_intern()</tt>, para obtener el átomo
11174 correspondiente a una cadena, y <tt>gdk_atom_name()</tt>, para obtener
11175 el nombre de un átomo. Ambas, selecciones y objetivos, están
11176 identificados por átomos.
11177
11178 <!-- ----------------------------------------------------------------- -->
11179 <sect1> Recuperando la selección
11180 <p>
11181 Recuperar la selección es un proceso asíncrono. Para comenzar el
11182 proceso, deberá llamar a:
11183
11184 <tscreen><verb>
11185 gint gtk_selection_convert( GtkWidget *widget, 
11186                             GdkAtom    selection, 
11187                             GdkAtom    target,
11188                             guint32    time );
11189 </verb</tscreen>
11190
11191 Este proceso <em/convierte/ la selección en la forma especificada por
11192 <tt/target/. Si es posible, el campo <tt/time/ debe ser el tiempo
11193 desde que el evento lanzó la selección. Esto ayuda a asegurarse de que
11194 los eventos ocurran en el orden en que el usuario los ha pedido. Sin
11195 embargo, si no está disponible (por ejemplo, si se empezó la
11196 conversión por una señal de «pulsación»), entonces puede utilizar la
11197 constante <tt>GDK_CURRENT_TIME</tt>.
11198
11199 Cuando el propietario de la selección responda a la petición, se
11200 enviará una señal «selection_received» a su aplicación. El manejador
11201 de esta señal recibe un puntero a una estructura
11202 <tt>GtkSelectionData</tt>, que se define como:
11203
11204 <tscreen><verb>
11205 struct _GtkSelectionData
11206 {
11207   GdkAtom selection;
11208   GdkAtom target;
11209   GdkAtom type;
11210   gint    format;
11211   guchar *data;
11212   gint    length;
11213 };
11214 </verb></tscreen>
11215
11216 <tt>selection</tt> y <tt>target</tt> son los valores que dió en su
11217 llamada a <tt>gtk_selection_convert()</tt>. <tt>type</tt> es un átomo
11218 que identifica el tipo de datos devueltos por el propietario de la
11219 selección. Algunos valores posibles son «STRING», un cadena de
11220 caracteres latin-1, «ATOM», una serie de átomos, «INTEGER», un
11221 entero, etc. Muchos objetivos sólo pueden devolver un
11222 tipo. <tt/format/ da la longitud de las unidades (por ejemplo
11223 caracteres) en bits. Normalmente, no tiene porque preocuparse de todo
11224 esto cuando recibe datos. <tt/data/ es un puntero a los datos
11225 devueltos, y <tt/length/ da la longitud de los datos devueltos, en
11226 bytes. Si <tt/length/ es negativo, es que a ocurrido un error y no se
11227 puede obtener la selección. Esto podría ocurrir si no hay ninguna
11228 aplicación que sea la propietaria de la selección, o si pide un
11229 objetivo que la aplicación no admite. Actualmente se garantiza que el
11230 búfer tendrá un byte más que <tt/length/; el byte extra siempre será
11231 cero, por lo que no es necesario hacer una copia de las cadenas sólo
11232 para añadirles un carácter nulo al final.
11233
11234 En el siguiente ejemplo, recuperamos el objetivo especial «TARGETS»,
11235 que es una lista de todos los objetivos en los que se puede convertir
11236 la selección.
11237
11238 <tscreen><verb>
11239 /* principio del ejemplo selection gettargets.c */
11240
11241 #include <gtk/gtk.h>
11242
11243 void selection_received (GtkWidget *widget, 
11244                          GtkSelectionData *selection_data, 
11245                          gpointer data);
11246
11247 /* Manejador de señal invocado cuando el usuario pulsa en el botón
11248 "Get Targets" */
11249 void
11250 get_targets (GtkWidget *widget, gpointer data)
11251 {
11252   static GdkAtom targets_atom = GDK_NONE;
11253
11254   /* Obtener el atom correpondiente a la cadena "TARGETS" */
11255   if (targets_atom == GDK_NONE)
11256     targets_atom = gdk_atom_intern ("TARGETS", FALSE);
11257
11258   /* Y pide el objetivo "TARGETS" de la selección primaria */
11259   gtk_selection_convert (widget, GDK_SELECTION_PRIMARY, targets_atom,
11260                          GDK_CURRENT_TIME);
11261 }
11262
11263 /* Manipulador de señal llamado cuando el propietario de la señal
11264  * devuelve los datos */
11265 void
11266 selection_received (GtkWidget *widget, GtkSelectionData *selection_data, 
11267                     gpointer data)
11268 {
11269   GdkAtom *atoms;
11270   GList *item_list;
11271   int i;
11272
11273   /* **** IMPORTANTE **** Comprobar si se da la recuperación de los
11274    * datos */
11275   if (selection_data->length < 0)
11276     {
11277       g_print ("Selection retrieval failed\n");
11278       return;
11279     }
11280   /* Asegurarse de que obtenemos los datos de la forma esperada */
11281   if (selection_data->type != GDK_SELECTION_TYPE_ATOM)
11282     {
11283       g_print ("Selection \"TARGETS\" was not returned as atoms!\n");
11284       return;
11285     }
11286   
11287   /* Imprimir los atoms que hemos recibido */
11288   atoms = (GdkAtom *)selection_data->data;
11289
11290   item_list = NULL;
11291   for (i=0; i<selection_data->length/sizeof(GdkAtom); i++)
11292     {
11293       char *name;
11294       name = gdk_atom_name (atoms[i]);
11295       if (name != NULL)
11296         g_print ("%s\n",name);
11297       else
11298         g_print ("(bad atom)\n");
11299     }
11300
11301   return;
11302 }
11303
11304 int 
11305 main (int argc, char *argv[])
11306 {
11307   GtkWidget *ventana;
11308   GtkWidget *boton;
11309   
11310   gtk_init (&amp;argc, &amp;argv);
11311
11312   /* Crear la ventana superior */
11313
11314   ventana = gtk_window_new (GTK_WINDOW_TOPLEVEL);
11315   gtk_window_set_title (GTK_WINDOW (ventana), "Event Box");
11316   gtk_container_border_width (GTK_CONTAINER (ventana), 10);
11317
11318   gtk_signal_connect (GTK_OBJECT (ventana), "destroy",
11319                       GTK_SIGNAL_FUNC (gtk_exit), NULL);
11320
11321   /* Crear un botón que el usuario puede pulsar para obtener los
11322    * objetivos */
11323
11324   boton = gtk_button_new_with_label ("Get Targets");
11325   gtk_container_add (GTK_CONTAINER (ventana), boton);
11326
11327   gtk_signal_connect (GTK_OBJECT(boton), "clicked",
11328                       GTK_SIGNAL_FUNC (get_targets), NULL);
11329   gtk_signal_connect (GTK_OBJECT(boton), "selection_received",
11330                       GTK_SIGNAL_FUNC (selection_received), NULL);
11331
11332   gtk_widget_show (boton);
11333   gtk_widget_show (ventana);
11334   
11335   gtk_main ();
11336   
11337   return 0;
11338 }
11339 /* fin del ejemplo */
11340 </verb></tscreen>
11341
11342 <!-- ----------------------------------------------------------------- -->
11343 <sect1> Proporcionando la selección
11344 <p>
11345 Proporcionar la selección es un poco más complicado. Debe registrar
11346 los manejadores a los que se llamarán cuando se le pida la
11347 selección. Por cada par selección/objetivo que quiera manejar, deberá
11348 hacer una llamada a:
11349
11350 <tscreen><verb>
11351 void gtk_selection_add_handler( GtkWidget            *widget, 
11352                                 GdkAtom               selection,
11353                                 GdkAtom               target,
11354                                 GtkSelectionFunction  function,
11355                                 GtkRemoveFunction     remove_func,
11356                                 gpointer              data );
11357 </verb></tscreen>
11358
11359 <tt/widget/, <tt/selection/, y <tt/target/ identifican las peticiones
11360 que este manejador puede manipular. Si <tt/remove_func/ no es NULL, se
11361 le llamará cuando se elimine el manejador de la señal. Esto es útil,
11362 por ejemplo, para los lenguajes interpretados que necesitan mantener
11363 una memoria de las referencias a <tt/data/.
11364
11365 La función de llamada tiene el prototipo:
11366
11367 <tscreen><verb>
11368 typedef void (*GtkSelectionFunction)( GtkWidget        *widget, 
11369                                       GtkSelectionData *selection_data,
11370                                       gpointer          data );
11371
11372 </verb></tscreen>
11373
11374 El <tt/GtkSelectionData/ es el mismo que hay más arriba, pero esta
11375 vez, seremos nosotros los responsables de rellenar los campos
11376 <tt/type/, <tt/format/, <tt/data/, y <tt/length/. (El campo
11377 <tt/format/ es importante - el servidor X lo utiliza para saber si
11378 tienen que intercambiarse los bytes que forman los datos o
11379 no. Normalmente será 8 - es decir un carácter - o 32 - es decir un
11380 entero.) Esto se hace llamando a la función:
11381
11382 <tscreen><verb>
11383 void gtk_selection_data_set( GtkSelectionData *selection_data,
11384                              GdkAtom           type,
11385                              gint              format,
11386                              guchar           *data,
11387                              gint              length );
11388 </verb></tscreen>
11389
11390 Esta función tiene la responsabilidad de hacer una copia de los datos
11391 para que no tenga que preocuparse de ir guardándolos. (No debería
11392 rellenar los campos de la estructura <tt/GtkSelectionData/ a mano.)
11393
11394 Cuando haga falta, puede pedir el propietario de la selección llamando
11395 a:
11396
11397 <tscreen><verb>
11398 gint gtk_selection_owner_set( GtkWidget *widget,
11399                               GdkAtom    selection,
11400                               guint32    time );
11401 </verb></tscreen>
11402
11403 Si otra aplicación pide el propietario de la selección, recibira un
11404 «selection_clear_event».
11405
11406 Como ejemplo de proporciar la selección, el programa siguiente le añade
11407 la posibilidad de selección a un botón de comprobación. Cuando se presione
11408 el botón de comprobación, el programa pedirá la selección primaria. El
11409 único objetivo que admite es un objetivo «STRING» (aparte de ciertos
11410 objetivos como "TARGETS", proporcionados por GTK). Cuando se pida este
11411 objetivo, se devolverá una representación del tiempo.
11412
11413 <tscreen><verb>
11414 /* principio del ejemplo selection setselection.c */
11415
11416 #include <gtk/gtk.h>
11417 #include <time.h>
11418
11419 /* Función de llamada para cuando el usuario cambia la selección */
11420 void
11421 selection_toggled (GtkWidget *widget, gint *have_selection)
11422 {
11423   if (GTK_TOGGLE_BUTTON(widget)->active)
11424     {
11425       *have_selection = gtk_selection_owner_set (widget,
11426                                                  GDK_SELECTION_PRIMARY,
11427                                                  GDK_CURRENT_TIME);
11428       /* Si la demanda de la selección ha fallado, ponemos el botón en
11429        * estado apagado */
11430       if (!*have_selection)
11431         gtk_toggle_button_set_state (GTK_TOGGLE_BUTTON(widget), FALSE);
11432     }
11433   else
11434     {
11435       if (*have_selection)
11436         {
11437           /* Antes de eliminar la seleción poniendo el propietario a
11438            * NULL, comprobamos si somos el propietario actual */
11439           if (gdk_selection_owner_get (GDK_SELECTION_PRIMARY) == widget->window)
11440             gtk_selection_owner_set (NULL, GDK_SELECTION_PRIMARY,
11441                                      GDK_CURRENT_TIME);
11442           *have_selection = FALSE;
11443         }
11444     }
11445 }
11446
11447 /* Llamado cuando otra aplicación pide la selección */
11448 gint
11449 selection_clear (GtkWidget *widget, GdkEventSelection *event,
11450                  gint *have_selection)
11451 {
11452   *have_selection = FALSE;
11453   gtk_toggle_button_set_state (GTK_TOGGLE_BUTTON(widget), FALSE);
11454
11455   return TRUE;
11456 }
11457
11458 /* Proporciona el tiempo actual como selección. */
11459 void
11460 selection_handle (GtkWidget *widget, 
11461                   GtkSelectionData *selection_data,
11462                   gpointer data)
11463 {
11464   gchar *timestr;
11465   time_t current_time;
11466
11467   current_time = time (NULL);
11468   timestr = asctime (localtime(&amp;current_time)); 
11469   /* Cuando devolvemos una cadena, no debe terminar en NULL. La
11470    * función lo hará por nosotros */
11471
11472   gtk_selection_data_set (selection_data, GDK_SELECTION_TYPE_STRING,
11473                           8, timestr, strlen(timestr));
11474 }
11475
11476 int
11477 main (int argc, char *argv[])
11478 {
11479   GtkWidget *ventana;
11480
11481   GtkWidget *selection_button;
11482
11483   static int have_selection = FALSE;
11484   
11485   gtk_init (&amp;argc, &amp;argv);
11486
11487   /* Crear la ventana superior */
11488
11489   ventana = gtk_window_new (GTK_WINDOW_TOPLEVEL);
11490   gtk_window_set_title (GTK_WINDOW (ventana), "Event Box");
11491   gtk_container_border_width (GTK_CONTAINER (ventana), 10);
11492
11493   gtk_signal_connect (GTK_OBJECT (ventana), "destroy",
11494                       GTK_SIGNAL_FUNC (gtk_exit), NULL);
11495
11496   /* Crear un botón de selección para que actue como la selección */
11497
11498   selection_button = gtk_toggle_button_new_with_label ("Claim Selection");
11499   gtk_container_add (GTK_CONTAINER (ventana), selection_button);
11500   gtk_widget_show (selection_button);
11501
11502   gtk_signal_connect (GTK_OBJECT(selection_button), "toggled",
11503                       GTK_SIGNAL_FUNC (selection_toggled), &amp;have_selection);
11504   gtk_signal_connect (GTK_OBJECT(selection_button), "selection_clear_event",
11505                       GTK_SIGNAL_FUNC (selection_clear), &amp;have_selection);
11506
11507   gtk_selection_add_handler (selection_button, GDK_SELECTION_PRIMARY,
11508                              GDK_SELECTION_TYPE_STRING,
11509                              selection_handle, NULL);
11510
11511   gtk_widget_show (selection_button);
11512   gtk_widget_show (ventana);
11513   
11514   gtk_main ();
11515   
11516   return 0;
11517 }
11518 /* fin del ejemplo */
11519 </verb></tscreen>
11520
11521
11522 <!-- ***************************************************************** -->
11523 <sect>Glib<label id="sec_glib">
11524 <!-- ***************************************************************** -->
11525 <p>
11526 Glib proporciona muchas definiciones y funciones útiles disponibles
11527 para su utilización cuando se crean aplicaciones GDK y GTK. Haré una
11528 lista con todas ellas incluyendo una pequeña explicación. Muchas no
11529 son más que duplicados de funciones estándar de libc por lo que no
11530 entraré en detalle en la explicación de las mismas. Esta sección está
11531 pensada principalmente para que se utilice como referencia, para que
11532 sepa que es lo que puede utilizar.
11533
11534 <!-- ----------------------------------------------------------------- -->
11535 <sect1>Definiciones
11536 <p>
11537 Las definiciones para los límites de muchos de los tipos estándar son:
11538
11539 <tscreen><verb>
11540 G_MINFLOAT
11541 G_MAXFLOAT
11542 G_MINDOUBLE
11543 G_MAXDOUBLE
11544 G_MINSHORT
11545 G_MAXSHORT
11546 G_MININT
11547 G_MAXINT
11548 G_MINLONG
11549 G_MAXLONG
11550 </verb></tscreen>
11551
11552 Y también, los siguientes <tt/typedefs/. Cuando no se especifica el
11553 tipo que debería aparecer a la izquierda significa que el mismo se
11554 establecerá dinámicamente en función de la arquitectura. ¡Recuerde
11555 evitar los calculos relativos al tamaño de un puntero si  quiere que
11556 su aplicación sea portable! P.e., un puntero en un Alpha tiene 8
11557 bytes, pero 4 en Intel.
11558
11559 <tscreen><verb>
11560 char   gchar;
11561 short  gshort;
11562 long   glong;
11563 int    gint;
11564 char   gboolean;
11565
11566 unsigned char   guchar;
11567 unsigned short  gushort;
11568 unsigned long   gulong;
11569 unsigned int    guint;
11570
11571 float   gfloat;
11572 double  gdouble;
11573 long double gldouble;
11574
11575 void* gpointer;
11576
11577 gint8
11578 guint8
11579 gint16
11580 guint16
11581 gint32
11582 guint32
11583 </verb></tscreen>
11584
11585 <!-- ----------------------------------------------------------------- -->
11586 <sect1>Listas doblemente enlazadas
11587 <p>
11588 Las funciones siguientes se utilizan para crear, manipular, y destruir
11589 listas doblemente enlazadas. Supondré que sabe lo que son las listas
11590 enlazadas, ya que explicarlas va más allá del objetivo de este
11591 documento. Por supuesto, no es necesario que conozca como manejar
11592 todo esto para utilizar GTK, pero siempre es bonito aprender cosas.
11593
11594 <tscreen><verb>
11595 GList *g_list_alloc( void );
11596
11597 void g_list_free( GList *list );
11598
11599 void g_list_free_1( GList *list );
11600
11601 GList *g_list_append( GList     *list,
11602                       gpointer   data );
11603                            
11604 GList *g_list_prepend( GList    *list,
11605                        gpointer  data );
11606                         
11607 GList *g_list_insert( GList    *list,
11608                       gpointer  data,
11609                       gint      posicion );
11610
11611 GList *g_list_remove( GList    *list,
11612                       gpointer  data );
11613                            
11614 GList *g_list_remove_link( GList *list,
11615                            GList *link );
11616
11617 GList *g_list_reverse( GList *list );
11618
11619 GList *g_list_nth( GList *list,
11620                    gint   n );
11621                            
11622 GList *g_list_find( GList    *list,
11623                     gpointer  data );
11624
11625 GList *g_list_last( GList *list );
11626
11627 GList *g_list_first( GList *list );
11628
11629 gint g_list_length( GList *list );
11630
11631 void g_list_foreach( GList    *list,
11632                      GFunc     func,
11633                      gpointer  user_data );
11634 </verb></tscreen>                                             
11635
11636 <!-- ----------------------------------------------------------------- -->
11637 <sect1>Listas simplemente enlazadas
11638 <p>
11639 Muchas de las funciones para las listas enlazadas son idénticas a las
11640 de más arriba. Aquí hay una lista completa:
11641
11642 <tscreen><verb>
11643 GSList *g_slist_alloc( void );
11644
11645 void g_slist_free( GSList *list );
11646
11647 void g_slist_free_1( GSList *list );
11648
11649 GSList *g_slist_append( GSList   *list,
11650                         gpointer  data );
11651                 
11652 GSList *g_slist_prepend( GSList   *list,
11653                          gpointer  data );
11654                              
11655 GSList *g_slist_insert( GSList   *list,
11656                         gpointer  data,
11657                             gint      posicion );
11658                              
11659 GSList *g_slist_remove( GSList   *list,
11660                         gpointer  data );
11661                              
11662 GSList *g_slist_remove_link( GSList *list,
11663                              GSList *link );
11664                              
11665 GSList *g_slist_reverse( GSList *list );
11666
11667 GSList *g_slist_nth( GSList *list,
11668                      gint    n );
11669                              
11670 GSList *g_slist_find( GSList   *list,
11671                       gpointer  data );
11672                              
11673 GSList *g_slist_last( GSList *list );
11674
11675 gint g_slist_length( GSList *list );
11676
11677 void g_slist_foreach( GSList   *list,
11678                       GFunc     func,
11679                       gpointer  user_data );
11680         
11681 </verb></tscreen>
11682
11683 <!-- ----------------------------------------------------------------- -->
11684 <sect1>Control de la memoria
11685 <p>
11686 <tscreen><verb>
11687 gpointer g_malloc( gulong size );
11688 </verb></tscreen>
11689
11690 Reemplaza a <tt/malloc()/. No necesita comprobar el valor devuelto, ya
11691 que ya lo hace por usted esta función.
11692
11693 <tscreen><verb>
11694 gpointer g_malloc0( gulong size );
11695 </verb></tscreen>
11696
11697 Lo mismo que antes, pero rellena con ceros la memoria antes de
11698 devolver un puntero a ella.
11699
11700 <tscreen><verb>
11701 gpointer g_realloc( gpointer mem,
11702                     gulong   size );
11703 </verb></tscreen>
11704
11705 Vuelve a reservar <tt/size/ bites de memoria empezando en
11706 <tt/mem/. Obviamente, la memoria debe haber sido previamente reservada.
11707
11708 <tscreen><verb>
11709 void g_free( gpointer mem );
11710 </verb></tscreen>
11711
11712 Libera la memoria. Fácil.
11713
11714 <tscreen><verb>
11715 void g_mem_profile( void );
11716 </verb></tscreen>
11717
11718 Crea un fichero donde vuelca la memoria que se está utilizando, pero
11719 tiene que añadir <tt/#define MEM_PROFILE/ en lo alto de
11720 <tt>glib/gmem.c</tt> y tendrá que hacer un make y un make install.
11721
11722 <tscreen><verb>
11723 void g_mem_check( gpointer mem );
11724 </verb></tscreen>
11725
11726 Comprueba que una dirección de memoria es válida. Tiene que añadir
11727 <tt/#define MEM_CHECK/ en lo alto de <tt/gmem.c/ y tiene que hacer un
11728 make y un make install.
11729
11730 <!-- ----------------------------------------------------------------- -->
11731 <sect1>Timers
11732 <p>
11733 Temporizadores...
11734
11735 <tscreen><verb>
11736 GTimer *g_timer_new( void );
11737
11738 void g_timer_destroy( GTimer *timer );
11739
11740 void g_timer_start( GTimer  *timer );
11741
11742 void g_timer_stop( GTimer  *timer );
11743
11744 void g_timer_reset( GTimer  *timer );
11745
11746 gdouble g_timer_elapsed( GTimer *timer,
11747                          gulong *microseconds );
11748 </verb></tscreen>                        
11749
11750 <!-- ----------------------------------------------------------------- -->
11751 <sect1>Manejo de cadenas de texto
11752 <p>
11753 Un puñado de funciones para manejar cadenas de texto. Parecen muy
11754 interesantes, y probablemente sean mejores en muchos aspectos que las
11755 funciones estándar de C, pero necesitan documentación.
11756
11757 <tscreen><verb>
11758 GString *g_string_new( gchar *init );
11759
11760 void g_string_free( GString *string,
11761                     gint     free_segment );
11762                              
11763 GString *g_string_assign( GString *lval,
11764                           gchar   *rval );
11765                              
11766 GString *g_string_truncate( GString *string,
11767                             gint     len );
11768                              
11769 GString *g_string_append( GString *string,
11770                           gchar   *val );
11771                             
11772 GString *g_string_append_c( GString *string,
11773                             gchar    c );
11774         
11775 GString *g_string_prepend( GString *string,
11776                            gchar   *val );
11777                              
11778 GString *g_string_prepend_c( GString *string,
11779                              gchar    c );
11780         
11781 void g_string_sprintf( GString *string,
11782                        gchar   *fmt,
11783                        ...);
11784         
11785 void g_string_sprintfa ( GString *string,
11786                          gchar   *fmt,
11787                          ... );
11788 </verb></tscreen>                                                         
11789
11790 <!-- ----------------------------------------------------------------- -->
11791 <sect1>Funciones de error y funciones varias
11792 <p>
11793 <tscreen><verb>
11794 gchar *g_strdup( const gchar *str );
11795 </verb></tscreen>
11796
11797 Reemplaza a la función <tt/strdup/. Copia el contenido de la cadena
11798 original en un nuevo lugar en memoria, y devuelve un puntero al nuevo
11799 lugar.
11800
11801 <tscreen><verb>
11802 gchar *g_strerror( gint errnum );
11803 </verb></tscreen>
11804
11805 Recomiendo utilizar esta función para todos los mensages de error. Es
11806 mucho más bonita, y más portable que <tt/perror()/ y demás funciones
11807 clásicas. La salida es normalmente de la forma:
11808
11809 <tscreen><verb>
11810 nombre del programa:función que falló:fichero o descripción adicional:strerror
11811 </verb></tscreen>
11812
11813 Aquí hay un ejemplo de una llamada utilizada en nuestro programa
11814 <tt/hello_world/:
11815
11816 <tscreen><verb>
11817 g_print("hello_world:open:%s:%s\n", filename, g_strerror(errno));
11818 </verb></tscreen>
11819
11820 <tscreen><verb>
11821 void g_error( gchar *format, ... );
11822 </verb></tscreen>
11823
11824 Imprime un mensaje de error. El formato es como el de <tt/printf/,
11825 pero le añade <tt/** ERROR **: / a su mensaje, y sale del
11826 programa. Sólo para errores fatales.
11827
11828 <tscreen><verb>
11829 void g_warning( gchar *format, ... );
11830 </verb></tscreen>
11831
11832 El mismo que el anterior, pero añade "** WARNING **: ", y no sale del
11833 programa.
11834
11835 <tscreen><verb>
11836 void g_message( gchar *format, ... );
11837 </verb></tscreen>
11838
11839 Imprime <tt/message: / antes de la cadena que le pase.
11840
11841 <tscreen><verb>
11842 void g_print( gchar *format, ... );
11843 </verb></tscreen>
11844
11845 Reemplazo de <tt/printf()/.
11846
11847 Y nuestra última función:
11848
11849 <tscreen><verb>
11850 gchar *g_strsignal( gint signum );
11851 </verb></tscreen>
11852
11853 Imprime el nombre de la señal del sistema Unix que corresponde con el
11854 número <tt/signum/. Útil para las funciones genéricas de manejo de señal.
11855
11856 Todo lo anterior está más o menos robado de <tt/glib.h/. Si alguien
11857 quiere documentar una función, ¡sólo tiene que enviarme un correo-e!
11858
11859 <!-- ***************************************************************** -->
11860 <sect>Ficheros rc de GTK
11861 <!-- ***************************************************************** -->
11862 <p>
11863 GTK tiene su propia forma de conseguir los valores por defecto de una
11864 aplicación, y es utilizando los ficheros <tt/rc/. Pueden ser
11865 utilizados para poner los colores de cualquier <em/widget/, y también
11866 pueden utilizarse para poner imágenes como fondos de algunos <em/widgets/.
11867
11868 <!-- ----------------------------------------------------------------- -->
11869 <sect1>Funciones para los ficheros <tt/rc/
11870 <p>
11871 Cuando empiece su aplicación, debería incluir una llamada a:
11872
11873 <tscreen><verb>
11874 void gtk_rc_parse( char *filename );
11875 </verb></tscreen>
11876
11877 Poniendo el nombre del fichero de su rc. Esto hará que GTK analice
11878 este fichero, y utilice el estilo para los <em/widgets/ que se definan
11879 ahí.
11880
11881 Si desea tener un conjunto especial de <em/widgets/ con un estilo
11882 diferente de los otros, o realizar cualquier otra división lógica de
11883 los <em/widgets/, haga una llamada a:
11884
11885 <tscreen><verb>
11886 void gtk_widget_set_name( GtkWidget *widget,
11887                           gchar     *name );
11888 </verb></tscreen>
11889
11890 Pasándole su nuevo <em/widget/ como primer argumento, y el nombre que
11891 desea darle como el segundo. Mediante este nombre podrá cambiar los
11892 atributos de ese <em/widget/.
11893
11894 Si hacemos algo así:
11895
11896 <tscreen><verb>
11897 boton = gtk_button_new_with_label ("Botón especial");
11898 gtk_widget_set_name (boton, "botón especial");
11899 </verb></tscreen>
11900
11901 El botón tendrá el nombre «botón especial» y podría hacersele
11902 referencia en el fichero <tt/rc/ como «botón especial.GtkButton».
11903 [<--- ¡Verificadme! ]
11904
11905 El fichero de ejemplo <tt/rc/ que mostramos a continuación, establece las
11906 propiedades de la ventana principal, y deja que todos los hijos de la
11907 ventana principal hereden el estilo descrito por «main button». El
11908 código utilizado en la aplicación es:
11909
11910 <tscreen><verb>
11911 ventana = gtk_window_new (GTK_WINDOW_TOPLEVEL);
11912 gtk_widget_set_name (ventana, "main window");
11913 </verb></tscreen>
11914
11915 Y el estilo se define en el fichero <tt/rc/ utilizando:
11916
11917 <tscreen><verb>
11918 widget "main window.*GtkButton*" style "main_button"
11919 </verb></tscreen>
11920
11921 Qué hace que todos los <em/widgets/ GtkButton de la «main window»
11922 (ventana principal) tengan el estilo "main_buttons" tal y como se
11923 define en el fichero <tt/rc/.
11924
11925 Como puede ver, es un sistema muy poderoso y flexible. Utilice su
11926 imaginación para aprovecharse al máximo de este sistema.
11927
11928 <!-- ----------------------------------------------------------------- -->
11929 <sect1>Formato de los ficheros <tt/rc/ de GTK
11930 <p>
11931 El formato de los ficheros GTK se muestra en el ejemplo de más
11932 abajo. Éste es el fichero <tt/testgtkrc/ de la distribución GTK, pero he
11933 añadido unos cuantos comentarios y alguna cosilla. Puede que quiera
11934 incluir esta explicación en su aplicación para permitir al usuario
11935 personalizar su aplicación.
11936
11937 Hay varias directivas para cambiar los atributos de un <em/widget/.
11938
11939 <itemize>
11940 <item>fg - Establece el color de primer plano de un <em/widget/.
11941 <item>bg - Establece el color de fondo de un <em/widget/.
11942 <item>bg_pixmap - Establece la imagen que servirá de fondo al
11943 <em/widget/ (como mosaico).
11944 <item>font - Establece el tipo de letra que se utilizará con el
11945 <em/widget/.
11946 </itemize>
11947
11948 Además de esto, hay varios estados en el que puede estar un
11949 <em/widget/, y puede especificar diferentes colores, imágenes y tipos
11950 de letra para cada estado. Estos estados son:
11951
11952 <itemize>
11953 <item>NORMAL - El estado normal de un <em/widget/, sin el ratón sobre
11954 él, y no siendo presionado, etc...
11955 <item>PRELIGHT - Cuando el ratón esté sobre este <em/widget/ se
11956 utilizarán los colores definidos para este estado. 
11957 <item>ACTIVE - Cuando se presiona o se pulsa sobre el <em/widget/,
11958 estará activo, y los atributos asignados por está etiqueta serán
11959 utilizados. 
11960 <item>INSENSITIVE - Cuando un <em/widget/ es insensible, y no se puede
11961 activar, tomará estos atributos.
11962 <item>SELECTED - Cuando se seleccione un objeto, tomará estos atributos.
11963 </itemize>
11964
11965 Cuando se utilizan las directivas «fg» y «bg» para poner los colores de
11966 los <em/widgets/, se utilizará el formato siguiente:
11967
11968 <tscreen><verb>
11969 fg[<STATE>] = { Red, Green, Blue }
11970 </verb></tscreen>
11971
11972 Donde <tt/STATE/ es uno de los estados anteriores (PRELIGHT, ACTIVE,
11973 etc...), y el <tt/Red/, <tt/Green/ y <tt/Blue/ (Rojo, Verde y Azul)
11974 son valores en el rango 0 - 1.0, { 1.0, 1.0, 1.0 } es blanco. Deben
11975 estar en formato flotante, o serán un 0, por lo que "1" no funcionará,
11976 debe ser "1.0". Un "0" está bien ya que es lo mismo si no se
11977 reconoce. Los valores no reconocidos se pondrán a 0.
11978
11979 <tt/bg_pixmap/ es muy similar al de arriba, salvo que los colores se
11980 reemplazan por un nombre de fichero.
11981
11982 <tt/pixmap_path/ es una lista de los caminos (<em/paths/) separados por
11983 «:». Estos caminos se utilizarán para buscar cualquier imagen que
11984 indique.
11985
11986 La directiva sobre el tipo de letra es simplemente:
11987 <tscreen><verb>
11988 font = "<nombre del tipo de letra>"
11989 </verb></tscreen>
11990
11991 Donde lo único difícil es saber la cadena del tipo de letra a
11992 elegir. Utilizar <tt/xfontsel/ o un programa similar debería ayudar.
11993
11994 El <tt/widget_class/ establece el estilo de una clase de
11995 <em/widgets/. Estas clases se muestran en el resumen de <em/widgets/
11996 dentro de la jerarquía de clases.
11997
11998 La directiva <tt/widget/ hace que un conjunto específico de
11999 <em/widgets/ tenga un estido determinado, sobreescribiendo cualquier
12000 estilo anterior que tuviese esa clase de <em/widgets/. Estos
12001 <em/widgets/ se registran dentro de la aplicación utilizando una
12002 llamada a <tt/gtk_widget_set_name()/. Esto le permitirá especificar
12003 los atributos de un <em/widget/ uno a uno, en vez de establecer los
12004 atributos de toda una clase <em/widget/. Deberá documentar cualquiera
12005 de estos <em/widgets/ especiales para que los usuarios puedan
12006 personalizarlos.
12007
12008 Cuando la palabra clave <tt/parent/ se utiliza como un atributo, el
12009 <em/widget/ tomará los atributos de su padre en la aplicación.
12010
12011 Puede asignar los atributos de un estilo previamente definido a uno
12012 nuevo.
12013
12014 <tscreen><verb>
12015 style "main_button" = "button"
12016 {
12017   font = "-adobe-helvetica-medium-r-normal--*-100-*-*-*-*-*-*"
12018   bg[PRELIGHT] = { 0.75, 0, 0 }
12019 }
12020 </verb></tscreen>
12021
12022 Este ejemplo toma el estilo «button», y crea un nuevo estilo
12023 «main_button» cambiando simplemente el tipo de letra y cambiando el
12024 color de fondo cuando el <em/widget/ esté en estado <tt/PRELIGHT/.
12025
12026 Por supuesto, muchos de estos atributos no se aplican a todos los
12027 <em/widgets/. Realmente es una cuestión de sentido común. Se utilizará
12028 cualquier atributo que se pueda aplicar.
12029
12030 <!-- ----------------------------------------------------------------- -->
12031 <sect1>Fichero <tt/rc/ de ejemplo
12032 <p>
12033
12034 <!-- Esto hay que traducirlo -->
12035 <tscreen><verb>
12036 # pixmap_path "<dir 1>:<dir 2>:<dir 3>:..."
12037 #
12038 pixmap_path "/usr/include/X11R6/pixmaps:/home/imain/pixmaps"
12039 #
12040 # style <name> [= <name>]
12041 # {
12042 #   <option>
12043 # }
12044 #
12045 # widget <widget_set> style <style_name>
12046 # widget_class <widget_class_set> style <style_name>
12047
12048
12049 # Here is a list of all the possible states.  Note that some do not apply to
12050 # certain widgets.
12051 #
12052 # NORMAL - The normal state of a widget, without the mouse over top of
12053 # it, and not being pressed etc.
12054 #
12055 # PRELIGHT - When the mouse is over top of the widget, colors defined
12056 # using this state will be in effect.
12057 #
12058 # ACTIVE - When the widget is pressed or clicked it will be active, and
12059 # the attributes assigned by this tag will be in effect.
12060 #
12061 # INSENSITIVE - When a widget is set insensitive, and cannot be
12062 # activated, it will take these attributes.
12063 #
12064 # SELECTED - When an object is selected, it takes these attributes.
12065 #
12066 # Given these states, we can set the attributes of the widgets in each of
12067 # these states using the following directives.
12068 #
12069 # fg - Sets the foreground color of a widget.
12070 # fg - Sets the background color of a widget.
12071 # bg_pixmap - Sets the background of a widget to a tiled pixmap.
12072 # font - Sets the font to be used with the given widget.
12073 #
12074
12075 # This sets a style called "button".  The name is not really important, as
12076 # it is assigned to the actual widgets at the bottom of the file.
12077
12078 style "window"
12079 {
12080   #This sets the padding around the window to the pixmap specified.
12081   #bg_pixmap[<STATE>] = "<pixmap filename>"
12082   bg_pixmap[NORMAL] = "warning.xpm"
12083 }
12084
12085 style "scale"
12086 {
12087   #Sets the foreground color (font color) to red when in the "NORMAL"
12088   #state.
12089   
12090   fg[NORMAL] = { 1.0, 0, 0 }
12091   
12092   #Sets the background pixmap of this widget to that of its parent.
12093   bg_pixmap[NORMAL] = "<parent>"
12094 }
12095
12096 style "button"
12097 {
12098   # This shows all the possible states for a button.  The only one that
12099   # doesn't apply is the SELECTED state.
12100   
12101   fg[PRELIGHT] = { 0, 1.0, 1.0 }
12102   bg[PRELIGHT] = { 0, 0, 1.0 }
12103   bg[ACTIVE] = { 1.0, 0, 0 }
12104   fg[ACTIVE] = { 0, 1.0, 0 }
12105   bg[NORMAL] = { 1.0, 1.0, 0 }
12106   fg[NORMAL] = { .99, 0, .99 }
12107   bg[INSENSITIVE] = { 1.0, 1.0, 1.0 }
12108   fg[INSENSITIVE] = { 1.0, 0, 1.0 }
12109 }
12110
12111 # In this example, we inherit the attributes of the "button" style and then
12112 # override the font and background color when prelit to create a new
12113 # "main_button" style.
12114
12115 style "main_button" = "button"
12116 {
12117   font = "-adobe-helvetica-medium-r-normal--*-100-*-*-*-*-*-*"
12118   bg[PRELIGHT] = { 0.75, 0, 0 }
12119 }
12120
12121 style "toggle_button" = "button"
12122 {
12123   fg[NORMAL] = { 1.0, 0, 0 }
12124   fg[ACTIVE] = { 1.0, 0, 0 }
12125   
12126   # This sets the background pixmap of the toggle_button to that of its
12127   # parent widget (as defined in the application).
12128   bg_pixmap[NORMAL] = "<parent>"
12129 }
12130
12131 style "text"
12132 {
12133   bg_pixmap[NORMAL] = "marble.xpm"
12134   fg[NORMAL] = { 1.0, 1.0, 1.0 }
12135 }
12136
12137 style "ruler"
12138 {
12139   font = "-adobe-helvetica-medium-r-normal--*-80-*-*-*-*-*-*"
12140 }
12141
12142 # pixmap_path "~/.pixmaps"
12143
12144 # These set the widget types to use the styles defined above.
12145 # The widget types are listed in the class hierarchy, but could probably be
12146 # just listed in this document for the users reference.
12147
12148 widget_class "GtkWindow" style "window"
12149 widget_class "GtkDialog" style "window"
12150 widget_class "GtkFileSelection" style "window"
12151 widget_class "*Gtk*Scale" style "scale"
12152 widget_class "*GtkCheckButton*" style "toggle_button"
12153 widget_class "*GtkRadioButton*" style "toggle_button"
12154 widget_class "*GtkButton*" style "button"
12155 widget_class "*Ruler" style "ruler"
12156 widget_class "*GtkText" style "text"
12157
12158 # This sets all the buttons that are children of the "main window" to
12159 # the main_button style.  These must be documented to be taken advantage of.
12160 widget "main window.*GtkButton*" style "main_button"
12161 </verb></tscreen>
12162
12163 <!-- ***************************************************************** -->
12164 <sect>Escribiendo sus propios <em/widgets/
12165 <!-- ***************************************************************** -->
12166
12167 <!-- ----------------------------------------------------------------- -->
12168 <sect1> Visión general
12169 <p>
12170 Aunque la distribución de GTK viene con muchos tipos de <em/widgets/
12171 que debería cubrir todas la mayoría de las necesidades básicas, puede
12172 que haya llegado el momento en que necesite crear su propio
12173 <em/widget/. Debido a que GTK utiliza mucho la herencia de
12174 <em/widgets/, y si ya hay un <em/widget/ que se acerque lo suficiente
12175 a lo que quiere, tal vez pueda hacer un nuevo <em/widget/ con tan solo
12176 unas cuantas líneas de código. Pero antes de empezar a trabajar en un
12177 nuevo <em/widget/, asegúrese primero de que no hay nadie que ya haya
12178 hecho otro parecido. Así evitará la duplicación de esfuerzo y
12179 mantendrá el número de <em/widgets/ GTK en su valor mínimo, lo que
12180 ayudará a que el código y la interfaz de las diferentes aplicaciones
12181 sea consistente. Por otra parte, cuando haya acabado su <em/widget/,
12182 anúncielo al mundo entreo para que todo el mundo se pueda
12183 beneficiar. Probablemente el mejor lugar para hacerlo sea la
12184 <tt>gtk-list</tt>.
12185
12186 Las fuentes completas de los <em/widgets/ de ejemplo están disponibles
12187 en el mismo lugar en el que consiguió este tutorial, o en:
12188
12189 <htmlurl url="http://www.gtk.org/~otaylor/gtk/tutorial/"
12190 name="http://www.gtk.org/~otaylor/gtk/tutorial/">
12191
12192
12193 <!-- ----------------------------------------------------------------- -->
12194 <sect1> La anatomía de un <em/widget/
12195 <p>
12196 Para crear un nuevo <em/widget/, es importante conocer como funcionan
12197 los objetos de GTK. Esta sección es sólo un breve resumen. Ver la
12198 documentación a la que se hace referencia para obtener más detalles.
12199
12200 Los widgets GTK están implementados siguiendo una orientación a
12201 objetos. Sin embargo, están implementados en C estándar. De esta forma
12202 se mejora enormemente la portabilidad y la estabilidad con respecto a
12203 la actual generación de compiladores C++; sin embargo, con todo esto
12204 no queremos decir que el creador de <em/widgets/ tenga que prestar
12205 atención a ninguno de los detalles de implementación. La información
12206 que es común a todos los <em/widgets/ de una clase de <em/widgets/
12207 (p.e., a todos los <em/widgets/ botón) se almacena en la
12208 <em>estructura de clase</em>. Sólo hay una copia de ésta en la que se
12209 almacena información sobre las señales de la clase (que actuan como
12210 funciones virtuales en C). Para permitir la herencia, el primer campo
12211 en la estructura de la clase debe ser una copia de la estructura de la
12212 clase del padre. La declaración de la estructura de la clase de
12213 GtkButton debe ser algo así:
12214
12215 <tscreen><verb>
12216 struct _GtkButtonClass
12217 {
12218   GtkContainerClass parent_class;
12219
12220   void (* pressed)  (GtkButton *button);
12221   void (* released) (GtkButton *button);
12222   void (* clicked)  (GtkButton *button);
12223   void (* enter)    (GtkButton *button);
12224   void (* leave)    (GtkButton *button);
12225 };
12226 </verb></tscreen>
12227
12228 Cuando un botón se trata como un contenedor (por ejemplo, cuando se le
12229 cambia el tamaño), su estructura de clase puede convertirse a
12230 GtkContainerClass, y los campos relevantes se utilizarán para manejar
12231 las señales.
12232
12233 También hay una estructura que se crea para cada <em/widget/. Esta
12234 estructura tiene campos para almacenar la información que es diferente
12235 para cada copia del <em/widget/. Nosotros llamaremos a esta estructura
12236 la <em>estructura objeto</em>. Para la clase botón, es así:
12237
12238 <tscreen><verb>
12239 struct _GtkButton
12240 {
12241   GtkContainer container;
12242
12243   GtkWidget *child;
12244
12245   guint in_button : 1;
12246   guint button_down : 1;
12247 };
12248 </verb></tscreen>
12249
12250 Observe que, como en la estructura de clase, el primer campo es la
12251 estructura objeto de la clase padre, por lo que esta estructura puede
12252 convertirse en la estructura de la clase del objeto padre cuando haga
12253 falta.
12254
12255 <!-- ----------------------------------------------------------------- -->
12256 <sect1> Creando un <em/widget/ compuesto
12257
12258 <!-- ----------------------------------------------------------------- -->
12259 <sect2> Introducción
12260 <p>
12261 Un tipo de widget que puede interesarnos es uno que sea un mero
12262 agregado de otros <em/widgets/ GTK. Este tipo de <em/widget/ no hace
12263 nada que no pueda hacerse sin la necesidad de crear un nuevo
12264 <em/widget/, pero proporciona una forma conveniente de empaquetar los
12265 elementos del interfaz de usuario para su reutilización. Los
12266 <em/widgets/ <tt/FileSelection/ y <tt/ColorSelection/ incluidos en la
12267 distribución estándar son ejemplos de este tipo de <em/widgets/.
12268
12269 El <em/widget/ ejemplo que hemos creado en esta sección es el
12270 <em/widget/ Tictactoe, una matriz de 3x3 de botones de selección que
12271 lanza una señal cuando están deseleccionados tres botones en una misma
12272 fila, columna, o diagonal.
12273
12274 <!-- ----------------------------------------------------------------- -->
12275 <sect2> Escogiendo una clase padre
12276 <p>
12277 Normalmente la clase padre para un <em/widget/ compuesto es la clase
12278 contenedor que tenga todos los elementos del <em/widget/
12279 compuesto. Por ejemplo, la clase padre del <em/widget/
12280 <tt/FileSelection/ es la clase <tt/Dialog/. Ya que nuestros botones se
12281 ordenarán en una tabla, parece natural hacer que nuestra clase padre
12282 sea la clase <tt/GtkTable/. Desafortunadamente, esto no
12283 funcionaría. La creación de un <em/widget/ se divide en dos funciones
12284 - una función <tt/NOMBREWIDGET_new()/ que utilizará el usuario, y una
12285 función <tt/NOMBREWIDGET_init()/ que hará el trabajo básico de
12286 inicializar el <em/widget/ que es independiente de los argumentos que
12287 se le pasen a la función <tt/_new()/. Los <em/widgets/ derivados sólo
12288 llaman a la función <tt/_init/ de su <em/widget/ padre. Pero esta
12289 división del trabajo no funciona bien con las tablas, que necesitan
12290 saber en el momento de su creación el número de filas y de columnas
12291 que deben tener. A menos que queramos duplicar la mayor parte de lo
12292 hecho en <tt/gtk_table_new()/ en nuestro <em/widget/ Tictactoe,
12293 haremos mejor si evitamos derivar de GtkTable. Por esta razón,
12294 derivaremos de <tt/GtkVBox/, y meteremos nuestra tabla dentro de la
12295 caja vertical.
12296
12297 <!-- ----------------------------------------------------------------- -->
12298 <sect2> El fichero de cabecera
12299 <p>
12300 Cada clase <em/widget/ tiene un fichero de cabecera que declara el
12301 objeto y las estructuras de clase para ese <em/widget/, así como las
12302 funciones públicas. Un par de características que merecen dejarse
12303 aparte. Para evitar la duplicación de definiciones, meteremos el
12304 fichero de cabecera al completo entre:
12305
12306 <tscreen><verb>
12307 #ifndef __TICTACTOE_H__
12308 #define __TICTACTOE_H__
12309 .
12310 .
12311 .
12312 #endif /* __TICTACTOE_H__ */
12313 </verb></tscreen>
12314
12315 Y para que los programas en C++ incluyan sin problemas el fichero de
12316 cabecera, pondremos:
12317
12318 <tscreen><verb>
12319 #ifdef __cplusplus
12320 extern "C" {
12321 #endif /* __cplusplus */
12322 .
12323 .
12324 .
12325 #ifdef __cplusplus
12326 }
12327 #endif /* __cplusplus */
12328 </verb></tscreen>
12329
12330 Con las funciones y las estructuras, declararemos tres macros estándar
12331 en nuestro fichero de cabecera, <tt/TICTACTOE(obj)/,
12332 <tt/TICTACTOE_CLASS(class)/, y <tt/IS_TICTACTOE(obj)/, que,
12333 convierten, respectivamente, un puntero en un puntero al objeto o a la
12334 estructura de la clase, y comprueba si un objeto es un <em/widget/
12335 Tictactoe.
12336
12337 Aquí está el fichero de cabecera al completo:
12338
12339 <tscreen><verb>
12340 /* tictactoe.h */
12341
12342 #ifndef __TICTACTOE_H__
12343 #define __TICTACTOE_H__
12344
12345 #include <gdk/gdk.h>
12346 #include <gtk/gtkvbox.h>
12347
12348 #ifdef __cplusplus
12349 extern "C" {
12350 #endif /* __cplusplus */
12351
12352 #define TICTACTOE(obj)          GTK_CHECK_CAST (obj, tictactoe_get_type (), Tictactoe)
12353 #define TICTACTOE_CLASS(klass)  GTK_CHECK_CLASS_CAST (klass, tictactoe_get_type (), TictactoeClass)
12354 #define IS_TICTACTOE(obj)       GTK_CHECK_TYPE (obj, tictactoe_get_type ())
12355
12356
12357 typedef struct _Tictactoe       Tictactoe;
12358 typedef struct _TictactoeClass  TictactoeClass;
12359
12360 struct _Tictactoe
12361 {
12362   GtkVBox vbox;
12363   
12364   GtkWidget *botones[3][3];
12365 };
12366
12367 struct _TictactoeClass
12368 {
12369   GtkVBoxClass parent_class;
12370
12371   void (* tictactoe) (Tictactoe *ttt);
12372 };
12373
12374 guint          tictactoe_get_type        (void);
12375 GtkWidget*     tictactoe_new             (void);
12376 void           tictactoe_clear           (Tictactoe *ttt);
12377
12378 #ifdef __cplusplus
12379 }
12380 #endif /* __cplusplus */
12381
12382 #endif /* __TICTACTOE_H__ */
12383
12384 </verb></tscreen>
12385
12386 <!-- ----------------------------------------------------------------- -->
12387 <sect2> La función <tt/_get_type()/.
12388 <p>
12389 Ahora continuaremos con la implementación de nuestro <em/widget/. Una
12390 función del núcleo de todo <em/widget/ es
12391 <tt/NOMBREWIDGET_get_type()/. Cuando se llame a esta función por
12392 vez primera, le informará a GTK sobre la clase del <em/widget/, y
12393 devolverá un ID que identificará unívocamente la clase <em/widget/. En
12394 las llamadas siguientes, lo único que hará será devolver el ID.
12395
12396 <tscreen><verb>
12397 guint
12398 tictactoe_get_type ()
12399 {
12400   static guint ttt_type = 0;
12401
12402   if (!ttt_type)
12403     {
12404       GtkTypeInfo ttt_info =
12405       {
12406         "Tictactoe",
12407         sizeof (Tictactoe),
12408         sizeof (TictactoeClass),
12409         (GtkClassInitFunc) tictactoe_class_init,
12410         (GtkObjectInitFunc) tictactoe_init,
12411         (GtkArgSetFunc) NULL,
12412         (GtkArgGetFunc) NULL
12413       };
12414
12415       ttt_type = gtk_type_unique (gtk_vbox_get_type (), &amp;ttt_info);
12416     }
12417
12418   return ttt_type;
12419 }
12420 </verb></tscreen>
12421
12422 La estructura GtkTypeInfo tiene la definición siguiente:
12423
12424 <tscreen><verb>
12425 struct _GtkTypeInfo
12426 {
12427   gchar *type_name;
12428   guint object_size;
12429   guint class_size;
12430   GtkClassInitFunc class_init_func;
12431   GtkObjectInitFunc object_init_func;
12432   GtkArgSetFunc arg_set_func;
12433   GtkArgGetFunc arg_get_func;
12434 };
12435 </verb></tscreen>
12436
12437 Los utilidad de cada campo de esta estructura se explica por su propio
12438 nombre. Ignoraremos por ahora los campos <tt/arg_set_func/
12439 y <tt/arg_get_func/: son importantes, pero todavía es raro
12440 utilizarlos, su papel es permitir que las opciones de los <em/wdigets/
12441 puedan establecerse correctamente mediante lenguajes
12442 interpretados. Una vez que GTK tiene una copia de esta estructura
12443 correctamente rellenada, sabrá como crear objetos de un tipo
12444 particular de <em/widget/.
12445
12446 <!-- ----------------------------------------------------------------- -->
12447 <sect2> La función <tt/_class_init()/
12448 <p>
12449 La función <tt/NOMBREWIDGET_class_init()/ inicializa los campos de la
12450 estructura clase del <em/widget/, y establece las señales de la
12451 clase. Para nuestro <em/widget/ Tictactoe será una cosa así:
12452
12453 <tscreen><verb>
12454
12455 enum {
12456   TICTACTOE_SIGNAL,
12457   LAST_SIGNAL
12458 };
12459
12460 static gint tictactoe_signals[LAST_SIGNAL] = { 0 };
12461
12462 static void
12463 tictactoe_class_init (TictactoeClass *class)
12464 {
12465   GtkObjectClass *object_class;
12466
12467   object_class = (GtkObjectClass*) class;
12468   
12469   tictactoe_signals[TICTACTOE_SIGNAL] = gtk_signal_new ("tictactoe",
12470                                          GTK_RUN_FIRST,
12471                                          object_class->type,
12472                                          GTK_SIGNAL_OFFSET (TictactoeClass, tictactoe),
12473                                          gtk_signal_default_marshaller, GTK_TYPE_NONE, 0);
12474
12475
12476   gtk_object_class_add_signals (object_class, tictactoe_signals, LAST_SIGNAL);
12477
12478   class->tictactoe = NULL;
12479 }
12480 </verb></tscreen>
12481
12482 Nuestro <em/widget/ sólo tiene una señal, la señal <tt/tictactoe/ que
12483 se invoca cuando una fila, columna, o diagonal se rellena
12484 completamente. No todos los <em/widgets/ compuestos necesitan señales,
12485 por lo que si está leyendo esto por primera vez, puede que sea mejor
12486 que pase a la sección siguiente, ya que las cosas van a complicarse un
12487 poco.
12488
12489 La función:
12490
12491 <tscreen><verb>
12492 gint gtk_signal_new( const gchar         *name,
12493                      GtkSignalRunType     run_type,
12494                      GtkType              object_type,
12495                      gint                 function_offset,
12496                      GtkSignalMarshaller  marshaller,
12497                      GtkType              return_val,
12498                      guint                nparams,
12499                      ...);
12500 </verb></tscreen>
12501
12502 crea una nueva señal. Los parámetros son:
12503
12504 <itemize>
12505 <item> <tt/name/: El nombre de la señal.
12506 <item> <tt/run_type/: Si el manejador por defecto se ejecuta antes o
12507 despues del manejador de usuario. Normalmente debe ser
12508 <tt/GTK_RUN_FIRST/, o <tt/GTK_RUN_LAST/, aunque hay otras
12509 posibilidades.
12510 <item> <tt/object_type/: El ID del objeto al que se le aplica esta
12511 señal. (También se aplicará a los descendientes de los objetos)
12512 <item> <tt/function_offset/: El desplazamiento en la estructura de la
12513 clase de un puntero al manejador por defecto.
12514 <item> <tt/marshaller/: Una función que se utiliza para invocar al
12515 manejador de señal. Para los manejadores de señal que no tengan más
12516 argumentos que el objeto que emitió la señal podemos utilizar la
12517 función marshaller por defecto <tt/gtk_signal_default_marshaller/.
12518 <item> <tt/return_val/: El tipo del valor devuelto.
12519 <item> <tt/nparams/: El número de parámetros del manejador de señal
12520 (distintos de los dos por defecto que hemos mencionado arriba).
12521 <item> <tt/.../: Los tipos de los parámetros.
12522 </itemize>
12523
12524 Cuando se especifican los tipos, se utilizará la enumeración
12525 <tt/GtkType/:
12526
12527 <tscreen><verb>
12528 typedef enum
12529 {
12530   GTK_TYPE_INVALID,
12531   GTK_TYPE_NONE,
12532   GTK_TYPE_CHAR,
12533   GTK_TYPE_BOOL,
12534   GTK_TYPE_INT,
12535   GTK_TYPE_UINT,
12536   GTK_TYPE_LONG,
12537   GTK_TYPE_ULONG,
12538   GTK_TYPE_FLOAT,
12539   GTK_TYPE_DOUBLE,
12540   GTK_TYPE_STRING,
12541   GTK_TYPE_ENUM,
12542   GTK_TYPE_FLAGS,
12543   GTK_TYPE_BOXED,
12544   GTK_TYPE_FOREIGN,
12545   GTK_TYPE_CALLBACK,
12546   GTK_TYPE_ARGS,
12547
12548   GTK_TYPE_POINTER,
12549
12550   /* it'd be great if the next two could be removed eventually */
12551   GTK_TYPE_SIGNAL,
12552   GTK_TYPE_C_CALLBACK,
12553
12554   GTK_TYPE_OBJECT
12555
12556 } GtkFundamentalType;
12557 </verb></tscreen>
12558
12559 <tt/gtk_signal_new()/ devuelve un identificador entero único para la
12560 señal, que almacenamos en el vector <tt/tictactoe_signals/, que
12561 indexaremos utilizando una enumeración. (Convencionalmente, los
12562 elementos de la enumeración son el nombre de la señal, en mayúsculas,
12563 pero aquí tendríamos un conflicto con la macro <tt/TICTACTOE()/, por
12564 lo que lo llamaremos <tt/TICTACTOE_SIGNAL/.
12565
12566 Después de crear nuestras señales, necesitamos llamar a GTK para
12567 asociarlas con la clase Tictactoe. Hacemos esto llamando a
12568 <tt/gtk_object_class_add_signals()/. Entonces haremos que el puntero
12569 que apunta al manejador por defecto para la señal `tictactoe' sea NULL,
12570 indicando que no hay ninguna acción por defecto.
12571
12572 <!-- ----------------------------------------------------------------- -->
12573 <sect2> La función <tt/_init()/.
12574 <p>
12575 Cada clase <em/widget/ también necesita una función para inicializar
12576 la estructura del objeto. Normalmente, esta función tiene el limitado
12577 rol de poner los distintos campos de la estructura a su valor por
12578 defecto. Sin embargo para los <em/widgets/ de composición, esta
12579 función también crea los distintos <em/widgets/ componentes.
12580
12581 <tscreen><verb>
12582 static void
12583 tictactoe_init (Tictactoe *ttt)
12584 {
12585   GtkWidget *table;
12586   gint i,j;
12587   
12588   table = gtk_table_new (3, 3, TRUE);
12589   gtk_container_add (GTK_CONTAINER(ttt), table);
12590   gtk_widget_show (table);
12591
12592   for (i=0;i<3; i++)
12593     for (j=0;j<3; j++)
12594       {
12595         ttt->buttons[i][j] = gtk_toggle_button_new ();
12596         gtk_table_attach_defaults (GTK_TABLE(table), ttt->buttons[i][j], 
12597                                    i, i+1, j, j+1);
12598         gtk_signal_connect (GTK_OBJECT (ttt->buttons[i][j]), "toggled",
12599                             GTK_SIGNAL_FUNC (tictactoe_toggle), ttt);
12600         gtk_widget_set_usize (ttt->buttons[i][j], 20, 20);
12601         gtk_widget_show (ttt->buttons[i][j]);
12602       }
12603 }
12604 </verb></tscreen>
12605
12606 <!-- ----------------------------------------------------------------- -->
12607 <sect2> Y el resto...
12608 <p>
12609 Hay una función más que cada <em/widget/ (excepto los <em/widget/ muy
12610 básicos como GtkBin que no pueden crear objetos) tiene que
12611 tener - la función que el usuario llama para crear un objeto de ese
12612 tipo. Normalmente se llama <tt/NOMBREWIDGET_new()/. En algunos
12613 <em/widgets/, que no es el caso del <em/widget/ Tictactoe, esta
12614 función toma argumentos, y hace alguna inicialización en función de
12615 estos. Las otras dos funciones son específicas al <em/widget/
12616 Tictactoe.
12617
12618 <tt/tictactoe_clear()/ es una función pública que reinicia todos los
12619 botones en el <em/widget/ a la posición alta. Observe la utilización
12620 de <tt/gtk_signal_handler_block_by_data()/ para hacer que no se
12621 ejecute nuestro manejador de señal innecesariamente por cambios en los
12622 botones.
12623
12624 <tt/tictactoe_toggle()/ es el manejador de señal que se invoca cuando
12625 el usuario pulsa un botón. Hace una comprobación para ver si hay
12626 alguna combinación ganadora, y si la hay, emite la señal
12627 «tictactoe».
12628
12629 <tscreen><verb>  
12630 GtkWidget*
12631 tictactoe_new ()
12632 {
12633   return GTK_WIDGET ( gtk_type_new (tictactoe_get_type ()));
12634 }
12635
12636 void           
12637 tictactoe_clear (Tictactoe *ttt)
12638 {
12639   int i,j;
12640
12641   for (i=0;i<3;i++)
12642     for (j=0;j<3;j++)
12643       {
12644         gtk_signal_handler_block_by_data (GTK_OBJECT(ttt->buttons[i][j]), ttt);
12645         gtk_toggle_button_set_state (GTK_TOGGLE_BUTTON (ttt->buttons[i][j]),
12646                                      FALSE);
12647         gtk_signal_handler_unblock_by_data (GTK_OBJECT(ttt->buttons[i][j]), ttt);
12648       }
12649 }
12650
12651 static void
12652 tictactoe_toggle (GtkWidget *widget, Tictactoe *ttt)
12653 {
12654   int i,k;
12655
12656   static int rwins[8][3] = { { 0, 0, 0 }, { 1, 1, 1 }, { 2, 2, 2 },
12657                              { 0, 1, 2 }, { 0, 1, 2 }, { 0, 1, 2 },
12658                              { 0, 1, 2 }, { 0, 1, 2 } };
12659   static int cwins[8][3] = { { 0, 1, 2 }, { 0, 1, 2 }, { 0, 1, 2 },
12660                              { 0, 0, 0 }, { 1, 1, 1 }, { 2, 2, 2 },
12661                              { 0, 1, 2 }, { 2, 1, 0 } };
12662
12663   int success, found;
12664
12665   for (k=0; k<8; k++)
12666     {
12667       success = TRUE;
12668       found = FALSE;
12669
12670       for (i=0;i<3;i++)
12671         {
12672           success = success &amp;&amp; 
12673             GTK_TOGGLE_BUTTON(ttt->buttons[rwins[k][i]][cwins[k][i]])->active;
12674           found = found ||
12675             ttt->buttons[rwins[k][i]][cwins[k][i]] == widget;
12676         }
12677       
12678       if (success &amp;&amp; found)
12679         {
12680           gtk_signal_emit (GTK_OBJECT (ttt), 
12681                            tictactoe_signals[TICTACTOE_SIGNAL]);
12682           break;
12683         }
12684     }
12685 }
12686 </verb></tscreen>
12687
12688 Y finalmente, un programa ejemplo que utiliza nuestro <em/widget/
12689 Tictactoe:
12690
12691 <tscreen><verb>
12692 #include <gtk/gtk.h>
12693 #include "tictactoe.h"
12694
12695 /* Invocado cuando se completa una fila, columna o diagonal */
12696 void
12697 win (GtkWidget *widget, gpointer data)
12698 {
12699   g_print ("Yay!\n");
12700   tictactoe_clear (TICTACTOE (widget));
12701 }
12702
12703 int 
12704 main (int argc, char *argv[])
12705 {
12706   GtkWidget *ventana;
12707   GtkWidget *ttt;
12708   
12709   gtk_init (&amp;argc, &amp;argv);
12710
12711   ventana = gtk_window_new (GTK_WINDOW_TOPLEVEL);
12712   
12713   gtk_window_set_title (GTK_WINDOW (ventana), "Aspect Frame");
12714   
12715   gtk_signal_connect (GTK_OBJECT (ventana), "destroy",
12716                       GTK_SIGNAL_FUNC (gtk_exit), NULL);
12717   
12718   gtk_container_border_width (GTK_CONTAINER (ventana), 10);
12719
12720   /* Create a new Tictactoe widget */
12721   ttt = tictactoe_new ();
12722   gtk_container_add (GTK_CONTAINER (ventana), ttt);
12723   gtk_widget_show (ttt);
12724
12725   /* And attach to its "tictactoe" signal */
12726   gtk_signal_connect (GTK_OBJECT (ttt), "tictactoe",
12727                       GTK_SIGNAL_FUNC (win), NULL);
12728
12729   gtk_widget_show (ventana);
12730   
12731   gtk_main ();
12732   
12733   return 0;
12734 }
12735
12736 </verb></tscreen>
12737
12738 <!-- ----------------------------------------------------------------- -->
12739 <sect1> Creando un <em/widget/ desde cero.
12740
12741 <!-- ----------------------------------------------------------------- -->
12742 <sect2> Introducción
12743 <p>
12744 En esta sección, averiguaremos como se dibujan los <em/widgets/ a sí
12745 mismos en pantalla y como interactuan con los eventos. Como ejemplo,
12746 crearemos un marcador analógico con un puntero que el usuario
12747 podrá arrastrar para hacer que el marcador tenga un valor dado.
12748
12749 <!-- ----------------------------------------------------------------- -->
12750 <sect2> Mostrando un <em/widget/ en la pantalla
12751 <p>
12752 Hay varios pasos que están involucrados en el dibujado en pantalla.
12753 Después de que el <em/widget/ se cree con una llamada a
12754 <tt/NOMBREWIDGET_new()/, se necesitarán muchas más funciones:
12755
12756 <itemize>
12757 <item> <tt/NOMBREWIDGET_realize()/ es la responsable de crear una
12758 ventana X para el <em/widget/, si tiene alguna.
12759 <item> <tt/NOMBREWIDGET_map()/ se invoca después de las llamadas del
12760 usuario
12761 <tt/gtk_widget_show()/. Es la responsable de asegurarse de que el
12762 <em/widget/ está dibujado (<em/mapeado/) en la pantalla. Para una
12763 clase contenedor, también deberá ocuparse de llamar a las funciones
12764 <tt/map()/ de cada <em/widget/ hijo.
12765 <item> <tt/NOMBREWIDGET_draw()/ se invoca cuando se llama a
12766 <tt/gtk_widget_draw()/ desde el <em/widget/ de uno de sus
12767 antepasados. Hace las llamadas necesarias a las funciones de dibujo
12768 para dibujar el <em/widget/ en la pantalla. Para los <em/widgets/
12769 contenedores, esta función debe llamar a las <tt/gtk_widget_draw/ de
12770 sus <em/widgets/ hijos.
12771 <item> <tt/NOMBREWIDGET_expose()/ es un manejador de los eventos
12772 <tt/expose/ del <em/widget/. Hace las llamadas necesarias a las
12773 funciones de dibujo para dibujar la parte expuesta en la
12774 pantalla. Para los <em/widgets/ contenedores, esta función debe
12775 generar los eventos <tt/expose/ de sus <em/widgets/ hijos que no
12776 tengan su propia ventana. (Si tuviesen su propia ventana, X generaría
12777 los eventos <tt/expose/ necesarios)
12778 </itemize>
12779
12780 Las últimas dos funciones son bastante similares - ambas son
12781 responsables de dibujar el <em/widget/ en pantalla. De hecho en muchos
12782 <em/widgets/ realmente no importa la diferencia que hay entre ambas
12783 funciones. La función <em/draw()/ que hay por defecto en
12784 la clase <em/widget/ simplemente genera un evento <tt/expose/
12785 artificial de la zona a redibujar. Sin embargo, algunos tipos de
12786 <em/widgets/ puede ahorrarse trabajo distinguiendo entre las dos
12787 funciones. Por ejemplo, si un <em/widget/ tiene varias ventanas X,
12788 entonces, como los eventos <tt/expose/ identifican a la ventana
12789 expuesta, podrán redibujar sólo la ventana afectada, lo que no es
12790 posible con llamadas a <tt/draw()/.
12791
12792 Los <em/widgets/ contenedores, aunque no utilicen la diferecia
12793 existente entre las dos funciones por sí mismos, no pueden utilizar
12794 simplemente las funciones <tt/draw()/ que hay por defecto ya que sus
12795 <em/widgets/ hijos puede que tengan que utilizar la diferencia. Sin
12796 embargo, sería un derroche duplicar el código de dibujado entre las
12797 dos funciones. Lo normal es que cada <em/widget/ tenga una función
12798 llamada <tt/NOMBREWIDGET_paint()/ que haga el trabajo de dibujar el
12799 <em/widget/, ésta función será a la que se llame por las funciones
12800 <tt/draw()/ y <tt/expose()/.
12801
12802 En nuestro ejemplo, como el <em/widget/ Dial no es un <em/widget/
12803 contenedor, y sólo tiene una ventana, podemos tomar el camino más
12804 corto, utilizar la función <tt/draw()/ por defecto y sólo
12805 implementar la función <tt/expose()/.
12806
12807 <!-- ----------------------------------------------------------------- -->
12808 <sect2> Los orígenes del <em/widget/ Dial
12809 <p>
12810 Así como todos los animales terrestes son variaciones del primer
12811 anfíbio que salió del barro, los <em/widgets/ Gtk tienden a nacer
12812 como variaciones de algún otro <em/widget/ escrito previamente. Por
12813 tanto, aunque esta sección se titule `Creando un <em/widget/ de la
12814 nada', el <em/widget/ Dial empieza realmente con el código fuente
12815 del <em/widget/ Range. He tomado éste como punto de arranque porque
12816 sería bonito que nuestro dial tuviese la misma interfaz que los
12817 <em/widgets/ Scale, que son sólo una especialización del <em/widget/
12818 Range. Por tanto, aunque el código fuente se presente más adelante en
12819 su forma final, no implica que fuese escrito de esta forma <em>deus ex
12820 machina</em>. Si todavía no está familiarizado, desde el punto de
12821 vista del escritor de aplicaciones, con la forma de funcionar de los
12822 <em/widgets/ Scale, sería una buena idea echarles un vistazo antes de
12823 continuar.
12824
12825 <!-- ----------------------------------------------------------------- -->
12826 <sect2> Los comienzos
12827 <p>
12828 Nuestro <em/widget/ tiene un aspecto algo parecido al del <em/widget/
12829 Tictactoe. Primero, tenemos un fichero de cabecera:
12830
12831 <tscreen><verb>
12832 /* GTK - The GIMP Toolkit
12833  * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
12834  *
12835  * This library is free software; you can redistribute it and/or
12836  * modify it under the terms of the GNU Library General Public
12837  * License as published by the Free Software Foundation; either
12838  * version 2 of the License, or (at your option) any later version.
12839  *
12840  * This library is distributed in the hope that it will be useful,
12841  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12842  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12843  * Library General Public License for more details.
12844  *
12845  * You should have received a copy of the GNU Library General Public
12846  * License along with this library; if not, write to the Free
12847  * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
12848  */
12849
12850 #ifndef __GTK_DIAL_H__
12851 #define __GTK_DIAL_H__
12852
12853 #include <gdk/gdk.h>
12854 #include <gtk/gtkadjustment.h>
12855 #include <gtk/gtkwidget.h>
12856
12857
12858 #ifdef __cplusplus
12859 extern "C" {
12860 #endif /* __cplusplus */
12861
12862
12863 #define GTK_DIAL(obj)          GTK_CHECK_CAST (obj, gtk_dial_get_type (), GtkDial)
12864 #define GTK_DIAL_CLASS(klass)  GTK_CHECK_CLASS_CAST (klass, gtk_dial_get_type (), GtkDialClass)
12865 #define GTK_IS_DIAL(obj)       GTK_CHECK_TYPE (obj, gtk_dial_get_type ())
12866
12867
12868 typedef struct _GtkDial        GtkDial;
12869 typedef struct _GtkDialClass   GtkDialClass;
12870
12871 struct _GtkDial
12872 {
12873   GtkWidget widget;
12874
12875   /* política de actualización
12876    * (GTK_UPDATE_[CONTINUOUS/DELAYED/DISCONTINUOUS]) */
12877   guint policy : 2;
12878
12879   /* Botón actualmente presionado o 0 si no hay ninguno */
12880   guint8 boton;
12881
12882   /* Dimensión de los componendes del dial */
12883   gint radius;
12884   gint pointer_width;
12885
12886   /* ID del temporizador de actualización, o 0 si no hay ninguno */
12887   guint32 timer;
12888
12889   /* ángulo actual */
12890   gfloat angle;
12891
12892   /* Viejos valores almacenados del adjustment, para que así no
12893    * tengamos que saber cuando cambia algo */
12894   gfloat old_value;
12895   gfloat old_lower;
12896   gfloat old_upper;
12897
12898   /* El objeto adjustment que almacena los datos para este dial */
12899   GtkAdjustment *adjustment;
12900 };
12901
12902 struct _GtkDialClass
12903 {
12904   GtkWidgetClass parent_class;
12905 };
12906
12907
12908 GtkWidget*     gtk_dial_new                    (GtkAdjustment *adjustment);
12909 guint          gtk_dial_get_type               (void);
12910 GtkAdjustment* gtk_dial_get_adjustment         (GtkDial      *dial);
12911 void           gtk_dial_set_update_policy      (GtkDial      *dial,
12912                                                 GtkUpdateType  policy);
12913
12914 void           gtk_dial_set_adjustment         (GtkDial      *dial,
12915                                                 GtkAdjustment *adjustment);
12916 #ifdef __cplusplus
12917 }
12918 #endif /* __cplusplus */
12919
12920
12921 #endif /* __GTK_DIAL_H__ */
12922 </verb></tscreen>
12923
12924 Como vamos a ir con este <em/widget/ un poco más lejos que con el
12925 último que creamos, ahora tenemos unos cuantos campos más en la
12926 estructura de datos, pero el resto de las cosas son muy parecidas.
12927
12928 Ahora, después de incluir los ficheros de cabecera, y declarar unas
12929 cuantas constantes, tenemos algunas funciones que proporcionan
12930 información sobre el <em/widget/ y lo inicializan:
12931
12932 <tscreen><verb>
12933 #include <math.h>
12934 #include <stdio.h>
12935 #include <gtk/gtkmain.h>
12936 #include <gtk/gtksignal.h>
12937
12938 #include "gtkdial.h"
12939
12940 #define SCROLL_DELAY_LENGTH  300
12941 #define DIAL_DEFAULT_SIZE 100
12942
12943 /* Declaraciones de funciones */
12944
12945 [ omitido para salvar espacio ]
12946
12947 /* datos locales */
12948
12949 static GtkWidgetClass *parent_class = NULL;
12950
12951 guint
12952 gtk_dial_get_type ()
12953 {
12954   static guint dial_type = 0;
12955
12956   if (!dial_type)
12957     {
12958       GtkTypeInfo dial_info =
12959       {
12960         "GtkDial",
12961         sizeof (GtkDial),
12962         sizeof (GtkDialClass),
12963         (GtkClassInitFunc) gtk_dial_class_init,
12964         (GtkObjectInitFunc) gtk_dial_init,
12965         (GtkArgSetFunc) NULL,
12966         (GtkArgGetFunc) NULL,
12967       };
12968
12969       dial_type = gtk_type_unique (gtk_widget_get_type (), &amp;dial_info);
12970     }
12971
12972   return dial_type;
12973 }
12974
12975 static void
12976 gtk_dial_class_init (GtkDialClass *class)
12977 {
12978   GtkObjectClass *object_class;
12979   GtkWidgetClass *widget_class;
12980
12981   object_class = (GtkObjectClass*) class;
12982   widget_class = (GtkWidgetClass*) class;
12983
12984   parent_class = gtk_type_class (gtk_widget_get_type ());
12985
12986   object_class->destroy = gtk_dial_destroy;
12987
12988   widget_class->realize = gtk_dial_realize;
12989   widget_class->expose_event = gtk_dial_expose;
12990   widget_class->size_request = gtk_dial_size_request;
12991   widget_class->size_allocate = gtk_dial_size_allocate;
12992   widget_class->button_press_event = gtk_dial_button_press;
12993   widget_class->button_release_event = gtk_dial_button_release;
12994   widget_class->motion_notify_event = gtk_dial_motion_notify;
12995 }
12996
12997 static void
12998 gtk_dial_init (GtkDial *dial)
12999 {
13000   dial->button = 0;
13001   dial->policy = GTK_UPDATE_CONTINUOUS;
13002   dial->timer = 0;
13003   dial->radius = 0;
13004   dial->pointer_width = 0;
13005   dial->angle = 0.0;
13006   dial->old_value = 0.0;
13007   dial->old_lower = 0.0;
13008   dial->old_upper = 0.0;
13009   dial->adjustment = NULL;
13010 }
13011
13012 GtkWidget*
13013 gtk_dial_new (GtkAdjustment *adjustment)
13014 {
13015   GtkDial *dial;
13016
13017   dial = gtk_type_new (gtk_dial_get_type ());
13018
13019   if (!adjustment)
13020     adjustment = (GtkAdjustment*) gtk_adjustment_new (0.0, 0.0, 0.0, 0.0, 0.0, 0.0);
13021
13022   gtk_dial_set_adjustment (dial, adjustment);
13023
13024   return GTK_WIDGET (dial);
13025 }
13026
13027 static void
13028 gtk_dial_destroy (GtkObject *object)
13029 {
13030   GtkDial *dial;
13031
13032   g_return_if_fail (object != NULL);
13033   g_return_if_fail (GTK_IS_DIAL (object));
13034
13035   dial = GTK_DIAL (object);
13036
13037   if (dial->adjustment)
13038     gtk_object_unref (GTK_OBJECT (dial->adjustment));
13039
13040   if (GTK_OBJECT_CLASS (parent_class)->destroy)
13041     (* GTK_OBJECT_CLASS (parent_class)->destroy) (object);
13042 }
13043 </verb></tscreen>
13044
13045 Observe que ésta función <tt/init()/ hace menos cosas de las que hacía
13046 la función <tt/init()/ que utilizamos con el <em/widget/ Tictactoe, ya
13047 que éste no es un <em/widget/ compuesto, y la función <tt/new()/ hace
13048 más cosas, ya que ahora admite un argumento. Observe también que
13049 cuando almacenamos un puntero en un objeto Adjustment, incrementamos
13050 su contador interno, (y lo decrementamos cuando ya no lo utilizamos)
13051 por lo que GTK puede saber cuando se puede destruir sin que se
13052 produzcan problemas.
13053
13054 <p>
13055 Aquí tenemos unas cuantas funciones para manipular las opciones del
13056 <em/widget/:
13057
13058 <tscreen><verb>
13059 GtkAdjustment*
13060 gtk_dial_get_adjustment (GtkDial *dial)
13061 {
13062   g_return_val_if_fail (dial != NULL, NULL);
13063   g_return_val_if_fail (GTK_IS_DIAL (dial), NULL);
13064
13065   return dial->adjustment;
13066 }
13067
13068 void
13069 gtk_dial_set_update_policy (GtkDial      *dial,
13070                              GtkUpdateType  policy)
13071 {
13072   g_return_if_fail (dial != NULL);
13073   g_return_if_fail (GTK_IS_DIAL (dial));
13074
13075   dial->policy = policy;
13076 }
13077
13078 void
13079 gtk_dial_set_adjustment (GtkDial      *dial,
13080                           GtkAdjustment *adjustment)
13081 {
13082   g_return_if_fail (dial != NULL);
13083   g_return_if_fail (GTK_IS_DIAL (dial));
13084
13085   if (dial->adjustment)
13086     {
13087       gtk_signal_disconnect_by_data (GTK_OBJECT (dial->adjustment), (gpointer) dial);
13088       gtk_object_unref (GTK_OBJECT (dial->adjustment));
13089     }
13090
13091   dial->adjustment = adjustment;
13092   gtk_object_ref (GTK_OBJECT (dial->adjustment));
13093
13094   gtk_signal_connect (GTK_OBJECT (adjustment), "changed",
13095                       (GtkSignalFunc) gtk_dial_adjustment_changed,
13096                       (gpointer) dial);
13097   gtk_signal_connect (GTK_OBJECT (adjustment), "value_changed",
13098                       (GtkSignalFunc) gtk_dial_adjustment_value_changed,
13099                       (gpointer) dial);
13100
13101   dial->old_value = adjustment->value;
13102   dial->old_lower = adjustment->lower;
13103   dial->old_upper = adjustment->upper;
13104
13105   gtk_dial_update (dial);
13106 }
13107 </verb></tscreen>
13108
13109 <sect2> <tt/gtk_dial_realize()/
13110
13111 <p>
13112 Ahora vienen algunas funciones nuevas. Primero, tenemos una función
13113 que hace el trabajo de crear la ventana X. A la función se le pasará
13114 una máscara <tt/gdk_window_new()/ que especifica que campos de la
13115 estructura <tt/GdkWindowAttr/ tienen datos (los campos restantes
13116 tendrán los valores por defecto). También es bueno fijarse en la forma
13117 en que se crea la máscara de eventos. Llamamos a
13118 <tt/gtk_widget_get_events()/ para recuperar la máscara de eventos que
13119 el usuario ha especificado para su <em/widget/ (con
13120 <tt/gtk_widget_set_events()/), y añadir nosotros mismos los eventos
13121 en los que estemos interesados.
13122
13123 <p>
13124 Después de crear la ventana, decidiremos su estilo y su fondo, y
13125 pondremos un puntero al <em/widget/ en el campo de datos del usuario
13126 de la <tt/GdkWindow/. Este último paso le permite a GTK despachar los
13127 eventos que hayan para esta ventana hacia el <em/widget/ correcto.
13128
13129 <tscreen><verb>
13130 static void
13131 gtk_dial_realize (GtkWidget *widget)
13132 {
13133   GtkDial *dial;
13134   GdkWindowAttr attributes;
13135   gint attributes_mask;
13136
13137   g_return_if_fail (widget != NULL);
13138   g_return_if_fail (GTK_IS_DIAL (widget));
13139
13140   GTK_WIDGET_SET_FLAGS (widget, GTK_REALIZED);
13141   dial = GTK_DIAL (widget);
13142
13143   attributes.x = widget->allocation.x;
13144   attributes.y = widget->allocation.y;
13145   attributes.width = widget->allocation.width;
13146   attributes.height = widget->allocation.height;
13147   attributes.wclass = GDK_INPUT_OUTPUT;
13148   attributes.window_type = GDK_WINDOW_CHILD;
13149   attributes.event_mask = gtk_widget_get_events (widget) | 
13150     GDK_EXPOSURE_MASK | GDK_BUTTON_PRESS_MASK | 
13151     GDK_BUTTON_RELEASE_MASK | GDK_POINTER_MOTION_MASK |
13152     GDK_POINTER_MOTION_HINT_MASK;
13153   attributes.visual = gtk_widget_get_visual (widget);
13154   attributes.colormap = gtk_widget_get_colormap (widget);
13155
13156   attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP;
13157   widget->window = gdk_window_new (widget->parent->window, &amp;attributes, attributes_mask);
13158
13159   widget->style = gtk_style_attach (widget->style, widget->window);
13160
13161   gdk_window_set_user_data (widget->window, widget);
13162
13163   gtk_style_set_background (widget->style, widget->window, GTK_STATE_ACTIVE);
13164 }
13165 </verb></tscreen>
13166
13167 <sect2> Negociación del tamaño
13168
13169 <p>
13170 Antes de que se muestre por primera vez la ventana conteniendo un
13171 <em/widget/, y cuando quiera que la capa de la ventana cambie, GTK le
13172 preguntara a cada <em/widget/ hijo por su tamaño deseado. Esta
13173 petición se controla mediante la función
13174 <tt/gtk_dial_size_request()/. Como nuestro <em/widget/ no es un
13175 <em/widget/ contenedor, y no tiene ninguna limitación en su tamaño,
13176 nos contentaremos con devolver un valor por defecto.
13177
13178 <tscreen><verb>
13179 static void 
13180 gtk_dial_size_request (GtkWidget      *widget,
13181                        GtkRequisition *requisition)
13182 {
13183   requisition->width = DIAL_DEFAULT_SIZE;
13184   requisition->height = DIAL_DEFAULT_SIZE;
13185 }
13186 </verb></tscreen>
13187
13188 <p>
13189 Después de que todos los <em/widgets/ hayan pedido su tamaño ideal,
13190 se calculará la ventana y cada <em/widget/ hijo será informado de su
13191 tamaño actual. Normalmente, éste será al menos tan grande como el
13192 pedido, pero si por ejemplo, el usuario ha redimensionado la ventana,
13193 entonces puede que el tamaño que se le de al <em/widget/ sea menor
13194 que el que pidió. La notificación del tamaño se maneja mediante la
13195 función <tt/gtk_dial_size_allocate()/. Fíjese que esta función calcula
13196 los tamaños de los diferentes elementos que componen la ventana para
13197 su uso futuro, así como todo el trabajo sucio que poner los
13198 <em/widgets/ de la ventana X en la nueva posición y con el nuevo
13199 tamaño.
13200
13201 <tscreen><verb>
13202 static void
13203 gtk_dial_size_allocate (GtkWidget     *widget,
13204                         GtkAllocation *allocation)
13205 {
13206   GtkDial *dial;
13207
13208   g_return_if_fail (widget != NULL);
13209   g_return_if_fail (GTK_IS_DIAL (widget));
13210   g_return_if_fail (allocation != NULL);
13211
13212   widget->allocation = *allocation;
13213   if (GTK_WIDGET_REALIZED (widget))
13214     {
13215       dial = GTK_DIAL (widget);
13216
13217       gdk_window_move_resize (widget->window,
13218                               allocation->x, allocation->y,
13219                               allocation->width, allocation->height);
13220
13221       dial->radius = MAX(allocation->width,allocation->height) * 0.45;
13222       dial->pointer_width = dial->radius / 5;
13223     }
13224 }
13225 </verb></tscreen>.
13226
13227 <!-- ----------------------------------------------------------------- -->
13228 <sect2> <tt/gtk_dial_expose()/
13229
13230 <p>
13231 Como se mencionó arriba, todo el dibujado de este <em/widget/ se hace
13232 en el manejador de los eventos <tt/expose/. No hay mucho destacable
13233 aquí, excepto la utilización de la función <tt/gtk_draw_polygon/ para
13234 dibujar el puntero con un degradado tridimensional de acuerdo con los
13235 colores almacenados en el estilo del <em/widget/.
13236
13237 <tscreen><verb>
13238 static gint
13239 gtk_dial_expose (GtkWidget      *widget,
13240                  GdkEventExpose *event)
13241 {
13242   GtkDial *dial;
13243   GdkPoint points[3];
13244   gdouble s,c;
13245   gdouble theta;
13246   gint xc, yc;
13247   gint tick_length;
13248   gint i;
13249
13250   g_return_val_if_fail (widget != NULL, FALSE);
13251   g_return_val_if_fail (GTK_IS_DIAL (widget), FALSE);
13252   g_return_val_if_fail (event != NULL, FALSE);
13253
13254   if (event->count > 0)
13255     return FALSE;
13256   
13257   dial = GTK_DIAL (widget);
13258
13259   gdk_window_clear_area (widget->window,
13260                          0, 0,
13261                          widget->allocation.width,
13262                          widget->allocation.height);
13263
13264   xc = widget->allocation.width/2;
13265   yc = widget->allocation.height/2;
13266
13267   /* Dibujar las rayitas */
13268
13269   for (i=0; i<25; i++)
13270     {
13271       theta = (i*M_PI/18. - M_PI/6.);
13272       s = sin(theta);
13273       c = cos(theta);
13274
13275       tick_length = (i%6 == 0) ? dial->pointer_width : dial->pointer_width/2;
13276       
13277       gdk_draw_line (widget->window,
13278                      widget->style->fg_gc[widget->state],
13279                      xc + c*(dial->radius - tick_length),
13280                      yc - s*(dial->radius - tick_length),
13281                      xc + c*dial->radius,
13282                      yc - s*dial->radius);
13283     }
13284
13285   /* Dibujar el puntero */
13286
13287   s = sin(dial->angle);
13288   c = cos(dial->angle);
13289
13290
13291   points[0].x = xc + s*dial->pointer_width/2;
13292   points[0].y = yc + c*dial->pointer_width/2;
13293   points[1].x = xc + c*dial->radius;
13294   points[1].y = yc - s*dial->radius;
13295   points[2].x = xc - s*dial->pointer_width/2;
13296   points[2].y = yc - c*dial->pointer_width/2;
13297
13298   gtk_draw_polygon (widget->style,
13299                     widget->window,
13300                     GTK_STATE_NORMAL,
13301                     GTK_SHADOW_OUT,
13302                     points, 3,
13303                     TRUE);
13304   
13305   return FALSE;
13306 }
13307 </verb></tscreen>
13308
13309 <!-- ----------------------------------------------------------------- -->
13310 <sect2> Manejo de eventos
13311
13312 <p>
13313 El resto del código del <em/widget/ controla varios tipos de eventos,
13314 y no es muy diferente del que podemos encontrar en muchas aplicaciones
13315 GTK. Pueden ocurrir dos tipos de eventos - el usuario puede pulsar en
13316 el <em/widget/ con el ratón y arrastrar para mover el puntero, o el
13317 valor del objeto Adjustement puede cambiar debido a alguna
13318 circunstancia externa.
13319
13320 <p>
13321 Cuando el usuario pulsa en el <em/widget/, haremos una comprobación
13322 para ver si la pulsación se hizo lo suficientemente cerca del
13323 puntero, y si así fue, almacenamos el botón que pulsó el usuario en
13324 en el campo <tt/button/ de la estructura del <em/widget/, y grabamos
13325 todos los eventos del ratón con una llamada a <tt/gtk_grab_add()/. El
13326 movimiento del ratón hará que se recalcule el valor del control
13327 (mediante la función <tt/gtk_dial_update_mouse/). Dependiendo de la
13328 política que sigamos, o bien se generarán instantáneamente los eventos
13329 <tt/value_changed/ (<tt/GTK_UPDATE_CONTINUOUS/), o bien después de una
13330 espera del temporizador establecido mediante <tt/gtk_timeout_add()/
13331 (<tt/GTK_UPDATE_DELAYED/), o bien sólo cuando se levante el botón
13332 (<tt/GTK_UPDATE_DISCONTINUOUS/).
13333
13334 <tscreen><verb>
13335 static gint
13336 gtk_dial_button_press (GtkWidget      *widget,
13337                        GdkEventButton *event)
13338 {
13339   GtkDial *dial;
13340   gint dx, dy;
13341   double s, c;
13342   double d_parallel;
13343   double d_perpendicular;
13344
13345   g_return_val_if_fail (widget != NULL, FALSE);
13346   g_return_val_if_fail (GTK_IS_DIAL (widget), FALSE);
13347   g_return_val_if_fail (event != NULL, FALSE);
13348
13349   dial = GTK_DIAL (widget);
13350
13351   /* Determinar si la pulsación del botón fue dentro de la región del
13352      puntero - esto lo hacemos calculando la distancia x e y del punto
13353      donde se pulsó el botón ratón de la línea que se ha pasado mediante el
13354      puntero */
13355   
13356   dx = event->x - widget->allocation.width / 2;
13357   dy = widget->allocation.height / 2 - event->y;
13358   
13359   s = sin(dial->angle);
13360   c = cos(dial->angle);
13361   
13362   d_parallel = s*dy + c*dx;
13363   d_perpendicular = fabs(s*dx - c*dy);
13364   
13365   if (!dial->button &&
13366       (d_perpendicular < dial->pointer_width/2) &&
13367       (d_parallel > - dial->pointer_width))
13368     {
13369       gtk_grab_add (widget);
13370
13371       dial->button = event->button;
13372
13373       gtk_dial_update_mouse (dial, event->x, event->y);
13374     }
13375
13376   return FALSE;
13377 }
13378
13379 static gint
13380 gtk_dial_button_release (GtkWidget      *widget,
13381                           GdkEventButton *event)
13382 {
13383   GtkDial *dial;
13384
13385   g_return_val_if_fail (widget != NULL, FALSE);
13386   g_return_val_if_fail (GTK_IS_DIAL (widget), FALSE);
13387   g_return_val_if_fail (event != NULL, FALSE);
13388
13389   dial = GTK_DIAL (widget);
13390
13391   if (dial->button == event->button)
13392     {
13393       gtk_grab_remove (widget);
13394
13395       dial->button = 0;
13396
13397       if (dial->policy == GTK_UPDATE_DELAYED)
13398         gtk_timeout_remove (dial->timer);
13399       
13400       if ((dial->policy != GTK_UPDATE_CONTINUOUS) &&
13401           (dial->old_value != dial->adjustment->value))
13402         gtk_signal_emit_by_name (GTK_OBJECT (dial->adjustment), "value_changed");
13403     }
13404
13405   return FALSE;
13406 }
13407
13408 static gint
13409 gtk_dial_motion_notify (GtkWidget      *widget,
13410                          GdkEventMotion *event)
13411 {
13412   GtkDial *dial;
13413   GdkModifierType mods;
13414   gint x, y, mask;
13415
13416   g_return_val_if_fail (widget != NULL, FALSE);
13417   g_return_val_if_fail (GTK_IS_DIAL (widget), FALSE);
13418   g_return_val_if_fail (event != NULL, FALSE);
13419
13420   dial = GTK_DIAL (widget);
13421
13422   if (dial->button != 0)
13423     {
13424       x = event->x;
13425       y = event->y;
13426
13427       if (event->is_hint || (event->window != widget->window))
13428         gdk_window_get_pointer (widget->window, &amp;x, &amp;y, &amp;mods);
13429
13430       switch (dial->button)
13431         {
13432         case 1:
13433           mask = GDK_BUTTON1_MASK;
13434           break;
13435         case 2:
13436           mask = GDK_BUTTON2_MASK;
13437           break;
13438         case 3:
13439           mask = GDK_BUTTON3_MASK;
13440           break;
13441         default:
13442           mask = 0;
13443           break;
13444         }
13445
13446       if (mods & mask)
13447         gtk_dial_update_mouse (dial, x,y);
13448     }
13449
13450   return FALSE;
13451 }
13452
13453 static gint
13454 gtk_dial_timer (GtkDial *dial)
13455 {
13456   g_return_val_if_fail (dial != NULL, FALSE);
13457   g_return_val_if_fail (GTK_IS_DIAL (dial), FALSE);
13458
13459   if (dial->policy == GTK_UPDATE_DELAYED)
13460     gtk_signal_emit_by_name (GTK_OBJECT (dial->adjustment), "value_changed");
13461
13462   return FALSE;
13463 }
13464
13465 static void
13466 gtk_dial_update_mouse (GtkDial *dial, gint x, gint y)
13467 {
13468   gint xc, yc;
13469   gfloat old_value;
13470
13471   g_return_if_fail (dial != NULL);
13472   g_return_if_fail (GTK_IS_DIAL (dial));
13473
13474   xc = GTK_WIDGET(dial)->allocation.width / 2;
13475   yc = GTK_WIDGET(dial)->allocation.height / 2;
13476
13477   old_value = dial->adjustment->value;
13478   dial->angle = atan2(yc-y, x-xc);
13479
13480   if (dial->angle < -M_PI/2.)
13481     dial->angle += 2*M_PI;
13482
13483   if (dial->angle < -M_PI/6)
13484     dial->angle = -M_PI/6;
13485
13486   if (dial->angle > 7.*M_PI/6.)
13487     dial->angle = 7.*M_PI/6.;
13488
13489   dial->adjustment->value = dial->adjustment->lower + (7.*M_PI/6 - dial->angle) *
13490     (dial->adjustment->upper - dial->adjustment->lower) / (4.*M_PI/3.);
13491
13492   if (dial->adjustment->value != old_value)
13493     {
13494       if (dial->policy == GTK_UPDATE_CONTINUOUS)
13495         {
13496           gtk_signal_emit_by_name (GTK_OBJECT (dial->adjustment), "value_changed");
13497         }
13498       else
13499         {
13500           gtk_widget_draw (GTK_WIDGET(dial), NULL);
13501
13502           if (dial->policy == GTK_UPDATE_DELAYED)
13503             {
13504               if (dial->timer)
13505                 gtk_timeout_remove (dial->timer);
13506
13507               dial->timer = gtk_timeout_add (SCROLL_DELAY_LENGTH,
13508                                              (GtkFunction) gtk_dial_timer,
13509                                              (gpointer) dial);
13510             }
13511         }
13512     }
13513 }
13514 </verb></tscreen>
13515
13516 <p>
13517 Cambios en el Adjustment por motivos externos significa que se le
13518 comunicarán a nuestro <em/widget/ mediante las señales <tt/changed/ y
13519 <tt/value_changed/. Los manejadores de estas funciones llaman a
13520 <tt/gtk_dial_update()/ para comprobar los argumentos, calcular el
13521 nuevo ángulo del puntero, y redibujar el <em/widget/ (llamando a
13522 <tt/gtk_widget_draw()/).
13523
13524 <tscreen><verb>
13525 static void
13526 gtk_dial_update (GtkDial *dial)
13527 {
13528   gfloat new_value;
13529   
13530   g_return_if_fail (dial != NULL);
13531   g_return_if_fail (GTK_IS_DIAL (dial));
13532
13533   new_value = dial->adjustment->value;
13534   
13535   if (new_value < dial->adjustment->lower)
13536     new_value = dial->adjustment->lower;
13537
13538   if (new_value > dial->adjustment->upper)
13539     new_value = dial->adjustment->upper;
13540
13541   if (new_value != dial->adjustment->value)
13542     {
13543       dial->adjustment->value = new_value;
13544       gtk_signal_emit_by_name (GTK_OBJECT (dial->adjustment), "value_changed");
13545     }
13546
13547   dial->angle = 7.*M_PI/6. - (new_value - dial->adjustment->lower) * 4.*M_PI/3. /
13548     (dial->adjustment->upper - dial->adjustment->lower);
13549
13550   gtk_widget_draw (GTK_WIDGET(dial), NULL);
13551 }
13552
13553 static void
13554 gtk_dial_adjustment_changed (GtkAdjustment *adjustment,
13555                               gpointer       data)
13556 {
13557   GtkDial *dial;
13558
13559   g_return_if_fail (adjustment != NULL);
13560   g_return_if_fail (data != NULL);
13561
13562   dial = GTK_DIAL (data);
13563
13564   if ((dial->old_value != adjustment->value) ||
13565       (dial->old_lower != adjustment->lower) ||
13566       (dial->old_upper != adjustment->upper))
13567     {
13568       gtk_dial_update (dial);
13569
13570       dial->old_value = adjustment->value;
13571       dial->old_lower = adjustment->lower;
13572       dial->old_upper = adjustment->upper;
13573     }
13574 }
13575
13576 static void
13577 gtk_dial_adjustment_value_changed (GtkAdjustment *adjustment,
13578                                     gpointer       data)
13579 {
13580   GtkDial *dial;
13581
13582   g_return_if_fail (adjustment != NULL);
13583   g_return_if_fail (data != NULL);
13584
13585   dial = GTK_DIAL (data);
13586
13587   if (dial->old_value != adjustment->value)
13588     {
13589       gtk_dial_update (dial);
13590
13591       dial->old_value = adjustment->value;
13592     }
13593 }
13594 </verb></tscreen>
13595
13596 <!-- ----------------------------------------------------------------- -->
13597 <sect2> Posibles mejoras
13598 <p>
13599
13600 El <em/widget/ Dial tal y como lo hemos descrito tiene unas 670
13601 líneas de código. Aunque pueda parecer un poco exagerado, todavía
13602 no hemos escrito demasiado código, ya que la mayoría de las líneas
13603 son de ficheros de cabecera y de adornos. Todavía se le pueden hacer
13604 algunas mejoras a este <em/widget/:
13605
13606 <itemize>
13607 <item> Si prueba el <em/widget/, verá que el puntero cambia a
13608 pantallazos cuando se le arrastra. Esto es debido a que todo el
13609 <em/widget/ se borra cada vez que se mueve el puntero, antes de
13610 redibujarse. Normalmente, la mejor forma de tratar este problema es
13611 dibujar en un <em/pixmap/ que no represente lo que se ve directamente
13612 en pantalla, y copiar el resultado final en la pantalla en sólo un
13613 paso. (El <em/widget/ ProgressBar funciona de esta forma.)
13614
13615 <item> El usuario debería ser capaz de utilizar las flechas de arriba
13616 y abajo para aumentar y decrementar el valor.
13617
13618 <item> Sería bonito si el <em/widget/ tuviese botones para
13619 incrementar y decrementar el valor a saltos más o menos
13620 grandes. Es posible utilizar <em/widgets/ botón, aunque también
13621 queremos que los botones pudiesen realizar la operación de incrementar
13622 o decrementar varias veces, mientras se mantenga el botón pulsado, tal
13623 y como lo hacen las flechas en una barra de desplazamiento. La mayoría
13624 del código para implementar todo esto lo podemos encontrar en el
13625 <em/widget/ GtkRange.
13626
13627 <item> El <em/widget/ Dial puede utilizarse en un <em/widget/
13628 contenedor con un simple <em/widget/ hijo colocado en la parte
13629 inferior entre los botones antes mencionados. El usuario puede añadir
13630 (según prefiera) una etiqueta o un <em/widget/ entry para mostrar el
13631 valor actual del marcador.
13632
13633 </itemize>
13634
13635 <!-- ----------------------------------------------------------------- -->
13636 <sect1> Aprendiendo más
13637
13638 <p>
13639 Sólo se han descrito una pequeña parte de los muchos detalles
13640 involucrados en la creación de <em/widgets/, la mejor fuente de
13641 ejemplos es el código mismo de GTK. Hágase algunas preguntas acerca
13642 del <em/widget/ que desea crear: ¿es un <em/widget/ contenedor?
13643 ¿Debe tener su propia ventana? ¿Es una modificación de un
13644 <em/widget/ existente? En ese momento busque un <em/widget/ similar, y
13645 comience a hacer los cambios.
13646 ¡Buena suerte!
13647
13648 <!-- ***************************************************************** -->
13649 <sect>Scribble, un sencillo programa de dibujo de ejemplo
13650 <!-- ***************************************************************** -->
13651
13652 <!-- ----------------------------------------------------------------- -->
13653 <sect1> Objetivos
13654
13655 <p>
13656 En esta sección, vamos a crear un sencillo programa de dibujo. En el
13657 proceso, vamos a examinar como se manejan los eventos de ratón, como
13658 dibujar en una ventana, y como mejorar el dibujado utilizando un
13659 <em/pixmap/ intermedio. Después de crear el programa de dibujo, lo
13660 ampliaremos añadiendole la posibilidad de utilizar dispositivos
13661 XInput, como tabletas digitalizadoras. GTK proporciona las rutinas que
13662 nos darán la posibilidad de obtener información extra, como la presión
13663 y la inclinación, de todo tipo de dispositivos de una forma sencilla. 
13664
13665 <!-- ----------------------------------------------------------------- -->
13666 <sect1> Manejo de eventos
13667
13668 <p>
13669 Las señales GTK sobre las que ya hemos discutido son para las
13670 acciones de alto nivel, como cuando se selecciona un elemento de un
13671 menú. Sin embargo a veces es útil tratar con los acontecimientos a
13672 bajo nivel, como cuando se mueve el ratón, o cuando se está
13673 presionando una tecla. También hay señales GTK relacionadas con
13674 estos <em/eventos/ de bajo nivel. Los manejadores de estas señales
13675 tienen un parámetro extra que es un puntero a una estructura
13676 conteniendo información sobre el evento. Por ejemplo, a los manejadores
13677 de los eventos de movimiento se les pasa una estructura
13678 <tt/GdkEventMotion/ que es (en parte) así:
13679
13680 <tscreen><verb>
13681 struct _GdkEventMotion
13682 {
13683   GdkEventType type;
13684   GdkWindow *ventana;
13685   guint32 time;
13686   gdouble x;
13687   gdouble y;
13688   ...
13689   guint state;
13690   ...
13691 };
13692 </verb></tscreen>
13693
13694 <tt/type/ adquirirá su valor adecuado dependiendo del tipo de evento,
13695 en nuestro caso <tt/GDK_MOTION_NOTIFY/, <tt/ventana/ es la ventana en
13696 la que ocurre el evento. <tt/x/ e <tt/y/ dan las coordenadas del
13697 evento, y <tt/state/ especifica cual es la modificación que ha habido
13698 cuando ocurrió el evento (esto es, especifica que teclas han cambiado
13699 su estado y que botones del ratón se han presionado.) Es la
13700 operación OR (O) de algunos de los siguientes valores:
13701
13702 <tscreen><verb>
13703 GDK_SHIFT_MASK  
13704 GDK_LOCK_MASK   
13705 GDK_CONTROL_MASK
13706 GDK_MOD1_MASK   
13707 GDK_MOD2_MASK   
13708 GDK_MOD3_MASK   
13709 GDK_MOD4_MASK   
13710 GDK_MOD5_MASK   
13711 GDK_BUTTON1_MASK
13712 GDK_BUTTON2_MASK
13713 GDK_BUTTON3_MASK
13714 GDK_BUTTON4_MASK
13715 GDK_BUTTON5_MASK
13716 </verb></tscreen>
13717
13718 <p>
13719 Como con las otras señales, para especificar que es lo que pasa cuando
13720 ocurre un evento, llamaremos a <tt>gtk_signal_connect()</tt>. Pero
13721 también necesitamos decirle a GTK sobre que eventos queremos ser
13722 informados. Para ello, llamaremos a la función:
13723
13724 <tscreen><verb>
13725 void gtk_widget_set_events (GtkWidget *widget,
13726                             gint      events);
13727 </verb></tscreen>
13728
13729 El segundo campo especifica los eventos en los que estamos
13730 interesados. Es el OR (O) de las constantes que especifican los
13731 diferentes tipos de eventos. Por las referencias futuras que podamos
13732 hacer, presentamos aquí los tipos de eventos que hay disponibles:
13733
13734 <tscreen><verb>
13735 GDK_EXPOSURE_MASK
13736 GDK_POINTER_MOTION_MASK
13737 GDK_POINTER_MOTION_HINT_MASK
13738 GDK_BUTTON_MOTION_MASK     
13739 GDK_BUTTON1_MOTION_MASK    
13740 GDK_BUTTON2_MOTION_MASK    
13741 GDK_BUTTON3_MOTION_MASK    
13742 GDK_BUTTON_PRESS_MASK      
13743 GDK_BUTTON_RELEASE_MASK    
13744 GDK_KEY_PRESS_MASK         
13745 GDK_KEY_RELEASE_MASK       
13746 GDK_ENTER_NOTIFY_MASK      
13747 GDK_LEAVE_NOTIFY_MASK      
13748 GDK_FOCUS_CHANGE_MASK      
13749 GDK_STRUCTURE_MASK         
13750 GDK_PROPERTY_CHANGE_MASK   
13751 GDK_PROXIMITY_IN_MASK      
13752 GDK_PROXIMITY_OUT_MASK     
13753 </verb></tscreen>
13754
13755 Hay unos cuantas sutilezas que debemos respetar cuando llamamos a
13756 <tt/gtk_widget_set_events()/. Primero, debemos llamar a esta función
13757 antes de que se cree la ventana X para el <em/widget/ GTK. En
13758 términos prácticos, significa que debemos llamarla inmediatamente
13759 después de crear el <em/widget/. Segundo, el <em/widget/ debe tener
13760 una ventana X asociado. Por motivos de eficiencia, hay muchos
13761 <em/widgets/ que no tienen su propia ventana, sino que dibujan en la
13762 de su padre. Estos <em/widgets/ son:
13763
13764 <tscreen><verb>
13765 GtkAlignment
13766 GtkArrow
13767 GtkBin
13768 GtkBox
13769 GtkImage
13770 GtkItem
13771 GtkLabel
13772 GtkPixmap
13773 GtkScrolledWindow
13774 GtkSeparator
13775 GtkTable
13776 GtkAspectFrame
13777 GtkFrame
13778 GtkVBox
13779 GtkHBox
13780 GtkVSeparator
13781 GtkHSeparator
13782 </verb></tscreen>
13783
13784 Para capturar eventos para estos <em/widgets/, necesita utilizar un
13785 <em/widget/ EventBox. Vea la sección <ref
13786 id="sec_The_EventBox_Widget" name="El widget EventBox"> para más
13787 detalles.
13788
13789 <p>
13790 Para nuestro programa de dibujo, queremos saber cuando se presiona el
13791 botón del ratón y cuando se mueve, por lo que debemos especificar
13792 los eventos <tt/GDK_POINTER_MOTION_MASK/ y
13793 <tt/GDK_BUTTON_PRESS_MASK/. También queremos saber cuando necesitamos
13794 redibujar nuestra ventana, por lo que especificaremos el evento
13795 <tt/GDK_EXPOSURE_MASK/. Aunque queremos estar informados mediante un
13796 evento <tt/Configure/ cuando cambie el tamaño de nuestra ventana, no
13797 tenemos que especificar la correspondiente <tt/GDK_STRUCTURE_MASK/,
13798 porque ya está activada por defecto para todas las ventanas.
13799
13800 <p>
13801 Tenemos un problema con lo que acabamos de hacer, y tiene que ver con
13802 la utilización de <tt/GDK_POINTER_MOTION_MASK/. Si especificamos este
13803 evento, el servidor añadirá un evento de movimiento a la cola de
13804 eventos cada vez que el usuario mueva el ratón. Imagine que nos
13805 cuesta 0'1 segundo tratar el evento de movimiento, pero que el
13806 servidor X añade a la cola un nuevo evento de moviento cada 0'05
13807 segundos. Pronto nos iremos quedando retrasados con respecto al resto
13808 de los eventos. Si el usuario dibuja durante 5 segundos, ¡nos llevará
13809 otros 5 segundos el cazarle después de que hay levantado el botón
13810 del ratón! Lo que queremos es sólo un evento de movimiento por cada
13811 evento que procesemos. La manera de hacerlo es especificando
13812 <tt/GDK_POINTER_MOTION_HINT_MASK/.
13813
13814 <p>
13815 Cuando especificamos <tt/GDK_POINTER_MOTION_HINT_MASK/, el servidor
13816 nos envia un evento de movimiento la primera ver que el puntero se
13817 mueve depués de entrar en nuestra ventana, o después de que se
13818 apriete o se suelte un botón (y se reciba el evento
13819 correspondiente). Los eventos de movimiento restantes se eliminarán a
13820 no ser que preguntemos especificamente por la posición del puntero
13821 utilizando la función:
13822
13823 <tscreen><verb>
13824 GdkWindow*    gdk_window_get_pointer     (GdkWindow       *ventana,
13825                                           gint            *x,
13826                                           gint            *y,
13827                                           GdkModifierType *mask);
13828 </verb></tscreen>
13829
13830 (Hay otra función, <tt>gtk_widget_get_pointer()</tt> que tiene una
13831 interfaz más sencillo, pero esta simplificación le resta utilidad, ya
13832 que sólo devuelve la posición del ratón, y no si alguno de sus botones
13833 está presionado.)
13834
13835 <p>
13836 El código para establecer los eventos para nuestra ventana es el
13837 siguiente:
13838
13839 <tscreen><verb>
13840   gtk_signal_connect (GTK_OBJECT (drawing_area), "expose_event",
13841                       (GtkSignalFunc) expose_event, NULL);
13842   gtk_signal_connect (GTK_OBJECT(drawing_area),"configure_event",
13843                       (GtkSignalFunc) configure_event, NULL);
13844   gtk_signal_connect (GTK_OBJECT (drawing_area), "motion_notify_event",
13845                       (GtkSignalFunc) motion_notify_event, NULL);
13846   gtk_signal_connect (GTK_OBJECT (drawing_area), "button_press_event",
13847                       (GtkSignalFunc) button_press_event, NULL);
13848
13849   gtk_widget_set_events (drawing_area, GDK_EXPOSURE_MASK
13850                          | GDK_LEAVE_NOTIFY_MASK
13851                          | GDK_BUTTON_PRESS_MASK
13852                          | GDK_POINTER_MOTION_MASK
13853                          | GDK_POINTER_MOTION_HINT_MASK);
13854 </verb></tscreen>
13855
13856 Vamos a dejar los manejadores de los eventos <tt/expose_event/ y
13857 <tt/configure_event/ para después. Los manejadores de
13858 <tt/motion_notify_event/ y de <tt/button_press_event/ son bastante
13859 simples:
13860
13861 <tscreen><verb>
13862 static gint
13863 button_press_event (GtkWidget *widget, GdkEventButton *event)
13864 {
13865   if (event->button == 1 &amp;&amp; pixmap != NULL)
13866       draw_brush (widget, event->x, event->y);
13867
13868   return TRUE;
13869 }
13870
13871 static gint
13872 motion_notify_event (GtkWidget *widget, GdkEventMotion *event)
13873 {
13874   int x, y;
13875   GdkModifierType state;
13876
13877   if (event->is_hint)
13878     gdk_window_get_pointer (event->window, &amp;x, &amp;y, &amp;state);
13879   else
13880     {
13881       x = event->x;
13882       y = event->y;
13883       state = event->state;
13884     }
13885     
13886   if (state &amp; GDK_BUTTON1_MASK &amp;&amp; pixmap != NULL)
13887     draw_brush (widget, x, y);
13888   
13889   return TRUE;
13890 }
13891 </verb></tscreen>
13892
13893 <!-- ----------------------------------------------------------------- -->
13894 <sect1> El <em/widget/ DrawingArea, y dibujando
13895
13896 <p>
13897 Vamos a pasar al proceso de dibujar en la pantalla. El <em/widget/ que
13898 utilizaremos será el DrawingArea. Un <em/widget/ DrawingArea es
13899 esencialmente una ventana X y nada más. Es un lienzo en blanco en
13900 el que podemos dibujar lo que queramos. Crearemos un área de dibujo
13901 utilizando la llamada:
13902
13903 <tscreen><verb>
13904 GtkWidget* gtk_drawing_area_new        (void);
13905 </verb></tscreen>
13906
13907 Se puede especificar un tamaño por defecto para el <em/widget/
13908 llamando a:
13909
13910 <tscreen><verb>
13911 void       gtk_drawing_area_size       (GtkDrawingArea      *darea,
13912                                         gint                 width,
13913                                         gint                 height);
13914 </verb></tscreen>
13915
13916 Se puede cambiar el tamaño por defecto, como para todos los
13917 <em/widgets/, llamando a <tt/gtk_widget_set_usize()/, y esto, además,
13918 puede cambiarse si el usuario cambia manualmente el tamaño de la
13919 ventana que contiene el área de dibujo.
13920
13921 <p>
13922 Debemos hacer notar que cuando creamos un <em/widget/ DrawingArea,
13923 seremos <em/completamente/ responsables de dibujar su contenido. Si
13924 nuestra ventana se tapa y se vuelve a poner al descubierto,
13925 obtendremos un evento de exposición y deberemos redibujar lo que se
13926 había tapado.
13927
13928 <p>
13929 Tener que recordar todo lo que se dibujó en la pantalla para que
13930 podamos redibujarla convenientemente es, por decirlo de alguna manera
13931 suave, una locura. Además puede quedar mal si hay que borrar partes
13932 de la pantalla y hay que redibujarlas paso a paso. La solución a este
13933 problema es utilizar un <em>pixmap</em> intermedio. En lugar de
13934 dibujar directamente en la pantalla, dibujaremos en una imagen que
13935 estará almacenada en la memoria del servidor, pero que no se mostrará,
13936 y cuando cambie la imagen o se muestren nuevas partes de
13937 la misma, copiaremos las porciones relevantes en la pantalla.
13938
13939 <p>
13940 Para crear un <em/pixmap/ intermedio, llamaremos a la función:
13941
13942 <tscreen><verb>
13943 GdkPixmap* gdk_pixmap_new               (GdkWindow  *ventana,
13944                                          gint        width,
13945                                          gint        height,
13946                                          gint        depth);
13947 </verb></tscreen>
13948
13949 El parámetro <tt/widget/ especifica una ventana GDK de las que este
13950 <em/pixmap/ tomará algunas propiedades. <tt/width/ y <tt/height/
13951 especifican el tamaño del <em/pixmap/. <tt/depth/ especifica la
13952 <em/profundidad del color/, que es el número de bits por pixel de la
13953 nueva ventana. Si la profundidad que se especifica es <tt/-1/, se
13954 utilizará la misma profundidad de color que tenga la <tt/ventana/.
13955
13956 <p>
13957 Creamos nuestro <em/pixmap/ en nuestro manejador del evento
13958 <tt/configure_event/. Este evento se genera cada vez que cambia el
13959 tamaño de la ventana, incluyendo cuando ésta se crea.
13960
13961 <tscreen><verb>
13962 /* Backing pixmap for drawing area */
13963 static GdkPixmap *pixmap = NULL;
13964
13965 /* Create a new backing pixmap of the appropriate size */
13966 static gint
13967 configure_event (GtkWidget *widget, GdkEventConfigure *event)
13968 {
13969   if (pixmap)
13970     gdk_pixmap_unref(pixmap);
13971
13972   pixmap = gdk_pixmap_new(widget->window,
13973                           widget->allocation.width,
13974                           widget->allocation.height,
13975                           -1);
13976   gdk_draw_rectangle (pixmap,
13977                       widget->style->white_gc,
13978                       TRUE,
13979                       0, 0,
13980                       widget->allocation.width,
13981                       widget->allocation.height);
13982
13983   return TRUE;
13984 }
13985 </verb></tscreen>
13986
13987 La llamada a <tt/gdk_draw_rectangle()/ rellena todo el <em/pixmap/ de
13988 blanco. Hablaremos más de todo esto en un momento.
13989
13990 <p>
13991 Nuestro manejador del evento de exposición simplemente copia la
13992 porción relevante del <em/pixmap/ en la pantalla (determinaremos la
13993 zona a redibujar utilizando el campo <tt/event->area/ del evento de
13994 exposición):
13995
13996 <tscreen><verb>
13997 /* Redraw the screen from the backing pixmap */
13998 static gint
13999 expose_event (GtkWidget *widget, GdkEventExpose *event)
14000 {
14001   gdk_draw_pixmap(widget->window,
14002                   widget->style->fg_gc[GTK_WIDGET_STATE (widget)],
14003                   pixmap,
14004                   event->area.x, event->area.y,
14005                   event->area.x, event->area.y,
14006                   event->area.width, event->area.height);
14007
14008   return FALSE;
14009 }
14010 </verb></tscreen>
14011
14012 Ahora ya sabemos como mantener la pantalla actualizada con el
14013 contenido de nuestro <em/pixmap/, pero ¿cómo podemos dibujar algo
14014 interesante en nuestro <em/pixmap/? Hay un gran número de llamadas en
14015 la biblioteca GDK para dibujar en los <em/dibujables/. Un dibujable es
14016 simplemente algo sobre lo que se puede dibujar. Puede ser una ventana,
14017 un <em/pixmap/, un <em/bitmap/ (una imagen en blanco y negro), etc. Ya
14018 hemos visto arriba dos de estas llamadas,
14019 <tt>gdk_draw_rectangle()</tt> y <tt>gdk_draw_pixmap()</tt>. La lista
14020 completa de funciones para dibujar es:
14021
14022 <tscreen><verb>
14023 gdk_draw_line ()
14024 gdk_draw_rectangle ()
14025 gdk_draw_arc ()
14026 gdk_draw_polygon ()
14027 gdk_draw_string ()
14028 gdk_draw_text ()
14029 gdk_draw_pixmap ()
14030 gdk_draw_bitmap ()
14031 gdk_draw_image ()
14032 gdk_draw_points ()
14033 gdk_draw_segments ()
14034 </verb></tscreen>
14035
14036 Ver la documentación de estas funciones o el fichero de cabecera
14037 <tt>&lt;gdk/gdk.h&gt;</tt> para obtener más detalles sobre estas
14038 funciones. Todas comparten los dos primeros argumentos. El primero es
14039 el dibujable en el que se dibujará, y el segundo argumento es un
14040 <em/contexto gráfico/ (GC).
14041
14042 <p>
14043 Un contexto gráfico reúne la información sobre cosas como el color
14044 de fondo y del color de lo que se dibuja, el ancho de la línea,
14045 etc... GDK tiene un conjunto completo de funciones para crear y
14046 modificar los contextos gráficos. Cada <em/widget/ tiene un GC
14047 asociado. (Que puede modificarse en un fichero gtkrc, ver la sección
14048 «Ficheros rc de GTK».) Estos, junto con otras cosas, almacenan
14049 GC's. Algunos ejemplos de como acceder a estos GC's son:
14050
14051 <tscreen><verb>
14052 widget->style->white_gc
14053 widget->style->black_gc
14054 widget->style->fg_gc[GTK_STATE_NORMAL]
14055 widget->style->bg_gc[GTK_WIDGET_STATE(widget)]
14056 </verb></tscreen>
14057
14058 Los campos <tt>fg_gc</tt>, <tt>bg_gc</tt>, <tt>dark_gc</tt>, y
14059 <tt>light_gc</tt> se indexan con un parámetro del tipo
14060 <tt/GtkStateType/ que puede tomar uno de los valores:
14061
14062 <tscreen><verb>
14063 GTK_STATE_NORMAL,
14064 GTK_STATE_ACTIVE,
14065 GTK_STATE_PRELIGHT,
14066 GTK_STATE_SELECTED,
14067 GTK_STATE_INSENSITIVE
14068 </verb></tscreen>
14069
14070 Por ejemplo, para el <tt/GTK_STATE_SELECTED/, el color que se utiliza
14071 para pintar por defecto es el blanco y el color del fondo por defecto,
14072 es el azul oscuro.
14073
14074 <p>
14075 Nuestra función <tt/draw_brush()/, que es la que dibuja en la
14076 pantalla, será la siguiente:
14077
14078 <tscreen><verb>
14079 /* Draw a rectangle on the screen */
14080 static void
14081 draw_brush (GtkWidget *widget, gdouble x, gdouble y)
14082 {
14083   GdkRectangle update_rect;
14084
14085   update_rect.x = x - 5;
14086   update_rect.y = y - 5;
14087   update_rect.width = 10;
14088   update_rect.height = 10;
14089   gdk_draw_rectangle (pixmap,
14090                       widget->style->black_gc,
14091                       TRUE,
14092                       update_rect.x, update_rect.y,
14093                       update_rect.width, update_rect.height);
14094   gtk_widget_draw (widget, &amp;update_rect);
14095 }
14096 </verb></tscreen>
14097
14098 Después de que dibujemos el rectángulo representando la brocha en el
14099 <em/pixmap/ llamaremos a la función:
14100
14101 <tscreen><verb>
14102 void       gtk_widget_draw                (GtkWidget           *widget,
14103                                            GdkRectangle        *area);
14104 </verb></tscreen>
14105
14106 que le informa a X de que la zona dada por el parámetro <tt/area/
14107 necesita actualizarse. X generará un evento de exposición
14108 (combinando posiblemente distintas zonas pasadas mediante distintas
14109 llamadas a <tt/gtk_widget_draw()/) que hará que nuestro manejador de
14110 eventos de exposición copie las porciones relevantes en la pantalla.
14111
14112 <p>
14113 Ya hemos cubierto el programa de dibujo completo, excepto unos cuantos
14114 detalles mundanos como crear la ventana principal. El código completo
14115 está disponible en el mismo lugar en el que consiguió este tutorial,
14116 o en:
14117
14118 <htmlurl url="http://www.gtk.org/~otaylor/gtk/tutorial/"
14119 name="http://www.gtk.org/~otaylor/gtk/tutorial/">
14120
14121
14122 <!-- ----------------------------------------------------------------- -->
14123 <sect1> Añadiendo la capacidad de utilizar XInput
14124
14125 <p>
14126 Ahora es posible comprar dispositos de entrada bastante baratos, como
14127 tabletas digitalizadoras, que permiten dibujar de forma artística
14128 mucho más fácilmente de cómo lo haríamos con un ratón. La forma
14129 más sencilla de utilizar estos dispositivos es simplemente
14130 reemplazando a los ratones, pero así perdemos muchas de las ventajas
14131 de este tipo de dispositivos, como por ejemplo:
14132
14133 <itemize>
14134 <item> Sensibilidad a la presión
14135 <item> Información sobre la inclinación
14136 <item> Colocación subpixel
14137 <item> Multiples entradas (por ejemplo, un lápiz con una punta y una
14138 goma)
14139 </itemize>
14140
14141 Para información sobre la extensión XInput, ver el <htmlurl
14142 url="http://www.msc.cornell.edu/~otaylor/xinput/XInput-HOWTO.html"
14143 name="XInput-HOWTO">.
14144
14145 <p>
14146 Si examinamos la definición completa de, por ejemplo, la estructura
14147 <tt/GdkEventMotion/, veremos que tiene campos para almacenar la
14148 información de los dispositivos extendidos.
14149
14150 <tscreen><verb>
14151 struct _GdkEventMotion
14152 {
14153   GdkEventType type;
14154   GdkWindow *ventana;
14155   guint32 time;
14156   gdouble x;
14157   gdouble y;
14158   gdouble pressure;
14159   gdouble xtilt;
14160   gdouble ytilt;
14161   guint state;
14162   gint16 is_hint;
14163   GdkInputSource source;
14164   guint32 deviceid;
14165 };
14166 </verb></tscreen>
14167
14168 <tt/pressure/ da la presión como un número de coma flotante entre 0
14169 y 1. <tt/xtilt/ e <tt/ytilt/ pueden tomar valores entre -1 y 1,
14170 correspondiendo al grado de inclinación en cada dirección. <tt/source/
14171 y <tt/deviceid/ especifican el dispositivo para el que ocurre el
14172 evento de dos maneras diferentes. <tt/source/ da alguna información
14173 simple sobre el tipo de dispositivo. Puede tomar los valores de la
14174 enumeración siguiente:
14175
14176 <tscreen><verb>
14177 GDK_SOURCE_MOUSE
14178 GDK_SOURCE_PEN
14179 GDK_SOURCE_ERASER
14180 GDK_SOURCE_CURSOR
14181 </verb></tscreen>
14182
14183 <tt/deviceid/ especifica un número único ID para el dispositivo. Puede
14184 utilizarse para obtener más información sobre el dispositivo
14185 utilizando la función <tt/gdk_input_list_devices()/ (ver abajo). El
14186 valor especial <tt/GDK_CORE_POINTER/ se utiliza para el núcleo del
14187 dispositivo apuntador. (Normalmente el ratón.)
14188
14189 <sect2> Activando la información del dispositivo extendido
14190
14191 <p>
14192 Para informar a GTK de nuestro interés en la información sobre los
14193 dispositivos extendidos, sólo tenemos que añadirle una línea a
14194 nuestro programa:
14195
14196 <tscreen><verb>
14197 gtk_widget_set_extension_events (drawing_area, GDK_EXTENSION_EVENTS_CURSOR);
14198 </verb></tscreen>
14199
14200 Dando el valor <tt/GDK_EXTENSION_EVENTS_CURSOR/ decimos que estamos
14201 interesados en los eventos de extensión, pero sólo si no tenemos que
14202 dibujar nuestro propio cursor. Ver la sección <ref
14203 id="sec_Further_Sophistications" name="Sofisticaciones adicionales">
14204 más abajo para obtener más información sobre el dibujado del
14205 cursor. También podríamos dar los valores
14206 <tt/GDK_EXTENSION_EVENTS_ALL/ si queremos dibujar nuestro propio
14207 cursor, o <tt/GDK_EXTENSION_EVENTS_NONE/ para volver al estado
14208 inicial.
14209
14210 <p>
14211 Todavía no hemos llegado al final de la historia. Por defecto, no hay
14212 ningún dispositivo extra activado. Necesitamos un mecanismo que
14213 permita a los usuarios activar y configurar sus dispositivos
14214 extra. GTK proporciona el <em/widget/ InputDialog para automatizar el
14215 proceso. El siguiente procedimiento utiliza el <em/widget/
14216 InputDialog. Crea el cuadro de diálogo si no ha sido ya creado, y lo
14217 pone en primer plano en caso contrario.
14218
14219 <tscreen><verb>
14220 void
14221 input_dialog_destroy (GtkWidget *w, gpointer data)
14222 {
14223   *((GtkWidget **)data) = NULL;
14224 }
14225
14226 void
14227 create_input_dialog ()
14228 {
14229   static GtkWidget *inputd = NULL;
14230
14231   if (!inputd)
14232     {
14233       inputd = gtk_input_dialog_new();
14234
14235       gtk_signal_connect (GTK_OBJECT(inputd), "destroy",
14236                           (GtkSignalFunc)input_dialog_destroy, &amp;inputd);
14237       gtk_signal_connect_object (GTK_OBJECT(GTK_INPUT_DIALOG(inputd)->close_button),
14238                                  "clicked",
14239                                  (GtkSignalFunc)gtk_widget_hide,
14240                                  GTK_OBJECT(inputd));
14241       gtk_widget_hide ( GTK_INPUT_DIALOG(inputd)->save_button);
14242
14243       gtk_widget_show (inputd);
14244     }
14245   else
14246     {
14247       if (!GTK_WIDGET_MAPPED(inputd))
14248         gtk_widget_show(inputd);
14249       else
14250         gdk_window_raise(inputd->window);
14251     }
14252 }
14253 </verb></tscreen>
14254
14255 (Tome nota de la manera en que hemos manejado el cuadro de
14256 diálogo. Conectando la señal <tt/destroy/, nos aseguramos de que no
14257 tendremos un puntero al cuadro de diálogo después de que haya sido
14258 destruido, lo que nos podría llevar a un segfault.)
14259
14260 <p>
14261 El InputDialog tiene dos botones «Cerrar» y «Guardar», que por
14262 defecto no tienen ninguna acción asignada. En la función anterior
14263 hemos hecho que «Cerrar» oculte el cuadro de diálogo, ocultando el
14264 botón «Guardar», ya que no implementaremos en este programa la
14265 acción de guardar las opciones de XInput.
14266
14267 <sect2> Utilizando la información de los dispositivos extras
14268
14269 <p>
14270 Una vez hemos activado el dispositivo, podemos utilizar la
14271 información que hay respecto a los dispositivos extendidos en los
14272 campos extras de las estructuras de los eventos. De hecho, es bueno
14273 utilizar esa información ya que esos campos tienen unos valores por
14274 defecto razonables aún cuando no se activen los eventos extendidos.
14275
14276 <p>
14277 Un cambio que tenemos que hacer es llamar a
14278 <tt/gdk_input_window_get_pointer()/ en vez de a
14279 <tt/gdk_window_get_pointer/. Esto es necesario porque
14280 <tt/gdk_window_get_pointer/ no devuelve la información de los
14281 dispositivos extra.
14282
14283 <tscreen><verb>
14284 void gdk_input_window_get_pointer     (GdkWindow       *ventana,
14285                                        guint32         deviceid,
14286                                        gdouble         *x,
14287                                        gdouble         *y,
14288                                        gdouble         *pressure,
14289                                        gdouble         *xtilt,
14290                                        gdouble         *ytilt,
14291                                        GdkModifierType *mask);
14292 </verb></tscreen>
14293
14294 Cuando llamamos a esta función, necesitamos especificar tanto el ID
14295 del dispositivo como la ventana. Normalmente, obtendremos el ID del
14296 dispositivo del campo <tt/deviceid/ de una estructura de evento. De
14297 nuevo, esta función devolverá valores razonables cuando no estén
14298 activados los eventos extendidos. (En ese caso, <tt/event->deviceid/
14299 tendrá el valor <tt/GDK_CORE_POINTER/).
14300
14301 Por tanto la estructura básica de nuestros manejadores de los
14302 eventos de movimiento y de pulsación del botón del ratón no
14303 cambiarán mucho - sólo tenemos que añadir código para manejar la
14304 información extra.
14305
14306 <tscreen><verb>
14307 static gint
14308 button_press_event (GtkWidget *widget, GdkEventButton *event)
14309 {
14310   print_button_press (event->deviceid);
14311   
14312   if (event->button == 1 &amp;&amp; pixmap != NULL)
14313     draw_brush (widget, event->source, event->x, event->y, event->pressure);
14314
14315   return TRUE;
14316 }
14317
14318 static gint
14319 motion_notify_event (GtkWidget *widget, GdkEventMotion *event)
14320 {
14321   gdouble x, y;
14322   gdouble pressure;
14323   GdkModifierType state;
14324
14325   if (event->is_hint)
14326     gdk_input_window_get_pointer (event->window, event->deviceid,
14327                                   &amp;x, &amp;y, &amp;pressure, NULL, NULL, &amp;state);
14328   else
14329     {
14330       x = event->x;
14331       y = event->y;
14332       pressure = event->pressure;
14333       state = event->state;
14334     }
14335     
14336   if (state &amp; GDK_BUTTON1_MASK &amp;&amp; pixmap != NULL)
14337     draw_brush (widget, event->source, x, y, pressure);
14338   
14339   return TRUE;
14340 }
14341 </verb></tscreen>
14342
14343 También tenemos que hacer algo con la nueva información. Nuestra
14344 nueva función <tt/draw_brush()/ dibuja con un color diferente
14345 dependiendo de <tt/event->source/ y cambia el tamaño de la brocha
14346 dependiendo de la presión.
14347
14348 <tscreen><verb>
14349 /* Draw a rectangle on the screen, size depending on pressure,
14350    and color on the type of device */
14351 static void
14352 draw_brush (GtkWidget *widget, GdkInputSource source,
14353             gdouble x, gdouble y, gdouble pressure)
14354 {
14355   GdkGC *gc;
14356   GdkRectangle update_rect;
14357
14358   switch (source)
14359     {
14360     case GDK_SOURCE_MOUSE:
14361       gc = widget->style->dark_gc[GTK_WIDGET_STATE (widget)];
14362       break;
14363     case GDK_SOURCE_PEN:
14364       gc = widget->style->black_gc;
14365       break;
14366     case GDK_SOURCE_ERASER:
14367       gc = widget->style->white_gc;
14368       break;
14369     default:
14370       gc = widget->style->light_gc[GTK_WIDGET_STATE (widget)];
14371     }
14372
14373   update_rect.x = x - 10 * pressure;
14374   update_rect.y = y - 10 * pressure;
14375   update_rect.width = 20 * pressure;
14376   update_rect.height = 20 * pressure;
14377   gdk_draw_rectangle (pixmap, gc, TRUE,
14378                       update_rect.x, update_rect.y,
14379                       update_rect.width, update_rect.height);
14380   gtk_widget_draw (widget, &amp;update_rect);
14381 }
14382 </verb></tscreen>
14383
14384 <sect2> Obteniendo más información de un dispositivo
14385
14386 <p>
14387 Como ejemplo de como podemos obtener más información de un
14388 dispositivo, nuestro programa imprimirá el nombre del dispositivo que
14389 genera cada pulsación de botón. Para encontrar el nombre de un
14390 dispositivo, llamaremos a la función:
14391
14392 <tscreen><verb>
14393 GList *gdk_input_list_devices               (void);
14394 </verb></tscreen>
14395
14396 que devuelve una GList (una lista enlazada de la biblioteca glib)
14397 de estructuras <tt/GdkDeviceInfo/. La estructura <tt/GdkDeviceInfo/ se
14398 define como:
14399
14400 <tscreen><verb>
14401 struct _GdkDeviceInfo
14402 {
14403   guint32 deviceid;
14404   gchar *name;
14405   GdkInputSource source;
14406   GdkInputMode mode;
14407   gint has_cursor;
14408   gint num_axes;
14409   GdkAxisUse *axes;
14410   gint num_keys;
14411   GdkDeviceKey *keys;
14412 };
14413 </verb></tscreen>
14414
14415 Muchos de estos campos son información de configuración que puede
14416 ignorar, a menos que quiera permitir la opción de grabar la
14417 configuración de XInput. El campo que nos interesa ahora es <tt/name/
14418 que es simplemente el nombre que X le asigna al dispositivo. El otro
14419 campo que no tiene información sobre la configuración es
14420 <tt/has_cursor/. Si <tt/has_cursor/ es falso, tendremos que dibujar
14421 nuestro propio cursor. Pero como hemos especificado
14422 <tt/GDK_EXTENSION_EVENTS_CURSOR/, no tendremos que preocuparnos por
14423 esto.
14424
14425 <p>
14426 Nuestra función <tt/print_button_press()/ simplemente recorre la
14427 lista devuelta hasta que encuentra una coincidencia, y entonces
14428 imprime el nombre del dispositivo.
14429
14430 <tscreen><verb>
14431 static void
14432 print_button_press (guint32 deviceid)
14433 {
14434   GList *tmp_list;
14435
14436   /* gdk_input_list_devices returns an internal list, so we shouldn't
14437      free it afterwards */
14438   tmp_list = gdk_input_list_devices();
14439
14440   while (tmp_list)
14441     {
14442       GdkDeviceInfo *info = (GdkDeviceInfo *)tmp_list->data;
14443
14444       if (info->deviceid == deviceid)
14445         {
14446           printf("Button press on device '%s'\n", info->name);
14447           return;
14448         }
14449
14450       tmp_list = tmp_list->next;
14451     }
14452 }
14453 </verb></tscreen>
14454
14455 Con esto hemos completado los cambios para `XInputizar' nuestro
14456 programa. Como ocurría con la primera versión, el código completo se
14457 encuentra disponible en el mismo sitio donde obtuvo este tutorial, o
14458 desde:
14459
14460 <htmlurl url="http://www.gtk.org/~otaylor/gtk/tutorial/"
14461 name="http://www.gtk.org/~otaylor/gtk/tutorial/">
14462
14463
14464 <sect2> Sofisticaciones adicionales <label id="sec_Further_Sophistications">
14465
14466 <p>
14467 Aunque ahora nuestro programa admite XInput bastante bien, todavía
14468 falla en algunas características que deberían estar disponibles en una
14469 aplicación bien hecha. Primero, el usuario no debería tener que
14470 configurar su dispositivo cada vez que ejecute el programa, por lo que
14471 debería estar disponible la opción de guardar la configuración del
14472 dispositivo. Esto se hace recorriendo el resultado de
14473 <tt/gdk_input_list_devices()/ y escribiendo la configuración en un
14474 fichero.
14475
14476 <p>
14477 Para cargar la configuración del dispositivo cuando se vuelva a
14478 ejecutar el programa, puede utilizar las funciones que proporciona GDK
14479 para cambiar la configuración de los dispositivos:
14480
14481 <tscreen><verb>
14482 gdk_input_set_extension_events()
14483 gdk_input_set_source()
14484 gdk_input_set_mode()
14485 gdk_input_set_axes()
14486 gdk_input_set_key()
14487 </verb></tscreen>
14488
14489 (La lista devuelta por <tt/gdk_input_list_devices()/ no debería
14490 modificarse directamente.) Podemos encontrar un ejemplo de como debe
14491 utilizarse en el programa de dibujo <tt/gsumi/. (Disponible en
14492 <htmlurl url="http://www.msc.cornell.edu/~otaylor/gsumi/"
14493 name="http://www.msc.cornell.edu/~otaylor/gsumi/">) Estaría bien
14494 tener un procedimiento estándar para poder hacer todo esto en
14495 cualquier aplicaciones. Probablemente se llegue a esto en una capa
14496 superior a GTK, quizás en la biblioteca GNOME.
14497
14498 <p>
14499 El programa tiene otra carencia importante que ya hemos mencionado más
14500 arriba, y es la falta del cursor. Ninguna plataforma distinta de
14501 XFree86 permite utilizar simultaneamente un dispositivo como puntero
14502 núcleo y como dispositivo directamente utilizable por una
14503 aplicación. Ver el <url
14504 url="http://www.msc.cornell.edu/~otaylor/xinput/XInput-HOWTO.html" 
14505 name="XInput-HOWTO"> para más información sobre esto. Con esto
14506 queremos decir que si quiere tener la máxima audiencia necesita
14507 dibujar su propio cursor.
14508
14509 <p>
14510 Una aplicación que dibuja su propio cursor necesita hacer dos cosas:
14511 determinar si el dispositivo actual necesita que se dibuje un cursor o
14512 no, y determinar si el dispositivo está «próximo». (Si el
14513 dispositivo es una tableta digitalizadora, queda muy bonito que el
14514 cursor desaparezca cuando el lápiz se separa de la tableta. Cuando el
14515 lápiz está tocando la tableta, se dice que el dispositivo está
14516 «próximo»). Lo primero se hace buscando la lista de dispositivos,
14517 tal y como hicimos para encontrar el nombre del dispositivo. Lo
14518 segundo se consigue seleccionando los eventos
14519 <em/proximity_out/. Podemos encontrar un ejemplo de como dibujar
14520 nuestro propio cursor en el programa `testinput' que viene con la
14521 distribución de GTK.
14522
14523 <!-- ***************************************************************** -->
14524 <sect>Trucos para escribir aplicaciones GTK
14525 <!-- ***************************************************************** -->
14526
14527 <p>
14528 Esta sección es sólo un compendio de sabiduria, de guías generales
14529 de estilo y de consejos para crear buenas aplicaciones GTK. Y es
14530 totalmente inútil por ahora ya que esta frase es sólo un tópico :)
14531
14532 ¡Utilice GNU autoconf y automake! Son sus amigos :) Pretendo poner
14533 aquí una rápida introducción a ambos.
14534
14535 <!-- ***************************************************************** -->
14536 <sect>Contribuyendo <label id="sec_Contributing">
14537 <!-- ***************************************************************** -->
14538
14539 <p>
14540 Este documento, como muchos otros grandes paquetes de programas que
14541 hay por ahí, fue creado de forma libre por voluntarios. Si comprende
14542 algo de GTK que todavía no se ha documentado, por favor piense en
14543 contribuir a este documento.
14544
14545 <p>
14546 Si decide contribuir, por favor mande un correo-e con su texto a Tony
14547 Gale,  <tt><htmlurl url="mailto:gale@gtk.org"
14548 name="gale@gtk.org"></tt>. Recuerde que todas las partes que componen
14549 este documento son libre, y cualquier añadido que haga debe ser
14550 libre. Esto es, la gente debe de poder utilizar cualquier trozo de sus
14551 ejemplos en sus programas, podrán distribuir copias de su documento
14552 como deseen, etc...
14553 <p>
14554 Gracias.
14555
14556 <!-- ***************************************************************** -->
14557 <sect>Créditos
14558 <!-- ***************************************************************** -->
14559 <p>
14560 Quiero agradecer a las siguientes personas por sus contribuciones a
14561 este texto.
14562
14563 <itemize>
14564 <item>Bawer Dagdeviren, <tt><htmlurl url="mailto:chamele0n@geocities.com"
14565 name="chamele0n@geocities.com"></tt> por el tutorial sobre los menús.
14566
14567 <item>Raph Levien, <tt><htmlurl url="mailto:raph@acm.org"
14568 name="raph@acm.org"></tt> por el «hola mundo» a la GTK, el
14569 empaquetado de <em/widgets/, y su sabiduría general. Ha donado
14570 generosamente un hogar para este tutorial.
14571
14572 <item>Peter Mattis, <tt><htmlurl url="mailto:petm@xcf.berkeley.edu"
14573 name="petm@xcf.berkeley.edu"></tt> por el más simple de los programas
14574 GTK... y por la posibilidad de hacerlo :)
14575
14576 <item>Werner Koch <tt><htmlurl url="mailto:werner.koch@guug.de"
14577 name="werner.koch@guug.de"></tt> por convertir el texto original a
14578 SGML, y por la jerarquia de clases de <em/widgets/.
14579
14580 <item>Mark Crichton <tt><htmlurl url="mailto:crichton@expert.cc.purdue.edu"
14581 name="crichton@expert.cc.purdue.edu"></tt> por el código del menú
14582 factory, y el tutorial sobre el empaquetamiento de las tablas.
14583
14584 <item>Owen Taylor <tt><htmlurl url="mailto:owt1@cornell.edu"
14585 name="owt1@cornell.edu"></tt> por la sección sobre el <em/widget/
14586 EventBox (y el parche para el distro). También es el responsable
14587 del código de las selecciones y el tutorial, así como de la
14588 sección de escribiendo su propio <em/widget/ GTK, y la aplicación de
14589 ejemplo. ¡Muchas gracias por toda tu ayuda, Owen!
14590
14591 <item>Mark VanderBoom <tt><htmlurl url="mailto:mvboom42@calvin.edu"
14592 name="mvboom42@calvin.edu"></tt> por su fantástico trabajo sobre los
14593 <em/widgets/ Notebook, Progress Bar, Dialog, y selección de ficheros.
14594 ¡Muchas gracias Mark!
14595 Has sido de una gran ayuda.
14596
14597 <item>Tim Janik <tt><htmlurl url="mailto:timj@gtk.org"
14598 name="timj@gtk.org"></tt> por su gran trabajo en el <em/widget/ List.
14599 Gracias Tim :)
14600
14601 <item>Rajat Datta <tt><htmlurl url="mailto:rajat@ix.netcom.com"
14602 name="rajat@ix.netcom.com"</tt> por el excelente trabajo con el
14603 tutorial Pixmap.
14604
14605 <item>Michael K. Johnson <tt><htmlurl url="mailto:johnsonm@redhat.com"
14606 name="johnsonm@redhat.com"></tt> por la información y el código de
14607 los menús ("popup").
14608
14609 <item>David Huggins-Daines <tt><htmlurl url="mailto:bn711@freenet.carleton.ca"
14610 name="bn711@freenet.carleton.ca"></tt> por las secciones sobre los
14611 <em/widgets/ Range y Tree.
14612
14613 <item>Stefan Mars <tt><htmlurl url="mailto:mars@lysator.liu.se"
14614 name="mars@lysator.liu.se"></tt> por la sección GtkCList
14615 </itemize>
14616 <p>
14617 Y a todos los que han comentado y ayudado a refinar este documento.
14618 <p>
14619 Gracias.
14620
14621 <!-- ***************************************************************** -->
14622 <sect> Copyright del Tutorial y notas sobre los permisos
14623 <!-- ***************************************************************** -->
14624
14625 <p>
14626 Esta traducción está bajo la misma licencia bajo la que está
14627 el documento original. A continuación se presenta la traducción
14628 de la licencia y la licencia en versión original. En caso de haber
14629 alguna discrepancia entre la traducción y la licencia original, se
14630 aplicará esta última.
14631
14632 El Tutorial GTK tiene Copyright (C) 1997 Ian Main.
14633
14634 Copyright (C) 1998 Tony Gale.
14635 <p>
14636 Se da permiso para hacer y distribuir copias idénticas de este manual
14637 siempre que se incluya el copyright en todas las copias.
14638 <p>
14639 Se da permiso para copiar y distribuir versiones modificadas de este
14640 documento bajo las mismas condiciones que para las copias idénticas,
14641 siempre que el copyright se incluya exactamente tal y como se
14642 encuentra en el original, y que el trabajo completo derivado de este
14643 documento se distribuya bajo los términos de un permiso idéntico a
14644 éste.
14645 <P>
14646 Se da permiso para copiar y distribuir traducciones de este documento
14647 en otro lenguaje, bajo las condiciones arriba mencionadas para las
14648 versiones modificadas.
14649 <P>
14650 Si se propone incluir este documento en un trabajo que vaya a ser
14651 impreso, por favor contacte con el encargado del mantenimiento, y
14652 haremos un esfuerzo para asegurarnos de que dispone de la información
14653 lo más actualizada posible.
14654 <P>
14655 No hay ninguna garantia de que este documento se mantenga activo lo
14656 suficiente como para conseguir cumplir con su propósito. Se
14657 proporciona como un documento libre. Como tal, los autores y
14658 encargados del mantenimiento de la información que se da en el
14659 documento no pueden dar ninguna garantia de que la misma esté al día.
14660 <P>
14661 -----------------------------
14662 <p>
14663 The GTK Tutorial is Copyright (C) 1997 Ian Main. 
14664
14665 Copyright (C) 1998 Tony Gale.
14666 <p>
14667 Permission is granted to make and distribute verbatim copies of this 
14668 manual provided the copyright notice and this permission notice are 
14669 preserved on all copies.
14670 <P>Permission is granted to copy and distribute modified versions of 
14671 this document under the conditions for verbatim copying, provided that 
14672 this copyright notice is included exactly as in the original,
14673 and that the entire resulting derived work is distributed under 
14674 the terms of a permission notice identical to this one.
14675 <P>Permission is granted to copy and distribute translations of this 
14676 document into another language, under the above conditions for modified 
14677 versions.
14678 <P>If you are intending to incorporate this document into a published 
14679 work, please contact the maintainer, and we will make an effort 
14680 to ensure that you have the most up to date information available.
14681 <P>There is no guarantee that this document lives up to its intended
14682 purpose.  This is simply provided as a free resource.  As such,
14683 the authors and maintainers of the information provided within can
14684 not make any guarantee that the information is even accurate.
14685
14686 <sect1>Acerca de la traducción
14687
14688 <p>
14689 Esta traduccion tiene copyright (C) 1999 de Joaquín Cuenca Abela
14690 <tt><htmlurl url="mailto:e98cuenc@criens.u-psud.fr" 
14691 name="&lt;e98cuenc@criens.u-psud.fr&gt;"></tt> 
14692 y de Eduardo Anglada Varela 
14693 <tt><htmlurl url="mailto:eduardo.anglada@adi.uam.es"
14694 name="&lt;eduardo.anglada@adi.uam.es&gt;"></tt>.
14695 Si tiene cualquier
14696 duda, sugerencia o corrección no dude en consultarnos.
14697
14698 Gracias a Manuel de Vega Barreiro <tt><htmlurl
14699 url="mailto:barreiro@arrakis.es"
14700 name="&lt;barreiro@arrakis.es&gt;"></tt> por haber hospedado las
14701 versiones beta y la versión actual de este tutorial en su página
14702 web Linux Landia <tt><url
14703 url="http://www.croftj.net/~barreiro/spain/gnome/"
14704 name="www.croftj.net/~barreiro/spain/gnome/"></tt>.
14705
14706 </sect1>
14707
14708 <!-- ***************************************************************** -->
14709 <appendix>
14710 <!-- ***************************************************************** -->
14711
14712 <!-- ***************************************************************** -->
14713 <sect> Señales GTK <label id="sec_GTK_Signals">
14714 <!-- ***************************************************************** -->
14715 <p>
14716 GTK+, al ser un conjunto de <em/widgets/ orientado al objeto, tiene
14717 una jerarquía de herencias. Este mecanismo de herencia se aplica a las
14718 señales. Por eso, debe utilizar el árbol de jerarquías de los
14719 <em/widgets/ cuando utilice las señales que aparecen en esta sección. 
14720
14721 <!-- ----------------------------------------------------------------- -->
14722 <sect1>GtkObject
14723 <!-- ----------------------------------------------------------------- -->
14724 <p>
14725 <tscreen><verb>
14726 void GtkObject::destroy (GtkObject *,
14727                          gpointer);
14728 </verb></tscreen>
14729
14730 <!-- ----------------------------------------------------------------- -->
14731 <sect1>GtkWidget
14732 <!-- ----------------------------------------------------------------- -->
14733 <p>
14734 <tscreen><verb>
14735
14736 void GtkWidget::show    (GtkWidget *,
14737                          gpointer);
14738 void GtkWidget::hide    (GtkWidget *,
14739                          gpointer);
14740 void GtkWidget::map     (GtkWidget *,
14741                          gpointer);
14742 void GtkWidget::unmap   (GtkWidget *,
14743                          gpointer);
14744 void GtkWidget::realize (GtkWidget *,
14745                          gpointer);
14746 void GtkWidget::unrealize       (GtkWidget *,
14747                                  gpointer);
14748 void GtkWidget::draw    (GtkWidget *,
14749                          ggpointer,
14750                          gpointer);
14751 void GtkWidget::draw-focus      (GtkWidget *,
14752                                  gpointer);
14753 void GtkWidget::draw-default    (GtkWidget *,
14754                                  gpointer);
14755 void GtkWidget::size-request    (GtkWidget *,
14756                                  ggpointer,
14757                                  gpointer);
14758 void GtkWidget::size-allocate   (GtkWidget *,
14759                                  ggpointer,
14760                                  gpointer);
14761 void GtkWidget::state-changed   (GtkWidget *,
14762                                  GtkStateType,
14763                                  gpointer);
14764 void GtkWidget::parent-set      (GtkWidget *,
14765                                  GtkObject *,
14766                                  gpointer);
14767 void GtkWidget::style-set       (GtkWidget *,
14768                                  GtkStyle *,
14769                                  gpointer);
14770 void GtkWidget::add-accelerator (GtkWidget *,
14771                                  gguint,
14772                                  GtkAccelGroup *,
14773                                  gguint,
14774                                  GdkModifierType,
14775                                  GtkAccelFlags,
14776                                  gpointer);
14777 void GtkWidget::remove-accelerator      (GtkWidget *,
14778                                          GtkAccelGroup *,
14779                                          gguint,
14780                                          GdkModifierType,
14781                                          gpointer);
14782 gboolean GtkWidget::event       (GtkWidget *,
14783                                  GdkEvent *,
14784                                  gpointer);
14785 gboolean GtkWidget::button-press-event  (GtkWidget *,
14786                                          GdkEvent *,
14787                                          gpointer);
14788 gboolean GtkWidget::button-release-event        (GtkWidget *,
14789                                                  GdkEvent *,
14790                                                  gpointer);
14791 gboolean GtkWidget::motion-notify-event (GtkWidget *,
14792                                          GdkEvent *,
14793                                          gpointer);
14794 gboolean GtkWidget::delete-event        (GtkWidget *,
14795                                          GdkEvent *,
14796                                          gpointer);
14797 gboolean GtkWidget::destroy-event       (GtkWidget *,
14798                                          GdkEvent *,
14799                                          gpointer);
14800 gboolean GtkWidget::expose-event        (GtkWidget *,
14801                                          GdkEvent *,
14802                                          gpointer);
14803 gboolean GtkWidget::key-press-event     (GtkWidget *,
14804                                          GdkEvent *,
14805                                          gpointer);
14806 gboolean GtkWidget::key-release-event   (GtkWidget *,
14807                                          GdkEvent *,
14808                                          gpointer);
14809 gboolean GtkWidget::enter-notify-event  (GtkWidget *,
14810                                          GdkEvent *,
14811                                          gpointer);
14812 gboolean GtkWidget::leave-notify-event  (GtkWidget *,
14813                                          GdkEvent *,
14814                                          gpointer);
14815 gboolean GtkWidget::configure-event     (GtkWidget *,
14816                                          GdkEvent *,
14817                                          gpointer);
14818 gboolean GtkWidget::focus-in-event      (GtkWidget *,
14819                                          GdkEvent *,
14820                                          gpointer);
14821 gboolean GtkWidget::focus-out-event     (GtkWidget *,
14822                                          GdkEvent *,
14823                                          gpointer);
14824 gboolean GtkWidget::map-event   (GtkWidget *,
14825                                  GdkEvent *,
14826                                  gpointer);
14827 gboolean GtkWidget::unmap-event (GtkWidget *,
14828                                  GdkEvent *,
14829                                  gpointer);
14830 gboolean GtkWidget::property-notify-event       (GtkWidget *,
14831                                                  GdkEvent *,
14832                                                  gpointer);
14833 gboolean GtkWidget::selection-clear-event       (GtkWidget *,
14834                                                  GdkEvent *,
14835                                                  gpointer);
14836 gboolean GtkWidget::selection-request-event     (GtkWidget *,
14837                                                  GdkEvent *,
14838                                                  gpointer);
14839 gboolean GtkWidget::selection-notify-event      (GtkWidget *,
14840                                                  GdkEvent *,
14841                                                  gpointer);
14842 void GtkWidget::selection-get   (GtkWidget *,
14843                                  GtkSelectionData *,
14844                                  gguint,
14845                                  gpointer);
14846 void GtkWidget::selection-received      (GtkWidget *,
14847                                          GtkSelectionData *,
14848                                          gguint,
14849                                          gpointer);
14850 gboolean GtkWidget::proximity-in-event  (GtkWidget *,
14851                                          GdkEvent *,
14852                                          gpointer);
14853 gboolean GtkWidget::proximity-out-event (GtkWidget *,
14854                                          GdkEvent *,
14855                                          gpointer);
14856 void GtkWidget::drag-begin      (GtkWidget *,
14857                                  GdkDragContext *,
14858                                  gpointer);
14859 void GtkWidget::drag-end        (GtkWidget *,
14860                                  GdkDragContext *,
14861                                  gpointer);
14862 void GtkWidget::drag-data-delete        (GtkWidget *,
14863                                          GdkDragContext *,
14864                                          gpointer);
14865 void GtkWidget::drag-leave      (GtkWidget *,
14866                                  GdkDragContext *,
14867                                  gguint,
14868                                  gpointer);
14869 gboolean GtkWidget::drag-motion (GtkWidget *,
14870                                  GdkDragContext *,
14871                                  ggint,
14872                                  ggint,
14873                                  gguint,
14874                                  gpointer);
14875 gboolean GtkWidget::drag-drop   (GtkWidget *,
14876                                  GdkDragContext *,
14877                                  ggint,
14878                                  ggint,
14879                                  gguint,
14880                                  gpointer);
14881 void GtkWidget::drag-data-get   (GtkWidget *,
14882                                  GdkDragContext *,
14883                                  GtkSelectionData *,
14884                                  gguint,
14885                                  gguint,
14886                                  gpointer);
14887 void GtkWidget::drag-data-received      (GtkWidget *,
14888                                          GdkDragContext *,
14889                                          ggint,
14890                                          ggint,
14891                                          GtkSelectionData *,
14892                                          gguint,
14893                                          gguint,
14894                                          gpointer);
14895 gboolean GtkWidget::client-event        (GtkWidget *,
14896                                          GdkEvent *,
14897                                          gpointer);
14898 gboolean GtkWidget::no-expose-event     (GtkWidget *,
14899                                          GdkEvent *,
14900                                          gpointer);
14901 gboolean GtkWidget::visibility-notify-event     (GtkWidget *,
14902                                                  GdkEvent *,
14903                                                  gpointer);
14904 void GtkWidget::debug-msg       (GtkWidget *,
14905                                  GtkString *,
14906                                  gpointer);
14907 </verb></tscreen>
14908
14909 <!-- ----------------------------------------------------------------- -->
14910 <sect1>GtkData
14911 <!-- ----------------------------------------------------------------- -->
14912 <p>
14913 <tscreen><verb>
14914 void GtkData::disconnect        (GtkData *,
14915                                  gpointer);
14916 </verb></tscreen>
14917
14918 <!-- ----------------------------------------------------------------- -->
14919 <sect1>GtkContainer
14920 <!-- ----------------------------------------------------------------- -->
14921 <p>
14922 <tscreen><verb>
14923 void GtkContainer::add  (GtkContainer *,
14924                          GtkWidget *,
14925                          gpointer);
14926 void GtkContainer::remove       (GtkContainer *,
14927                                  GtkWidget *,
14928                                  gpointer);
14929 void GtkContainer::check-resize (GtkContainer *,
14930                                  gpointer);
14931 GtkDirectionType GtkContainer::focus    (GtkContainer *,
14932                                          GtkDirectionType,
14933                                          gpointer);
14934 void GtkContainer::set-focus-child      (GtkContainer *,
14935                                          GtkWidget *,
14936                                          gpointer);
14937 </verb></tscreen>
14938
14939 <!-- ----------------------------------------------------------------- -->
14940 <sect1>GtkCalendar
14941 <!-- ----------------------------------------------------------------- -->
14942 <p>
14943 <tscreen><verb>
14944 void GtkCalendar::month-changed (GtkCalendar *,
14945                                  gpointer);
14946 void GtkCalendar::day-selected  (GtkCalendar *,
14947                                  gpointer);
14948 void GtkCalendar::day-selected-double-click     (GtkCalendar *,
14949                                                  gpointer);
14950 void GtkCalendar::prev-month    (GtkCalendar *,
14951                                  gpointer);
14952 void GtkCalendar::next-month    (GtkCalendar *,
14953                                  gpointer);
14954 void GtkCalendar::prev-year     (GtkCalendar *,
14955                                  gpointer);
14956 void GtkCalendar::next-year     (GtkCalendar *,
14957                                  gpointer);
14958 </verb></tscreen>
14959
14960 <!-- ----------------------------------------------------------------- -->
14961 <sect1>GtkEditable
14962 <!-- ----------------------------------------------------------------- -->
14963 <p>
14964 <tscreen><verb>
14965 void GtkEditable::changed       (GtkEditable *,
14966                                  gpointer);
14967 void GtkEditable::insert-text   (GtkEditable *,
14968                                  GtkString *,
14969                                  ggint,
14970                                  ggpointer,
14971                                  gpointer);
14972 void GtkEditable::delete-text   (GtkEditable *,
14973                                  ggint,
14974                                  ggint,
14975                                  gpointer);
14976 void GtkEditable::activate      (GtkEditable *,
14977                                  gpointer);
14978 void GtkEditable::set-editable  (GtkEditable *,
14979                                  gboolean,
14980                                  gpointer);
14981 void GtkEditable::move-cursor   (GtkEditable *,
14982                                  ggint,
14983                                  ggint,
14984                                  gpointer);
14985 void GtkEditable::move-word     (GtkEditable *,
14986                                  ggint,
14987                                  gpointer);
14988 void GtkEditable::move-page     (GtkEditable *,
14989                                  ggint,
14990                                  ggint,
14991                                  gpointer);
14992 void GtkEditable::move-to-row   (GtkEditable *,
14993                                  ggint,
14994                                  gpointer);
14995 void GtkEditable::move-to-column        (GtkEditable *,
14996                                          ggint,
14997                                          gpointer);
14998 void GtkEditable::kill-char     (GtkEditable *,
14999                                  ggint,
15000                                  gpointer);
15001 void GtkEditable::kill-word     (GtkEditable *,
15002                                  ggint,
15003                                  gpointer);
15004 void GtkEditable::kill-line     (GtkEditable *,
15005                                  ggint,
15006                                  gpointer);
15007 void GtkEditable::cut-clipboard (GtkEditable *,
15008                                  gpointer);
15009 void GtkEditable::copy-clipboard        (GtkEditable *,
15010                                          gpointer);
15011 void GtkEditable::paste-clipboard       (GtkEditable *,
15012                                          gpointer);
15013 </verb></tscreen>
15014
15015 <!-- ----------------------------------------------------------------- -->
15016 <sect1>GtkTipsQuery
15017 <!-- ----------------------------------------------------------------- -->
15018 <p>
15019 <tscreen><verb>
15020 void GtkTipsQuery::start-query  (GtkTipsQuery *,
15021                                  gpointer);
15022 void GtkTipsQuery::stop-query   (GtkTipsQuery *,
15023                                  gpointer);
15024 void GtkTipsQuery::widget-entered       (GtkTipsQuery *,
15025                                          GtkWidget *,
15026                                          GtkString *,
15027                                          GtkString *,
15028                                          gpointer);
15029 gboolean GtkTipsQuery::widget-selected  (GtkTipsQuery *,
15030                                          GtkWidget *,
15031                                          GtkString *,
15032                                          GtkString *,
15033                                          GdkEvent *,
15034                                          gpointer);
15035 </verb></tscreen>
15036
15037 <!-- ----------------------------------------------------------------- -->
15038 <sect1>GtkCList
15039 <!-- ----------------------------------------------------------------- -->
15040 <p>
15041 <tscreen><verb>
15042 void GtkCList::select-row       (GtkCList *,
15043                                  ggint,
15044                                  ggint,
15045                                  GdkEvent *,
15046                                  gpointer);
15047 void GtkCList::unselect-row     (GtkCList *,
15048                                  ggint,
15049                                  ggint,
15050                                  GdkEvent *,
15051                                  gpointer);
15052 void GtkCList::row-move (GtkCList *,
15053                          ggint,
15054                          ggint,
15055                          gpointer);
15056 void GtkCList::click-column     (GtkCList *,
15057                                  ggint,
15058                                  gpointer);
15059 void GtkCList::resize-column    (GtkCList *,
15060                                  ggint,
15061                                  ggint,
15062                                  gpointer);
15063 void GtkCList::toggle-focus-row (GtkCList *,
15064                                  gpointer);
15065 void GtkCList::select-all       (GtkCList *,
15066                                  gpointer);
15067 void GtkCList::unselect-all     (GtkCList *,
15068                                  gpointer);
15069 void GtkCList::undo-selection   (GtkCList *,
15070                                  gpointer);
15071 void GtkCList::start-selection  (GtkCList *,
15072                                  gpointer);
15073 void GtkCList::end-selection    (GtkCList *,
15074                                  gpointer);
15075 void GtkCList::toggle-add-mode  (GtkCList *,
15076                                  gpointer);
15077 void GtkCList::extend-selection (GtkCList *,
15078                                  GtkScrollType,
15079                                  ggfloat,
15080                                  gboolean,
15081                                  gpointer);
15082 void GtkCList::scroll-vertical  (GtkCList *,
15083                                  GtkScrollType,
15084                                  ggfloat,
15085                                  gpointer);
15086 void GtkCList::scroll-horizontal        (GtkCList *,
15087                                          GtkScrollType,
15088                                          ggfloat,
15089                                          gpointer);
15090 void GtkCList::abort-column-resize      (GtkCList *,
15091                                          gpointer);
15092 </verb></tscreen>
15093
15094 <!-- ----------------------------------------------------------------- -->
15095 <sect1>GtkNotebook
15096 <!-- ----------------------------------------------------------------- -->
15097 <p>
15098 <tscreen><verb>
15099 void GtkNotebook::switch-page   (GtkNotebook *,
15100                                  ggpointer,
15101                                  gguint,
15102                                  gpointer);
15103
15104 </verb></tscreen>
15105
15106 <!-- ----------------------------------------------------------------- -->
15107 <sect1>GtkList
15108 <!-- ----------------------------------------------------------------- -->
15109 <p>
15110 <tscreen><verb>
15111 void GtkList::selection-changed (GtkList *,
15112                                  gpointer);
15113 void GtkList::select-child      (GtkList *,
15114                                  GtkWidget *,
15115                                  gpointer);
15116 void GtkList::unselect-child    (GtkList *,
15117                                  GtkWidget *,
15118                                  gpointer);
15119 </verb></tscreen>
15120
15121 <!-- ----------------------------------------------------------------- -->
15122 <sect1>GtkMenuShell
15123 <!-- ----------------------------------------------------------------- -->
15124 <p>
15125 <tscreen><verb>
15126 void GtkMenuShell::deactivate   (GtkMenuShell *,
15127                                  gpointer);
15128 void GtkMenuShell::selection-done       (GtkMenuShell *,
15129                                          gpointer);
15130 void GtkMenuShell::move-current (GtkMenuShell *,
15131                                  GtkMenuDirectionType,
15132                                  gpointer);
15133 void GtkMenuShell::activate-current     (GtkMenuShell *,
15134                                          gboolean,
15135                                          gpointer);
15136 void GtkMenuShell::cancel       (GtkMenuShell *,
15137                                  gpointer);
15138 </verb></tscreen>
15139
15140 <!-- ----------------------------------------------------------------- -->
15141 <sect1>GtkToolbar
15142 <!-- ----------------------------------------------------------------- -->
15143 <p>
15144 <tscreen><verb>
15145 void GtkToolbar::orientation-changed    (GtkToolbar *,
15146                                          ggint,
15147                                          gpointer);
15148 void GtkToolbar::style-changed  (GtkToolbar *,
15149                                  ggint,
15150                                  gpointer);
15151 </verb></tscreen>
15152
15153 <!-- ----------------------------------------------------------------- -->
15154 <sect1>GtkTree
15155 <!-- ----------------------------------------------------------------- -->
15156 <p>
15157 <tscreen><verb>
15158 void GtkTree::selection-changed (GtkTree *,
15159                                  gpointer);
15160 void GtkTree::select-child      (GtkTree *,
15161                                  GtkWidget *,
15162                                  gpointer);
15163 void GtkTree::unselect-child    (GtkTree *,
15164                                  GtkWidget *,
15165                                  gpointer);
15166 </verb></tscreen>
15167
15168 <!-- ----------------------------------------------------------------- -->
15169 <sect1>GtkButton
15170 <!-- ----------------------------------------------------------------- -->
15171 <p>
15172 <tscreen><verb>
15173 void GtkButton::pressed (GtkButton *,
15174                          gpointer);
15175 void GtkButton::released        (GtkButton *,
15176                                  gpointer);
15177 void GtkButton::clicked (GtkButton *,
15178                          gpointer);
15179 void GtkButton::enter   (GtkButton *,
15180                          gpointer);
15181 void GtkButton::leave   (GtkButton *,
15182                          gpointer);
15183 </verb></tscreen>
15184
15185 <!-- ----------------------------------------------------------------- -->
15186 <sect1>GtkItem
15187 <!-- ----------------------------------------------------------------- -->
15188 <p>
15189 <tscreen><verb>
15190 void GtkItem::select    (GtkItem *,
15191                          gpointer);
15192 void GtkItem::deselect  (GtkItem *,
15193                          gpointer);
15194 void GtkItem::toggle    (GtkItem *,
15195                          gpointer);
15196 </verb></tscreen>
15197
15198 <!-- ----------------------------------------------------------------- -->
15199 <sect1>GtkWindow
15200 <!-- ----------------------------------------------------------------- -->
15201 <p>
15202 <tscreen><verb>
15203 void GtkWindow::set-focus       (GtkWindow *,
15204                                  ggpointer,
15205                                  gpointer);
15206 </verb></tscreen>
15207
15208 <!-- ----------------------------------------------------------------- -->
15209 <sect1>GtkHandleBox
15210 <!-- ----------------------------------------------------------------- -->
15211 <p>
15212 <tscreen><verb>
15213 void GtkHandleBox::child-attached       (GtkHandleBox *,
15214                                          GtkWidget *,
15215                                          gpointer);
15216 void GtkHandleBox::child-detached       (GtkHandleBox *,
15217                                          GtkWidget *,
15218                                          gpointer);
15219 </verb></tscreen>
15220
15221 <!-- ----------------------------------------------------------------- -->
15222 <sect1>GtkToggleButton
15223 <!-- ----------------------------------------------------------------- -->
15224 <p>
15225 <tscreen><verb>
15226 void GtkToggleButton::toggled   (GtkToggleButton *,
15227                                  gpointer);
15228
15229 </verb></tscreen>
15230
15231 <!-- ----------------------------------------------------------------- -->
15232 <sect1>GtkMenuItem
15233 <!-- ----------------------------------------------------------------- -->
15234 <p>
15235 <tscreen><verb>
15236 void GtkMenuItem::activate      (GtkMenuItem *,
15237                                  gpointer);
15238 void GtkMenuItem::activate-item (GtkMenuItem *,
15239                                  gpointer);
15240 </verb></tscreen>
15241
15242 <!-- ----------------------------------------------------------------- -->
15243 <sect1>GtkListItem
15244 <!-- ----------------------------------------------------------------- -->
15245 <p>
15246 <tscreen><verb>
15247 void GtkListItem::toggle-focus-row      (GtkListItem *,
15248                                          gpointer);
15249 void GtkListItem::select-all    (GtkListItem *,
15250                                  gpointer);
15251 void GtkListItem::unselect-all  (GtkListItem *,
15252                                  gpointer);
15253 void GtkListItem::undo-selection        (GtkListItem *,
15254                                          gpointer);
15255 void GtkListItem::start-selection       (GtkListItem *,
15256                                          gpointer);
15257 void GtkListItem::end-selection (GtkListItem *,
15258                                  gpointer);
15259 void GtkListItem::toggle-add-mode       (GtkListItem *,
15260                                          gpointer);
15261 void GtkListItem::extend-selection      (GtkListItem *,
15262                                          GtkEnum,
15263                                          ggfloat,
15264                                          gboolean,
15265                                          gpointer);
15266 void GtkListItem::scroll-vertical       (GtkListItem *,
15267                                          GtkEnum,
15268                                          ggfloat,
15269                                          gpointer);
15270 void GtkListItem::scroll-horizontal     (GtkListItem *,
15271                                          GtkEnum,
15272                                          ggfloat,
15273                                          gpointer);
15274 </verb></tscreen>
15275
15276 <!-- ----------------------------------------------------------------- -->
15277 <sect1>GtkTreeItem
15278 <!-- ----------------------------------------------------------------- -->
15279 <p>
15280 <tscreen><verb>
15281 void GtkTreeItem::collapse      (GtkTreeItem *,
15282                                  gpointer);
15283 void GtkTreeItem::expand        (GtkTreeItem *,
15284                                  gpointer);
15285 </verb></tscreen>
15286
15287 <!-- ----------------------------------------------------------------- -->
15288 <sect1>GtkCheckMenuItem
15289 <!-- ----------------------------------------------------------------- -->
15290 <p>
15291 <tscreen><verb>
15292 void GtkCheckMenuItem::toggled  (GtkCheckMenuItem *,
15293                                  gpointer);
15294 </verb></tscreen>
15295
15296 <!-- ----------------------------------------------------------------- -->
15297 <sect1>GtkInputDialog
15298 <!-- ----------------------------------------------------------------- -->
15299 <p>
15300 <tscreen><verb>
15301 void GtkInputDialog::enable-device      (GtkInputDialog *,
15302                                          ggint,
15303                                          gpointer);
15304 void GtkInputDialog::disable-device     (GtkInputDialog *,
15305                                          ggint,
15306                                          gpointer);
15307 </verb></tscreen>
15308
15309 <!-- ----------------------------------------------------------------- -->
15310 <sect1>GtkColorSelection
15311 <!-- ----------------------------------------------------------------- -->
15312 <p>
15313 <tscreen><verb>
15314 void GtkColorSelection::color-changed   (GtkColorSelection *,
15315                                          gpointer);
15316 </verb></tscreen>
15317
15318 <!-- ----------------------------------------------------------------- -->
15319 <sect1>GtkStatusBar
15320 <!-- ----------------------------------------------------------------- -->
15321 <p>
15322 <tscreen><verb>
15323 void GtkStatusbar::text-pushed  (GtkStatusbar *,
15324                                  gguint,
15325                                  GtkString *,
15326                                  gpointer);
15327 void GtkStatusbar::text-popped  (GtkStatusbar *,
15328                                  gguint,
15329                                  GtkString *,
15330                                  gpointer);
15331 </verb></tscreen>
15332
15333 <!-- ----------------------------------------------------------------- -->
15334 <sect1>GtkCTree
15335 <!-- ----------------------------------------------------------------- -->
15336 <p>
15337 <tscreen><verb>
15338 void GtkCTree::tree-select-row  (GtkCTree *,
15339                                  GtkCTreeNode *,
15340                                  ggint,
15341                                  gpointer);
15342 void GtkCTree::tree-unselect-row        (GtkCTree *,
15343                                          GtkCTreeNode *,
15344                                          ggint,
15345                                          gpointer);
15346 void GtkCTree::tree-expand      (GtkCTree *,
15347                                  GtkCTreeNode *,
15348                                  gpointer);
15349 void GtkCTree::tree-collapse    (GtkCTree *,
15350                                  ggpointer,
15351                                  gpointer);
15352 void GtkCTree::tree-move        (GtkCTree *,
15353                                  GtkCTreeNode *,
15354                                  GtkCTreeNode *,
15355                                  GtkCTreeNode *,
15356                                  gpointer);
15357 void GtkCTree::change-focus-row-expansion       (GtkCTree *,
15358                                                  GtkCTreeExpansionType,
15359                                                  gpointer);
15360 </verb></tscreen>
15361
15362 <!-- ----------------------------------------------------------------- -->
15363 <sect1>GtkCurve
15364 <!-- ----------------------------------------------------------------- -->
15365 <p>
15366 <tscreen><verb>
15367 void GtkCurve::curve-type-changed       (GtkCurve *,
15368                                          gpointer);
15369 </verb></tscreen>
15370
15371 <!-- ----------------------------------------------------------------- -->
15372 <sect1>GtkAdjustment
15373 <!-- ----------------------------------------------------------------- -->
15374 <p>
15375 <tscreen><verb>
15376 void GtkAdjustment::changed     (GtkAdjustment *,
15377                                  gpointer);
15378 void GtkAdjustment::value-changed       (GtkAdjustment *,
15379                                          gpointer);
15380 </verb></tscreen>
15381
15382 <!-- ***************************************************************** -->
15383 <sect> Tipos de eventos GDK<label id="sec_GDK_Event_Types">
15384 <!-- ***************************************************************** -->
15385 <p>
15386 Los siguientes tipos de datos se pasan en los manejadores de los
15387 eventos por GTK+. Para cada tipo de dato que se muestra, se muestran
15388 las señales que utilizan ese tipo de dato.
15389
15390 <itemize>
15391 <item>  GdkEvent
15392           <itemize>
15393           <item>drag_end_event
15394           </itemize>
15395
15396 <item>  GdkEventType
15397
15398 <item>  GdkEventAny
15399           <itemize>
15400           <item>delete_event
15401           <item>destroy_event
15402           <item>map_event
15403           <item>unmap_event
15404           <item>no_expose_event
15405           </itemize>
15406
15407 <item>  GdkEventExpose
15408           <itemize>
15409           <item>expose_event
15410           </itemize>
15411
15412 <item>  GdkEventNoExpose
15413
15414 <item>  GdkEventVisibility
15415
15416 <item>  GdkEventMotion
15417           <itemize>
15418           <item>motion_notify_event
15419           </itemize>
15420
15421 <item>  GdkEventButton
15422           <itemize>
15423           <item>button_press_event
15424           <item>button_release_event
15425           </itemize>
15426
15427 <item>  GdkEventKey
15428           <itemize>
15429           <item>key_press_event
15430           <item>key_release_event
15431           </itemize>
15432
15433 <item>  GdkEventCrossing
15434           <itemize>
15435           <item>enter_notify_event
15436           <item>leave_notify_event
15437           </itemize>
15438
15439 <item>  GdkEventFocus
15440           <itemize>
15441           <item>focus_in_event
15442           <item>focus_out_event
15443           </itemize>
15444
15445 <item>  GdkEventConfigure
15446           <itemize>
15447           <item>configure_event
15448           </itemize>
15449
15450 <item>  GdkEventProperty
15451           <itemize>
15452           <item>property_notify_event
15453           </itemize>
15454
15455 <item>  GdkEventSelection
15456           <itemize>
15457           <item>selection_clear_event
15458           <item>selection_request_event
15459           <item>selection_notify_event
15460           </itemize>
15461
15462 <item>  GdkEventProximity
15463           <itemize>
15464           <item>proximity_in_event
15465           <item>proximity_out_event
15466           </itemize>
15467
15468 <item>  GdkEventDragBegin
15469           <itemize>
15470           <item>drag_begin_event
15471           </itemize>
15472
15473 <item>  GdkEventDragRequest
15474           <itemize>
15475           <item>drag_request_event
15476           </itemize>
15477
15478 <item>  GdkEventDropEnter
15479           <itemize>
15480           <item>drop_enter_event
15481           </itemize>
15482
15483 <item>  GdkEventDropLeave
15484           <itemize>
15485           <item>drop_leave_event
15486           </itemize>
15487
15488 <item>  GdkEventDropDataAvailable
15489           <itemize>
15490           <item>drop_data_available_event
15491           </itemize>
15492
15493 <item>  GdkEventClient
15494           <itemize>
15495           <item>client_event
15496           </itemize>
15497
15498 <item>  GdkEventOther
15499           <itemize>
15500           <item>other_event
15501           </itemize>
15502 </itemize>
15503
15504 El tipo de dato <tt/GdkEventType/ es un tipo de dato especial que se
15505 utiliza por todos los otros tipos de datos como un indicador del tipo
15506 de dato que se le está pasando al manejador de señal. Como verá
15507 más adelante, cada una de estructuras de los datos de los eventos
15508 tienen un miembro de este tipo. Se define como la siguiente
15509 enumeración:
15510
15511 <tscreen><verb>
15512 typedef enum
15513 {
15514   GDK_NOTHING           = -1,
15515   GDK_DELETE            = 0,
15516   GDK_DESTROY           = 1,
15517   GDK_EXPOSE            = 2,
15518   GDK_MOTION_NOTIFY     = 3,
15519   GDK_BUTTON_PRESS      = 4,
15520   GDK_2BUTTON_PRESS     = 5,
15521   GDK_3BUTTON_PRESS     = 6,
15522   GDK_BUTTON_RELEASE    = 7,
15523   GDK_KEY_PRESS         = 8,
15524   GDK_KEY_RELEASE       = 9,
15525   GDK_ENTER_NOTIFY      = 10,
15526   GDK_LEAVE_NOTIFY      = 11,
15527   GDK_FOCUS_CHANGE      = 12,
15528   GDK_CONFIGURE         = 13,
15529   GDK_MAP               = 14,
15530   GDK_UNMAP             = 15,
15531   GDK_PROPERTY_NOTIFY   = 16,
15532   GDK_SELECTION_CLEAR   = 17,
15533   GDK_SELECTION_REQUEST = 18,
15534   GDK_SELECTION_NOTIFY  = 19,
15535   GDK_PROXIMITY_IN      = 20,
15536   GDK_PROXIMITY_OUT     = 21,
15537   GDK_DRAG_BEGIN        = 22,
15538   GDK_DRAG_REQUEST      = 23,
15539   GDK_DROP_ENTER        = 24,
15540   GDK_DROP_LEAVE        = 25,
15541   GDK_DROP_DATA_AVAIL   = 26,
15542   GDK_CLIENT_EVENT      = 27,
15543   GDK_VISIBILITY_NOTIFY = 28,
15544   GDK_NO_EXPOSE         = 29,
15545   GDK_OTHER_EVENT       = 9999  /* Anacrónico, utilice en su lugar los
15546                                    filtros */
15547 } GdkEventType;
15548 </verb></tscreen>
15549
15550 El otro tipo de evento que es diferente del resto es el mismo
15551 <tt/GdkEvent/. Ésta es una unión de todos los otros tipos de
15552 datos, que permite que se convierta en un tipo de dato de evento
15553 específico con un manejador de señal.
15554
15555 <!-- Just a big list for now, needs expanding upon - TRG -->
15556 Por tanto, los tipos de los datos de los eventos se definen como
15557 sigue:
15558
15559 <tscreen><verb>
15560 struct _GdkEventAny
15561 {
15562   GdkEventType type;
15563   GdkWindow *window;
15564   gint8 send_event;
15565 };
15566
15567 struct _GdkEventExpose
15568 {
15569   GdkEventType type;
15570   GdkWindow *window;
15571   gint8 send_event;
15572   GdkRectangle area;
15573   gint count; /* Si count no es, entonces es el número de eventos que
15574                * siguen. */
15575 };
15576
15577 struct _GdkEventNoExpose
15578 {
15579   GdkEventType type;
15580   GdkWindow *window;
15581   gint8 send_event;
15582   /* XXX: ¿Hay alguien que necesite los campos major_code y minor_code
15583      de X ? */
15584 };
15585
15586 struct _GdkEventVisibility
15587 {
15588   GdkEventType type;
15589   GdkWindow *window;
15590   gint8 send_event;
15591   GdkVisibilityState state;
15592 };
15593
15594 struct _GdkEventMotion
15595 {
15596   GdkEventType type;
15597   GdkWindow *window;
15598   gint8 send_event;
15599   guint32 time;
15600   gdouble x;
15601   gdouble y;
15602   gdouble pressure;
15603   gdouble xtilt;
15604   gdouble ytilt;
15605   guint state;
15606   gint16 is_hint;
15607   GdkInputSource source;
15608   guint32 deviceid;
15609   gdouble x_root, y_root;
15610 };
15611
15612 struct _GdkEventButton
15613 {
15614   GdkEventType type;
15615   GdkWindow *window;
15616   gint8 send_event;
15617   guint32 time;
15618   gdouble x;
15619   gdouble y;
15620   gdouble pressure;
15621   gdouble xtilt;
15622   gdouble ytilt;
15623   guint state;
15624   guint button;
15625   GdkInputSource source;
15626   guint32 deviceid;
15627   gdouble x_root, y_root;
15628 };
15629
15630 struct _GdkEventKey
15631 {
15632   GdkEventType type;
15633   GdkWindow *window;
15634   gint8 send_event;
15635   guint32 time;
15636   guint state;
15637   guint keyval;
15638   gint length;
15639   gchar *string;
15640 };
15641
15642 struct _GdkEventCrossing
15643 {
15644   GdkEventType type;
15645   GdkWindow *window;
15646   gint8 send_event;
15647   GdkWindow *subwindow;
15648   GdkNotifyType detail;
15649 };
15650
15651 struct _GdkEventFocus
15652 {
15653   GdkEventType type;
15654   GdkWindow *window;
15655   gint8 send_event;
15656   gint16 in;
15657 };
15658
15659 struct _GdkEventConfigure
15660 {
15661   GdkEventType type;
15662   GdkWindow *window;
15663   gint8 send_event;
15664   gint16 x, y;
15665   gint16 width;
15666   gint16 height;
15667 };
15668
15669 struct _GdkEventProperty
15670 {
15671   GdkEventType type;
15672   GdkWindow *window;
15673   gint8 send_event;
15674   GdkAtom atom;
15675   guint32 time;
15676   guint state;
15677 };
15678
15679 struct _GdkEventSelection
15680 {
15681   GdkEventType type;
15682   GdkWindow *window;
15683   gint8 send_event;
15684   GdkAtom selection;
15685   GdkAtom target;
15686   GdkAtom property;
15687   guint32 requestor;
15688   guint32 time;
15689 };
15690
15691 /* Este tipo de evento se utiliza muy raramente. Solamente es
15692  * importante para los programas que utilizan XInput y que dibujar su
15693  * propio cursor */
15694
15695 struct _GdkEventProximity
15696 {
15697   GdkEventType type;
15698   GdkWindow *window;
15699   gint8 send_event;
15700   guint32 time;
15701   GdkInputSource source;
15702   guint32 deviceid;
15703 };
15704
15705 struct _GdkEventDragRequest
15706 {
15707   GdkEventType type;
15708   GdkWindow *window;
15709   gint8 send_event;
15710   guint32 requestor;
15711   union {
15712     struct {
15713       guint protocol_version:4;
15714       guint sendreply:1;
15715       guint willaccept:1;
15716       guint delete_data:1; /* No borrar si se ha mandado un enlace,
15717                               sólo si se ha mandado el dato */
15718       guint senddata:1;
15719       guint reserved:22;
15720     } flags;
15721     glong allflags;
15722   } u;
15723   guint8 isdrop; /* Este evento gdk puede ser generado por un par de
15724                     eventos X - esto le permite a las aplicaciones
15725                     saber si ha ocurrido realmente el soltado (drop),
15726                     o si sólo hemos cambiado el valor de algunos datos
15727                   */
15728
15729   GdkPoint drop_coords;
15730   gchar *data_type;
15731   guint32 timestamp;
15732 };
15733
15734 struct _GdkEventDragBegin
15735 {
15736   GdkEventType type;
15737   GdkWindow *window;
15738   gint8 send_event;
15739   union {
15740     struct {
15741       guint protocol_version:4;
15742       guint reserved:28;
15743     } flags;
15744     glong allflags;
15745   } u;
15746 };
15747
15748 struct _GdkEventDropEnter
15749 {
15750   GdkEventType type;
15751   GdkWindow *window;
15752   gint8 send_event;
15753   guint32 requestor;
15754   union {
15755     struct {
15756       guint protocol_version:4;
15757       guint sendreply:1;
15758       guint extended_typelist:1;
15759       guint reserved:26;
15760     } flags;
15761     glong allflags;
15762   } u;
15763 };
15764
15765 struct _GdkEventDropLeave
15766 {
15767   GdkEventType type;
15768   GdkWindow *window;
15769   gint8 send_event;
15770   guint32 requestor;
15771   union {
15772     struct {
15773       guint protocol_version:4;
15774       guint reserved:28;
15775     } flags;
15776     glong allflags;
15777   } u;
15778 };
15779
15780 struct _GdkEventDropDataAvailable
15781 {
15782   GdkEventType type;
15783   GdkWindow *window;
15784   gint8 send_event;
15785   guint32 requestor;
15786   union {
15787     struct {
15788       guint protocol_version:4;
15789       guint isdrop:1;
15790       guint reserved:25;
15791     } flags;
15792     glong allflags;
15793   } u;
15794   gchar *data_type; /* tipo MIME */
15795   gulong data_numbytes;
15796   gpointer data;
15797   guint32 timestamp;
15798   GdkPoint coords;
15799 };
15800
15801 struct _GdkEventClient
15802 {
15803   GdkEventType type;
15804   GdkWindow *window;
15805   gint8 send_event;
15806   GdkAtom message_type;
15807   gushort data_format;
15808   union {
15809     char b[20];
15810     short s[10];
15811     long l[5];
15812   } data;
15813 };
15814
15815 struct _GdkEventOther
15816 {
15817   GdkEventType type;
15818   GdkWindow *window;
15819   gint8 send_event;
15820   GdkXEvent *xevent;
15821 };
15822 </verb></tscreen>
15823
15824 <!-- ***************************************************************** -->
15825 <sect> Código ejemplo
15826 <!-- ***************************************************************** -->
15827 <p>
15828 A continuación tenemos el código ejemplo que se ha utilizado en el
15829 texto anterior y que no se ha incluido al completo en otro lugar.
15830
15831 <!-- ----------------------------------------------------------------- -->
15832 <sect1>Tictactoe
15833 <!-- ----------------------------------------------------------------- -->
15834 <sect2>tictactoe.h
15835 <p>
15836 <tscreen><verb>
15837 /* principio del ejemplo tictactoe tictactoe.h */
15838
15839 /* GTK - The GIMP Toolkit
15840  * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
15841  *
15842  * This library is free software; you can redistribute it and/or
15843  * modify it under the terms of the GNU Library General Public
15844  * License as published by the Free Software Foundation; either
15845  * version 2 of the License, or (at your option) any later version.
15846  *
15847  * This library is distributed in the hope that it will be useful,
15848  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15849  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15850  * Library General Public License for more details.
15851  *
15852  * You should have received a copy of the GNU Library General Public
15853  * License along with this library; if not, write to the
15854  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
15855  * Boston, MA 02111-1307, USA.
15856  */
15857 #ifndef __TICTACTOE_H__
15858 #define __TICTACTOE_H__
15859
15860
15861 #include <gdk/gdk.h>
15862 #include <gtk/gtkvbox.h>
15863
15864
15865 #ifdef __cplusplus
15866 extern "C" {
15867 #endif /* __cplusplus */
15868
15869 #define TICTACTOE(obj)          GTK_CHECK_CAST (obj, tictactoe_get_type (), Tictactoe)
15870 #define TICTACTOE_CLASS(klass)  GTK_CHECK_CLASS_CAST (klass, tictactoe_get_type (), TictactoeClass)
15871 #define IS_TICTACTOE(obj)       GTK_CHECK_TYPE (obj, tictactoe_get_type ())
15872
15873
15874 typedef struct _Tictactoe       Tictactoe;
15875 typedef struct _TictactoeClass  TictactoeClass;
15876
15877 struct _Tictactoe
15878 {
15879   GtkVBox vbox;
15880   
15881   GtkWidget *botones[3][3];
15882 };
15883
15884 struct _TictactoeClass
15885 {
15886   GtkVBoxClass parent_class;
15887
15888   void (* tictactoe) (Tictactoe *ttt);
15889 };
15890
15891 guint          tictactoe_get_type        (void);
15892 GtkWidget*     tictactoe_new             (void);
15893 void           tictactoe_clear           (Tictactoe *ttt);
15894
15895 #ifdef __cplusplus
15896 }
15897 #endif /* __cplusplus */
15898
15899 #endif /* __TICTACTOE_H__ */
15900
15901 /* fin del ejemplo */
15902 </verb></tscreen>
15903
15904 <!-- ----------------------------------------------------------------- -->
15905 <sect2>tictactoe.c
15906 <p>
15907 <tscreen><verb>
15908 /* principio del ejemplo tictactoe tictactoe.c */
15909
15910 /* GTK - The GIMP Toolkit
15911  * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
15912  *
15913  * This library is free software; you can redistribute it and/or
15914  * modify it under the terms of the GNU Library General Public
15915  * License as published by the Free Software Foundation; either
15916  * version 2 of the License, or (at your option) any later version.
15917  *
15918  * This library is distributed in the hope that it will be useful,
15919  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15920  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15921  * Library General Public License for more details.
15922  *
15923  * You should have received a copy of the GNU Library General Public
15924  * License along with this library; if not, write to the
15925  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
15926  * Boston, MA 02111-1307, USA.
15927  */
15928 #include "gtk/gtksignal.h"
15929 #include "gtk/gtktable.h"
15930 #include "gtk/gtktogglebutton.h"
15931 #include "tictactoe.h"
15932
15933 enum {
15934   TICTACTOE_SIGNAL,
15935   LAST_SIGNAL
15936 };
15937
15938 static void tictactoe_class_init          (TictactoeClass *klass);
15939 static void tictactoe_init                (Tictactoe      *ttt);
15940 static void tictactoe_toggle              (GtkWidget *widget, Tictactoe *ttt);
15941
15942 static gint tictactoe_signals[LAST_SIGNAL] = { 0 };
15943
15944 guint
15945 tictactoe_get_type ()
15946 {
15947   static guint ttt_type = 0;
15948
15949   if (!ttt_type)
15950     {
15951       GtkTypeInfo ttt_info =
15952       {
15953         "Tictactoe",
15954         sizeof (Tictactoe),
15955         sizeof (TictactoeClass),
15956         (GtkClassInitFunc) tictactoe_class_init,
15957         (GtkObjectInitFunc) tictactoe_init,
15958         (GtkArgSetFunc) NULL,
15959         (GtkArgGetFunc) NULL
15960       };
15961
15962       ttt_type = gtk_type_unique (gtk_vbox_get_type (), &amp;ttt_info);
15963     }
15964
15965   return ttt_type;
15966 }
15967
15968 static void
15969 tictactoe_class_init (TictactoeClass *class)
15970 {
15971   GtkObjectClass *object_class;
15972
15973   object_class = (GtkObjectClass*) class;
15974   
15975   tictactoe_signals[TICTACTOE_SIGNAL] = gtk_signal_new ("tictactoe",
15976                                          GTK_RUN_FIRST,
15977                                          object_class->type,
15978                                          GTK_SIGNAL_OFFSET (TictactoeClass, tictactoe),
15979                                          gtk_signal_default_marshaller, GTK_TYPE_NONE, 0);
15980
15981
15982   gtk_object_class_add_signals (object_class, tictactoe_signals, LAST_SIGNAL);
15983
15984   class->tictactoe = NULL;
15985 }
15986
15987 static void
15988 tictactoe_init (Tictactoe *ttt)
15989 {
15990   GtkWidget *table;
15991   gint i,j;
15992   
15993   table = gtk_table_new (3, 3, TRUE);
15994   gtk_container_add (GTK_CONTAINER(ttt), table);
15995   gtk_widget_show (table);
15996
15997   for (i=0;i<3; i++)
15998     for (j=0;j<3; j++)
15999       {
16000         ttt->buttons[i][j] = gtk_toggle_button_new ();
16001         gtk_table_attach_defaults (GTK_TABLE(table), ttt->buttons[i][j], 
16002                                    i, i+1, j, j+1);
16003         gtk_signal_connect (GTK_OBJECT (ttt->buttons[i][j]), "toggled",
16004                             GTK_SIGNAL_FUNC (tictactoe_toggle), ttt);
16005         gtk_widget_set_usize (ttt->buttons[i][j], 20, 20);
16006         gtk_widget_show (ttt->buttons[i][j]);
16007       }
16008 }
16009
16010 GtkWidget*
16011 tictactoe_new ()
16012 {
16013   return GTK_WIDGET ( gtk_type_new (tictactoe_get_type ()));
16014 }
16015
16016 void           
16017 tictactoe_clear (Tictactoe *ttt)
16018 {
16019   int i,j;
16020
16021   for (i=0;i<3;i++)
16022     for (j=0;j<3;j++)
16023       {
16024         gtk_signal_handler_block_by_data (GTK_OBJECT(ttt->buttons[i][j]), ttt);
16025         gtk_toggle_button_set_state (GTK_TOGGLE_BUTTON (ttt->buttons[i][j]),
16026                                      FALSE);
16027         gtk_signal_handler_unblock_by_data (GTK_OBJECT(ttt->buttons[i][j]), ttt);
16028       }
16029 }
16030
16031 static void
16032 tictactoe_toggle (GtkWidget *widget, Tictactoe *ttt)
16033 {
16034   int i,k;
16035
16036   static int rwins[8][3] = { { 0, 0, 0 }, { 1, 1, 1 }, { 2, 2, 2 },
16037                              { 0, 1, 2 }, { 0, 1, 2 }, { 0, 1, 2 },
16038                              { 0, 1, 2 }, { 0, 1, 2 } };
16039   static int cwins[8][3] = { { 0, 1, 2 }, { 0, 1, 2 }, { 0, 1, 2 },
16040                              { 0, 0, 0 }, { 1, 1, 1 }, { 2, 2, 2 },
16041                              { 0, 1, 2 }, { 2, 1, 0 } };
16042
16043   int success, found;
16044
16045   for (k=0; k<8; k++)
16046     {
16047       success = TRUE;
16048       found = FALSE;
16049
16050       for (i=0;i<3;i++)
16051         {
16052           success = success &amp;&amp; 
16053             GTK_TOGGLE_BUTTON(ttt->buttons[rwins[k][i]][cwins[k][i]])->active;
16054           found = found ||
16055             ttt->buttons[rwins[k][i]][cwins[k][i]] == widget;
16056         }
16057       
16058       if (success &amp;&amp; found)
16059         {
16060           gtk_signal_emit (GTK_OBJECT (ttt), 
16061                            tictactoe_signals[TICTACTOE_SIGNAL]);
16062           break;
16063         }
16064     }
16065 }
16066
16067 /* fin del ejemplo */
16068 </verb></tscreen>
16069
16070 <!-- ----------------------------------------------------------------- -->
16071 <sect2>ttt_test.c
16072 <p>
16073 <tscreen><verb>
16074 /* principio del ejemplo tictactoe ttt_test.c */
16075
16076 #include <gtk/gtk.h>
16077 #include "tictactoe.h"
16078
16079 void
16080 win (GtkWidget *widget, gpointer data)
16081 {
16082   g_print ("Yay!\n");
16083   tictactoe_clear (TICTACTOE (widget));
16084 }
16085
16086 int 
16087 main (int argc, char *argv[])
16088 {
16089   GtkWidget *ventana;
16090   GtkWidget *ttt;
16091   
16092   gtk_init (&amp;argc, &amp;argv);
16093
16094   ventana = gtk_window_new (GTK_WINDOW_TOPLEVEL);
16095   
16096   gtk_window_set_title (GTK_WINDOW (ventana), "Aspect Frame");
16097   
16098   gtk_signal_connect (GTK_OBJECT (ventana), "destroy",
16099                       GTK_SIGNAL_FUNC (gtk_exit), NULL);
16100   
16101   gtk_container_border_width (GTK_CONTAINER (ventana), 10);
16102
16103   ttt = tictactoe_new ();
16104   
16105   gtk_container_add (GTK_CONTAINER (ventana), ttt);
16106   gtk_widget_show (ttt);
16107
16108   gtk_signal_connect (GTK_OBJECT (ttt), "tictactoe",
16109                       GTK_SIGNAL_FUNC (win), NULL);
16110
16111   gtk_widget_show (ventana);
16112   
16113   gtk_main ();
16114   
16115   return 0;
16116 }
16117
16118 /* fin del ejemplo */
16119 </verb></tscreen>
16120
16121 <!-- ----------------------------------------------------------------- -->
16122 <sect1> GtkDial
16123
16124 <!-- ----------------------------------------------------------------- -->
16125 <sect2> gtkdial.h
16126 <p>
16127 <tscreen><verb>
16128 /* principio del ejmplo gtkdial gtkdial.h */
16129
16130 /* GTK - The GIMP Toolkit
16131  * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
16132  *
16133  * This library is free software; you can redistribute it and/or
16134  * modify it under the terms of the GNU Library General Public
16135  * License as published by the Free Software Foundation; either
16136  * version 2 of the License, or (at your option) any later version.
16137  *
16138  * This library is distributed in the hope that it will be useful,
16139  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16140  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16141  * Library General Public License for more details.
16142  *
16143  * You should have received a copy of the GNU Library General Public
16144  * License along with this library; if not, write to the
16145  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
16146  * Boston, MA 02111-1307, USA.
16147  */
16148 #ifndef __GTK_DIAL_H__
16149 #define __GTK_DIAL_H__
16150
16151
16152 #include <gdk/gdk.h>
16153 #include <gtk/gtkadjustment.h>
16154 #include <gtk/gtkwidget.h>
16155
16156
16157 #ifdef __cplusplus
16158 extern "C" {
16159 #endif /* __cplusplus */
16160
16161
16162 #define GTK_DIAL(obj)          GTK_CHECK_CAST (obj, gtk_dial_get_type (), GtkDial)
16163 #define GTK_DIAL_CLASS(klass)  GTK_CHECK_CLASS_CAST (klass, gtk_dial_get_type (), GtkDialClass)
16164 #define GTK_IS_DIAL(obj)       GTK_CHECK_TYPE (obj, gtk_dial_get_type ())
16165
16166
16167 typedef struct _GtkDial        GtkDial;
16168 typedef struct _GtkDialClass   GtkDialClass;
16169
16170 struct _GtkDial
16171 {
16172   GtkWidget widget;
16173
16174   /* política de actualización
16175    * (GTK_UPDATE_[CONTINUOUS/DELAYED/DISCONTINUOUS]) */
16176   guint policy : 2;
16177
16178   /* Botón actualmente presionado o 0 si no hay ninguno */
16179   guint8 boton;
16180
16181   /* Dimensión de los componendes del dial */
16182   gint radius;
16183   gint pointer_width;
16184
16185   /* ID del temporizador de actualización, o 0 si no hay ninguno */
16186   guint32 timer;
16187
16188   /* ángulo actual */
16189   gfloat angle;
16190
16191   /* Viejos valores almacenados del adjustment, para que así no
16192    * tengamos que saber cuando cambia algo */
16193   gfloat old_value;
16194   gfloat old_lower;
16195   gfloat old_upper;
16196
16197   /* El objeto adjustment que almacena los datos para este dial */
16198   GtkAdjustment *adjustment;
16199 };
16200
16201 struct _GtkDialClass
16202 {
16203   GtkWidgetClass parent_class;
16204 };
16205
16206
16207 GtkWidget*     gtk_dial_new                    (GtkAdjustment *adjustment);
16208 guint          gtk_dial_get_type               (void);
16209 GtkAdjustment* gtk_dial_get_adjustment         (GtkDial      *dial);
16210 void           gtk_dial_set_update_policy      (GtkDial      *dial,
16211                                                 GtkUpdateType  policy);
16212
16213 void           gtk_dial_set_adjustment         (GtkDial      *dial,
16214                                                 GtkAdjustment *adjustment);
16215 #ifdef __cplusplus
16216 }
16217 #endif /* __cplusplus */
16218
16219
16220 #endif /* __GTK_DIAL_H__ */
16221 /* fin del ejemplo */
16222 </verb></tscreen>
16223
16224 <!-- ----------------------------------------------------------------- -->
16225 <sect2> gtkdial.c
16226 <p>
16227 <tscreen><verb>
16228 /* principio del ejemplo gtkdial gtkdial.c */
16229
16230 /* GTK - The GIMP Toolkit
16231  * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
16232  *
16233  * This library is free software; you can redistribute it and/or
16234  * modify it under the terms of the GNU Library General Public
16235  * License as published by the Free Software Foundation; either
16236  * version 2 of the License, or (at your option) any later version.
16237  *
16238  * This library is distributed in the hope that it will be useful,
16239  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16240  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16241  * Library General Public License for more details.
16242  *
16243  * You should have received a copy of the GNU Library General Public
16244  * License along with this library; if not, write to the
16245  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
16246  * Boston, MA 02111-1307, USA.
16247  */
16248 #include <math.h>
16249 #include <stdio.h>
16250 #include <gtk/gtkmain.h>
16251 #include <gtk/gtksignal.h>
16252
16253 #include "gtkdial.h"
16254
16255 #define SCROLL_DELAY_LENGTH  300
16256 #define DIAL_DEFAULT_SIZE 100
16257
16258 /* declaraciones de funciones */
16259
16260 static void gtk_dial_class_init               (GtkDialClass    *klass);
16261 static void gtk_dial_init                     (GtkDial         *dial);
16262 static void gtk_dial_destroy                  (GtkObject        *object);
16263 static void gtk_dial_realize                  (GtkWidget        *widget);
16264 static void gtk_dial_size_request             (GtkWidget      *widget,
16265                                                GtkRequisition *requisition);
16266 static void gtk_dial_size_allocate            (GtkWidget     *widget,
16267                                                GtkAllocation *allocation);
16268 static gint gtk_dial_expose                   (GtkWidget        *widget,
16269                                                 GdkEventExpose   *event);
16270 static gint gtk_dial_button_press             (GtkWidget        *widget,
16271                                                 GdkEventButton   *event);
16272 static gint gtk_dial_button_release           (GtkWidget        *widget,
16273                                                 GdkEventButton   *event);
16274 static gint gtk_dial_motion_notify            (GtkWidget        *widget,
16275                                                 GdkEventMotion   *event);
16276 static gint gtk_dial_timer                    (GtkDial         *dial);
16277
16278 static void gtk_dial_update_mouse             (GtkDial *dial, gint x, gint y);
16279 static void gtk_dial_update                   (GtkDial *dial);
16280 static void gtk_dial_adjustment_changed       (GtkAdjustment    *adjustment,
16281                                                 gpointer          data);
16282 static void gtk_dial_adjustment_value_changed (GtkAdjustment    *adjustment,
16283                                                 gpointer          data);
16284
16285 /* datos locales */
16286
16287 static GtkWidgetClass *parent_class = NULL;
16288
16289 guint
16290 gtk_dial_get_type ()
16291 {
16292   static guint dial_type = 0;
16293
16294   if (!dial_type)
16295     {
16296       GtkTypeInfo dial_info =
16297       {
16298         "GtkDial",
16299         sizeof (GtkDial),
16300         sizeof (GtkDialClass),
16301         (GtkClassInitFunc) gtk_dial_class_init,
16302         (GtkObjectInitFunc) gtk_dial_init,
16303         (GtkArgSetFunc) NULL,
16304         (GtkArgGetFunc) NULL,
16305       };
16306
16307       dial_type = gtk_type_unique (gtk_widget_get_type (), &amp;dial_info);
16308     }
16309
16310   return dial_type;
16311 }
16312
16313 static void
16314 gtk_dial_class_init (GtkDialClass *class)
16315 {
16316   GtkObjectClass *object_class;
16317   GtkWidgetClass *widget_class;
16318
16319   object_class = (GtkObjectClass*) class;
16320   widget_class = (GtkWidgetClass*) class;
16321
16322   parent_class = gtk_type_class (gtk_widget_get_type ());
16323
16324   object_class->destroy = gtk_dial_destroy;
16325
16326   widget_class->realize = gtk_dial_realize;
16327   widget_class->expose_event = gtk_dial_expose;
16328   widget_class->size_request = gtk_dial_size_request;
16329   widget_class->size_allocate = gtk_dial_size_allocate;
16330   widget_class->button_press_event = gtk_dial_button_press;
16331   widget_class->button_release_event = gtk_dial_button_release;
16332   widget_class->motion_notify_event = gtk_dial_motion_notify;
16333 }
16334
16335 static void
16336 gtk_dial_init (GtkDial *dial)
16337 {
16338   dial->button = 0;
16339   dial->policy = GTK_UPDATE_CONTINUOUS;
16340   dial->timer = 0;
16341   dial->radius = 0;
16342   dial->pointer_width = 0;
16343   dial->angle = 0.0;
16344   dial->old_value = 0.0;
16345   dial->old_lower = 0.0;
16346   dial->old_upper = 0.0;
16347   dial->adjustment = NULL;
16348 }
16349
16350 GtkWidget*
16351 gtk_dial_new (GtkAdjustment *adjustment)
16352 {
16353   GtkDial *dial;
16354
16355   dial = gtk_type_new (gtk_dial_get_type ());
16356
16357   if (!adjustment)
16358     adjustment = (GtkAdjustment*) gtk_adjustment_new (0.0, 0.0, 0.0, 0.0, 0.0, 0.0);
16359
16360   gtk_dial_set_adjustment (dial, adjustment);
16361
16362   return GTK_WIDGET (dial);
16363 }
16364
16365 static void
16366 gtk_dial_destroy (GtkObject *object)
16367 {
16368   GtkDial *dial;
16369
16370   g_return_if_fail (object != NULL);
16371   g_return_if_fail (GTK_IS_DIAL (object));
16372
16373   dial = GTK_DIAL (object);
16374
16375   if (dial->adjustment)
16376     gtk_object_unref (GTK_OBJECT (dial->adjustment));
16377
16378   if (GTK_OBJECT_CLASS (parent_class)->destroy)
16379     (* GTK_OBJECT_CLASS (parent_class)->destroy) (object);
16380 }
16381
16382 GtkAdjustment*
16383 gtk_dial_get_adjustment (GtkDial *dial)
16384 {
16385   g_return_val_if_fail (dial != NULL, NULL);
16386   g_return_val_if_fail (GTK_IS_DIAL (dial), NULL);
16387
16388   return dial->adjustment;
16389 }
16390
16391 void
16392 gtk_dial_set_update_policy (GtkDial      *dial,
16393                              GtkUpdateType  policy)
16394 {
16395   g_return_if_fail (dial != NULL);
16396   g_return_if_fail (GTK_IS_DIAL (dial));
16397
16398   dial->policy = policy;
16399 }
16400
16401 void
16402 gtk_dial_set_adjustment (GtkDial      *dial,
16403                           GtkAdjustment *adjustment)
16404 {
16405   g_return_if_fail (dial != NULL);
16406   g_return_if_fail (GTK_IS_DIAL (dial));
16407
16408   if (dial->adjustment)
16409     {
16410       gtk_signal_disconnect_by_data (GTK_OBJECT (dial->adjustment), (gpointer) dial);
16411       gtk_object_unref (GTK_OBJECT (dial->adjustment));
16412     }
16413
16414   dial->adjustment = adjustment;
16415   gtk_object_ref (GTK_OBJECT (dial->adjustment));
16416
16417   gtk_signal_connect (GTK_OBJECT (adjustment), "changed",
16418                       (GtkSignalFunc) gtk_dial_adjustment_changed,
16419                       (gpointer) dial);
16420   gtk_signal_connect (GTK_OBJECT (adjustment), "value_changed",
16421                       (GtkSignalFunc) gtk_dial_adjustment_value_changed,
16422                       (gpointer) dial);
16423
16424   dial->old_value = adjustment->value;
16425   dial->old_lower = adjustment->lower;
16426   dial->old_upper = adjustment->upper;
16427
16428   gtk_dial_update (dial);
16429 }
16430
16431 static void
16432 gtk_dial_realize (GtkWidget *widget)
16433 {
16434   GtkDial *dial;
16435   GdkWindowAttr attributes;
16436   gint attributes_mask;
16437
16438   g_return_if_fail (widget != NULL);
16439   g_return_if_fail (GTK_IS_DIAL (widget));
16440
16441   GTK_WIDGET_SET_FLAGS (widget, GTK_REALIZED);
16442   dial = GTK_DIAL (widget);
16443
16444   attributes.x = widget->allocation.x;
16445   attributes.y = widget->allocation.y;
16446   attributes.width = widget->allocation.width;
16447   attributes.height = widget->allocation.height;
16448   attributes.wclass = GDK_INPUT_OUTPUT;
16449   attributes.window_type = GDK_WINDOW_CHILD;
16450   attributes.event_mask = gtk_widget_get_events (widget) | 
16451     GDK_EXPOSURE_MASK | GDK_BUTTON_PRESS_MASK | 
16452     GDK_BUTTON_RELEASE_MASK | GDK_POINTER_MOTION_MASK |
16453     GDK_POINTER_MOTION_HINT_MASK;
16454   attributes.visual = gtk_widget_get_visual (widget);
16455   attributes.colormap = gtk_widget_get_colormap (widget);
16456
16457   attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP;
16458   widget->window = gdk_window_new (widget->parent->window, &amp;attributes, attributes_mask);
16459
16460   widget->style = gtk_style_attach (widget->style, widget->window);
16461
16462   gdk_window_set_user_data (widget->window, widget);
16463
16464   gtk_style_set_background (widget->style, widget->window, GTK_STATE_ACTIVE);
16465 }
16466
16467 static void 
16468 gtk_dial_size_request (GtkWidget      *widget,
16469                        GtkRequisition *requisition)
16470 {
16471   requisition->width = DIAL_DEFAULT_SIZE;
16472   requisition->height = DIAL_DEFAULT_SIZE;
16473 }
16474
16475 static void
16476 gtk_dial_size_allocate (GtkWidget     *widget,
16477                         GtkAllocation *allocation)
16478 {
16479   GtkDial *dial;
16480
16481   g_return_if_fail (widget != NULL);
16482   g_return_if_fail (GTK_IS_DIAL (widget));
16483   g_return_if_fail (allocation != NULL);
16484
16485   widget->allocation = *allocation;
16486   dial = GTK_DIAL (widget);
16487
16488   if (GTK_WIDGET_REALIZED (widget))
16489     {
16490
16491       gdk_window_move_resize (widget->window,
16492                               allocation->x, allocation->y,
16493                               allocation->width, allocation->height);
16494
16495     }
16496   dial->radius = MIN(allocation->width,allocation->height) * 0.45;
16497   dial->pointer_width = dial->radius / 5;
16498 }
16499
16500 static gint
16501 gtk_dial_expose (GtkWidget      *widget,
16502                  GdkEventExpose *event)
16503 {
16504   GtkDial *dial;
16505   GdkPoint points[3];
16506   gdouble s,c;
16507   gdouble theta;
16508   gint xc, yc;
16509   gint tick_length;
16510   gint i;
16511
16512   g_return_val_if_fail (widget != NULL, FALSE);
16513   g_return_val_if_fail (GTK_IS_DIAL (widget), FALSE);
16514   g_return_val_if_fail (event != NULL, FALSE);
16515
16516   if (event->count > 0)
16517     return FALSE;
16518   
16519   dial = GTK_DIAL (widget);
16520
16521   gdk_window_clear_area (widget->window,
16522                          0, 0,
16523                          widget->allocation.width,
16524                          widget->allocation.height);
16525
16526   xc = widget->allocation.width/2;
16527   yc = widget->allocation.height/2;
16528
16529   /* Dibuja las rayitas */
16530
16531   for (i=0; i<25; i++)
16532     {
16533       theta = (i*M_PI/18. - M_PI/6.);
16534       s = sin(theta);
16535       c = cos(theta);
16536
16537       tick_length = (i%6 == 0) ? dial->pointer_width : dial->pointer_width/2;
16538       
16539       gdk_draw_line (widget->window,
16540                      widget->style->fg_gc[widget->state],
16541                      xc + c*(dial->radius - tick_length),
16542                      yc - s*(dial->radius - tick_length),
16543                      xc + c*dial->radius,
16544                      yc - s*dial->radius);
16545     }
16546
16547   /* Dibuja el puntero */
16548
16549   s = sin(dial->angle);
16550   c = cos(dial->angle);
16551
16552
16553   points[0].x = xc + s*dial->pointer_width/2;
16554   points[0].y = yc + c*dial->pointer_width/2;
16555   points[1].x = xc + c*dial->radius;
16556   points[1].y = yc - s*dial->radius;
16557   points[2].x = xc - s*dial->pointer_width/2;
16558   points[2].y = yc - c*dial->pointer_width/2;
16559
16560   gtk_draw_polygon (widget->style,
16561                     widget->window,
16562                     GTK_STATE_NORMAL,
16563                     GTK_SHADOW_OUT,
16564                     points, 3,
16565                     TRUE);
16566   
16567   return FALSE;
16568 }
16569
16570 static gint
16571 gtk_dial_button_press (GtkWidget      *widget,
16572                        GdkEventButton *event)
16573 {
16574   GtkDial *dial;
16575   gint dx, dy;
16576   double s, c;
16577   double d_parallel;
16578   double d_perpendicular;
16579
16580   g_return_val_if_fail (widget != NULL, FALSE);
16581   g_return_val_if_fail (GTK_IS_DIAL (widget), FALSE);
16582   g_return_val_if_fail (event != NULL, FALSE);
16583
16584   dial = GTK_DIAL (widget);
16585
16586
16587   /* Determinar si la pulsación del botón fue dentro de la región del
16588      puntero - esto lo hacemos calculando la distancia x e y del punto
16589      donde se pulsó el botón ratón de la línea que se ha pasado mediante el
16590      puntero */
16591   
16592   dx = event->x - widget->allocation.width / 2;
16593   dy = widget->allocation.height / 2 - event->y;
16594   
16595   s = sin(dial->angle);
16596   c = cos(dial->angle);
16597   
16598   d_parallel = s*dy + c*dx;
16599   d_perpendicular = fabs(s*dx - c*dy);
16600   
16601   if (!dial->button &amp;&amp;
16602       (d_perpendicular < dial->pointer_width/2) &amp;&amp;
16603       (d_parallel > - dial->pointer_width))
16604     {
16605       gtk_grab_add (widget);
16606
16607       dial->button = event->button;
16608
16609       gtk_dial_update_mouse (dial, event->x, event->y);
16610     }
16611
16612   return FALSE;
16613 }
16614
16615 static gint
16616 gtk_dial_button_release (GtkWidget      *widget,
16617                           GdkEventButton *event)
16618 {
16619   GtkDial *dial;
16620
16621   g_return_val_if_fail (widget != NULL, FALSE);
16622   g_return_val_if_fail (GTK_IS_DIAL (widget), FALSE);
16623   g_return_val_if_fail (event != NULL, FALSE);
16624
16625   dial = GTK_DIAL (widget);
16626
16627   if (dial->button == event->button)
16628     {
16629       gtk_grab_remove (widget);
16630
16631       dial->button = 0;
16632
16633       if (dial->policy == GTK_UPDATE_DELAYED)
16634         gtk_timeout_remove (dial->timer);
16635       
16636       if ((dial->policy != GTK_UPDATE_CONTINUOUS) &amp;&amp;
16637           (dial->old_value != dial->adjustment->value))
16638         gtk_signal_emit_by_name (GTK_OBJECT (dial->adjustment), "value_changed");
16639     }
16640
16641   return FALSE;
16642 }
16643
16644 static gint
16645 gtk_dial_motion_notify (GtkWidget      *widget,
16646                          GdkEventMotion *event)
16647 {
16648   GtkDial *dial;
16649   GdkModifierType mods;
16650   gint x, y, mask;
16651
16652   g_return_val_if_fail (widget != NULL, FALSE);
16653   g_return_val_if_fail (GTK_IS_DIAL (widget), FALSE);
16654   g_return_val_if_fail (event != NULL, FALSE);
16655
16656   dial = GTK_DIAL (widget);
16657
16658   if (dial->button != 0)
16659     {
16660       x = event->x;
16661       y = event->y;
16662
16663       if (event->is_hint || (event->window != widget->window))
16664         gdk_window_get_pointer (widget->window, &amp;x, &amp;y, &amp;mods);
16665
16666       switch (dial->button)
16667         {
16668         case 1:
16669           mask = GDK_BUTTON1_MASK;
16670           break;
16671         case 2:
16672           mask = GDK_BUTTON2_MASK;
16673           break;
16674         case 3:
16675           mask = GDK_BUTTON3_MASK;
16676           break;
16677         default:
16678           mask = 0;
16679           break;
16680         }
16681
16682       if (mods &amp; mask)
16683         gtk_dial_update_mouse (dial, x,y);
16684     }
16685
16686   return FALSE;
16687 }
16688
16689 static gint
16690 gtk_dial_timer (GtkDial *dial)
16691 {
16692   g_return_val_if_fail (dial != NULL, FALSE);
16693   g_return_val_if_fail (GTK_IS_DIAL (dial), FALSE);
16694
16695   if (dial->policy == GTK_UPDATE_DELAYED)
16696     gtk_signal_emit_by_name (GTK_OBJECT (dial->adjustment), "value_changed");
16697
16698   return FALSE;
16699 }
16700
16701 static void
16702 gtk_dial_update_mouse (GtkDial *dial, gint x, gint y)
16703 {
16704   gint xc, yc;
16705   gfloat old_value;
16706
16707   g_return_if_fail (dial != NULL);
16708   g_return_if_fail (GTK_IS_DIAL (dial));
16709
16710   xc = GTK_WIDGET(dial)->allocation.width / 2;
16711   yc = GTK_WIDGET(dial)->allocation.height / 2;
16712
16713   old_value = dial->adjustment->value;
16714   dial->angle = atan2(yc-y, x-xc);
16715
16716   if (dial->angle < -M_PI/2.)
16717     dial->angle += 2*M_PI;
16718
16719   if (dial->angle < -M_PI/6)
16720     dial->angle = -M_PI/6;
16721
16722   if (dial->angle > 7.*M_PI/6.)
16723     dial->angle = 7.*M_PI/6.;
16724
16725   dial->adjustment->value = dial->adjustment->lower + (7.*M_PI/6 - dial->angle) *
16726     (dial->adjustment->upper - dial->adjustment->lower) / (4.*M_PI/3.);
16727
16728   if (dial->adjustment->value != old_value)
16729     {
16730       if (dial->policy == GTK_UPDATE_CONTINUOUS)
16731         {
16732           gtk_signal_emit_by_name (GTK_OBJECT (dial->adjustment), "value_changed");
16733         }
16734       else
16735         {
16736           gtk_widget_draw (GTK_WIDGET(dial), NULL);
16737
16738           if (dial->policy == GTK_UPDATE_DELAYED)
16739             {
16740               if (dial->timer)
16741                 gtk_timeout_remove (dial->timer);
16742
16743               dial->timer = gtk_timeout_add (SCROLL_DELAY_LENGTH,
16744                                              (GtkFunction) gtk_dial_timer,
16745                                              (gpointer) dial);
16746             }
16747         }
16748     }
16749 }
16750
16751 static void
16752 gtk_dial_update (GtkDial *dial)
16753 {
16754   gfloat new_value;
16755   
16756   g_return_if_fail (dial != NULL);
16757   g_return_if_fail (GTK_IS_DIAL (dial));
16758
16759   new_value = dial->adjustment->value;
16760   
16761   if (new_value < dial->adjustment->lower)
16762     new_value = dial->adjustment->lower;
16763
16764   if (new_value > dial->adjustment->upper)
16765     new_value = dial->adjustment->upper;
16766
16767   if (new_value != dial->adjustment->value)
16768     {
16769       dial->adjustment->value = new_value;
16770       gtk_signal_emit_by_name (GTK_OBJECT (dial->adjustment), "value_changed");
16771     }
16772
16773   dial->angle = 7.*M_PI/6. - (new_value - dial->adjustment->lower) * 4.*M_PI/3. /
16774     (dial->adjustment->upper - dial->adjustment->lower);
16775
16776   gtk_widget_draw (GTK_WIDGET(dial), NULL);
16777 }
16778
16779 static void
16780 gtk_dial_adjustment_changed (GtkAdjustment *adjustment,
16781                               gpointer       data)
16782 {
16783   GtkDial *dial;
16784
16785   g_return_if_fail (adjustment != NULL);
16786   g_return_if_fail (data != NULL);
16787
16788   dial = GTK_DIAL (data);
16789
16790   if ((dial->old_value != adjustment->value) ||
16791       (dial->old_lower != adjustment->lower) ||
16792       (dial->old_upper != adjustment->upper))
16793     {
16794       gtk_dial_update (dial);
16795
16796       dial->old_value = adjustment->value;
16797       dial->old_lower = adjustment->lower;
16798       dial->old_upper = adjustment->upper;
16799     }
16800 }
16801
16802 static void
16803 gtk_dial_adjustment_value_changed (GtkAdjustment *adjustment,
16804                                     gpointer       data)
16805 {
16806   GtkDial *dial;
16807
16808   g_return_if_fail (adjustment != NULL);
16809   g_return_if_fail (data != NULL);
16810
16811   dial = GTK_DIAL (data);
16812
16813   if (dial->old_value != adjustment->value)
16814     {
16815       gtk_dial_update (dial);
16816
16817       dial->old_value = adjustment->value;
16818     }
16819 }
16820 /* fin del ejemplo */
16821 </verb></tscreen>
16822
16823 <!-- ----------------------------------------------------------------- -->
16824 <sect1> Scribble
16825 <p>
16826 <tscreen><verb>
16827 /* principio del ejemplo scribble-simple scribble-simple.c */
16828
16829 /* GTK - The GIMP Toolkit
16830  * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
16831  *
16832  * This library is free software; you can redistribute it and/or
16833  * modify it under the terms of the GNU Library General Public
16834  * License as published by the Free Software Foundation; either
16835  * version 2 of the License, or (at your option) any later version.
16836  *
16837  * This library is distributed in the hope that it will be useful,
16838  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16839  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16840  * Library General Public License for more details.
16841  *
16842  * You should have received a copy of the GNU Library General Public
16843  * License along with this library; if not, write to the
16844  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
16845  * Boston, MA 02111-1307, USA.
16846  */
16847
16848 #include <gtk/gtk.h>
16849
16850 /* Creamos un backing pixmap para la zona donde dibujamos */
16851 static GdkPixmap *pixmap = NULL;
16852
16853 /* Creamos un nuevo backing pixmap del tamaño apropiado */
16854 static gint
16855 configure_event (GtkWidget *widget, GdkEventConfigure *event)
16856 {
16857   if (pixmap)
16858     gdk_pixmap_unref(pixmap);
16859
16860   pixmap = gdk_pixmap_new(widget->window,
16861                           widget->allocation.width,
16862                           widget->allocation.height,
16863                           -1);
16864   gdk_draw_rectangle (pixmap,
16865                       widget->style->white_gc,
16866                       TRUE,
16867                       0, 0,
16868                       widget->allocation.width,
16869                       widget->allocation.height);
16870
16871   return TRUE;
16872 }
16873
16874 /* Redibujamos la pantalla con el backing pixmap */
16875 static gint
16876 expose_event (GtkWidget *widget, GdkEventExpose *event)
16877 {
16878   gdk_draw_pixmap(widget->window,
16879                   widget->style->fg_gc[GTK_WIDGET_STATE (widget)],
16880                   pixmap,
16881                   event->area.x, event->area.y,
16882                   event->area.x, event->area.y,
16883                   event->area.width, event->area.height);
16884
16885   return FALSE;
16886 }
16887
16888 /* Dibujamos un rectángulo en la pantalla */
16889 static void
16890 draw_brush (GtkWidget *widget, gdouble x, gdouble y)
16891 {
16892   GdkRectangle update_rect;
16893
16894   update_rect.x = x - 5;
16895   update_rect.y = y - 5;
16896   update_rect.width = 10;
16897   update_rect.height = 10;
16898   gdk_draw_rectangle (pixmap,
16899                       widget->style->black_gc,
16900                       TRUE,
16901                       update_rect.x, update_rect.y,
16902                       update_rect.width, update_rect.height);
16903   gtk_widget_draw (widget, &amp;update_rect);
16904 }
16905
16906 static gint
16907 button_press_event (GtkWidget *widget, GdkEventButton *event)
16908 {
16909   if (event->button == 1 &amp;&amp; pixmap != NULL)
16910     draw_brush (widget, event->x, event->y);
16911
16912   return TRUE;
16913 }
16914
16915 static gint
16916 motion_notify_event (GtkWidget *widget, GdkEventMotion *event)
16917 {
16918   int x, y;
16919   GdkModifierType state;
16920
16921   if (event->is_hint)
16922     gdk_window_get_pointer (event->window, &amp;x, &amp;y, &amp;state);
16923   else
16924     {
16925       x = event->x;
16926       y = event->y;
16927       state = event->state;
16928     }
16929     
16930   if (state &amp; GDK_BUTTON1_MASK &amp;&amp; pixmap != NULL)
16931     draw_brush (widget, x, y);
16932   
16933   return TRUE;
16934 }
16935
16936 void
16937 quit ()
16938 {
16939   gtk_exit (0);
16940 }
16941
16942 int
16943 main (int argc, char *argv[])
16944 {
16945   GtkWidget *ventana;
16946   GtkWidget *drawing_area;
16947   GtkWidget *vbox;
16948
16949   GtkWidget *boton;
16950
16951   gtk_init (&amp;argc, &amp;argv);
16952
16953   ventana = gtk_window_new (GTK_WINDOW_TOPLEVEL);
16954   gtk_widget_set_name (ventana, "Test Input");
16955
16956   vbox = gtk_vbox_new (FALSE, 0);
16957   gtk_container_add (GTK_CONTAINER (ventana), vbox);
16958   gtk_widget_show (vbox);
16959
16960   gtk_signal_connect (GTK_OBJECT (ventana), "destroy",
16961                       GTK_SIGNAL_FUNC (quit), NULL);
16962
16963   /* Crear la zona de dibujado */
16964
16965   drawing_area = gtk_drawing_area_new ();
16966   gtk_drawing_area_size (GTK_DRAWING_AREA (drawing_area), 200, 200);
16967   gtk_box_pack_start (GTK_BOX (vbox), drawing_area, TRUE, TRUE, 0);
16968
16969   gtk_widget_show (drawing_area);
16970
16971   /* Las señales utilizadas para manejar el backing pixmap */
16972
16973   gtk_signal_connect (GTK_OBJECT (drawing_area), "expose_event",
16974                       (GtkSignalFunc) expose_event, NULL);
16975   gtk_signal_connect (GTK_OBJECT(drawing_area),"configure_event",
16976                       (GtkSignalFunc) configure_event, NULL);
16977
16978   /* Señales evento */
16979
16980   gtk_signal_connect (GTK_OBJECT (drawing_area), "motion_notify_event",
16981                       (GtkSignalFunc) motion_notify_event, NULL);
16982   gtk_signal_connect (GTK_OBJECT (drawing_area), "button_press_event",
16983                       (GtkSignalFunc) button_press_event, NULL);
16984
16985   gtk_widget_set_events (drawing_area, GDK_EXPOSURE_MASK
16986                          | GDK_LEAVE_NOTIFY_MASK
16987                          | GDK_BUTTON_PRESS_MASK
16988                          | GDK_POINTER_MOTION_MASK
16989                          | GDK_POINTER_MOTION_HINT_MASK);
16990
16991   /* .. Y un botón para salir */
16992   boton = gtk_button_new_with_label ("Quit");
16993   gtk_box_pack_start (GTK_BOX (vbox), boton, FALSE, FALSE, 0);
16994
16995   gtk_signal_connect_object (GTK_OBJECT (boton), "clicked",
16996                              GTK_SIGNAL_FUNC (gtk_widget_destroy),
16997                              GTK_OBJECT (ventana));
16998   gtk_widget_show (boton);
16999
17000   gtk_widget_show (ventana);
17001
17002   gtk_main ();
17003
17004   return 0;
17005 }
17006 /* fin del ejemplo */
17007 </verb></tscreen>
17008
17009 <!-- ***************************************************************** -->
17010 <sect> El <em>widget</em> lista
17011 <!-- ***************************************************************** -->
17012 <p>
17013 ATENCIÓN: El <em>widget</em> GtkList ha sido reemplazado por el
17014 <em>widget</em> GtkCList.
17015
17016 El <em>widget</em> GtkList está diseñado para actuar como un
17017 contenedor vertical de <em>widgets</em> que deben ser del tipo
17018 GtkListItem.
17019
17020 Un <em>widget</em> GtkList tiene su propia ventana para recibir
17021 eventos y su propio color de fondo, que normalmente es blanco.
17022 Como es un objeto derivado directamente de GtkContainer puede tratarse
17023 utilizando la macro GTK_CONTAINER(List), ver el <em>widget</em>
17024 GtkContainer para obtener más información.
17025
17026 Debería familiarizarse con la utilización de un GList y con sus
17027 funciones relacionadas <tt/g_list_*()/ para ser capaz de explotar el
17028 <em>widget</em> GtkList hasta su límite.
17029
17030 Sólo hay un campo dentro de la definición de la estructura del
17031 <em>widget</em> GtkList que nos es de interés, y es:
17032
17033 <tscreen><verb>
17034 struct _GtkList
17035 {
17036   ...
17037   GList *selection;
17038   guint selection_mode;
17039   ...
17040 }; 
17041 </verb></tscreen>
17042
17043 El campo <tt/selection/ de un GtkList apunta a una lista enlazada de
17044 todos los elementos que están actualmente seleccionados, o NULL si la
17045 selección está vacia. Por lo tanto para saber quien es la actual
17046 selección debemos leer el campo <tt/GTK_LIST()->selection/, pero no
17047 modificarlo ya que los campos de los que está constituido GtkList
17048 están controlados por las funciones gtk_list_*().
17049
17050 El <tt/selection_mode/ de la GtkList determina las posibilidades de
17051 selección de una GtkList y por tanto los contenidos del campo
17052 <tt/GTK_LIST()->selection/. El <tt/selection_mode/ puede tener uno de
17053 los valores siguientes:
17054
17055 <itemize>
17056 <item> GTK_SELECTION_SINGLE - La selección es o NULL o contiene un
17057 puntero a un GList con un solo elemento seleccionado.
17058
17059 <item> GTK_SELECTION_BROWSE - La selección es NULL si la lista no
17060 contiene <em>widgets</em> o si los que contiene no son sensibles, en
17061 cualquier otro caso contiene un puntero GList a una estructura GList,
17062 y contendrá por tanto un solo elemento.
17063
17064 <item> GTK_SELECTION_MULTIPLE -  La selección es NULL si no hay
17065 elementos seleccionados o un puntero GList hacia el primer elemento
17066 seleccionado. ("That in turn") apunta a una estructura GList para
17067 el segundo elemento seleccionado y así.
17068
17069 <item> GTK_SELECTION_EXTENDED - La selección siempre es NULL.
17070 </itemize>
17071
17072 El valor por defecto es GTK_SELECTION_MULTIPLE.
17073
17074 <!-- ----------------------------------------------------------------- -->
17075 <sect1> Señales
17076 <p>
17077 <tscreen><verb>
17078 void selection_changed( GtkList *list );
17079 </verb></tscreen>
17080
17081 Se invocará esta señal cuando cambie el campo <tt/selection/ de un
17082 GtkList. Es decir, cuando un hijo de una GtkList se selecciona o
17083 deselecciona.
17084
17085 <tscreen><verb>
17086 void select_child( GtkList   *list,
17087                    GtkWidget *hijo);
17088 </verb></tscreen>
17089
17090 Se invoca esta señal cuando un hijo de la GtkList está siendo
17091 seleccionado. Esto ocurre principalmente en llamadas a
17092 <tt/gtk_list_select_item()/, a <tt/gtk_list_select_child()/, cuando se 
17093 pulsa algún botón y a veces se lanza indirectamente cuando se añade o
17094 se elimina un hijo del GtkList.
17095
17096 <tscreen><verb>
17097 void unselect_child( GtkList   *list,
17098                      GtkWidget *hijo );
17099 </verb></tscreen>
17100
17101 Se invoca esta señal cuando un hijo del GtkList está siendo
17102 deseleccionado. Esto ocurre principalmente cuando ocurre una llamada a
17103 <tt/gtk_list_unselect_item()/, <tt/gtk_list_unselect_item()/,
17104 pulsaciones de botón y a veces se lanza indirectamente cuando se añade
17105 o se elimina algún hijo de la GtkList.
17106
17107 <!-- ----------------------------------------------------------------- -->
17108 <sect1> Funciones
17109 <p>
17110 <tscreen><verb>
17111 guint gtk_list_get_type( void );
17112 </verb></tscreen>
17113
17114 Devuelve el identificador de tipo `GtkList'.
17115
17116 <tscreen><verb>
17117 GtkWidget *gtk_list_new( void );
17118 </verb></tscreen>
17119
17120 Crea un nuevo objeto GtkList. Se devuelve el nuevo <em/widget/ como un
17121 puntero a un objeto GtkWidget. Se devuelve NULL en caso de producirse
17122 algún fallo.
17123
17124 <tscreen><verb>
17125 void gtk_list_insert_items( GtkList *list,
17126                             GList   *items,
17127                             gint     posicion );
17128 </verb></tscreen>
17129
17130 Introduce elementos en la lista, comenzando en la posición
17131 <tt/posicion/. <tt/items/ es una lista doblemente enlazada donde cada
17132 puntero de datos de cada nodo se supone que apunta a una nueva
17133 GtkListItem (recien creada). Los nodos GList de <tt/items/ son
17134 controlados por la lista.
17135
17136 <tscreen><verb>
17137 void gtk_list_append_items( GtkList *list,
17138                             GList   *items);
17139 </verb></tscreen>
17140
17141 Introduce elementos tal y como lo hace <tt/gtk_list_insert_items()/,
17142 pero los mete en el final de la lista. Los nodos GList de <tt/items/
17143 son controlados por la lista.
17144
17145 <tscreen><verb>
17146 void gtk_list_prepend_items( GtkList *list,
17147                              GList   *items);
17148 </verb></tscreen>
17149
17150 Introduce elementos tal y como lo hace <tt/gtk_list_insert_items()/,
17151 pero los mete al principio de la lista. Los nodos GList de <tt/items/
17152 son controlados por la lista.
17153
17154 <tscreen><verb>
17155 void gtk_list_remove_items( GtkList *list,
17156                             GList   *items);
17157 </verb></tscreen>
17158
17159 Elimina elementos de la lista. <tt/items/ es una lista doblemente
17160 enlazada donde cada puntero de datos de cada nodo se supone que apunta
17161 a un hijo directo de la lista. El ejecutar o no
17162 <tt/g_list_free(items)/ cuando la función termine de ejecutarse es
17163 responsabilidad del que llama a la misma. Está bajo su responsabilidad
17164 la destrucción de los elementos de la lista.
17165
17166 <tscreen><verb>
17167 void gtk_list_clear_items( GtkList *list,
17168                            gint start,
17169                            gint end );
17170 </verb></tscreen>
17171
17172 Elimina y destruye los elementos de la lista. Esta operación afectará
17173 a todos los <em/widgets/ que se encuentren en la lista y en el rango
17174 especificado por <tt/start/ y <tt/end/.
17175
17176 <tscreen><verb>
17177 void gtk_list_select_item( GtkList *list,
17178                            gint     item );
17179 </verb></tscreen>
17180
17181 Invoca la señal <tt/select_child/ para el elemento especificado
17182 mediante su posición actual en la lista.
17183
17184 <tscreen><verb>
17185 void gtk_list_unselect_item( GtkList *list,
17186                              gint     item);
17187 </verb></tscreen>
17188
17189 Invoca la señal <tt/unselect_child/ para un elemento especificado
17190 mediante su posición actual en la lista.
17191
17192 <tscreen><verb>
17193 void gtk_list_select_child( GtkList *list,
17194                             GtkWidget *hijo);
17195 </verb></tscreen>
17196
17197 Invoca la señal <tt/select_child/ para el hijo especificado.
17198
17199 <tscreen><verb>
17200 void gtk_list_unselect_child( GtkList   *list,
17201                               GtkWidget *hijo);
17202 </verb></tscreen>
17203
17204 Invoca la señal <tt/unselect_child/ para el hijo especificado.
17205
17206 <tscreen><verb>
17207 gint gtk_list_child_position( GtkList *list,
17208                               GtkWidget *hijo);
17209 </verb></tscreen>
17210
17211 Devuelve la posición de <tt/hijo/ en la lista. Se devuelve «-1» en
17212 caso de producirse algún error.
17213
17214 <tscreen><verb>
17215 void gtk_list_set_selection_mode( GtkList         *list,
17216                                   GtkSelectionMode mode );
17217 </verb></tscreen>
17218
17219 Pone el modo de selección, que puede ser <tt/GTK_SELECTION_SINGLE/,
17220 <tt/GTK_SELECTION_BROWSE/, <tt/GTK_SELECTION_MULTIPLE/ o
17221 <tt/GTK_SELECTION_EXTENDED/.
17222
17223 <tscreen><verb>
17224 GtkList *GTK_LIST( gpointer obj );
17225 </verb></tscreen>
17226
17227 Convierte un puntero general en `GtkList *'. Para más información *Note
17228 Standard Macros::.
17229
17230 <tscreen><verb>
17231 GtkListClass *GTK_LIST_CLASS( gpointer class);
17232 </verb></tscreen>
17233
17234 Convierte un puntero general en `GtkListClass *'. Para más información
17235 *Note Standard Macros::.
17236
17237 <tscreen><verb>
17238 gint GTK_IS_LIST( gpointer obj);
17239 </verb></tscreen>
17240
17241 Determina si un puntero general se refiere a un objeto `GtkList'. Para
17242 más información, *Note Standard Macros::.
17243
17244 <!-- ----------------------------------------------------------------- -->
17245 <sect1> Ejemplo
17246 <p>
17247 A continuación tenemos un programa ejemplo que muestra los cambios de
17248 la selección de un GtkList, y le deja «arrestar» elementos de la
17249 lista en una prisión, seleccionándolos con el botón derecho del ratón.
17250
17251 <tscreen><verb>
17252 /* principio del ejemplo list list.c */
17253
17254 /* incluye los ficheros de cabecera de gtk+
17255  * incluye stdio.h, que necesitamos para la función printf()
17256  */
17257 #include        <gtk/gtk.h>
17258 #include        <stdio.h>
17259
17260 /* ésta es nuestra cadena de identificación para almacenar datos en la
17261  * lista de elementos
17262  */
17263 const   gchar   *list_item_data_key="list_item_data";
17264
17265
17266 /* prototipos para los manejadores de señal que vamos a conectar con
17267  * el widget GtkList
17268  */
17269 static  void    sigh_print_selection    (GtkWidget      *gtklist,
17270                                          gpointer       func_data);
17271 static  void    sigh_button_event       (GtkWidget      *gtklist,
17272                                          GdkEventButton *event,
17273                                          GtkWidget      *frame);
17274
17275
17276 /* función principal donde se establece el interface con el usuario */
17277
17278 gint main (int argc, gchar *argv[])
17279 {                                  
17280     GtkWidget       *separator;
17281     GtkWidget       *ventana;
17282     GtkWidget       *vbox;
17283     GtkWidget       *scrolled_window;
17284     GtkWidget       *frame;
17285     GtkWidget       *gtklist;
17286     GtkWidget       *boton;
17287     GtkWidget       *list_item;
17288     GList           *dlist;
17289     guint           i;
17290     gchar           buffer[64];
17291     
17292     
17293     /* inicializar gtk+ (y consecuentemente gdk) */
17294
17295     gtk_init(&amp;argc, &amp;argv);
17296     
17297     
17298     /* crear una ventana donde meter todos los widgets y conectar
17299      * gtk_main_quit() con el evento "destroy" de la ventana para
17300      * poder controlar los eventos de cerrado de ventana del
17301      * administrador de ventanas
17302      */
17303     ventana=gtk_window_new(GTK_WINDOW_TOPLEVEL);
17304     gtk_window_set_title(GTK_WINDOW(ventana), "GtkList Example");
17305     gtk_signal_connect(GTK_OBJECT(ventana),
17306                        "destroy",
17307                        GTK_SIGNAL_FUNC(gtk_main_quit),
17308                        NULL);
17309     
17310     
17311     /* dentro de la ventana necesitamos una caja para alinear los
17312      * widgets verticalmente */
17313     vbox=gtk_vbox_new(FALSE, 5);
17314     gtk_container_border_width(GTK_CONTAINER(vbox), 5);
17315     gtk_container_add(GTK_CONTAINER(ventana), vbox);
17316     gtk_widget_show(vbox);
17317     
17318     /* Ésta es la ventana con barras de desplazamiento donde meteremos
17319      * el widget GtkList */
17320     scrolled_window=gtk_scrolled_window_new(NULL, NULL);
17321     gtk_widget_set_usize(scrolled_window, 250, 150);
17322     gtk_container_add(GTK_CONTAINER(vbox), scrolled_window);
17323     gtk_widget_show(scrolled_window);
17324     
17325     /* crear el widget GtkList
17326      * conectar la función manipuladora de señal
17327      * sigh_print_selection() a la señal "selection_changed" del
17328      * GtkList para imprimir los elementos seleccionados cada vez que
17329      * cambie la selección */
17330     gtklist=gtk_list_new();
17331     gtk_container_add(GTK_CONTAINER(scrolled_window), gtklist);
17332     gtk_widget_show(gtklist);
17333     gtk_signal_connect(GTK_OBJECT(gtklist),
17334                        "selection_changed",
17335                        GTK_SIGNAL_FUNC(sigh_print_selection),
17336                        NULL);
17337     
17338     /* creamos una "Prisión" donde meteremos una lista de elementos ;)
17339      */
17340     frame=gtk_frame_new("Prison");
17341     gtk_widget_set_usize(frame, 200, 50);
17342     gtk_container_border_width(GTK_CONTAINER(frame), 5);
17343     gtk_frame_set_shadow_type(GTK_FRAME(frame), GTK_SHADOW_OUT);
17344     gtk_container_add(GTK_CONTAINER(vbox), frame);
17345     gtk_widget_show(frame);
17346     
17347     /* conectamos el manipulador de señal sigh_button_event() al
17348      * GtkList que manejará la lista de elementos "arrestados"
17349      */
17350     gtk_signal_connect(GTK_OBJECT(gtklist),
17351                        "button_release_event",
17352                        GTK_SIGNAL_FUNC(sigh_button_event),
17353                        frame);
17354     
17355     /* crear un separador
17356      */
17357     separator=gtk_hseparator_new();
17358     gtk_container_add(GTK_CONTAINER(vbox), separator);
17359     gtk_widget_show(separator);
17360     
17361     /* crear finalmente un botón y conectar su señal "clicked" con la
17362      * destrucción de la ventana
17363      */
17364     boton=gtk_button_new_with_label("Close");
17365     gtk_container_add(GTK_CONTAINER(vbox), boton);
17366     gtk_widget_show(boton);
17367     gtk_signal_connect_object(GTK_OBJECT(boton),
17368                               "clicked",
17369                               GTK_SIGNAL_FUNC(gtk_widget_destroy),
17370                               GTK_OBJECT(ventana));
17371     
17372     
17373     /* ahora creamos 5 elementos de lista, teniendo cada uno su propia
17374      * etiqueta y añadiéndolos a la GtkList mediante
17375      * gtk_container_add() también consultaremos la cadena de texto de
17376      * la etiqueta y la asociaremos con la list_item_data_key para
17377      * cada elemento de la lista
17378      */
17379     for (i=0; i<5; i++) {
17380         GtkWidget       *etiqueta;
17381         gchar           *string;
17382         
17383         sprintf(buffer, "ListItemContainer with Label #%d", i);
17384         etiqueta=gtk_label_new(buffer);
17385         list_item=gtk_list_item_new();
17386         gtk_container_add(GTK_CONTAINER(list_item), etiqueta);
17387         gtk_widget_show(etiqueta);
17388         gtk_container_add(GTK_CONTAINER(gtklist), list_item);
17389         gtk_widget_show(list_item);
17390         gtk_label_get(GTK_LABEL(etiqueta), &amp;string);
17391         gtk_object_set_data(GTK_OBJECT(list_item),
17392                             list_item_data_key,
17393                             string);
17394     }
17395     /* aquí, estamos creando otras 5 etiquetas, esta vez utilizaremos
17396      * gtk_list_item_new_with_label() para la creación
17397      * no podemos consultar la cadena de texto de la etiqueta ya que
17398      * no tenemos el puntero de etiquetas y por tanto lo único que
17399      * haremos será asociar el list_item_data_key de cada elemento de
17400      * la lista con la misma cadena de texto. Para añadirlo a la lista
17401      * de elementos los pondremos en lista doblemente enlazada
17402      * (GList), y entonces los añadimos mediante una simple llamada a
17403      * gtk_list_append_items()
17404      * como utilizamos g_list_prepend() para poner los elementos en la
17405      * lista doblemente enlazada, su orden será descendente (en vez de
17406      * ascendente como cuando utilizamos g_list_append())
17407      */
17408     dlist=NULL;
17409     for (; i<10; i++) {
17410         sprintf(buffer, "List Item with Label %d", i);
17411         list_item=gtk_list_item_new_with_label(buffer);
17412         dlist=g_list_prepend(dlist, list_item);
17413         gtk_widget_show(list_item);
17414         gtk_object_set_data(GTK_OBJECT(list_item),
17415                             list_item_data_key,
17416                             "ListItem with integrated Label");
17417     }
17418     gtk_list_append_items(GTK_LIST(gtklist), dlist);
17419     
17420     /* finalmente queremos ver la ventana, ¿verdad? ;)
17421      */
17422     gtk_widget_show(ventana);
17423     
17424     /* y nos metemos en el bucle de eventos de gtk
17425      */
17426     gtk_main();
17427     
17428     /* llegaremos aquí después de que se llame a gtk_main_quit(), lo
17429      * que ocurre si se destruye la ventana
17430      */
17431     return 0;
17432 }
17433
17434 /* éste es el manejador de señal que se conectó a los eventos de
17435  * pulsar/soltar de los botones de la GtkList
17436  */
17437 void
17438 sigh_button_event       (GtkWidget      *gtklist,
17439                          GdkEventButton *event,
17440                          GtkWidget      *frame)
17441 {
17442     /* sólo hacemos algo si el tercer botón (el botón derecho) se
17443      * levanta
17444      */
17445     if (event->type==GDK_BUTTON_RELEASE &amp;&amp;
17446         event->button==3) {
17447         GList           *dlist, *free_list;
17448         GtkWidget       *new_prisoner;
17449         
17450         /* sacar la lista de elementos que están actualmente
17451          * seleccionados y que serán nuestro próximos prisioneros ;)
17452          */
17453         dlist=GTK_LIST(gtklist)->selection;
17454         if (dlist)
17455                 new_prisoner=GTK_WIDGET(dlist->data);
17456         else
17457                 new_prisoner=NULL;
17458         
17459         /* buscar por elementos de la lista ya encarcelados, los
17460          * volveremos a poner en la lista, recordar que hay que
17461          * eliminar la lista doblemente enlazada que devuelve
17462          * gtk_container_children()
17463          */
17464         dlist=gtk_container_children(GTK_CONTAINER(frame));
17465         free_list=dlist;
17466         while (dlist) {
17467             GtkWidget       *list_item;
17468             
17469             list_item=dlist->data;
17470             
17471             gtk_widget_reparent(list_item, gtklist);
17472             
17473             dlist=dlist->next;
17474         }
17475         g_list_free(free_list);
17476         
17477         /* si tenemos un nuevo prisionero, lo eliminamos de la GtkList
17478          * y lo ponemos en el marco "Prisión". Primero tenemos que
17479          * deseleccionarlo
17480          */
17481         if (new_prisoner) {
17482             GList   static_dlist;
17483             
17484             static_dlist.data=new_prisoner;
17485             static_dlist.next=NULL;
17486             static_dlist.prev=NULL;
17487             
17488             gtk_list_unselect_child(GTK_LIST(gtklist),
17489                                     new_prisoner);
17490             gtk_widget_reparent(new_prisoner, frame);
17491         }
17492     }
17493 }
17494
17495 /* éste es el manipulador de señal que se llama si GtkList emite la
17496  * señal "selection_changed"
17497  */
17498 void
17499 sigh_print_selection    (GtkWidget      *gtklist,
17500                          gpointer       func_data)
17501 {
17502     GList   *dlist;
17503     
17504     /* sacar la lista doblemente enlazada de los elementos
17505      * seleccionados en GtkList, ¡recuerde que hay que tratarla como
17506      * de solo lectura!
17507      */
17508     dlist=GTK_LIST(gtklist)->selection;
17509     
17510     /* si no hay elementos seleccionados no queda nada por hacer
17511      * excepto informar al usuario
17512      */
17513     if (!dlist) {
17514         g_print("Selection cleared\n");
17515         return;
17516     }
17517     /* Bien, conseguimos una selección y la imprimimos
17518      */
17519     g_print("The selection is a ");
17520     
17521     /* obtenemos la lista de elementos de la lista doblemente enlazada
17522      * y entonces consultamos los datos asociados con la
17523      * list_item_data_key que acabamos de imprimir
17524      */
17525     while (dlist) {
17526         GtkObject       *list_item;
17527         gchar           *item_data_string;
17528         
17529         list_item=GTK_OBJECT(dlist->data);
17530         item_data_string=gtk_object_get_data(list_item,
17531                                              list_item_data_key);
17532         g_print("%s ", item_data_string);
17533         
17534         dlist=dlist->next;
17535     }
17536     g_print("\n");
17537 }
17538 /* fin del ejemplo */
17539 </verb></tscreen>
17540
17541 <!-- ----------------------------------------------------------------- -->
17542 <sect1> El <em/widget/ GtkListItem
17543 <p>
17544 El <em/widget/ GtkListItem está diseñado para comportarse como un
17545 contenedor que tiene un hijo, proporcionando funciones para la
17546 selección/deselección justo como las necesitan los hijos del
17547 <em/widget/ GtkList.
17548
17549 Un GtkListItem tiene su propia ventana para recibir eventos y tiene su
17550 propio color de fondo, que normalmente es blanco.
17551
17552 Como está derivado directamente de un GtkItem, puede tratarse como tal
17553 utilizando la macro GTK_ITEM(ListItem), ver el <em/widget/ GtkItem
17554 para más detalles. Normalmente un GtkListItem sólo tiene una etiqueta
17555 para identificar, por ejemplo, el nombre de un fichero dentro de una
17556 GtkList -- por lo tanto se proporciona la función
17557 <tt/gtk_list_item_new_with_label()/. Se puede conseguir el mismo
17558 efecto creando un GtkLabel, poniendo su alineación a <tt/xalign=0/ e
17559 <tt/yalign=0.5/ y seguido de una adición al contenedor GtkListItem.
17560
17561 Nadie le obliga a meter un GtkLabel en un GtkListItem, puede meter un
17562 GtkVBox o un GtkArrow, etc...
17563
17564 <!-- ----------------------------------------------------------------- -->
17565 <sect1> Señales
17566 <p>
17567 Un GtkListItem no crea por sí misma nuevas señales, pero hereda las
17568 señales de un GtkItem. Para más información *Note GtkItem::.
17569
17570 <!-- ----------------------------------------------------------------- -->
17571 <sect1> Funciones
17572 <p>
17573 <tscreen><verb>
17574 guint gtk_list_item_get_type( void );
17575 </verb></tscreen>
17576
17577 Devuelve el identificador de tipo `GtkListItem'.
17578
17579 <tscreen><verb>
17580 GtkWidget *gtk_list_item_new( void );
17581 </verb></tscreen>
17582
17583 Crea un nuevo objeto GtkListItem. Se devuelve el nuevo <em/widget/
17584 como un puntero a un objeto GtkWidget. Se devuelve NULL en caso de
17585 producirse algún error.
17586
17587 <tscreen><verb>
17588 GtkWidget *gtk_list_item_new_with_label( gchar *etiqueta );
17589 </verb></tscreen>
17590
17591 Crea un nuevo objeto GtkListItem, con una sola GtkLabel como único
17592 hijo. Se devuelve el nuevo <em/widget/ como un puntero a un objeto
17593 GtkWidget. Se devuelve NULL en caso de producirse algún error.
17594
17595 <tscreen><verb>
17596 void gtk_list_item_select( GtkListItem *list_item );
17597 </verb></tscreen>
17598
17599 Esta función es, básicamente, un recubrimiento de una llamada a
17600 <tt/gtk_item_select (GTK_ITEM (list_item))/, y emitirá la señal
17601 <tt/select/. Para más información *Note GtkItem::.
17602
17603 <tscreen><verb>
17604 void gtk_list_item_deselect( GtkListItem *list_item );
17605 </verb></tscreen>
17606
17607 Esta función es, básicamente, un recubrimiento de una llamada a
17608 <tt/gtk_item_deselect (GTK_ITEM (list_item))/, y emitirá la señal
17609 <tt/deselect/. Para más información *Note GtkItem::.
17610
17611 <tscreen><verb>
17612 GtkListItem *GTK_LIST_ITEM( gpointer obj );
17613 </verb></tscreen>
17614
17615 Convierte un puntero general a `GtkListItem *'. Para más información
17616 *Note Standard Macros::.
17617
17618 <tscreen><verb>
17619 GtkListItemClass *GTK_LIST_ITEM_CLASS( gpointer class );
17620 </verb></tscreen>
17621
17622 Convierte un puntero general a `GtkListItemClass *'. Para más
17623 información *Note Standard Macros::.
17624
17625 <tscreen><verb>
17626 gint GTK_IS_LIST_ITEM( gpointer obj );
17627 </verb></tscreen>
17628
17629 Determina si un puntero general se refiere a un puntero
17630 `GtkListItem'. Para más información *Note Standard Macros::.
17631  
17632 <!-- ----------------------------------------------------------------- -->
17633 <sect1> Ejemplo
17634 <p>
17635 Para ver un ejemplo de todo esto, mire el de GtkList, que también
17636 cubre la utilización un GtkListItem.
17637
17638 </article>