source: trunk/third/gtk/docs/html/gtk_tut_fr-16.html @ 14482

Revision 14482, 14.6 KB checked in by ghudson, 25 years ago (diff)
This commit was generated by cvs2svn to compensate for changes in r14481, which included commits to RCS files with non-trunk default branches.
Line 
1<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
2<HTML>
3<HEAD>
4 <META NAME="GENERATOR" CONTENT="SGML-Tools 1.0.9">
5 <TITLE>Didacticiel: Gestion des sélections</TITLE>
6 <LINK HREF="gtk_tut_fr-17.html" REL=next>
7 <LINK HREF="gtk_tut_fr-15.html" REL=previous>
8 <LINK HREF="gtk_tut_fr.html#toc16" REL=contents>
9</HEAD>
10<BODY BGCOLOR="#FFFFFF">
11<A HREF="gtk_tut_fr-17.html">Page suivante</A>
12<A HREF="gtk_tut_fr-15.html">Page précédente</A>
13<A HREF="gtk_tut_fr.html#toc16">Table des matières</A>
14<HR NOSHADE>
15<H2><A NAME="s16">16. Gestion des sélections</A></H2>
16
17<H2><A NAME="ss16.1">16.1 Introduction</A>
18</H2>
19
20<P>Un type de communication inter-processus gérée par GTK est les
21<EM>sélections</EM>. Une sélection identifie un morceau de données,
22par exemple une portion de texte sélectionnée par l'utilisateur avec
23la souris. Seule une application sur un écran (le <EM>propriétaire</EM>)
24peut posséder une sélection particulière à un moment donné, ainsi
25lorsqu'une sélection est réclamée par une application, le propriétaire
26précédent doit indiquer à l'utilisateur que la sélection a été
27abandonnée. Les autres applications peuvent demander le contenu d'une
28sélection sous différentes formes appelées <EM>cibles</EM>. Il peut y
29avoir un nombre quelconque de sélections, mais la plupart des
30applications X n'en gèrent qu'une, la <EM>sélection primaire</EM>.
31<P>
32<P>Dans la plupart des cas, une application GTK n'a pas besoin de gérer elle-même
33les sélections. Les widgets standards, comme le widget Entrée de texte,
34possèdent déjà la capacité de réclamer la sélection lorsqu'il le faut (par
35exemple, lorsque l'utilisateur glisse au dessus d'un texte) et de récupérer le
36contenu de la sélection détenue par un autre widget ou une autre application
37(par exemple, lorsque l'utilisateur clique avec le deuxième bouton de la
38souris). Cependant, il peut il y avoir des cas dans lesquels vous voulez donner
39aux autres widgets la possibilité de fournir la sélection, ou vous désirez
40récupérer des cibles non supportées par défaut.
41<P>
42<P>Un concept fondamental dans la compréhension du fonctionnement des
43sélections est celui d'<EM>atome</EM>. Un atome est un entier qui définit
44de façon unique une chaîne (sur un affichage particulier). Certains
45atomes sont prédéfinis par le serveur X et, dans certains cas, des
46constantes définies dans <EM>gtk.h</EM> correspondent à ces atomes. Par
47exemple, la constante GDK_PRIMARY_SELECTION correspond à la chaîne
48"PRIMARY".  Dans d'autres cas, on doit utiliser les fonctions
49<EM>gdk_atom_intern()</EM>, pour obtenir l'atome correspondant à une
50chaîne, et <EM>gdk_atom_name()</EM>, pour obtenir le nom d'un atome. Les
51sélections et les cibles sont identifiés par des atomes.
52<P>
53<H2><A NAME="ss16.2">16.2 Récupération de la sélection</A>
54</H2>
55
56<P>La récupération de la sélection est un processus asynchrone. Pour démarrer le processus, on appelle&nbsp;:
57<P>
58<BLOCKQUOTE><CODE>
59<PRE>
60gint gtk_selection_convert   (GtkWidget           *widget,
61                              GdkAtom              selection,
62                              GdkAtom              target,
63                              guint32              time)
64</PRE>
65</CODE></BLOCKQUOTE>
66<P>Cela <EM>convertit</EM> la sélection dans la forme spécifiée par
67<EM>target</EM>. Si tout est possible, le paramètre <EM>time</EM> sera le
68moment de l'événement qui a déclenché la sélection. Ceci aide à
69s'assurer que les événements arrivent dans l'ordre où l'utilisateur
70les a demandé. Cependant, si cela n'est pas possible (par exemple,
71lorsque la conversion a été déclenchée par un signal "clicked"), alors
72on peut utiliser la macro GDK_CURRENT_TIME.
73<P>
74<P>Quand le propriétaire de la sélection répond à la requête, un signal
75"selection_received" est envoyé à notre application. Le gestionnaire
76de ce signal reçoit un pointeur vers une structure
77<CODE>GtkSelectionData</CODE> définie ainsi&nbsp;:
78<P>
79<BLOCKQUOTE><CODE>
80<PRE>
81struct _GtkSelectionData
82{
83  GdkAtom selection;
84  GdkAtom target;
85  GdkAtom type;
86  gint    format;
87  guchar *data;
88  gint    length;
89};
90</PRE>
91</CODE></BLOCKQUOTE>
92<P><EM>selection</EM> et <EM>target</EM> sont les valeurs que l'on a donné dans
93notre appel <EM>gtk_selection_convert()</EM>. <EM>type</EM> est un atome qui
94identifie le type de données retourné par le propriétaire de la
95sélection. Quelques valeurs possibles sont&nbsp;: "STRING", une chaîne
96de caractères latin-1, "ATOM", une série d'atomes, "INTEGER", un
97entier, etc. La plupart des cibles ne peuvent retourner qu'un
98type. <EM>format</EM> donne la longueur des unités (les caractères, par
99exemple) en bits. Habituellement, on ne se préoccupe pas de cela
100lorsqu'on reçoit des données. <EM>data</EM> est un pointeur vers la donnée
101retournée et <EM>length</EM> donne la longueur en octets de la donnée
102retournée. Si <EM>length</EM> est négative, cela indique qu'une erreur est
103survenue et que la sélection ne peut être récupérée. Ceci peut arriver
104si aucune application n'est propriétaire de la sélection, ou si vous
105avez demandé une cible que l'application ne sait pas gérer. Le tampon
106est garanti d'être un octet plus long que <EM>length</EM> ; l'octet
107supplémentaire sera toujours zéro, et il n'est donc pas nécessaire de
108faire une copie de chaîne simplement pour qu'elle soit terminée par
109zéro (comme doivent l'être toutes les chaînes C).
110<P>
111<P>Dans l'exemple qui suit, on récupère la cible spéciale "TARGETS", qui
112est une liste de toutes les cibles en lesquelles la sélection peut
113être convertie.
114<P>
115<BLOCKQUOTE><CODE>
116<PRE>
117#include &lt;gtk/gtk.h>
118
119void selection_received (GtkWidget *widget,
120                         GtkSelectionData *selection_data,
121                         gpointer data);
122
123/* Gestionnaire de signal invoqué lorsque l'utilisateur clique sur
124 * le bouton « Obtenir les cibles ». */
125
126void get_targets (GtkWidget *widget, gpointer data)
127{
128  static GdkAtom targets_atom = GDK_NONE;
129
130  /* Obtention de l'atome correspondant à la chaîne "TARGETS" */
131
132  if (targets_atom == GDK_NONE)
133    targets_atom = gdk_atom_intern ("TARGETS", FALSE);
134
135  /* Demande de la cible "TARGETS" pour la sélection primaire */
136
137  gtk_selection_convert (widget, GDK_SELECTION_PRIMARY, targets_atom,
138                         GDK_CURRENT_TIME);
139}
140
141/* Gestionnaire de signal appelé quand le propriétaire des sélections
142 * retourne la donnée. */
143
144void selection_received (GtkWidget *widget, GtkSelectionData *selection_data,
145                    gpointer data)
146{
147  GdkAtom *atoms;
148  GList *item_list;
149  int i;
150
151  /* **** IMPORTANT **** On vérifie si la récupération s'est bien passée. */
152
153  if (selection_data->length &lt; 0)
154    {
155      g_print ("Selection retrieval failed\n");
156      return;
157    }
158
159  /* On s'assure que l'on a obtenu la donnée sous la forme attendue. */
160
161  if (selection_data->type != GDK_SELECTION_TYPE_ATOM)
162    {
163      g_print ("La sélection \"TARGETS\" n'a pas été retournée sous la forme d'atomes !\n");
164      return;
165    }
166 
167  /* Affichage des atomes reçus. */
168
169  atoms = (GdkAtom *)selection_data->data;
170
171  item_list = NULL;
172  for (i=0; i&lt;selection_data->length/sizeof(GdkAtom); i++)
173    {
174      char *name;
175      name = gdk_atom_name (atoms[i]);
176      if (name != NULL)
177        g_print ("%s\n",name);
178      else
179        g_print ("(atome incorrect)\n");
180    }
181
182  return;
183}
184
185int
186main (int argc, char *argv[])
187{
188  GtkWidget *window;
189  GtkWidget *button;
190 
191  gtk_init (&amp;argc, &amp;argv);
192
193  /* Création de la fenêtre de l'application. */
194
195  window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
196  gtk_window_set_title (GTK_WINDOW (window), "Sélections");
197  gtk_container_border_width (GTK_CONTAINER (window), 10);
198
199  gtk_signal_connect (GTK_OBJECT (window), "destroy",
200                      GTK_SIGNAL_FUNC (gtk_exit), NULL);
201
202  /* Création d'un bouton pour obtenir les cibles */
203
204  button = gtk_button_new_with_label ("Obtenir les cibles");
205  gtk_container_add (GTK_CONTAINER (window), button);
206
207  gtk_signal_connect (GTK_OBJECT(button), "clicked",
208                      GTK_SIGNAL_FUNC (get_targets), NULL);
209  gtk_signal_connect (GTK_OBJECT(button), "selection_received",
210                      GTK_SIGNAL_FUNC (selection_received), NULL);
211
212  gtk_widget_show (button);
213  gtk_widget_show (window);
214 
215  gtk_main ();
216 
217  return 0;
218}
219</PRE>
220</CODE></BLOCKQUOTE>
221<P>
222<H2><A NAME="ss16.3">16.3 Fournir la sélection </A>
223</H2>
224
225<P>
226<P>Fournir la sélection est un peu plus compliqué. On doit enregistrer
227les gestionnaires qui seront appelés lorsque notre sélection est
228demandée. Pour chaque paire sélection/cible que l'on gèrera, on fera
229un appel à&nbsp;:
230<P>
231<BLOCKQUOTE><CODE>
232<PRE>
233void gtk_selection_add_handler (GtkWidget           *widget,
234                                GdkAtom              selection,
235                                GdkAtom              target,
236                                GtkSelectionFunction function,
237                                GtkRemoveFunction    remove_func,
238                                gpointer             data);
239</PRE>
240</CODE></BLOCKQUOTE>
241<P><EM>widget</EM>, <EM>selection</EM> et <EM>target</EM> identifient les requêtes
242que ce gestionnaire gèrera. S'il ne vaut pas NULL, <EM>remove_func</EM>
243sera appelé lorsque le gestionnaire de signal est supprimé. Ceci est
244utile, par exemple, pour des langages interprétés qui doivent garder
245une trace du nombre de références à <EM>data</EM>.
246<P>
247<P>La fonction de rappel <EM>function</EM> doit avoir la signature suivante&nbsp;:
248<P>
249<BLOCKQUOTE><CODE>
250<PRE>
251typedef void (*GtkSelectionFunction) (GtkWidget *widget,
252                                      GtkSelectionData *selection_data,
253                                      gpointer data);
254</PRE>
255</CODE></BLOCKQUOTE>
256<P>Le <EM>GtkSelectionData</EM> est le même qu'au dessus, mais, cette fois,
257nous sommes responsables de l'initialisation de ses champs <EM>type</EM>,
258<EM>format</EM>, <EM>data</EM>, et <EM>length</EM>. (Le champ <EM>format</EM> est
259important ici - le serveur X l'utilise pour savoir si la donnée doit
260être échangée par octet ou non. Habituellement, ce sera 8 (un
261caractère), ou 32 (un entier)). Cette initialisation est faite en
262utilisant l'appel&nbsp;:
263<P>
264<BLOCKQUOTE><CODE>
265<PRE>
266void gtk_selection_data_set (GtkSelectionData *selection_data,
267                             GdkAtom           type,
268                             gint              format,
269                             guchar           *data,
270                             gint              length);
271</PRE>
272</CODE></BLOCKQUOTE>
273<P>Cette fonction s'occupe de faire une copie correcte des données afin
274que l'on n'ait pas à se soucier du reste. (On ne doit pas remplir ces
275champs à la main).
276<P>
277<P>Lorsque cela est demandé par l'utilisateur, on réclame la possession
278de la sélection en appelant&nbsp;:
279<P>
280<BLOCKQUOTE><CODE>
281<PRE>
282gint gtk_selection_owner_set (GtkWidget           *widget,
283                              GdkAtom              selection,
284                              guint32              time);
285</PRE>
286</CODE></BLOCKQUOTE>
287<P>Si une autre application réclame la possession de la sélection, on
288recevra un "selection_clear_event".
289<P>Comme exemple de fourniture de sélection, l'exemple suivant ajoute une
290fonctionnalité de sélection à un bouton commutateur. Lorsque ce bouton
291est appuyé, le programme réclame la sélection primaire. La seule cible
292supportée (à part certaines cibles fournies par GTK lui-même, comme
293« TARGETS ») est « STRING ». Lorsque celle-ci est demandée, on
294retourne une représentation de l'heure sous forme de chaîne.
295<P>
296<BLOCKQUOTE><CODE>
297<PRE>
298#include &lt;gtk/gtk.h>
299#include &lt;time.h>
300
301/* Fonction de rappel appelée lorsque l'utilisateur commute la sélection. */
302
303void selection_toggled (GtkWidget *widget, gint *have_selection)
304{
305  if (GTK_TOGGLE_BUTTON(widget)->active)
306    {
307      *have_selection = gtk_selection_owner_set (widget,
308                                                 GDK_SELECTION_PRIMARY,
309                                                 GDK_CURRENT_TIME);
310      /* Si la demande de sélection échoue, on remet le bouton en position sortie. */
311
312      if (!*have_selection)
313        gtk_toggle_button_set_state (GTK_TOGGLE_BUTTON(widget), FALSE);
314    }
315  else
316    {
317      if (*have_selection)
318        {
319          /* Avant de nettoyer la selection en mettant son propriétaire à NULL,
320           * on vérifie que nous sommes bien son propriétaire actuel. */
321
322          if (gdk_selection_owner_get (GDK_SELECTION_PRIMARY) == widget->window)
323            gtk_selection_owner_set (NULL, GDK_SELECTION_PRIMARY,
324                                     GDK_CURRENT_TIME);
325          *have_selection = FALSE;
326        }
327    }
328}
329
330/* Appelée lorsqu'une autre application demande la sélection. */
331
332gint selection_clear (GtkWidget *widget, GdkEventSelection *event,
333                 gint *have_selection)
334{
335  *have_selection = FALSE;
336  gtk_toggle_button_set_state (GTK_TOGGLE_BUTTON(widget), FALSE);
337
338  return TRUE;
339}
340
341/* Fournit l'heure comme sélection. */
342
343void selection_handle (GtkWidget *widget,
344                  GtkSelectionData *selection_data,
345                  gpointer data)
346{
347  gchar *timestr;
348  time_t current_time;
349
350  current_time = time (NULL);
351  timestr = asctime (localtime(&amp;current_time));
352
353  /* Lorsqu'on retourne une chaîne, elle ne doit pas se terminer par
354   * 0, ce sera fait pour nous. */
355
356  gtk_selection_data_set (selection_data, GDK_SELECTION_TYPE_STRING,
357                          8, timestr, strlen(timestr));
358}
359
360int main (int argc, char *argv[])
361{
362  GtkWidget *window;
363
364  GtkWidget *selection_button;
365
366  static int have_selection = FALSE;
367 
368  gtk_init (&amp;argc, &amp;argv);
369
370  /* Création de la fenêtre principale. */
371
372  window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
373  gtk_window_set_title (GTK_WINDOW (window), "Event Box");
374  gtk_container_border_width (GTK_CONTAINER (window), 10);
375
376  gtk_signal_connect (GTK_OBJECT (window), "destroy",
377                      GTK_SIGNAL_FUNC (gtk_exit), NULL);
378
379  /* Création d'un bouton commutateur pour qu'il agisse comme une sélection. */
380
381  selection_button = gtk_toggle_button_new_with_label ("Demande de sélection");
382  gtk_container_add (GTK_CONTAINER (window), selection_button);
383  gtk_widget_show (selection_button);
384
385  gtk_signal_connect (GTK_OBJECT(selection_button), "toggled",
386                      GTK_SIGNAL_FUNC (selection_toggled), &amp;have_selection);
387  gtk_signal_connect (GTK_OBJECT(selection_button), "selection_clear_event",
388                      GTK_SIGNAL_FUNC (selection_clear), &amp;have_selection);
389
390  gtk_selection_add_handler (selection_button, GDK_SELECTION_PRIMARY,
391                             GDK_SELECTION_TYPE_STRING,
392                             selection_handle, NULL, NULL);
393
394  gtk_widget_show (selection_button);
395  gtk_widget_show (window);
396 
397  gtk_main ();
398 
399  return 0;
400}
401</PRE>
402</CODE></BLOCKQUOTE>
403<P>
404<P>
405<P>
406<HR NOSHADE>
407<A HREF="gtk_tut_fr-17.html">Page suivante</A>
408<A HREF="gtk_tut_fr-15.html">Page précédente</A>
409<A HREF="gtk_tut_fr.html#toc16">Table des matières</A>
410</BODY>
411</HTML>
Note: See TracBrowser for help on using the repository browser.