]> Pileus Git - ~andy/gtk/blob - modules/other/gail/gailrange.c
Deprecate widget flag: GTK_WIDGET_VISIBLE
[~andy/gtk] / modules / other / gail / gailrange.c
1 /* GAIL - The GNOME Accessibility Implementation Library
2  * Copyright 2001, 2002, 2003 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 <string.h>
23 #include <gtk/gtk.h>
24 #include <gdk/gdkkeysyms.h>
25 #include "gailrange.h"
26 #include "gailadjustment.h"
27 #include "gail-private-macros.h"
28
29 static void         gail_range_class_init        (GailRangeClass *klass);
30
31 static void         gail_range_init              (GailRange      *range);
32
33 static void         gail_range_real_initialize   (AtkObject      *obj,
34                                                   gpointer      data);
35
36 static void         gail_range_finalize          (GObject        *object);
37
38 static AtkStateSet* gail_range_ref_state_set     (AtkObject      *obj);
39
40
41 static void         gail_range_real_notify_gtk   (GObject        *obj,
42                                                   GParamSpec     *pspec);
43
44 static void         atk_value_interface_init     (AtkValueIface  *iface);
45 static void         gail_range_get_current_value (AtkValue       *obj,
46                                                   GValue         *value);
47 static void         gail_range_get_maximum_value (AtkValue       *obj,
48                                                   GValue         *value);
49 static void         gail_range_get_minimum_value (AtkValue       *obj,
50                                                   GValue         *value);
51 static gboolean     gail_range_set_current_value (AtkValue       *obj,
52                                                   const GValue   *value);
53 static void         gail_range_value_changed     (GtkAdjustment  *adjustment,
54                                                   gpointer       data);
55
56 static void         atk_action_interface_init    (AtkActionIface *iface);
57 static gboolean     gail_range_do_action        (AtkAction       *action,
58                                                 gint            i);
59 static gboolean     idle_do_action              (gpointer        data);
60 static gint         gail_range_get_n_actions    (AtkAction       *action);
61 static G_CONST_RETURN gchar* gail_range_get_description  (AtkAction    *action, 
62                                                          gint          i);
63 static G_CONST_RETURN gchar* gail_range_get_keybinding   (AtkAction     *action,
64                                                          gint            i);
65 static G_CONST_RETURN gchar* gail_range_action_get_name  (AtkAction    *action,
66                                                         gint            i);
67 static gboolean   gail_range_set_description  (AtkAction       *action,
68                                               gint            i,
69                                               const gchar     *desc);
70
71 G_DEFINE_TYPE_WITH_CODE (GailRange, gail_range, GAIL_TYPE_WIDGET,
72                          G_IMPLEMENT_INTERFACE (ATK_TYPE_ACTION, atk_action_interface_init)
73                          G_IMPLEMENT_INTERFACE (ATK_TYPE_VALUE, atk_value_interface_init))
74
75 static void      
76 gail_range_class_init           (GailRangeClass *klass)
77 {
78   GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
79   AtkObjectClass *class = ATK_OBJECT_CLASS (klass);
80   GailWidgetClass *widget_class;
81
82   widget_class = (GailWidgetClass*)klass;
83
84   widget_class->notify_gtk = gail_range_real_notify_gtk;
85
86   class->ref_state_set = gail_range_ref_state_set;
87   class->initialize = gail_range_real_initialize;
88
89   gobject_class->finalize = gail_range_finalize;
90 }
91
92 static void
93 gail_range_init (GailRange      *range)
94 {
95 }
96
97 static void
98 gail_range_real_initialize (AtkObject *obj,
99                             gpointer  data)
100 {
101   GailRange *range = GAIL_RANGE (obj);
102   GtkRange *gtk_range;
103
104   ATK_OBJECT_CLASS (gail_range_parent_class)->initialize (obj, data);
105
106   gtk_range = GTK_RANGE (data);
107   /*
108    * If a GtkAdjustment already exists for the GtkRange,
109    * create the GailAdjustment
110    */
111   if (gtk_range->adjustment)
112     {
113       range->adjustment = gail_adjustment_new (gtk_range->adjustment);
114       g_signal_connect (gtk_range->adjustment,
115                         "value-changed",
116                         G_CALLBACK (gail_range_value_changed),
117                         range);
118     }
119   else
120     range->adjustment = NULL;
121   range->activate_keybinding=NULL;
122   range->activate_description=NULL;
123   /*
124    * Assumed to GtkScale (either GtkHScale or GtkVScale)
125    */
126   obj->role = ATK_ROLE_SLIDER;
127 }
128
129 static AtkStateSet*
130 gail_range_ref_state_set (AtkObject *obj)
131 {
132   AtkStateSet *state_set;
133   GtkWidget *widget;
134   GtkRange *range;
135
136   state_set = ATK_OBJECT_CLASS (gail_range_parent_class)->ref_state_set (obj);
137   widget = GTK_ACCESSIBLE (obj)->widget;
138
139   if (widget == NULL)
140     return state_set;
141
142   range = GTK_RANGE (widget);
143
144   /*
145    * We do not generate property change for orientation change as there
146    * is no interface to change the orientation which emits a notification
147    */
148   if (range->orientation == GTK_ORIENTATION_HORIZONTAL)
149     atk_state_set_add_state (state_set, ATK_STATE_HORIZONTAL);
150   else
151     atk_state_set_add_state (state_set, ATK_STATE_VERTICAL);
152
153   return state_set;
154 }
155
156 static void      
157 atk_value_interface_init (AtkValueIface *iface)
158 {
159   iface->get_current_value = gail_range_get_current_value;
160   iface->get_maximum_value = gail_range_get_maximum_value;
161   iface->get_minimum_value = gail_range_get_minimum_value;
162   iface->set_current_value = gail_range_set_current_value;
163 }
164
165 static void      
166 gail_range_get_current_value (AtkValue          *obj,
167                               GValue            *value)
168 {
169   GailRange *range;
170
171   g_return_if_fail (GAIL_IS_RANGE (obj));
172
173   range = GAIL_RANGE (obj);
174   if (range->adjustment == NULL)
175     /*
176      * Adjustment has not been specified
177      */
178     return;
179
180   atk_value_get_current_value (ATK_VALUE (range->adjustment), value);
181 }
182
183 static void      
184 gail_range_get_maximum_value (AtkValue          *obj,
185                               GValue            *value)
186 {
187   GailRange *range;
188
189   g_return_if_fail (GAIL_IS_RANGE (obj));
190
191   range = GAIL_RANGE (obj);
192   if (range->adjustment == NULL)
193     /*
194      * Adjustment has not been specified
195      */
196     return;
197
198   atk_value_get_maximum_value (ATK_VALUE (range->adjustment), value);
199 }
200
201 static void      
202 gail_range_get_minimum_value (AtkValue          *obj,
203                               GValue            *value)
204 {
205   GailRange *range;
206
207   g_return_if_fail (GAIL_IS_RANGE (obj));
208
209   range = GAIL_RANGE (obj);
210   if (range->adjustment == NULL)
211     /*
212      * Adjustment has not been specified
213      */
214     return;
215
216   atk_value_get_minimum_value (ATK_VALUE (range->adjustment), value);
217 }
218
219 static gboolean  gail_range_set_current_value (AtkValue         *obj,
220                                                const GValue     *value)
221 {
222   GtkWidget *widget;
223
224   g_return_val_if_fail (GAIL_IS_RANGE (obj), FALSE);
225
226   widget = GTK_ACCESSIBLE (obj)->widget;
227   if (widget == NULL)
228     return FALSE;
229
230   if (G_VALUE_HOLDS_DOUBLE (value))
231     {
232       GtkRange *range = GTK_RANGE (widget);
233       gdouble new_value;
234
235       new_value = g_value_get_double (value);
236       gtk_range_set_value (range, new_value);
237       return TRUE;
238     }
239   else
240     {
241       return FALSE;
242     }
243 }
244
245 static void
246 gail_range_finalize (GObject            *object)
247 {
248   GailRange *range = GAIL_RANGE (object);
249
250   if (range->adjustment)
251     {
252       /*
253        * The GtkAdjustment may live on so we need to dicsonnect the
254        * signal handler
255        */
256       if (GAIL_ADJUSTMENT (range->adjustment)->adjustment)
257         {
258           g_signal_handlers_disconnect_by_func (GAIL_ADJUSTMENT (range->adjustment)->adjustment,
259                                                 (void *)gail_range_value_changed,
260                                                 range);
261         }
262       g_object_unref (range->adjustment);
263       range->adjustment = NULL;
264     }
265   range->activate_keybinding=NULL;
266   range->activate_description=NULL;
267   if (range->action_idle_handler)
268    {
269     g_source_remove (range->action_idle_handler);
270     range->action_idle_handler = 0;
271    }
272
273   G_OBJECT_CLASS (gail_range_parent_class)->finalize (object);
274 }
275
276
277 static void
278 gail_range_real_notify_gtk (GObject           *obj,
279                             GParamSpec        *pspec)
280 {
281   GtkWidget *widget = GTK_WIDGET (obj);
282   GailRange *range = GAIL_RANGE (gtk_widget_get_accessible (widget));
283
284   if (strcmp (pspec->name, "adjustment") == 0)
285     {
286       /*
287        * Get rid of the GailAdjustment for the GtkAdjustment
288        * which was associated with the range.
289        */
290       if (range->adjustment)
291         {
292           g_object_unref (range->adjustment);
293           range->adjustment = NULL;
294         }
295       /*
296        * Create the GailAdjustment when notify for "adjustment" property
297        * is received
298        */
299       range->adjustment = gail_adjustment_new (GTK_RANGE (widget)->adjustment);
300       g_signal_connect (GTK_RANGE (widget)->adjustment,
301                         "value-changed",
302                         G_CALLBACK (gail_range_value_changed),
303                         range);
304     }
305   else
306     GAIL_WIDGET_CLASS (gail_range_parent_class)->notify_gtk (obj, pspec);
307 }
308
309 static void
310 gail_range_value_changed (GtkAdjustment    *adjustment,
311                           gpointer         data)
312 {
313   GailRange *range;
314
315   g_return_if_fail (adjustment != NULL);
316   gail_return_if_fail (data != NULL);
317
318   range = GAIL_RANGE (data);
319
320   g_object_notify (G_OBJECT (range), "accessible-value");
321 }
322
323 static void
324 atk_action_interface_init (AtkActionIface *iface)
325 {
326   iface->do_action = gail_range_do_action;
327   iface->get_n_actions = gail_range_get_n_actions;
328   iface->get_description = gail_range_get_description;
329   iface->get_keybinding = gail_range_get_keybinding;
330   iface->get_name = gail_range_action_get_name;
331   iface->set_description = gail_range_set_description;
332 }
333
334 static gboolean
335 gail_range_do_action (AtkAction *action,
336                      gint      i)
337 {
338   GailRange *range;
339   GtkWidget *widget;
340   gboolean return_value = TRUE;
341
342   range = GAIL_RANGE (action);
343   widget = GTK_ACCESSIBLE (action)->widget;
344   if (widget == NULL)
345     /*
346      * State is defunct
347      */
348     return FALSE;
349   if (!gtk_widget_get_sensitive (widget) || !gtk_widget_get_visible (widget))
350     return FALSE;
351   if(i==0)
352    {
353     if (range->action_idle_handler)
354       return_value = FALSE;
355     else
356       range->action_idle_handler = gdk_threads_add_idle (idle_do_action, range);
357    }
358   else
359      return_value = FALSE;
360   return return_value;
361 }
362
363 static gboolean
364 idle_do_action (gpointer data)
365 {
366   GailRange *range;
367   GtkWidget *widget;
368
369   range = GAIL_RANGE (data);
370   range->action_idle_handler = 0;
371   widget = GTK_ACCESSIBLE (range)->widget;
372   if (widget == NULL /* State is defunct */ ||
373      !gtk_widget_get_sensitive (widget) || !gtk_widget_get_visible (widget))
374     return FALSE;
375
376    gtk_widget_activate (widget);
377
378    return FALSE;
379 }
380
381 static gint
382 gail_range_get_n_actions (AtkAction *action)
383 {
384     return 1;
385 }
386
387 static G_CONST_RETURN gchar*
388 gail_range_get_description (AtkAction *action,
389                               gint      i)
390 {
391   GailRange *range;
392   G_CONST_RETURN gchar *return_value;
393
394   range = GAIL_RANGE (action);
395   if (i==0)
396    return_value = range->activate_description;
397   else
398    return_value = NULL;
399   return return_value;
400 }
401
402 static G_CONST_RETURN gchar*
403 gail_range_get_keybinding (AtkAction *action,
404                               gint      i)
405 {
406   GailRange *range;
407   gchar *return_value = NULL;
408   range = GAIL_RANGE (action);
409   if(i==0)
410    {
411     GtkWidget *widget;
412     GtkWidget *label;
413     AtkRelationSet *set;
414     AtkRelation *relation;
415     GPtrArray *target;
416     gpointer target_object;
417     guint key_val;
418
419     range = GAIL_RANGE (action);
420     widget = GTK_ACCESSIBLE (range)->widget;
421     if (widget == NULL)
422        return NULL;
423     set = atk_object_ref_relation_set (ATK_OBJECT (action));
424
425     if (!set)
426       return NULL;
427     label = NULL;
428     relation = atk_relation_set_get_relation_by_type (set, ATK_RELATION_LABELLED_BY);    
429     if (relation)
430      {
431       target = atk_relation_get_target (relation);
432       target_object = g_ptr_array_index (target, 0);
433       if (GTK_IS_ACCESSIBLE (target_object))
434          label = GTK_ACCESSIBLE (target_object)->widget;
435      }
436     g_object_unref (set);
437     if (GTK_IS_LABEL (label))
438      {
439       key_val = gtk_label_get_mnemonic_keyval (GTK_LABEL (label));
440       if (key_val != GDK_VoidSymbol)
441          return_value = gtk_accelerator_name (key_val, GDK_MOD1_MASK);
442       }
443     g_free (range->activate_keybinding);
444     range->activate_keybinding = return_value;
445    }
446   return return_value;
447 }
448
449 static G_CONST_RETURN gchar*
450 gail_range_action_get_name (AtkAction *action,
451                            gint      i)
452 {
453   G_CONST_RETURN gchar *return_value;
454   
455   if (i==0)
456    return_value = "activate";
457   else
458    return_value = NULL;
459
460   return return_value;
461 }
462
463 static gboolean
464 gail_range_set_description (AtkAction      *action,
465                            gint           i,
466                            const gchar    *desc)
467 {
468   GailRange *range;
469   gchar **value;
470
471   range = GAIL_RANGE (action);
472   
473   if (i==0)
474    value = &range->activate_description;
475   else
476    value = NULL;
477
478   if (value)
479    {
480     g_free (*value);
481     *value = g_strdup (desc);
482     return TRUE;
483    }
484   else
485    return FALSE;
486 }
487
488