]> Pileus Git - ~andy/gtk/blob - modules/other/gail/gailcombobox.c
Deprecate widget flag: GTK_WIDGET_MAPPED
[~andy/gtk] / modules / other / gail / gailcombobox.c
1 /* GAIL - The GNOME Accessibility Implementation Library
2  * Copyright 2004 Sun Microsystems Inc.
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Lesser General Public
6  * License as published by the Free Software Foundation; either
7  * version 2 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser General Public
15  * License along with this library; if not, write to the
16  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17  * Boston, MA 02111-1307, USA.
18  */
19
20 #include "config.h"
21
22 #include <gtk/gtk.h>
23 #include <gdk/gdkkeysyms.h>
24 #include "gailcombobox.h"
25
26 static void         gail_combo_box_class_init              (GailComboBoxClass *klass);
27 static void         gail_combo_box_init                    (GailComboBox      *combo_box);
28 static void         gail_combo_box_real_initialize         (AtkObject      *obj,
29                                                             gpointer       data);
30
31 static void         gail_combo_box_changed_gtk             (GtkWidget      *widget);
32
33 static G_CONST_RETURN gchar* gail_combo_box_get_name       (AtkObject      *obj);
34 static gint         gail_combo_box_get_n_children          (AtkObject      *obj);
35 static AtkObject*   gail_combo_box_ref_child               (AtkObject      *obj,
36                                                             gint           i);
37 static void         gail_combo_box_finalize                (GObject        *object);
38 static void         atk_action_interface_init              (AtkActionIface *iface);
39
40 static gboolean     gail_combo_box_do_action               (AtkAction      *action,
41                                                             gint           i);
42 static gboolean     idle_do_action                         (gpointer       data);
43 static gint         gail_combo_box_get_n_actions           (AtkAction      *action);
44 static G_CONST_RETURN gchar* gail_combo_box_get_description(AtkAction      *action,
45                                                             gint           i);
46 static G_CONST_RETURN gchar* gail_combo_box_get_keybinding   (AtkAction       *action,
47                                                              gint            i);
48 static G_CONST_RETURN gchar* gail_combo_box_action_get_name(AtkAction      *action,
49                                                             gint           i);
50 static gboolean              gail_combo_box_set_description(AtkAction      *action,
51                                                             gint           i,
52                                                             const gchar    *desc);
53 static void         atk_selection_interface_init           (AtkSelectionIface *iface);
54 static gboolean     gail_combo_box_add_selection           (AtkSelection   *selection,
55                                                             gint           i);
56 static gboolean     gail_combo_box_clear_selection         (AtkSelection   *selection);
57 static AtkObject*   gail_combo_box_ref_selection           (AtkSelection   *selection,
58                                                             gint           i);
59 static gint         gail_combo_box_get_selection_count     (AtkSelection   *selection);
60 static gboolean     gail_combo_box_is_child_selected       (AtkSelection   *selection,
61                                                             gint           i);
62 static gboolean     gail_combo_box_remove_selection        (AtkSelection   *selection,
63                                                             gint           i);
64
65 G_DEFINE_TYPE_WITH_CODE (GailComboBox, gail_combo_box, GAIL_TYPE_CONTAINER,
66                          G_IMPLEMENT_INTERFACE (ATK_TYPE_ACTION, atk_action_interface_init)
67                          G_IMPLEMENT_INTERFACE (ATK_TYPE_SELECTION, atk_selection_interface_init))
68
69 static void
70 gail_combo_box_class_init (GailComboBoxClass *klass)
71 {
72   GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
73   AtkObjectClass *class = ATK_OBJECT_CLASS (klass);
74
75   gobject_class->finalize = gail_combo_box_finalize;
76
77   class->get_name = gail_combo_box_get_name;
78   class->get_n_children = gail_combo_box_get_n_children;
79   class->ref_child = gail_combo_box_ref_child;
80   class->initialize = gail_combo_box_real_initialize;
81 }
82
83 static void
84 gail_combo_box_init (GailComboBox      *combo_box)
85 {
86   combo_box->press_description = NULL;
87   combo_box->press_keybinding = NULL;
88   combo_box->old_selection = -1;
89   combo_box->name = NULL;
90   combo_box->popup_set = FALSE;
91 }
92
93 static void
94 gail_combo_box_real_initialize (AtkObject *obj,
95                                 gpointer  data)
96 {
97   GtkComboBox *combo_box;
98   GailComboBox *gail_combo_box;
99   AtkObject *popup;
100
101   ATK_OBJECT_CLASS (gail_combo_box_parent_class)->initialize (obj, data);
102
103   combo_box = GTK_COMBO_BOX (data);
104
105   gail_combo_box = GAIL_COMBO_BOX (obj);
106
107   g_signal_connect (combo_box,
108                     "changed",
109                     G_CALLBACK (gail_combo_box_changed_gtk),
110                     NULL);
111   gail_combo_box->old_selection = gtk_combo_box_get_active (combo_box);
112
113   popup = gtk_combo_box_get_popup_accessible (combo_box);
114   if (popup)
115     {
116       atk_object_set_parent (popup, obj);
117       gail_combo_box->popup_set = TRUE;
118     }
119   if (GTK_IS_COMBO_BOX_ENTRY (combo_box))
120     atk_object_set_parent (gtk_widget_get_accessible (gtk_bin_get_child (GTK_BIN (combo_box))), obj);
121
122   obj->role = ATK_ROLE_COMBO_BOX;
123 }
124
125 static void
126 gail_combo_box_changed_gtk (GtkWidget *widget)
127 {
128   GtkComboBox *combo_box;
129   AtkObject *obj;
130   GailComboBox *gail_combo_box;
131   gint index;
132
133   combo_box = GTK_COMBO_BOX (widget);
134
135   index = gtk_combo_box_get_active (combo_box);
136   obj = gtk_widget_get_accessible (widget);
137   gail_combo_box = GAIL_COMBO_BOX (obj);
138   if (gail_combo_box->old_selection != index)
139     {
140       gail_combo_box->old_selection = index;
141       g_object_notify (G_OBJECT (obj), "accessible-name");
142       g_signal_emit_by_name (obj, "selection_changed");
143     }
144 }
145
146 static G_CONST_RETURN gchar* 
147 gail_combo_box_get_name (AtkObject *obj)
148 {
149   GtkWidget *widget;
150   GtkComboBox *combo_box;
151   GailComboBox *gail_combo_box;
152   GtkTreeIter iter;
153   G_CONST_RETURN gchar *name;
154   GtkTreeModel *model;
155   gint n_columns;
156   gint i;
157
158   g_return_val_if_fail (GAIL_IS_COMBO_BOX (obj), NULL);
159
160   name = ATK_OBJECT_CLASS (gail_combo_box_parent_class)->get_name (obj);
161   if (name)
162     return name;
163
164   widget = GTK_ACCESSIBLE (obj)->widget;
165   if (widget == NULL)
166     /*
167      * State is defunct
168      */
169     return NULL;
170
171   combo_box = GTK_COMBO_BOX (widget);
172   gail_combo_box = GAIL_COMBO_BOX (obj);
173   if (gtk_combo_box_get_active_iter (combo_box, &iter))
174     {
175       model = gtk_combo_box_get_model (combo_box);
176       n_columns = gtk_tree_model_get_n_columns (model);
177       for (i = 0; i < n_columns; i++)
178         {
179           GValue value = { 0, };
180
181           gtk_tree_model_get_value (model, &iter, i, &value);
182           if (G_VALUE_HOLDS_STRING (&value))
183             {
184               if (gail_combo_box->name) g_free (gail_combo_box->name);
185               gail_combo_box->name =  g_strdup ((gchar *) 
186                                                 g_value_get_string (&value));
187               g_value_unset (&value);
188               break;
189             }
190           else
191             g_value_unset (&value);
192         }
193     }
194   return gail_combo_box->name;
195 }
196
197 /*
198  * The children of a GailComboBox are the list of items and the entry field
199  * if it is editable.
200  */
201 static gint
202 gail_combo_box_get_n_children (AtkObject* obj)
203 {
204   gint n_children = 0;
205   GtkWidget *widget;
206
207   g_return_val_if_fail (GAIL_IS_COMBO_BOX (obj), 0);
208
209   widget = GTK_ACCESSIBLE (obj)->widget;
210   if (widget == NULL)
211     /*
212      * State is defunct
213      */
214     return 0;
215
216   n_children++;
217   if (GTK_IS_COMBO_BOX_ENTRY (widget))
218     n_children ++;
219
220   return n_children;
221 }
222
223 static AtkObject*
224 gail_combo_box_ref_child (AtkObject *obj,
225                           gint      i)
226 {
227   GtkWidget *widget;
228   AtkObject *child;
229   GailComboBox *box;
230
231   g_return_val_if_fail (GAIL_IS_COMBO_BOX (obj), NULL);
232
233   widget = GTK_ACCESSIBLE (obj)->widget;
234
235   if (widget == NULL)
236     /*
237      * State is defunct
238      */
239     return NULL;
240
241   if (i == 0)
242     {
243       child = gtk_combo_box_get_popup_accessible (GTK_COMBO_BOX (widget));
244       box = GAIL_COMBO_BOX (obj);
245       if (box->popup_set == FALSE)
246         {
247           atk_object_set_parent (child, obj);
248           box->popup_set = TRUE;
249         }
250     }
251   else if (i == 1 && GTK_IS_COMBO_BOX_ENTRY (widget))
252     {
253       child = gtk_widget_get_accessible (gtk_bin_get_child (GTK_BIN (widget)));
254     }
255   else
256     {
257       return NULL;
258     }
259   return g_object_ref (child);
260 }
261
262 static void
263 atk_action_interface_init (AtkActionIface *iface)
264 {
265   iface->do_action = gail_combo_box_do_action;
266   iface->get_n_actions = gail_combo_box_get_n_actions;
267   iface->get_description = gail_combo_box_get_description;
268   iface->get_keybinding = gail_combo_box_get_keybinding;
269   iface->get_name = gail_combo_box_action_get_name;
270   iface->set_description = gail_combo_box_set_description;
271 }
272
273 static gboolean
274 gail_combo_box_do_action (AtkAction *action,
275                           gint      i)
276 {
277   GailComboBox *combo_box;
278   GtkWidget *widget;
279
280   widget = GTK_ACCESSIBLE (action)->widget;
281   if (widget == NULL)
282     /*
283      * State is defunct
284      */
285     return FALSE;
286
287   if (!gtk_widget_get_sensitive (widget) || !gtk_widget_get_visible (widget))
288     return FALSE;
289
290   combo_box = GAIL_COMBO_BOX (action);
291   if (i == 0)
292     {
293       if (combo_box->action_idle_handler)
294         return FALSE;
295
296       combo_box->action_idle_handler = gdk_threads_add_idle (idle_do_action, combo_box);
297       return TRUE;
298     }
299   else
300     return FALSE;
301 }
302
303 static gboolean
304 idle_do_action (gpointer data)
305 {
306   GtkComboBox *combo_box;
307   GtkWidget *widget;
308   GailComboBox *gail_combo_box;
309   AtkObject *popup;
310   gboolean do_popup;
311
312   gail_combo_box = GAIL_COMBO_BOX (data);
313   gail_combo_box->action_idle_handler = 0;
314   widget = GTK_ACCESSIBLE (gail_combo_box)->widget;
315   if (widget == NULL || /* State is defunct */
316       !gtk_widget_get_sensitive (widget) || !gtk_widget_get_visible (widget))
317     return FALSE;
318
319   combo_box = GTK_COMBO_BOX (widget);
320
321   popup = gtk_combo_box_get_popup_accessible (combo_box);
322   do_popup = !gtk_widget_get_mapped (GTK_ACCESSIBLE (popup)->widget);
323   if (do_popup)
324       gtk_combo_box_popup (combo_box);
325   else
326       gtk_combo_box_popdown (combo_box);
327
328   return FALSE;
329 }
330
331 static gint
332 gail_combo_box_get_n_actions (AtkAction *action)
333 {
334   /*
335    * The default behavior of a combo_box box is to have one action -
336    */
337   return 1;
338 }
339
340 static G_CONST_RETURN gchar*
341 gail_combo_box_get_description (AtkAction *action,
342                            gint      i)
343 {
344   if (i == 0)
345     {
346       GailComboBox *combo_box;
347
348       combo_box = GAIL_COMBO_BOX (action);
349       return combo_box->press_description;
350     }
351   else
352     return NULL;
353 }
354
355 static G_CONST_RETURN gchar*
356 gail_combo_box_get_keybinding (AtkAction *action,
357                                     gint      i)
358 {
359   GailComboBox *combo_box;
360   gchar *return_value = NULL;
361   switch (i)
362   {
363      case 0:
364       {
365           GtkWidget *widget;
366           GtkWidget *label;
367           AtkRelationSet *set;
368           AtkRelation *relation;
369           GPtrArray *target;
370           gpointer target_object;
371           guint key_val;
372
373           combo_box = GAIL_COMBO_BOX (action);
374           widget = GTK_ACCESSIBLE (combo_box)->widget;
375           if (widget == NULL)
376              return NULL;
377           set = atk_object_ref_relation_set (ATK_OBJECT (action));
378           if (!set)
379              return NULL;
380           label = NULL;
381           relation = atk_relation_set_get_relation_by_type (set, ATK_RELATION_LABELLED_BY);
382           if (relation)
383           {
384              target = atk_relation_get_target (relation);
385              target_object = g_ptr_array_index (target, 0);
386              if (GTK_IS_ACCESSIBLE (target_object))
387              {
388                 label = GTK_ACCESSIBLE (target_object)->widget;
389              }
390           }
391           g_object_unref (set);
392           if (GTK_IS_LABEL (label))
393           {
394              key_val = gtk_label_get_mnemonic_keyval (GTK_LABEL (label));
395              if (key_val != GDK_VoidSymbol)
396              return_value = gtk_accelerator_name (key_val, GDK_MOD1_MASK);
397           }
398            g_free (combo_box->press_keybinding);
399            combo_box->press_keybinding = return_value;
400            break;
401        }
402     default:
403            break;
404   }
405   return return_value;
406 }
407
408
409 static G_CONST_RETURN gchar*
410 gail_combo_box_action_get_name (AtkAction *action,
411                                 gint      i)
412 {
413   if (i == 0)
414     return "press";
415   else
416     return NULL;
417 }
418
419 static gboolean
420 gail_combo_box_set_description (AtkAction   *action,
421                                 gint        i,
422                                 const gchar *desc)
423 {
424   if (i == 0)
425     {
426       GailComboBox *combo_box;
427
428       combo_box = GAIL_COMBO_BOX (action);
429       g_free (combo_box->press_description);
430       combo_box->press_description = g_strdup (desc);
431       return TRUE;
432     }
433   else
434     return FALSE;
435 }
436
437 static void
438 atk_selection_interface_init (AtkSelectionIface *iface)
439 {
440   iface->add_selection = gail_combo_box_add_selection;
441   iface->clear_selection = gail_combo_box_clear_selection;
442   iface->ref_selection = gail_combo_box_ref_selection;
443   iface->get_selection_count = gail_combo_box_get_selection_count;
444   iface->is_child_selected = gail_combo_box_is_child_selected;
445   iface->remove_selection = gail_combo_box_remove_selection;
446   /*
447    * select_all_selection does not make sense for a combo_box
448    * so no implementation is provided.
449    */
450 }
451
452 static gboolean
453 gail_combo_box_add_selection (AtkSelection *selection,
454                               gint         i)
455 {
456   GtkComboBox *combo_box;
457   GtkWidget *widget;
458
459   widget = GTK_ACCESSIBLE (selection)->widget;
460   if (widget == NULL)
461     /*
462      * State is defunct
463      */
464     return FALSE;
465
466   combo_box = GTK_COMBO_BOX (widget);
467
468   gtk_combo_box_set_active (combo_box, i);
469   return TRUE;
470 }
471
472 static gboolean 
473 gail_combo_box_clear_selection (AtkSelection *selection)
474 {
475   GtkComboBox *combo_box;
476   GtkWidget *widget;
477
478   widget = GTK_ACCESSIBLE (selection)->widget;
479   if (widget == NULL)
480     /*
481      * State is defunct
482      */
483     return FALSE;
484
485   combo_box = GTK_COMBO_BOX (widget);
486
487   gtk_combo_box_set_active (combo_box, -1);
488   return TRUE;
489 }
490
491 static AtkObject*
492 gail_combo_box_ref_selection (AtkSelection *selection,
493                               gint         i)
494 {
495   GtkComboBox *combo_box;
496   GtkWidget *widget;
497   AtkObject *obj;
498   gint index;
499
500   widget = GTK_ACCESSIBLE (selection)->widget;
501   if (widget == NULL)
502     /*
503      * State is defunct
504      */
505     return NULL;
506
507   combo_box = GTK_COMBO_BOX (widget);
508
509   /*
510    * A combo_box box can have only one selection.
511    */
512   if (i != 0)
513     return NULL;
514
515   obj = gtk_combo_box_get_popup_accessible (combo_box);
516   index = gtk_combo_box_get_active (combo_box);
517   return atk_object_ref_accessible_child (obj, index);
518 }
519
520 static gint
521 gail_combo_box_get_selection_count (AtkSelection *selection)
522 {
523   GtkComboBox *combo_box;
524   GtkWidget *widget;
525
526   widget = GTK_ACCESSIBLE (selection)->widget;
527   if (widget == NULL)
528     /*
529      * State is defunct
530      */
531     return 0;
532
533   combo_box = GTK_COMBO_BOX (widget);
534
535   return (gtk_combo_box_get_active (combo_box) == -1) ? 0 : 1;
536 }
537
538 static gboolean
539 gail_combo_box_is_child_selected (AtkSelection *selection,
540                                   gint         i)
541 {
542   GtkComboBox *combo_box;
543   gint j;
544   GtkWidget *widget;
545
546   widget = GTK_ACCESSIBLE (selection)->widget;
547   if (widget == NULL)
548     /*
549      * State is defunct
550      */
551     return FALSE;
552
553   combo_box = GTK_COMBO_BOX (widget);
554
555   j = gtk_combo_box_get_active (combo_box);
556
557   return (j == i);
558 }
559
560 static gboolean
561 gail_combo_box_remove_selection (AtkSelection *selection,
562                                  gint         i)
563 {
564   if (atk_selection_is_child_selected (selection, i))
565     atk_selection_clear_selection (selection);
566
567   return TRUE;
568 }
569
570 static void
571 gail_combo_box_finalize (GObject *object)
572 {
573   GailComboBox *combo_box = GAIL_COMBO_BOX (object);
574
575   g_free (combo_box->press_description);
576   g_free (combo_box->press_keybinding);
577   g_free (combo_box->name);
578   if (combo_box->action_idle_handler)
579     {
580       g_source_remove (combo_box->action_idle_handler);
581       combo_box->action_idle_handler = 0;
582     }
583   G_OBJECT_CLASS (gail_combo_box_parent_class)->finalize (object);
584 }