]> Pileus Git - ~andy/gtk/blob - modules/other/gail/gailcombobox.c
Remove relocations from the atk factories. Remove unused gail_foo_new()
[~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_signal_emit_by_name (obj, "selection_changed");
142     }
143 }
144
145 static G_CONST_RETURN gchar* 
146 gail_combo_box_get_name (AtkObject *obj)
147 {
148   GtkWidget *widget;
149   GtkComboBox *combo_box;
150   GailComboBox *gail_combo_box;
151   GtkTreeIter iter;
152   G_CONST_RETURN gchar *name;
153   GtkTreeModel *model;
154   gint n_columns;
155   gint i;
156
157   g_return_val_if_fail (GAIL_IS_COMBO_BOX (obj), NULL);
158
159   name = ATK_OBJECT_CLASS (gail_combo_box_parent_class)->get_name (obj);
160   if (name)
161     return name;
162
163   widget = GTK_ACCESSIBLE (obj)->widget;
164   if (widget == NULL)
165     /*
166      * State is defunct
167      */
168     return NULL;
169
170   combo_box = GTK_COMBO_BOX (widget);
171   gail_combo_box = GAIL_COMBO_BOX (obj);
172   if (gtk_combo_box_get_active_iter (combo_box, &iter))
173     {
174       model = gtk_combo_box_get_model (combo_box);
175       n_columns = gtk_tree_model_get_n_columns (model);
176       for (i = 0; i < n_columns; i++)
177         {
178           GValue value = { 0, };
179
180           gtk_tree_model_get_value (model, &iter, i, &value);
181           if (G_VALUE_HOLDS_STRING (&value))
182             {
183               if (gail_combo_box->name) g_free (gail_combo_box->name);
184               gail_combo_box->name =  g_strdup ((gchar *) 
185                                                 g_value_get_string (&value));
186               g_value_unset (&value);
187               break;
188             }
189           else
190             g_value_unset (&value);
191         }
192     }
193   return gail_combo_box->name;
194 }
195
196 /*
197  * The children of a GailComboBox are the list of items and the entry field
198  * if it is editable.
199  */
200 static gint
201 gail_combo_box_get_n_children (AtkObject* obj)
202 {
203   gint n_children = 0;
204   GtkWidget *widget;
205
206   g_return_val_if_fail (GAIL_IS_COMBO_BOX (obj), 0);
207
208   widget = GTK_ACCESSIBLE (obj)->widget;
209   if (widget == NULL)
210     /*
211      * State is defunct
212      */
213     return 0;
214
215   n_children++;
216   if (GTK_IS_COMBO_BOX_ENTRY (widget))
217     n_children ++;
218
219   return n_children;
220 }
221
222 static AtkObject*
223 gail_combo_box_ref_child (AtkObject *obj,
224                           gint      i)
225 {
226   GtkWidget *widget;
227   AtkObject *child;
228   GailComboBox *box;
229
230   g_return_val_if_fail (GAIL_IS_COMBO_BOX (obj), NULL);
231
232   widget = GTK_ACCESSIBLE (obj)->widget;
233
234   if (widget == NULL)
235     /*
236      * State is defunct
237      */
238     return NULL;
239
240   if (i == 0)
241     {
242       child = gtk_combo_box_get_popup_accessible (GTK_COMBO_BOX (widget));
243       box = GAIL_COMBO_BOX (obj);
244       if (box->popup_set == FALSE)
245         {
246           atk_object_set_parent (child, obj);
247           box->popup_set = TRUE;
248         }
249     }
250   else if (i == 1 && GTK_IS_COMBO_BOX_ENTRY (widget))
251     {
252       child = gtk_widget_get_accessible (gtk_bin_get_child (GTK_BIN (widget)));
253     }
254   else
255     {
256       return NULL;
257     }
258   return g_object_ref (child);
259 }
260
261 static void
262 atk_action_interface_init (AtkActionIface *iface)
263 {
264   iface->do_action = gail_combo_box_do_action;
265   iface->get_n_actions = gail_combo_box_get_n_actions;
266   iface->get_description = gail_combo_box_get_description;
267   iface->get_keybinding = gail_combo_box_get_keybinding;
268   iface->get_name = gail_combo_box_action_get_name;
269   iface->set_description = gail_combo_box_set_description;
270 }
271
272 static gboolean
273 gail_combo_box_do_action (AtkAction *action,
274                           gint      i)
275 {
276   GailComboBox *combo_box;
277   GtkWidget *widget;
278
279   widget = GTK_ACCESSIBLE (action)->widget;
280   if (widget == NULL)
281     /*
282      * State is defunct
283      */
284     return FALSE;
285
286   if (!GTK_WIDGET_SENSITIVE (widget) || !GTK_WIDGET_VISIBLE (widget))
287     return FALSE;
288
289   combo_box = GAIL_COMBO_BOX (action);
290   if (i == 0)
291     {
292       if (combo_box->action_idle_handler)
293         return FALSE;
294
295       combo_box->action_idle_handler = gdk_threads_add_idle (idle_do_action, combo_box);
296       return TRUE;
297     }
298   else
299     return FALSE;
300 }
301
302 static gboolean
303 idle_do_action (gpointer data)
304 {
305   GtkComboBox *combo_box;
306   GtkWidget *widget;
307   GailComboBox *gail_combo_box;
308   AtkObject *popup;
309   gboolean do_popup;
310
311   gail_combo_box = GAIL_COMBO_BOX (data);
312   gail_combo_box->action_idle_handler = 0;
313   widget = GTK_ACCESSIBLE (gail_combo_box)->widget;
314   if (widget == NULL || /* State is defunct */
315       !GTK_WIDGET_SENSITIVE (widget) || !GTK_WIDGET_VISIBLE (widget))
316     return FALSE;
317
318   combo_box = GTK_COMBO_BOX (widget);
319
320   popup = gtk_combo_box_get_popup_accessible (combo_box);
321   do_popup = !GTK_WIDGET_MAPPED (GTK_ACCESSIBLE (popup)->widget);
322   if (do_popup)
323       gtk_combo_box_popup (combo_box);
324   else
325       gtk_combo_box_popdown (combo_box);
326
327   return FALSE;
328 }
329
330 static gint
331 gail_combo_box_get_n_actions (AtkAction *action)
332 {
333   /*
334    * The default behavior of a combo_box box is to have one action -
335    */
336   return 1;
337 }
338
339 static G_CONST_RETURN gchar*
340 gail_combo_box_get_description (AtkAction *action,
341                            gint      i)
342 {
343   if (i == 0)
344     {
345       GailComboBox *combo_box;
346
347       combo_box = GAIL_COMBO_BOX (action);
348       return combo_box->press_description;
349     }
350   else
351     return NULL;
352 }
353
354 static G_CONST_RETURN gchar*
355 gail_combo_box_get_keybinding (AtkAction *action,
356                                     gint      i)
357 {
358   GailComboBox *combo_box;
359   gchar *return_value = NULL;
360   combo_box = GAIL_COMBO_BOX (action);
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     default:
402            break;
403   }
404   return return_value;
405 }
406
407
408 static G_CONST_RETURN gchar*
409 gail_combo_box_action_get_name (AtkAction *action,
410                                 gint      i)
411 {
412   if (i == 0)
413     return "press";
414   else
415     return NULL;
416 }
417
418 static gboolean
419 gail_combo_box_set_description (AtkAction   *action,
420                                 gint        i,
421                                 const gchar *desc)
422 {
423   if (i == 0)
424     {
425       GailComboBox *combo_box;
426
427       combo_box = GAIL_COMBO_BOX (action);
428       g_free (combo_box->press_description);
429       combo_box->press_description = g_strdup (desc);
430       return TRUE;
431     }
432   else
433     return FALSE;
434 }
435
436 static void
437 atk_selection_interface_init (AtkSelectionIface *iface)
438 {
439   iface->add_selection = gail_combo_box_add_selection;
440   iface->clear_selection = gail_combo_box_clear_selection;
441   iface->ref_selection = gail_combo_box_ref_selection;
442   iface->get_selection_count = gail_combo_box_get_selection_count;
443   iface->is_child_selected = gail_combo_box_is_child_selected;
444   iface->remove_selection = gail_combo_box_remove_selection;
445   /*
446    * select_all_selection does not make sense for a combo_box
447    * so no implementation is provided.
448    */
449 }
450
451 static gboolean
452 gail_combo_box_add_selection (AtkSelection *selection,
453                               gint         i)
454 {
455   GtkComboBox *combo_box;
456   GtkWidget *widget;
457
458   widget = GTK_ACCESSIBLE (selection)->widget;
459   if (widget == NULL)
460     /*
461      * State is defunct
462      */
463     return FALSE;
464
465   combo_box = GTK_COMBO_BOX (widget);
466
467   gtk_combo_box_set_active (combo_box, i);
468   return TRUE;
469 }
470
471 static gboolean 
472 gail_combo_box_clear_selection (AtkSelection *selection)
473 {
474   GtkComboBox *combo_box;
475   GtkWidget *widget;
476
477   widget = GTK_ACCESSIBLE (selection)->widget;
478   if (widget == NULL)
479     /*
480      * State is defunct
481      */
482     return FALSE;
483
484   combo_box = GTK_COMBO_BOX (widget);
485
486   gtk_combo_box_set_active (combo_box, -1);
487   return TRUE;
488 }
489
490 static AtkObject*
491 gail_combo_box_ref_selection (AtkSelection *selection,
492                               gint         i)
493 {
494   GtkComboBox *combo_box;
495   GtkWidget *widget;
496   AtkObject *obj;
497   gint index;
498
499   widget = GTK_ACCESSIBLE (selection)->widget;
500   if (widget == NULL)
501     /*
502      * State is defunct
503      */
504     return NULL;
505
506   combo_box = GTK_COMBO_BOX (widget);
507
508   /*
509    * A combo_box box can have only one selection.
510    */
511   if (i != 0)
512     return NULL;
513
514   obj = gtk_combo_box_get_popup_accessible (combo_box);
515   index = gtk_combo_box_get_active (combo_box);
516   return atk_object_ref_accessible_child (obj, index);
517 }
518
519 static gint
520 gail_combo_box_get_selection_count (AtkSelection *selection)
521 {
522   GtkComboBox *combo_box;
523   GtkWidget *widget;
524
525   widget = GTK_ACCESSIBLE (selection)->widget;
526   if (widget == NULL)
527     /*
528      * State is defunct
529      */
530     return 0;
531
532   combo_box = GTK_COMBO_BOX (widget);
533
534   return (gtk_combo_box_get_active (combo_box) == -1) ? 0 : 1;
535 }
536
537 static gboolean
538 gail_combo_box_is_child_selected (AtkSelection *selection,
539                                   gint         i)
540 {
541   GtkComboBox *combo_box;
542   gint j;
543   GtkWidget *widget;
544
545   widget = GTK_ACCESSIBLE (selection)->widget;
546   if (widget == NULL)
547     /*
548      * State is defunct
549      */
550     return FALSE;
551
552   combo_box = GTK_COMBO_BOX (widget);
553
554   j = gtk_combo_box_get_active (combo_box);
555
556   return (j == i);
557 }
558
559 static gboolean
560 gail_combo_box_remove_selection (AtkSelection *selection,
561                                  gint         i)
562 {
563   if (atk_selection_is_child_selected (selection, i))
564     atk_selection_clear_selection (selection);
565
566   return TRUE;
567 }
568
569 static void
570 gail_combo_box_finalize (GObject *object)
571 {
572   GailComboBox *combo_box = GAIL_COMBO_BOX (object);
573
574   g_free (combo_box->press_description);
575   g_free (combo_box->press_keybinding);
576   g_free (combo_box->name);
577   if (combo_box->action_idle_handler)
578     {
579       g_source_remove (combo_box->action_idle_handler);
580       combo_box->action_idle_handler = 0;
581     }
582   G_OBJECT_CLASS (gail_combo_box_parent_class)->finalize (object);
583 }