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