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