]> Pileus Git - ~andy/gtk/blob - gtk/a11y/gailscale.c
gail: No need to include modules/other in CFLAGS anymore
[~andy/gtk] / gtk / a11y / gailscale.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 <string.h>
23 #include <gtk/gtk.h>
24 #include "gailscale.h"
25 #include <libgail-util/gailmisc.h>
26
27 static void         gail_scale_class_init        (GailScaleClass *klass);
28
29 static void         gail_scale_init              (GailScale      *scale);
30
31 static void         gail_scale_real_initialize   (AtkObject      *obj,
32                                                   gpointer      data);
33 static void         gail_scale_notify            (GObject       *obj,
34                                                   GParamSpec    *pspec);
35 static void         gail_scale_finalize          (GObject        *object);
36
37 /* atktext.h */ 
38 static void         atk_text_interface_init        (AtkTextIface      *iface);
39
40 static gchar*       gail_scale_get_text            (AtkText           *text,
41                                                     gint              start_pos,
42                                                     gint              end_pos);
43 static gunichar     gail_scale_get_character_at_offset
44                                                    (AtkText           *text,
45                                                     gint              offset);
46 static gchar*       gail_scale_get_text_before_offset
47                                                    (AtkText           *text,
48                                                     gint              offset,
49                                                     AtkTextBoundary   boundary_type,
50                                                     gint              *start_offset,
51                                                     gint              *end_offset);
52 static gchar*       gail_scale_get_text_at_offset  (AtkText           *text,
53                                                     gint              offset,
54                                                     AtkTextBoundary   boundary_type,
55                                                     gint              *start_offset,
56                                                     gint              *end_offset);
57 static gchar*      gail_scale_get_text_after_offset
58                                                    (AtkText           *text,
59                                                     gint              offset,
60                                                     AtkTextBoundary   boundary_type,
61                                                     gint              *start_offset,
62                                                     gint              *end_offset);
63 static gint        gail_scale_get_character_count  (AtkText           *text);
64 static void        gail_scale_get_character_extents
65                                                    (AtkText           *text,
66                                                     gint              offset,
67                                                     gint              *x,
68                                                     gint              *y,
69                                                     gint              *width,
70                                                     gint              *height,
71                                                     AtkCoordType      coords);
72 static gint        gail_scale_get_offset_at_point  (AtkText           *text,
73                                                     gint              x,
74                                                     gint              y,
75                                                     AtkCoordType      coords);
76 static AtkAttributeSet* gail_scale_get_run_attributes 
77                                                    (AtkText           *text,
78                                                     gint              offset,
79                                                     gint              *start_offset,
80                                                     gint              *end_offset);
81 static AtkAttributeSet* gail_scale_get_default_attributes
82                                                    (AtkText           *text);
83
84 G_DEFINE_TYPE_WITH_CODE (GailScale, gail_scale, GAIL_TYPE_RANGE,
85                          G_IMPLEMENT_INTERFACE (ATK_TYPE_TEXT, atk_text_interface_init))
86
87 static void      
88 gail_scale_class_init (GailScaleClass *klass)
89 {
90   GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
91   AtkObjectClass *class = ATK_OBJECT_CLASS (klass);
92
93   class->initialize = gail_scale_real_initialize;
94
95   gobject_class->finalize = gail_scale_finalize;
96   gobject_class->notify = gail_scale_notify;
97 }
98
99 static void
100 gail_scale_init (GailScale      *scale)
101 {
102 }
103
104 static void
105 gail_scale_real_initialize (AtkObject *obj,
106                             gpointer  data)
107 {
108   GailScale *gail_scale;
109   const gchar *txt;
110   PangoLayout *layout;
111
112   ATK_OBJECT_CLASS (gail_scale_parent_class)->initialize (obj, data);
113
114   gail_scale = GAIL_SCALE (obj);
115   gail_scale->textutil = gail_text_util_new ();
116
117   layout = gtk_scale_get_layout (GTK_SCALE (data));
118   if (layout)
119     {
120       txt = pango_layout_get_text (layout);
121       if (txt)
122         {
123           gail_text_util_text_setup (gail_scale->textutil, txt);
124         }
125     }
126 }
127
128 static void
129 gail_scale_finalize (GObject *object)
130 {
131   GailScale *scale = GAIL_SCALE (object);
132
133   g_object_unref (scale->textutil);
134   G_OBJECT_CLASS (gail_scale_parent_class)->finalize (object);
135
136 }
137
138 static void
139 gail_scale_notify (GObject    *obj,
140                    GParamSpec *pspec)
141 {
142   GailScale *scale = GAIL_SCALE (obj);
143
144   if (strcmp (pspec->name, "accessible-value") == 0)
145     {
146       GtkWidget *widget;
147
148       widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (obj));
149       if (widget)
150         {
151           GtkScale *gtk_scale;
152           PangoLayout *layout;
153           const gchar *txt;
154
155           gtk_scale = GTK_SCALE (widget);
156           layout = gtk_scale_get_layout (gtk_scale);
157           if (layout)
158             {
159               txt = pango_layout_get_text (layout);
160               if (txt)
161                 {
162                   g_signal_emit_by_name (obj, "text_changed::delete", 0,
163                                          gtk_text_buffer_get_char_count (scale->textutil->buffer));
164                   gail_text_util_text_setup (scale->textutil, txt);
165                   g_signal_emit_by_name (obj, "text_changed::insert", 0,
166                                          g_utf8_strlen (txt, -1));
167                 }
168             }
169         }
170     }
171   G_OBJECT_CLASS (gail_scale_parent_class)->notify (obj, pspec);
172 }
173
174 /* atktext.h */
175
176 static void
177 atk_text_interface_init (AtkTextIface *iface)
178 {
179   iface->get_text = gail_scale_get_text;
180   iface->get_character_at_offset = gail_scale_get_character_at_offset;
181   iface->get_text_before_offset = gail_scale_get_text_before_offset;
182   iface->get_text_at_offset = gail_scale_get_text_at_offset;
183   iface->get_text_after_offset = gail_scale_get_text_after_offset;
184   iface->get_character_count = gail_scale_get_character_count;
185   iface->get_character_extents = gail_scale_get_character_extents;
186   iface->get_offset_at_point = gail_scale_get_offset_at_point;
187   iface->get_run_attributes = gail_scale_get_run_attributes;
188   iface->get_default_attributes = gail_scale_get_default_attributes;
189 }
190
191 static gchar*
192 gail_scale_get_text (AtkText *text,
193                      gint    start_pos,
194                      gint    end_pos)
195 {
196   GtkWidget *widget;
197   GailScale *scale;
198
199   widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (text));
200   if (widget == NULL)
201     /* State is defunct */
202     return NULL;
203
204   scale = GAIL_SCALE (text);
205   return gail_text_util_get_substring (scale->textutil, 
206                                        start_pos, end_pos);
207 }
208
209 static gchar*
210 gail_scale_get_text_before_offset (AtkText         *text,
211                                    gint            offset,
212                                    AtkTextBoundary boundary_type,
213                                    gint            *start_offset,
214                                    gint            *end_offset)
215 {
216   GtkWidget *widget;
217   GailScale *scale;
218   PangoLayout *layout;
219   gchar *txt;
220   
221   widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (text));
222   
223   if (widget == NULL)
224     /* State is defunct */
225     return NULL;
226   
227   scale = GAIL_SCALE (text);
228   layout = gtk_scale_get_layout (GTK_SCALE (widget));
229   if (layout)
230     {
231       txt =  gail_text_util_get_text (scale->textutil,
232                            layout, GAIL_BEFORE_OFFSET, 
233                            boundary_type, offset, start_offset, end_offset); 
234     }
235   else
236     txt = NULL;
237
238   return txt;
239 }
240
241 static gchar*
242 gail_scale_get_text_at_offset (AtkText         *text,
243                                gint            offset,
244                                AtkTextBoundary boundary_type,
245                                gint            *start_offset,
246                                gint            *end_offset)
247 {
248   GtkWidget *widget;
249   GailScale *scale;
250   PangoLayout *layout;
251   gchar *txt;
252  
253   widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (text));
254   
255   if (widget == NULL)
256     /* State is defunct */
257     return NULL;
258   
259   scale = GAIL_SCALE (text);
260   layout = gtk_scale_get_layout (GTK_SCALE (widget));
261   if (layout)
262     {
263       txt =  gail_text_util_get_text (scale->textutil,
264                               layout, GAIL_AT_OFFSET, 
265                               boundary_type, offset, start_offset, end_offset);
266     }
267   else
268     txt = NULL;
269
270   return txt;
271 }
272
273 static gchar*
274 gail_scale_get_text_after_offset (AtkText         *text,
275                                   gint            offset,
276                                   AtkTextBoundary boundary_type,
277                                   gint            *start_offset,
278                                   gint            *end_offset)
279 {
280   GtkWidget *widget;
281   GailScale *scale;
282   PangoLayout *layout;
283   gchar *txt;
284
285   widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (text));
286   
287   if (widget == NULL)
288     /* State is defunct */
289     return NULL;
290   
291   scale = GAIL_SCALE (text);
292   layout = gtk_scale_get_layout (GTK_SCALE (widget));
293   if (layout)
294     {
295       txt =  gail_text_util_get_text (scale->textutil,
296                               layout, GAIL_AFTER_OFFSET, 
297                               boundary_type, offset, start_offset, end_offset);
298     }
299   else
300     txt = NULL;
301
302   return txt;
303 }
304
305 static gint
306 gail_scale_get_character_count (AtkText *text)
307 {
308   GtkWidget *widget;
309   GailScale *scale;
310
311   widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (text));
312   if (widget == NULL)
313     /* State is defunct */
314     return 0;
315
316   scale = GAIL_SCALE (text);
317   if (scale->textutil->buffer)
318     return gtk_text_buffer_get_char_count (scale->textutil->buffer);
319   else
320     return 0;
321
322 }
323
324 static void
325 gail_scale_get_character_extents (AtkText      *text,
326                                   gint         offset,
327                                   gint         *x,
328                                   gint         *y,
329                                   gint         *width,
330                                   gint         *height,
331                                   AtkCoordType coords)
332 {
333   GtkWidget *widget;
334   GtkScale *scale;
335   PangoRectangle char_rect;
336   PangoLayout *layout;
337   gint index, x_layout, y_layout;
338   const gchar *scale_text;
339  
340   widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (text));
341
342   if (widget == NULL)
343     /* State is defunct */
344     return;
345
346   scale = GTK_SCALE (widget);
347   layout = gtk_scale_get_layout (scale);
348   if (!layout)
349     return;
350   scale_text = pango_layout_get_text (layout);
351   if (!scale_text)
352     return;
353   index = g_utf8_offset_to_pointer (scale_text, offset) - scale_text;
354   gtk_scale_get_layout_offsets (scale, &x_layout, &y_layout);
355   pango_layout_index_to_pos (layout, index, &char_rect);
356   gail_misc_get_extents_from_pango_rectangle (widget, &char_rect, 
357                     x_layout, y_layout, x, y, width, height, coords);
358
359
360 static gint 
361 gail_scale_get_offset_at_point (AtkText      *text,
362                                 gint         x,
363                                 gint         y,
364                                 AtkCoordType coords)
365
366   GtkWidget *widget;
367   GtkScale *scale;
368   PangoLayout *layout;
369   gint index, x_layout, y_layout;
370   const gchar *scale_text;
371
372   widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (text));
373   if (widget == NULL)
374     /* State is defunct */
375     return -1;
376
377   scale = GTK_SCALE (widget);
378   layout = gtk_scale_get_layout (scale);
379   if (!layout)
380     return -1;
381   scale_text = pango_layout_get_text (layout);
382   if (!scale_text)
383     return -1;
384   
385   gtk_scale_get_layout_offsets (scale, &x_layout, &y_layout);
386   index = gail_misc_get_index_at_point_in_layout (widget, 
387                                               layout, 
388                                               x_layout, y_layout, x, y, coords);
389   if (index == -1)
390     {
391       if (coords == ATK_XY_WINDOW || coords == ATK_XY_SCREEN)
392         index = g_utf8_strlen (scale_text, -1);
393     }
394   else
395     index = g_utf8_pointer_to_offset (scale_text, scale_text + index);  
396
397   return index;
398 }
399
400 static AtkAttributeSet*
401 gail_scale_get_run_attributes (AtkText *text,
402                                gint    offset,
403                                gint    *start_offset,
404                                gint    *end_offset)
405 {
406   GtkWidget *widget;
407   GtkScale *scale;
408   AtkAttributeSet *at_set = NULL;
409   GtkTextDirection dir;
410   PangoLayout *layout;
411   const gchar *scale_text;
412
413   widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (text));
414   if (widget == NULL)
415     /* State is defunct */
416     return NULL;
417
418   scale = GTK_SCALE (widget);
419
420   layout = gtk_scale_get_layout (scale);
421   if (!layout)
422     return at_set;
423   scale_text = pango_layout_get_text (layout);
424   if (!scale_text)
425     return at_set;
426
427   dir = gtk_widget_get_direction (widget);
428   if (dir == GTK_TEXT_DIR_RTL)
429     {
430       at_set = gail_misc_add_attribute (at_set, 
431                                         ATK_TEXT_ATTR_DIRECTION,
432      g_strdup (atk_text_attribute_get_value (ATK_TEXT_ATTR_DIRECTION, dir)));
433     }
434
435   at_set = gail_misc_layout_get_run_attributes (at_set,
436                                                 layout,
437                                                 (gchar *)scale_text,
438                                                 offset,
439                                                 start_offset,
440                                                 end_offset);
441   return at_set;
442 }
443
444 static AtkAttributeSet*
445 gail_scale_get_default_attributes (AtkText *text)
446 {
447   GtkWidget *widget;
448   AtkAttributeSet *at_set = NULL;
449   PangoLayout *layout;
450
451   widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (text));
452   if (widget == NULL)
453     /* State is defunct */
454     return NULL;
455
456   layout = gtk_scale_get_layout (GTK_SCALE (widget));
457   if (layout)
458     {
459       at_set = gail_misc_get_default_attributes (at_set,
460                                                  layout,
461                                                  widget);
462     }
463   return at_set;
464 }
465
466 static gunichar 
467 gail_scale_get_character_at_offset (AtkText *text,
468                                     gint    offset)
469 {
470   GtkWidget *widget;
471   GtkScale *scale;
472   PangoLayout *layout;
473   const gchar *string;
474   gchar *index;
475   gunichar c;
476
477   widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (text));
478   if (widget == NULL)
479     /* State is defunct */
480     return '\0';
481
482   scale = GTK_SCALE (widget);
483
484   layout = gtk_scale_get_layout (scale);
485   if (!layout)
486     return '\0';
487   string = pango_layout_get_text (layout);
488   if (offset >= g_utf8_strlen (string, -1))
489     c = '\0';
490   else
491     {
492       index = g_utf8_offset_to_pointer (string, offset);
493
494       c = g_utf8_get_char (index);
495     }
496
497   return c;
498 }