]> Pileus Git - ~andy/gtk/blob - modules/other/gail/libgail-util/gailmisc.c
Include "config.h" instead of <config.h> Command used: find -name
[~andy/gtk] / modules / other / gail / libgail-util / gailmisc.c
1 /* GAIL - The GNOME Accessibility Implementation Library
2  * Copyright 2001 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 Library 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  * Library General Public License for more details.
13  *
14  * You should have received a copy of the GNU Library 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 <stdlib.h>
23 #include <gtk/gtk.h>
24 #include "gailmisc.h"
25
26 /* IMPORTANT!!! This source file does NOT contain the implementation
27  * code for AtkUtil - for that code, please see gail/gail.c.
28  */
29
30 /**
31  * gail_misc_get_extents_from_pango_rectangle:
32  * @widget: The widget that contains the PangoLayout, that contains
33  *   the PangoRectangle
34  * @char_rect: The #PangoRectangle from which to calculate extents
35  * @x_layout: The x-offset at which the widget displays the
36  *   PangoLayout that contains the PangoRectangle, relative to @widget
37  * @y_layout: The y-offset at which the widget displays the
38  *   PangoLayout that contains the PangoRectangle, relative to @widget
39  * @x: The x-position of the #PangoRectangle relative to @coords
40  * @y: The y-position of the #PangoRectangle relative to @coords
41  * @width: The width of the #PangoRectangle
42  * @height: The  height of the #PangoRectangle
43  * @coords: An #AtkCoordType enumeration
44  *
45  * Gets the extents of @char_rect in device coordinates,
46  * relative to either top-level window or screen coordinates as
47  * specified by @coords.
48  **/
49 void
50 gail_misc_get_extents_from_pango_rectangle (GtkWidget      *widget,
51                                             PangoRectangle *char_rect,
52                                             gint           x_layout,
53                                             gint           y_layout,
54                                             gint           *x,
55                                             gint           *y,
56                                             gint           *width,
57                                             gint           *height,
58                                             AtkCoordType   coords)
59 {
60   gint x_window, y_window, x_toplevel, y_toplevel;
61
62   gail_misc_get_origins (widget, &x_window, &y_window, 
63                          &x_toplevel, &y_toplevel);
64
65   *x = (char_rect->x / PANGO_SCALE) + x_layout + x_window;
66   *y = (char_rect->y / PANGO_SCALE) + y_layout + y_window;
67   if (coords == ATK_XY_WINDOW)
68     {
69       *x -= x_toplevel;
70       *y -= y_toplevel;
71     }
72   else if (coords != ATK_XY_SCREEN)
73     {
74       *x = 0;
75       *y = 0;
76       *height = 0;
77       *width = 0;
78       return;
79     }
80   *height = char_rect->height / PANGO_SCALE;
81   *width = char_rect->width / PANGO_SCALE;
82
83   return;
84 }
85
86 /**
87  * gail_misc_get_index_at_point_in_layout:
88  * @widget: A #GtkWidget
89  * @layout: The #PangoLayout from which to get the index at the
90  *   specified point.
91  * @x_layout: The x-offset at which the widget displays the
92  *   #PangoLayout, relative to @widget
93  * @y_layout: The y-offset at which the widget displays the
94  *   #PangoLayout, relative to @widget
95  * @x: The x-coordinate relative to @coords at which to
96  *   calculate the index
97  * @y: The y-coordinate relative to @coords at which to
98  *   calculate the index
99  * @coords: An #AtkCoordType enumeration
100  *
101  * Gets the byte offset at the specified @x and @y in a #PangoLayout.
102  *
103  * Returns: the byte offset at the specified @x and @y in a
104  *   #PangoLayout
105  **/
106 gint
107 gail_misc_get_index_at_point_in_layout (GtkWidget   *widget,
108                                         PangoLayout *layout,
109                                         gint        x_layout,
110                                         gint        y_layout,
111                                         gint        x,
112                                         gint        y,
113                                         AtkCoordType coords)
114 {
115   gint index, x_window, y_window, x_toplevel, y_toplevel;
116   gint x_temp, y_temp;
117   gboolean ret;
118
119   gail_misc_get_origins (widget, &x_window, &y_window, 
120                          &x_toplevel, &y_toplevel);
121   x_temp =  x - x_layout - x_window;
122   y_temp =  y - y_layout - y_window;
123   if (coords == ATK_XY_WINDOW)
124     {
125       x_temp += x_toplevel;  
126       y_temp += y_toplevel;
127     }
128   else if (coords != ATK_XY_SCREEN)
129     return -1;
130
131   ret = pango_layout_xy_to_index (layout, 
132                                   x_temp * PANGO_SCALE,
133                                   y_temp * PANGO_SCALE,
134                                   &index, NULL);
135   if (!ret)
136     {
137       if (x_temp < 0 || y_temp < 0)
138         index = 0;
139       else
140         index = -1; 
141     }
142   return index;
143 }
144
145 /**
146  * gail_misc_add_attribute:
147  * @attrib_set: The #AtkAttributeSet to add the attribute to
148  * @attr: The AtkTextAttrribute which identifies the attribute to be added
149  * @value: The attribute value
150  *
151  * Creates an #AtkAttribute from @attr and @value, and adds it
152  * to @attrib_set. 
153  *
154  * Returns: A pointer to the new #AtkAttributeSet.
155  **/
156 AtkAttributeSet*
157 gail_misc_add_attribute (AtkAttributeSet *attrib_set,
158                          AtkTextAttribute attr,
159                          gchar           *value)
160 {
161   AtkAttributeSet *return_set;
162   AtkAttribute *at = g_malloc (sizeof (AtkAttribute));
163   at->name = g_strdup (atk_text_attribute_get_name (attr));
164   at->value = value;
165   return_set = g_slist_prepend(attrib_set, at);
166   return return_set;
167 }
168
169 /**
170  * gail_misc_layout_get_run_attributes:
171  * @attrib_set: The #AtkAttributeSet to add the attribute to
172  * @layout: The PangoLayout from which the attributes will be obtained
173  * @text: The text 
174  * @offset: The offset at which the attributes are required
175  * @start_offset: The start offset of the current run
176  * @end_offset: The end offset of the current run
177  *
178  * Adds the attributes for the run starting at offset to the specified
179  * attribute set.
180  *
181  * Returns: A pointer to the #AtkAttributeSet.
182  **/
183 AtkAttributeSet* 
184 gail_misc_layout_get_run_attributes (AtkAttributeSet *attrib_set,
185                                      PangoLayout     *layout,
186                                      gchar           *text,
187                                      gint            offset,
188                                      gint            *start_offset,
189                                      gint            *end_offset)
190 {
191   PangoAttrIterator *iter;
192   PangoAttrList *attr;  
193   PangoAttrString *pango_string;
194   PangoAttrInt *pango_int;
195   PangoAttrColor *pango_color;
196   PangoAttrLanguage *pango_lang;
197   PangoAttrFloat *pango_float;
198   gint index, start_index, end_index;
199   gboolean is_next = TRUE;
200   gchar *value = NULL;
201   glong len;
202
203   len = g_utf8_strlen (text, -1);
204   /* Grab the attributes of the PangoLayout, if any */
205   if ((attr = pango_layout_get_attributes (layout)) == NULL)
206     {
207       *start_offset = 0;
208       *end_offset = len;
209       return attrib_set;
210     }
211   iter = pango_attr_list_get_iterator (attr);
212   /* Get invariant range offsets */
213   /* If offset out of range, set offset in range */
214   if (offset > len)
215     offset = len;
216   else if (offset < 0)
217     offset = 0;
218
219   index = g_utf8_offset_to_pointer (text, offset) - text;
220   pango_attr_iterator_range (iter, &start_index, &end_index);
221   while (is_next)
222     {
223       if (index >= start_index && index < end_index)
224         {
225           *start_offset = g_utf8_pointer_to_offset (text, 
226                                                     text + start_index);  
227           if (end_index == G_MAXINT)
228           /* Last iterator */
229             end_index = len;
230       
231           *end_offset = g_utf8_pointer_to_offset (text, 
232                                                   text + end_index);  
233           break;
234         }  
235       is_next = pango_attr_iterator_next (iter);
236       pango_attr_iterator_range (iter, &start_index, &end_index);
237     }
238   /* Get attributes */
239   if ((pango_string = (PangoAttrString*) pango_attr_iterator_get (iter, 
240                                    PANGO_ATTR_FAMILY)) != NULL)
241     {
242       value = g_strdup_printf("%s", pango_string->value);
243       attrib_set = gail_misc_add_attribute (attrib_set, 
244                                             ATK_TEXT_ATTR_FAMILY_NAME, 
245                                             value);
246     } 
247   if ((pango_int = (PangoAttrInt*) pango_attr_iterator_get (iter, 
248                                    PANGO_ATTR_STYLE)) != NULL)
249     {
250       attrib_set = gail_misc_add_attribute (attrib_set, 
251                                             ATK_TEXT_ATTR_STYLE, 
252       g_strdup (atk_text_attribute_get_value (ATK_TEXT_ATTR_STYLE, pango_int->value)));
253     } 
254   if ((pango_int = (PangoAttrInt*) pango_attr_iterator_get (iter, 
255                                    PANGO_ATTR_WEIGHT)) != NULL)
256     {
257       value = g_strdup_printf("%i", pango_int->value);
258       attrib_set = gail_misc_add_attribute (attrib_set, 
259                                             ATK_TEXT_ATTR_WEIGHT, 
260                                             value);
261     } 
262   if ((pango_int = (PangoAttrInt*) pango_attr_iterator_get (iter, 
263                                    PANGO_ATTR_VARIANT)) != NULL)
264     {
265       attrib_set = gail_misc_add_attribute (attrib_set, 
266                                             ATK_TEXT_ATTR_VARIANT, 
267        g_strdup (atk_text_attribute_get_value (ATK_TEXT_ATTR_VARIANT, pango_int->value)));
268     } 
269   if ((pango_int = (PangoAttrInt*) pango_attr_iterator_get (iter, 
270                                    PANGO_ATTR_STRETCH)) != NULL)
271     {
272       attrib_set = gail_misc_add_attribute (attrib_set, 
273                                             ATK_TEXT_ATTR_STRETCH, 
274        g_strdup (atk_text_attribute_get_value (ATK_TEXT_ATTR_STRETCH, pango_int->value)));
275     } 
276   if ((pango_int = (PangoAttrInt*) pango_attr_iterator_get (iter, 
277                                    PANGO_ATTR_SIZE)) != NULL)
278     {
279       value = g_strdup_printf("%i", pango_int->value / PANGO_SCALE);
280       attrib_set = gail_misc_add_attribute (attrib_set, 
281                                             ATK_TEXT_ATTR_SIZE,
282                                             value);
283     } 
284   if ((pango_int = (PangoAttrInt*) pango_attr_iterator_get (iter, 
285                                    PANGO_ATTR_UNDERLINE)) != NULL)
286     {
287       attrib_set = gail_misc_add_attribute (attrib_set, 
288                                             ATK_TEXT_ATTR_UNDERLINE, 
289        g_strdup (atk_text_attribute_get_value (ATK_TEXT_ATTR_UNDERLINE, pango_int->value)));
290     } 
291   if ((pango_int = (PangoAttrInt*) pango_attr_iterator_get (iter, 
292                                    PANGO_ATTR_STRIKETHROUGH)) != NULL)
293     {
294       attrib_set = gail_misc_add_attribute (attrib_set, 
295                                             ATK_TEXT_ATTR_STRIKETHROUGH, 
296        g_strdup (atk_text_attribute_get_value (ATK_TEXT_ATTR_STRIKETHROUGH, pango_int->value)));
297     } 
298   if ((pango_int = (PangoAttrInt*) pango_attr_iterator_get (iter, 
299                                    PANGO_ATTR_RISE)) != NULL)
300     {
301       value = g_strdup_printf("%i", pango_int->value);
302       attrib_set = gail_misc_add_attribute (attrib_set, 
303                                             ATK_TEXT_ATTR_RISE,
304                                             value);
305     } 
306   if ((pango_lang = (PangoAttrLanguage*) pango_attr_iterator_get (iter, 
307                                    PANGO_ATTR_LANGUAGE)) != NULL)
308     {
309       value = g_strdup( pango_language_to_string( pango_lang->value));
310       attrib_set = gail_misc_add_attribute (attrib_set, 
311                                             ATK_TEXT_ATTR_LANGUAGE, 
312                                             value);
313     } 
314   if ((pango_float = (PangoAttrFloat*) pango_attr_iterator_get (iter, 
315                                    PANGO_ATTR_SCALE)) != NULL)
316     {
317       value = g_strdup_printf("%g", pango_float->value);
318       attrib_set = gail_misc_add_attribute (attrib_set, 
319                                             ATK_TEXT_ATTR_SCALE, 
320                                             value);
321     } 
322   if ((pango_color = (PangoAttrColor*) pango_attr_iterator_get (iter, 
323                                     PANGO_ATTR_FOREGROUND)) != NULL)
324     {
325       value = g_strdup_printf ("%u,%u,%u", 
326                                pango_color->color.red, 
327                                pango_color->color.green, 
328                                pango_color->color.blue);
329       attrib_set = gail_misc_add_attribute (attrib_set, 
330                                             ATK_TEXT_ATTR_FG_COLOR, 
331                                             value);
332     } 
333   if ((pango_color = (PangoAttrColor*) pango_attr_iterator_get (iter, 
334                                      PANGO_ATTR_BACKGROUND)) != NULL)
335     {
336       value = g_strdup_printf ("%u,%u,%u", 
337                                pango_color->color.red, 
338                                pango_color->color.green, 
339                                pango_color->color.blue);
340       attrib_set = gail_misc_add_attribute (attrib_set, 
341                                             ATK_TEXT_ATTR_BG_COLOR, 
342                                             value);
343     } 
344   pango_attr_iterator_destroy (iter);
345   return attrib_set;
346 }
347
348 /**
349  * gail_misc_get_default_attributes:
350  * @attrib_set: The #AtkAttributeSet to add the attribute to
351  * @layout: The PangoLayout from which the attributes will be obtained
352  * @widget: The GtkWidget for which the default attributes are required.
353  *
354  * Adds the default attributes to the specified attribute set.
355  *
356  * Returns: A pointer to the #AtkAttributeSet.
357  **/
358 AtkAttributeSet* 
359 gail_misc_get_default_attributes (AtkAttributeSet *attrib_set,
360                                   PangoLayout     *layout,
361                                   GtkWidget       *widget)
362 {
363   PangoContext *context;
364   GtkStyle *style_value;
365   gint int_value;
366   PangoWrapMode mode;
367
368   attrib_set = gail_misc_add_attribute (attrib_set, 
369                                         ATK_TEXT_ATTR_DIRECTION,
370      g_strdup (atk_text_attribute_get_value (ATK_TEXT_ATTR_DIRECTION, 
371                                         gtk_widget_get_direction (widget))));
372
373   context = pango_layout_get_context (layout);
374   if (context)
375     {
376       PangoLanguage* language;
377       PangoFontDescription* font;
378
379       language = pango_context_get_language (context);
380       if (language)
381         {
382           attrib_set = gail_misc_add_attribute (attrib_set,
383                                                 ATK_TEXT_ATTR_LANGUAGE,
384                       g_strdup (pango_language_to_string (language)));
385         }
386       font = pango_context_get_font_description (context);
387       if (font)
388         {
389           attrib_set = gail_misc_add_attribute (attrib_set,
390                                                 ATK_TEXT_ATTR_STYLE,
391               g_strdup (atk_text_attribute_get_value (ATK_TEXT_ATTR_STYLE,
392                                    pango_font_description_get_style (font))));
393           attrib_set = gail_misc_add_attribute (attrib_set,
394                                                 ATK_TEXT_ATTR_VARIANT,
395               g_strdup (atk_text_attribute_get_value (ATK_TEXT_ATTR_VARIANT,
396                                    pango_font_description_get_variant (font))));
397           attrib_set = gail_misc_add_attribute (attrib_set,
398                                                 ATK_TEXT_ATTR_STRETCH,
399               g_strdup (atk_text_attribute_get_value (ATK_TEXT_ATTR_STRETCH,
400                                    pango_font_description_get_stretch (font))));
401           attrib_set = gail_misc_add_attribute (attrib_set,
402                                                 ATK_TEXT_ATTR_FAMILY_NAME,
403               g_strdup (pango_font_description_get_family (font)));
404           attrib_set = gail_misc_add_attribute (attrib_set,
405                                                 ATK_TEXT_ATTR_WEIGHT,
406                     g_strdup_printf ("%d",
407                                    pango_font_description_get_weight (font)));
408           attrib_set = gail_misc_add_attribute (attrib_set,
409                                                 ATK_TEXT_ATTR_SIZE,
410                     g_strdup_printf ("%i",
411                                    pango_font_description_get_size (font) / PANGO_SCALE));
412         }
413     }
414   if (pango_layout_get_justify (layout))
415     {
416       int_value = 3;
417     }
418   else
419     {
420       PangoAlignment align;
421
422       align = pango_layout_get_alignment (layout);
423       if (align == PANGO_ALIGN_LEFT)
424         int_value = 0;
425       else if (align == PANGO_ALIGN_CENTER)
426         int_value = 2;
427       else /* if (align == PANGO_ALIGN_RIGHT) */
428         int_value = 1;
429     }
430   attrib_set = gail_misc_add_attribute (attrib_set,
431                                         ATK_TEXT_ATTR_JUSTIFICATION,
432               g_strdup (atk_text_attribute_get_value (ATK_TEXT_ATTR_JUSTIFICATION, 
433                                                       int_value))); 
434   mode = pango_layout_get_wrap (layout);
435   if (mode == PANGO_WRAP_WORD)
436     int_value = 2;
437   else /* if (mode == PANGO_WRAP_CHAR) */
438     int_value = 1;
439   attrib_set = gail_misc_add_attribute (attrib_set,
440                                         ATK_TEXT_ATTR_WRAP_MODE,
441               g_strdup (atk_text_attribute_get_value (ATK_TEXT_ATTR_WRAP_MODE, 
442                                                       int_value))); 
443
444   style_value = gtk_widget_get_style (widget);
445   if (style_value)
446     {
447       GdkColor color;
448       gchar *value;
449
450       color = style_value->base[GTK_STATE_NORMAL];
451       value = g_strdup_printf ("%u,%u,%u",
452                                color.red, color.green, color.blue);
453       attrib_set = gail_misc_add_attribute (attrib_set,
454                                             ATK_TEXT_ATTR_BG_COLOR,
455                                             value); 
456       color = style_value->text[GTK_STATE_NORMAL];
457       value = g_strdup_printf ("%u,%u,%u",
458                                color.red, color.green, color.blue);
459       attrib_set = gail_misc_add_attribute (attrib_set,
460                                             ATK_TEXT_ATTR_FG_COLOR,
461                                             value); 
462     }
463   attrib_set = gail_misc_add_attribute (attrib_set,
464                                         ATK_TEXT_ATTR_FG_STIPPLE,
465               g_strdup (atk_text_attribute_get_value (ATK_TEXT_ATTR_FG_STIPPLE, 
466                                                       0))); 
467   attrib_set = gail_misc_add_attribute (attrib_set,
468                                         ATK_TEXT_ATTR_BG_STIPPLE,
469               g_strdup (atk_text_attribute_get_value (ATK_TEXT_ATTR_BG_STIPPLE, 
470                                                       0))); 
471   attrib_set = gail_misc_add_attribute (attrib_set,
472                                         ATK_TEXT_ATTR_STRIKETHROUGH,
473               g_strdup (atk_text_attribute_get_value (ATK_TEXT_ATTR_STRIKETHROUGH, 
474                                                       0))); 
475   attrib_set = gail_misc_add_attribute (attrib_set,
476                                         ATK_TEXT_ATTR_UNDERLINE,
477               g_strdup (atk_text_attribute_get_value (ATK_TEXT_ATTR_UNDERLINE, 
478                                                       0))); 
479   attrib_set = gail_misc_add_attribute (attrib_set,
480                                         ATK_TEXT_ATTR_RISE,
481                                                g_strdup_printf ("%i", 0));
482   attrib_set = gail_misc_add_attribute (attrib_set,
483                                         ATK_TEXT_ATTR_SCALE,
484                                                g_strdup_printf ("%g", 1.0));
485   attrib_set = gail_misc_add_attribute (attrib_set,
486                                         ATK_TEXT_ATTR_BG_FULL_HEIGHT,
487                                                g_strdup_printf ("%i", 0));
488   attrib_set = gail_misc_add_attribute (attrib_set,
489                                         ATK_TEXT_ATTR_PIXELS_INSIDE_WRAP,
490                                                g_strdup_printf ("%i", 0));
491   attrib_set = gail_misc_add_attribute (attrib_set,
492                                         ATK_TEXT_ATTR_PIXELS_BELOW_LINES,
493                                         g_strdup_printf ("%i", 0));
494   attrib_set = gail_misc_add_attribute (attrib_set,
495                                         ATK_TEXT_ATTR_PIXELS_ABOVE_LINES,
496                                         g_strdup_printf ("%i", 0));
497   attrib_set = gail_misc_add_attribute (attrib_set,
498                                         ATK_TEXT_ATTR_EDITABLE,
499               g_strdup (atk_text_attribute_get_value (ATK_TEXT_ATTR_EDITABLE, 
500                                                       0))); 
501   attrib_set = gail_misc_add_attribute (attrib_set,
502                                         ATK_TEXT_ATTR_INVISIBLE,
503               g_strdup (atk_text_attribute_get_value (ATK_TEXT_ATTR_INVISIBLE, 
504                                                       0))); 
505   attrib_set = gail_misc_add_attribute (attrib_set,
506                                         ATK_TEXT_ATTR_INDENT,
507                                         g_strdup_printf ("%i", 0));
508   attrib_set = gail_misc_add_attribute (attrib_set,
509                                         ATK_TEXT_ATTR_RIGHT_MARGIN,
510                                         g_strdup_printf ("%i", 0));
511   attrib_set = gail_misc_add_attribute (attrib_set,
512                                         ATK_TEXT_ATTR_LEFT_MARGIN,
513                                         g_strdup_printf ("%i", 0));
514   return attrib_set;
515 }
516
517 /**
518  * gail_misc_get_origins:
519  * @widget: a #GtkWidget
520  * @x_window: the x-origin of the widget->window
521  * @y_window: the y-origin of the widget->window
522  * @x_toplevel: the x-origin of the toplevel window for widget->window
523  * @y_toplevel: the y-origin of the toplevel window for widget->window
524  *
525  * Gets the origin of the widget window, and the origin of the
526  * widgets top-level window.
527  **/
528 void
529 gail_misc_get_origins (GtkWidget *widget,
530                        gint      *x_window,
531                        gint      *y_window,
532                        gint      *x_toplevel,
533                        gint      *y_toplevel)
534 {
535   GdkWindow *window;
536
537   if (GTK_IS_TREE_VIEW (widget))
538     window = gtk_tree_view_get_bin_window (GTK_TREE_VIEW (widget));
539   else
540     window = widget->window;
541   gdk_window_get_origin (window, x_window, y_window);
542   window = gdk_window_get_toplevel (widget->window);
543   gdk_window_get_origin (window, x_toplevel, y_toplevel);
544 }
545
546 /**
547  * gail_misc_add_to_attr_set:
548  * @attrib_set: An #AtkAttributeSet
549  * @attrs: The #GtkTextAttributes containing the attribute value
550  * @attr: The #AtkTextAttribute to be added
551  *
552  * Gets the value for the AtkTextAttribute from the GtkTextAttributes
553  * and adds it to the AttributeSet.
554  *
555  * Returns: A pointer to the updated #AtkAttributeSet.
556  **/
557 AtkAttributeSet*
558 gail_misc_add_to_attr_set (AtkAttributeSet   *attrib_set,
559                            GtkTextAttributes *attrs,
560                            AtkTextAttribute  attr)
561 {
562   gchar *value;
563
564   switch (attr)
565     {
566     case ATK_TEXT_ATTR_LEFT_MARGIN:
567       value = g_strdup_printf ("%i", attrs->left_margin);
568       break;
569     case ATK_TEXT_ATTR_RIGHT_MARGIN:
570       value = g_strdup_printf ("%i", attrs->right_margin);
571       break;
572     case ATK_TEXT_ATTR_INDENT:
573       value = g_strdup_printf ("%i", attrs->indent);
574       break;
575     case ATK_TEXT_ATTR_INVISIBLE:
576       value = g_strdup (atk_text_attribute_get_value (attr, attrs->invisible));
577       break;
578     case ATK_TEXT_ATTR_EDITABLE:
579       value = g_strdup (atk_text_attribute_get_value (attr, attrs->editable));
580       break;
581     case ATK_TEXT_ATTR_PIXELS_ABOVE_LINES:
582       value = g_strdup_printf ("%i", attrs->pixels_above_lines);
583       break;
584     case ATK_TEXT_ATTR_PIXELS_BELOW_LINES:
585       value = g_strdup_printf ("%i", attrs->pixels_below_lines);
586       break;
587     case ATK_TEXT_ATTR_PIXELS_INSIDE_WRAP:
588       value = g_strdup_printf ("%i", attrs->pixels_inside_wrap);
589       break;
590     case ATK_TEXT_ATTR_BG_FULL_HEIGHT:
591       value = g_strdup (atk_text_attribute_get_value (attr, attrs->bg_full_height));
592       break;
593     case ATK_TEXT_ATTR_RISE:
594       value = g_strdup_printf ("%i", attrs->appearance.rise);
595       break;
596     case ATK_TEXT_ATTR_UNDERLINE:
597       value = g_strdup (atk_text_attribute_get_value (attr, attrs->appearance.underline));
598       break;
599     case ATK_TEXT_ATTR_STRIKETHROUGH:
600       value = g_strdup (atk_text_attribute_get_value (attr, attrs->appearance.strikethrough));
601       break;
602     case ATK_TEXT_ATTR_SIZE:
603       value = g_strdup_printf ("%i", 
604                               pango_font_description_get_size (attrs->font) / PANGO_SCALE);
605       break;
606     case ATK_TEXT_ATTR_SCALE:
607       value = g_strdup_printf ("%g", attrs->font_scale);
608       break;
609     case ATK_TEXT_ATTR_WEIGHT:
610       value = g_strdup_printf ("%d", 
611                               pango_font_description_get_weight (attrs->font));
612       break;
613     case ATK_TEXT_ATTR_LANGUAGE:
614       value = g_strdup ((gchar *)(attrs->language));
615       break;
616     case ATK_TEXT_ATTR_FAMILY_NAME:
617       value = g_strdup (pango_font_description_get_family (attrs->font));
618       break;
619     case ATK_TEXT_ATTR_BG_COLOR:
620       value = g_strdup_printf ("%u,%u,%u",
621                                attrs->appearance.bg_color.red,
622                                attrs->appearance.bg_color.green,
623                                attrs->appearance.bg_color.blue);
624       break;
625     case ATK_TEXT_ATTR_FG_COLOR:
626       value = g_strdup_printf ("%u,%u,%u",
627                                attrs->appearance.fg_color.red,
628                                attrs->appearance.fg_color.green,
629                                attrs->appearance.fg_color.blue);
630       break;
631     case ATK_TEXT_ATTR_BG_STIPPLE:
632       value = g_strdup (atk_text_attribute_get_value (attr, attrs->appearance.bg_stipple ? 1 : 0));
633       break;
634     case ATK_TEXT_ATTR_FG_STIPPLE:
635       value = g_strdup (atk_text_attribute_get_value (attr, attrs->appearance.fg_stipple ? 1 : 0));
636       break;
637     case ATK_TEXT_ATTR_WRAP_MODE:
638       value = g_strdup (atk_text_attribute_get_value (attr, attrs->wrap_mode));
639       break;
640     case ATK_TEXT_ATTR_DIRECTION:
641       value = g_strdup (atk_text_attribute_get_value (attr, attrs->direction));
642       break;
643     case ATK_TEXT_ATTR_JUSTIFICATION:
644       value = g_strdup (atk_text_attribute_get_value (attr, attrs->justification));
645       break;
646     case ATK_TEXT_ATTR_STRETCH:
647       value = g_strdup (atk_text_attribute_get_value (attr, 
648                         pango_font_description_get_stretch (attrs->font)));
649       break;
650     case ATK_TEXT_ATTR_VARIANT:
651       value = g_strdup (atk_text_attribute_get_value (attr, 
652                         pango_font_description_get_variant (attrs->font)));
653       break;
654     case ATK_TEXT_ATTR_STYLE:
655       value = g_strdup (atk_text_attribute_get_value (attr, 
656                         pango_font_description_get_style (attrs->font)));
657       break;
658     default:
659       value = NULL;
660       break;
661     }
662   return gail_misc_add_attribute (attrib_set, attr, value);
663 }
664
665 /**
666  * gail_misc_buffer_get_run_attributes:
667  * @buffer: The #GtkTextBuffer for which the attributes will be obtained
668  * @offset: The offset at which the attributes are required
669  * @start_offset: The start offset of the current run
670  * @end_offset: The end offset of the current run
671  *
672  * Creates an AtkAttributeSet which contains the attributes for the 
673  * run starting at offset.
674  *
675  * Returns: A pointer to the #AtkAttributeSet.
676  **/
677 AtkAttributeSet*
678 gail_misc_buffer_get_run_attributes (GtkTextBuffer *buffer,
679                                      gint          offset,
680                                      gint           *start_offset,
681                                      gint          *end_offset)
682 {
683   GtkTextIter iter;
684   AtkAttributeSet *attrib_set = NULL;
685   AtkAttribute *at;
686   GSList *tags, *temp_tags;
687   gdouble scale = 1;
688   gboolean val_set = FALSE;
689   PangoFontMask mask;
690
691   gtk_text_buffer_get_iter_at_offset (buffer, &iter, offset);
692
693   gtk_text_iter_forward_to_tag_toggle (&iter, NULL);
694   *end_offset = gtk_text_iter_get_offset (&iter);
695
696   gtk_text_iter_backward_to_tag_toggle (&iter, NULL);
697   *start_offset = gtk_text_iter_get_offset (&iter);
698
699   gtk_text_buffer_get_iter_at_offset (buffer, &iter, offset);
700
701   tags = gtk_text_iter_get_tags (&iter);
702   tags = g_slist_reverse (tags);
703
704   temp_tags = tags;
705   while (temp_tags && !val_set)
706     {
707       GtkTextTag *tag = GTK_TEXT_TAG (temp_tags->data);
708       PangoFontDescription *font;
709
710       font = tag->values->font;
711
712       if (font)
713         {
714           mask = pango_font_description_get_set_fields (font);
715           val_set = mask & PANGO_FONT_MASK_STYLE;
716           if (val_set)
717             attrib_set = gail_misc_add_to_attr_set (attrib_set, tag->values, 
718                                                     ATK_TEXT_ATTR_STYLE);
719         }
720       temp_tags = temp_tags->next;
721     }
722   val_set = FALSE;
723
724   temp_tags = tags;
725   while (temp_tags && !val_set)
726     {
727       GtkTextTag *tag = GTK_TEXT_TAG (temp_tags->data);
728       PangoFontDescription *font;
729
730       font = tag->values->font;
731
732       if (font)
733         {
734           mask = pango_font_description_get_set_fields (font);
735           val_set = mask & PANGO_FONT_MASK_VARIANT;
736           if (val_set)
737             attrib_set = gail_misc_add_to_attr_set (attrib_set, tag->values, 
738                                                     ATK_TEXT_ATTR_VARIANT);
739         }
740       temp_tags = temp_tags->next;
741     }
742   val_set = FALSE;
743
744   temp_tags = tags;
745   while (temp_tags && !val_set)
746     {
747       GtkTextTag *tag = GTK_TEXT_TAG (temp_tags->data);
748       PangoFontDescription *font;
749
750       font = tag->values->font;
751
752       if (font)
753         {
754           mask = pango_font_description_get_set_fields (font);
755           val_set = mask & PANGO_FONT_MASK_STRETCH;
756           if (val_set)
757             attrib_set = gail_misc_add_to_attr_set (attrib_set, tag->values, 
758                                                     ATK_TEXT_ATTR_STRETCH);
759         }
760       temp_tags = temp_tags->next;
761     }
762   val_set = FALSE;
763
764   temp_tags = tags;
765   while (temp_tags && !val_set)
766     {
767       GtkTextTag *tag = GTK_TEXT_TAG (temp_tags->data);
768
769       val_set = tag->justification_set;
770       if (val_set)
771         attrib_set = gail_misc_add_to_attr_set (attrib_set, tag->values, 
772                                                 ATK_TEXT_ATTR_JUSTIFICATION);
773       temp_tags = temp_tags->next;
774     }
775   val_set = FALSE;
776
777   temp_tags = tags;
778   while (temp_tags && !val_set)
779     {
780       GtkTextTag *tag = GTK_TEXT_TAG (temp_tags->data);
781
782       if (tag->values->direction != GTK_TEXT_DIR_NONE)
783         {
784           val_set = TRUE;
785           attrib_set = gail_misc_add_to_attr_set (attrib_set, tag->values, 
786                                                   ATK_TEXT_ATTR_DIRECTION);
787         }
788       temp_tags = temp_tags->next;
789     }
790   val_set = FALSE;
791
792   temp_tags = tags;
793   while (temp_tags && !val_set)
794     {
795       GtkTextTag *tag = GTK_TEXT_TAG (temp_tags->data);
796
797       val_set = tag->wrap_mode_set;
798       if (val_set)
799         attrib_set = gail_misc_add_to_attr_set (attrib_set, tag->values, 
800                                                 ATK_TEXT_ATTR_WRAP_MODE);
801       temp_tags = temp_tags->next;
802     }
803   val_set = FALSE;
804
805   temp_tags = tags;
806   while (temp_tags && !val_set)
807     {
808       GtkTextTag *tag = GTK_TEXT_TAG (temp_tags->data);
809
810       val_set = tag->fg_stipple_set;
811       if (val_set)
812         attrib_set = gail_misc_add_to_attr_set (attrib_set, tag->values, 
813                                                 ATK_TEXT_ATTR_FG_STIPPLE);
814       temp_tags = temp_tags->next;
815     }
816   val_set = FALSE;
817
818   temp_tags = tags;
819   while (temp_tags && !val_set)
820     {
821       GtkTextTag *tag = GTK_TEXT_TAG (temp_tags->data);
822
823       val_set = tag->bg_stipple_set;
824       if (val_set)
825         attrib_set = gail_misc_add_to_attr_set (attrib_set, tag->values, 
826                                                 ATK_TEXT_ATTR_BG_STIPPLE);
827       temp_tags = temp_tags->next;
828     }
829   val_set = FALSE;
830
831   temp_tags = tags;
832   while (temp_tags && !val_set)
833     {
834       GtkTextTag *tag = GTK_TEXT_TAG (temp_tags->data);
835
836       val_set = tag->fg_color_set;
837       if (val_set)
838         attrib_set = gail_misc_add_to_attr_set (attrib_set, tag->values, 
839                                                 ATK_TEXT_ATTR_FG_COLOR);
840       temp_tags = temp_tags->next;
841     }
842   val_set = FALSE;
843
844   temp_tags = tags;
845   while (temp_tags && !val_set)
846     {
847       GtkTextTag *tag = GTK_TEXT_TAG (temp_tags->data);
848   
849       val_set = tag->bg_color_set;
850       if (val_set)
851         attrib_set = gail_misc_add_to_attr_set (attrib_set, tag->values, 
852                                                 ATK_TEXT_ATTR_BG_COLOR);
853       temp_tags = temp_tags->next;
854     }
855   val_set = FALSE;
856
857   temp_tags = tags;
858   while (temp_tags && !val_set)
859     {
860       GtkTextTag *tag = GTK_TEXT_TAG (temp_tags->data);
861       PangoFontDescription *font;
862
863       font = tag->values->font;
864
865       if (font)
866         {
867           mask = pango_font_description_get_set_fields (font);
868           val_set = mask & PANGO_FONT_MASK_FAMILY;
869           if (val_set)
870             attrib_set = gail_misc_add_to_attr_set (attrib_set, tag->values, 
871                                                     ATK_TEXT_ATTR_FAMILY_NAME);
872         }
873       temp_tags = temp_tags->next;
874     }
875   val_set = FALSE;
876
877   temp_tags = tags;
878   while (temp_tags && !val_set)
879     {
880       GtkTextTag *tag = GTK_TEXT_TAG (temp_tags->data);
881
882       val_set = tag->language_set;
883       if (val_set)
884         attrib_set = gail_misc_add_to_attr_set (attrib_set, tag->values, 
885                                                 ATK_TEXT_ATTR_LANGUAGE);
886       temp_tags = temp_tags->next;
887     }
888   val_set = FALSE;
889
890   temp_tags = tags;
891   while (temp_tags && !val_set)
892     {
893       GtkTextTag *tag = GTK_TEXT_TAG (temp_tags->data);
894       PangoFontDescription *font;
895
896       font = tag->values->font;
897
898       if (font)
899         {
900           mask = pango_font_description_get_set_fields (font);
901           val_set = mask & PANGO_FONT_MASK_WEIGHT;
902           if (val_set)
903             attrib_set = gail_misc_add_to_attr_set (attrib_set, tag->values, 
904                                                     ATK_TEXT_ATTR_WEIGHT);
905         }
906       temp_tags = temp_tags->next;
907     }
908   val_set = FALSE;
909
910
911   /*
912    * scale is special as the scale is the product of all scale values
913    * specified.
914    */
915   temp_tags = tags;
916   while (temp_tags)
917     {
918       GtkTextTag *tag = GTK_TEXT_TAG (temp_tags->data);
919
920       if (tag->scale_set)
921         {
922           val_set = TRUE;
923           scale *= tag->values->font_scale;
924         }
925       temp_tags = temp_tags->next;
926     }
927   if (val_set)
928     {
929       at = g_malloc(sizeof(AtkAttribute));
930       at->name = g_strdup(atk_text_attribute_get_name (ATK_TEXT_ATTR_SCALE));
931       at->value = g_strdup_printf("%g", scale);
932       attrib_set = g_slist_prepend(attrib_set, at);
933     }
934   val_set = FALSE;
935
936   temp_tags = tags;
937   while (temp_tags && !val_set)
938     {
939       GtkTextTag *tag = GTK_TEXT_TAG (temp_tags->data);
940       PangoFontDescription *font;
941
942       font = tag->values->font;
943
944       if (font)
945         {
946           mask = pango_font_description_get_set_fields (font);
947           val_set = mask & PANGO_FONT_MASK_SIZE;
948           if (val_set)
949             attrib_set = gail_misc_add_to_attr_set (attrib_set, tag->values, 
950                                                     ATK_TEXT_ATTR_SIZE);
951         }
952       temp_tags = temp_tags->next;
953     }
954   val_set = FALSE;
955
956   temp_tags = tags;
957   while (temp_tags && !val_set)
958     {
959       GtkTextTag *tag = GTK_TEXT_TAG (temp_tags->data);
960
961       val_set = tag->strikethrough_set;
962       if (val_set)
963         attrib_set = gail_misc_add_to_attr_set (attrib_set, tag->values, 
964                                                 ATK_TEXT_ATTR_STRIKETHROUGH);
965       temp_tags = temp_tags->next;
966     }
967   val_set = FALSE;
968
969   temp_tags = tags;
970   while (temp_tags && !val_set)
971     {
972       GtkTextTag *tag = GTK_TEXT_TAG (temp_tags->data);
973
974       val_set = tag->underline_set;
975       if (val_set)
976         attrib_set = gail_misc_add_to_attr_set (attrib_set, tag->values, 
977                                                 ATK_TEXT_ATTR_UNDERLINE);
978       temp_tags = temp_tags->next;
979     }
980   val_set = FALSE;
981
982   temp_tags = tags;
983   while (temp_tags && !val_set)
984     {
985       GtkTextTag *tag = GTK_TEXT_TAG (temp_tags->data);
986
987       val_set = tag->rise_set;
988       if (val_set)
989         attrib_set = gail_misc_add_to_attr_set (attrib_set, tag->values, 
990                                                 ATK_TEXT_ATTR_RISE);
991       temp_tags = temp_tags->next;
992     }
993   val_set = FALSE;
994
995   temp_tags = tags;
996   while (temp_tags && !val_set)
997     {
998       GtkTextTag *tag = GTK_TEXT_TAG (temp_tags->data);
999
1000       val_set = tag->bg_full_height_set;
1001       if (val_set)
1002         attrib_set = gail_misc_add_to_attr_set (attrib_set, tag->values, 
1003                                                 ATK_TEXT_ATTR_BG_FULL_HEIGHT);
1004       temp_tags = temp_tags->next;
1005     }
1006   val_set = FALSE;
1007
1008   temp_tags = tags;
1009   while (temp_tags && !val_set)
1010     {
1011       GtkTextTag *tag = GTK_TEXT_TAG (temp_tags->data);
1012
1013       val_set = tag->pixels_inside_wrap_set;
1014       if (val_set)
1015         attrib_set = gail_misc_add_to_attr_set (attrib_set, tag->values, 
1016                                                 ATK_TEXT_ATTR_PIXELS_INSIDE_WRAP);
1017       temp_tags = temp_tags->next;
1018     }
1019   val_set = FALSE;
1020
1021   temp_tags = tags;
1022   while (temp_tags && !val_set)
1023     {
1024       GtkTextTag *tag = GTK_TEXT_TAG (temp_tags->data);
1025
1026       val_set = tag->pixels_below_lines_set;
1027       if (val_set)
1028         attrib_set = gail_misc_add_to_attr_set (attrib_set, tag->values, 
1029                                                 ATK_TEXT_ATTR_PIXELS_BELOW_LINES);
1030       temp_tags = temp_tags->next;
1031     }
1032   val_set = FALSE;
1033
1034   temp_tags = tags;
1035   while (temp_tags && !val_set)
1036     {
1037       GtkTextTag *tag = GTK_TEXT_TAG (temp_tags->data);
1038
1039       val_set = tag->pixels_above_lines_set;
1040       if (val_set)
1041         attrib_set = gail_misc_add_to_attr_set (attrib_set, tag->values, 
1042                                                 ATK_TEXT_ATTR_PIXELS_ABOVE_LINES);
1043       temp_tags = temp_tags->next;
1044     }
1045   val_set = FALSE;
1046
1047   temp_tags = tags;
1048   while (temp_tags && !val_set)
1049     {
1050       GtkTextTag *tag = GTK_TEXT_TAG (temp_tags->data);
1051
1052       val_set = tag->editable_set;
1053       if (val_set)
1054         attrib_set = gail_misc_add_to_attr_set (attrib_set, tag->values, 
1055                                                 ATK_TEXT_ATTR_EDITABLE);
1056       temp_tags = temp_tags->next;
1057     }
1058   val_set = FALSE;
1059
1060   temp_tags = tags;
1061   while (temp_tags && !val_set)
1062     {
1063       GtkTextTag *tag = GTK_TEXT_TAG (temp_tags->data);
1064
1065       val_set = tag->invisible_set;
1066       if (val_set)
1067         attrib_set = gail_misc_add_to_attr_set (attrib_set, tag->values, 
1068                                                 ATK_TEXT_ATTR_INVISIBLE);
1069       temp_tags = temp_tags->next;
1070     }
1071   val_set = FALSE;
1072
1073   temp_tags = tags;
1074   while (temp_tags && !val_set)
1075     {
1076       GtkTextTag *tag = GTK_TEXT_TAG (temp_tags->data);
1077
1078       val_set = tag->indent_set;
1079       if (val_set)
1080         attrib_set = gail_misc_add_to_attr_set (attrib_set, tag->values, 
1081                                                 ATK_TEXT_ATTR_INDENT);
1082       temp_tags = temp_tags->next;
1083     }
1084   val_set = FALSE;
1085
1086   temp_tags = tags;
1087   while (temp_tags && !val_set)
1088     {
1089       GtkTextTag *tag = GTK_TEXT_TAG (temp_tags->data);
1090
1091       val_set = tag->right_margin_set;
1092       if (val_set)
1093         attrib_set = gail_misc_add_to_attr_set (attrib_set, tag->values, 
1094                                                 ATK_TEXT_ATTR_RIGHT_MARGIN);
1095       temp_tags = temp_tags->next;
1096     }
1097   val_set = FALSE;
1098
1099   temp_tags = tags;
1100   while (temp_tags && !val_set)
1101     {
1102       GtkTextTag *tag = GTK_TEXT_TAG (temp_tags->data);
1103
1104       val_set = tag->left_margin_set;
1105       if (val_set)
1106         attrib_set = gail_misc_add_to_attr_set (attrib_set, tag->values, 
1107                                                 ATK_TEXT_ATTR_LEFT_MARGIN);
1108       temp_tags = temp_tags->next;
1109     }
1110   val_set = FALSE;
1111
1112   g_slist_free (tags);
1113   return attrib_set;
1114 }