]> Pileus Git - ~andy/gtk/blob - modules/other/gail/libgail-util/gailmisc.c
Correctly treat GdkColor properties
[~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_buffer_get_run_attributes:
565  * @buffer: The #GtkTextBuffer for which the attributes will be obtained
566  * @offset: The offset at which the attributes are required
567  * @start_offset: The start offset of the current run
568  * @end_offset: The end offset of the current run
569  *
570  * Creates an AtkAttributeSet which contains the attributes for the 
571  * run starting at offset.
572  *
573  * Returns: A pointer to the #AtkAttributeSet.
574  **/
575 AtkAttributeSet*
576 gail_misc_buffer_get_run_attributes (GtkTextBuffer *buffer,
577                                      gint          offset,
578                                      gint           *start_offset,
579                                      gint          *end_offset)
580 {
581   GtkTextIter iter;
582   AtkAttributeSet *attrib_set = NULL;
583   AtkAttribute *at;
584   GSList *tags, *temp_tags;
585   gdouble scale = 1;
586   gboolean val_set = FALSE;
587
588   gtk_text_buffer_get_iter_at_offset (buffer, &iter, offset);
589
590   gtk_text_iter_forward_to_tag_toggle (&iter, NULL);
591   *end_offset = gtk_text_iter_get_offset (&iter);
592
593   gtk_text_iter_backward_to_tag_toggle (&iter, NULL);
594   *start_offset = gtk_text_iter_get_offset (&iter);
595
596   gtk_text_buffer_get_iter_at_offset (buffer, &iter, offset);
597
598   tags = gtk_text_iter_get_tags (&iter);
599   tags = g_slist_reverse (tags);
600
601   temp_tags = tags;
602   while (temp_tags && !val_set)
603     {
604       GtkTextTag *tag = GTK_TEXT_TAG (temp_tags->data);
605
606       g_object_get (tag, "style-set", &val_set, NULL);
607       if (val_set)
608         {
609           PangoStyle style;
610           gchar *value;
611
612           g_object_get (tag, "style", &style, NULL);
613           value = g_strdup (atk_text_attribute_get_value (ATK_TEXT_ATTR_STYLE, style));
614           attrib_set = gail_misc_add_attribute (attrib_set, ATK_TEXT_ATTR_STYLE, value);
615         }
616       temp_tags = temp_tags->next;
617     }
618   val_set = FALSE;
619
620   temp_tags = tags;
621   while (temp_tags && !val_set)
622     {
623       GtkTextTag *tag = GTK_TEXT_TAG (temp_tags->data);
624
625       g_object_get (tag, "variant-set", &val_set, NULL);
626       if (val_set)
627         {
628           PangoVariant variant;
629           gchar *value;
630
631           g_object_get (tag, "variant", &variant, NULL);
632           value = g_strdup (atk_text_attribute_get_value (ATK_TEXT_ATTR_VARIANT, variant));
633           attrib_set = gail_misc_add_attribute (attrib_set, ATK_TEXT_ATTR_VARIANT, value);
634         }
635       temp_tags = temp_tags->next;
636     }
637   val_set = FALSE;
638
639   temp_tags = tags;
640   while (temp_tags && !val_set)
641     {
642       GtkTextTag *tag = GTK_TEXT_TAG (temp_tags->data);
643
644       g_object_get (tag, "stretch-set", &val_set, NULL);
645       if (val_set)
646         {
647           PangoStretch stretch;
648           gchar *value;
649
650           g_object_get (tag, "stretch", &stretch, NULL);
651           value = g_strdup (atk_text_attribute_get_value (ATK_TEXT_ATTR_STRETCH, stretch));
652           attrib_set = gail_misc_add_attribute (attrib_set, ATK_TEXT_ATTR_STRETCH, value);
653         }
654       temp_tags = temp_tags->next;
655     }
656   val_set = FALSE;
657
658   temp_tags = tags;
659   while (temp_tags && !val_set)
660     {
661       GtkTextTag *tag = GTK_TEXT_TAG (temp_tags->data);
662
663       g_object_get (tag, "justification-set", &val_set, NULL);
664       if (val_set)
665         {
666           GtkJustification justification;
667           gchar *value;
668
669           g_object_get (tag, "justification", &justification, NULL);
670           value = g_strdup (atk_text_attribute_get_value (ATK_TEXT_ATTR_JUSTIFICATION, justification));
671           attrib_set = gail_misc_add_attribute (attrib_set, ATK_TEXT_ATTR_JUSTIFICATION, value);
672         }
673       temp_tags = temp_tags->next;
674     }
675   val_set = FALSE;
676
677   temp_tags = tags;
678   while (temp_tags && !val_set)
679     {
680       GtkTextTag *tag = GTK_TEXT_TAG (temp_tags->data);
681       GtkTextDirection direction;
682
683       g_object_get (tag, "direction", &direction, NULL);
684
685       if (direction != GTK_TEXT_DIR_NONE)
686         {
687           gchar *value;
688           val_set = TRUE;
689           value = g_strdup (atk_text_attribute_get_value (ATK_TEXT_ATTR_DIRECTION, direction));
690           attrib_set = gail_misc_add_attribute (attrib_set, ATK_TEXT_ATTR_DIRECTION, value);
691         }
692       temp_tags = temp_tags->next;
693     }
694   val_set = FALSE;
695
696   temp_tags = tags;
697   while (temp_tags && !val_set)
698     {
699       GtkTextTag *tag = GTK_TEXT_TAG (temp_tags->data);
700
701       g_object_get (tag, "wrap-mode-set", &val_set, NULL);
702       if (val_set)
703         {
704           GtkWrapMode wrap_mode;
705           gchar *value;
706
707           g_object_get (tag, "wrap-mode", &wrap_mode, NULL);
708           value = g_strdup (atk_text_attribute_get_value (ATK_TEXT_ATTR_WRAP_MODE, wrap_mode));
709           attrib_set = gail_misc_add_attribute (attrib_set, ATK_TEXT_ATTR_WRAP_MODE, value);
710         }
711       temp_tags = temp_tags->next;
712     }
713   val_set = FALSE;
714
715   temp_tags = tags;
716   while (temp_tags && !val_set)
717     {
718       GtkTextTag *tag = GTK_TEXT_TAG (temp_tags->data);
719
720       g_object_get (tag, "foreground-set", &val_set, NULL);
721       if (val_set)
722         {
723           GdkColor *c;
724           gchar *value;
725
726           g_object_get (tag, "foreground-gdk", &c, NULL);
727           value = g_strdup_printf ("%u,%u,%u", c->red, c->green, c->blue);
728           gdk_color_free (c);
729           attrib_set = gail_misc_add_attribute (attrib_set, ATK_TEXT_ATTR_FG_COLOR, value);
730         }
731       temp_tags = temp_tags->next;
732     }
733   val_set = FALSE;
734
735   temp_tags = tags;
736   while (temp_tags && !val_set)
737     {
738       GtkTextTag *tag = GTK_TEXT_TAG (temp_tags->data);
739
740       g_object_get (tag, "background-set", &val_set, NULL);
741       if (val_set)
742         {
743           GdkColor *c;
744           gchar *value;
745
746           g_object_get (tag, "background-gdk", &c, NULL);
747           value = g_strdup_printf ("%u,%u,%u", c->red, c->green, c->blue);
748           gdk_color_free (c);
749           attrib_set = gail_misc_add_attribute (attrib_set, ATK_TEXT_ATTR_BG_COLOR, value);
750         }
751       temp_tags = temp_tags->next;
752     }
753   val_set = FALSE;
754
755   temp_tags = tags;
756   while (temp_tags && !val_set)
757     {
758       GtkTextTag *tag = GTK_TEXT_TAG (temp_tags->data);
759
760       g_object_get (tag, "family-set", &val_set, NULL);
761
762       if (val_set)
763         {
764           gchar *value;
765           g_object_get (tag, "family", &value, NULL);
766           attrib_set = gail_misc_add_attribute (attrib_set, ATK_TEXT_ATTR_FAMILY_NAME, value);
767         }
768       temp_tags = temp_tags->next;
769     }
770   val_set = FALSE;
771
772   temp_tags = tags;
773   while (temp_tags && !val_set)
774     {
775       GtkTextTag *tag = GTK_TEXT_TAG (temp_tags->data);
776
777       g_object_get (tag, "language-set", &val_set, NULL);
778
779       if (val_set)
780         {
781           gchar *value;
782           g_object_get (tag, "language", &value, NULL);
783           attrib_set = gail_misc_add_attribute (attrib_set, ATK_TEXT_ATTR_LANGUAGE, value);
784         }
785       temp_tags = temp_tags->next;
786     }
787   val_set = FALSE;
788
789   temp_tags = tags;
790   while (temp_tags && !val_set)
791     {
792       GtkTextTag *tag = GTK_TEXT_TAG (temp_tags->data);
793
794       g_object_get (tag, "weight-set", &val_set, NULL);
795
796       if (val_set)
797         {
798           gint weight;
799           gchar *value;
800
801           g_object_get (tag, "weight", &weight, NULL);
802           value = g_strdup_printf ("%d", weight);
803           attrib_set = gail_misc_add_attribute (attrib_set, ATK_TEXT_ATTR_WEIGHT, value);
804         }
805       temp_tags = temp_tags->next;
806     }
807   val_set = FALSE;
808
809
810   /*
811    * scale is special as the scale is the product of all scale values
812    * specified.
813    */
814   temp_tags = tags;
815   while (temp_tags)
816     {
817       GtkTextTag *tag = GTK_TEXT_TAG (temp_tags->data);
818       gboolean scale_set;
819
820       g_object_get (tag, "scale-set", &scale_set, NULL);
821       if (scale_set)
822         {
823           gdouble font_scale;
824
825           g_object_get (tag, "scale", &font_scale, NULL);
826           val_set = TRUE;
827           scale *= font_scale;
828         }
829       temp_tags = temp_tags->next;
830     }
831   if (val_set)
832     {
833       at = g_malloc(sizeof(AtkAttribute));
834       at->name = g_strdup(atk_text_attribute_get_name (ATK_TEXT_ATTR_SCALE));
835       at->value = g_strdup_printf("%g", scale);
836       attrib_set = g_slist_prepend(attrib_set, at);
837     }
838   val_set = FALSE;
839
840   temp_tags = tags;
841   while (temp_tags && !val_set)
842     {
843       GtkTextTag *tag = GTK_TEXT_TAG (temp_tags->data);
844
845       g_object_get (tag, "size-set", &val_set, NULL);
846       if (val_set)
847         {
848           gint size;
849           gchar *value;
850           g_object_get (tag, "size", &size, NULL);
851           value = g_strdup_printf ("%i", size);
852           attrib_set = gail_misc_add_attribute (attrib_set, ATK_TEXT_ATTR_SIZE, value);
853         }
854       temp_tags = temp_tags->next;
855     }
856   val_set = FALSE;
857
858   temp_tags = tags;
859   while (temp_tags && !val_set)
860     {
861       GtkTextTag *tag = GTK_TEXT_TAG (temp_tags->data);
862
863       g_object_get (tag, "strikethrough-set", &val_set, NULL);
864       if (val_set)
865         {
866           gboolean strikethrough;
867           gchar *value;
868           g_object_get (tag, "strikethrough", &strikethrough, NULL);
869           value = g_strdup (atk_text_attribute_get_value (ATK_TEXT_ATTR_STRIKETHROUGH, strikethrough));
870           attrib_set = gail_misc_add_attribute (attrib_set, ATK_TEXT_ATTR_STRIKETHROUGH, value);
871         }
872       temp_tags = temp_tags->next;
873     }
874   val_set = FALSE;
875
876   temp_tags = tags;
877   while (temp_tags && !val_set)
878     {
879       GtkTextTag *tag = GTK_TEXT_TAG (temp_tags->data);
880
881       g_object_get (tag, "underline-set", &val_set, NULL);
882       if (val_set)
883         {
884           PangoUnderline underline;
885           gchar *value;
886           g_object_get (tag, "underline", &underline, NULL);
887           value = g_strdup (atk_text_attribute_get_value (ATK_TEXT_ATTR_UNDERLINE, underline));
888           attrib_set = gail_misc_add_attribute (attrib_set, ATK_TEXT_ATTR_UNDERLINE, value);
889         }
890       temp_tags = temp_tags->next;
891     }
892   val_set = FALSE;
893
894   temp_tags = tags;
895   while (temp_tags && !val_set)
896     {
897       GtkTextTag *tag = GTK_TEXT_TAG (temp_tags->data);
898
899       g_object_get (tag, "rise-set", &val_set, NULL);
900       if (val_set)
901         {
902           gint rise;
903           gchar *value;
904           g_object_get (tag, "rise", &rise, NULL);
905           value = g_strdup_printf ("%i", rise);
906           attrib_set = gail_misc_add_attribute (attrib_set, ATK_TEXT_ATTR_RISE, value);
907         }
908       temp_tags = temp_tags->next;
909     }
910   val_set = FALSE;
911
912   temp_tags = tags;
913   while (temp_tags && !val_set)
914     {
915       GtkTextTag *tag = GTK_TEXT_TAG (temp_tags->data);
916
917       g_object_get (tag, "background-full-height-set", &val_set, NULL);
918       if (val_set)
919         {
920           gboolean bg_full_height;
921           gchar *value;
922           g_object_get (tag, "background-full-height", &bg_full_height, NULL);
923           value = g_strdup (atk_text_attribute_get_value (ATK_TEXT_ATTR_BG_FULL_HEIGHT, bg_full_height));
924           attrib_set = gail_misc_add_attribute (attrib_set, ATK_TEXT_ATTR_BG_FULL_HEIGHT, value);
925         }
926       temp_tags = temp_tags->next;
927     }
928   val_set = FALSE;
929
930   temp_tags = tags;
931   while (temp_tags && !val_set)
932     {
933       GtkTextTag *tag = GTK_TEXT_TAG (temp_tags->data);
934
935       g_object_get (tag, "pixels-inside-wrap-set", &val_set, NULL);
936       if (val_set)
937         {
938           gint pixels;
939           gchar *value;
940           g_object_get (tag, "pixels-inside-wrap", &pixels, NULL);
941           value = g_strdup_printf ("%i", pixels);
942           attrib_set = gail_misc_add_attribute (attrib_set, ATK_TEXT_ATTR_PIXELS_INSIDE_WRAP, value);
943         }
944       temp_tags = temp_tags->next;
945     }
946   val_set = FALSE;
947
948   temp_tags = tags;
949   while (temp_tags && !val_set)
950     {
951       GtkTextTag *tag = GTK_TEXT_TAG (temp_tags->data);
952
953       g_object_get (tag, "pixels-below-lines-set", &val_set, NULL);
954       if (val_set)
955         {
956           gint pixels;
957           gchar *value;
958           g_object_get (tag, "pixels-below-lines", &pixels, NULL);
959           value = g_strdup_printf ("%i", pixels);
960           attrib_set = gail_misc_add_attribute (attrib_set, ATK_TEXT_ATTR_PIXELS_BELOW_LINES, value);
961         }
962       temp_tags = temp_tags->next;
963     }
964   val_set = FALSE;
965
966   temp_tags = tags;
967   while (temp_tags && !val_set)
968     {
969       GtkTextTag *tag = GTK_TEXT_TAG (temp_tags->data);
970
971       g_object_get (tag, "pixels-above-lines-set", &val_set, NULL);
972       if (val_set)
973         {
974           gint pixels;
975           gchar *value;
976           g_object_get (tag, "pixels-above-lines", &pixels, NULL);
977           value = g_strdup_printf ("%i", pixels);
978           attrib_set = gail_misc_add_attribute (attrib_set, ATK_TEXT_ATTR_PIXELS_ABOVE_LINES, value);
979         }
980       temp_tags = temp_tags->next;
981     }
982   val_set = FALSE;
983
984   temp_tags = tags;
985   while (temp_tags && !val_set)
986     {
987       GtkTextTag *tag = GTK_TEXT_TAG (temp_tags->data);
988
989       g_object_get (tag, "editable-set", &val_set, NULL);
990       if (val_set)
991         {
992           gboolean editable;
993           gchar *value;
994           g_object_get (tag, "editable", &editable, NULL);
995           value = g_strdup (atk_text_attribute_get_value (ATK_TEXT_ATTR_EDITABLE, editable));
996           attrib_set = gail_misc_add_attribute (attrib_set, ATK_TEXT_ATTR_EDITABLE, value);
997         }
998       temp_tags = temp_tags->next;
999     }
1000   val_set = FALSE;
1001
1002   temp_tags = tags;
1003   while (temp_tags && !val_set)
1004     {
1005       GtkTextTag *tag = GTK_TEXT_TAG (temp_tags->data);
1006
1007       g_object_get (tag, "invisible-set", &val_set, NULL);
1008       if (val_set)
1009         {
1010           gboolean invisible;
1011           gchar *value;
1012           g_object_get (tag, "invisible", &invisible, NULL);
1013           value = g_strdup (atk_text_attribute_get_value (ATK_TEXT_ATTR_INVISIBLE, invisible));
1014           attrib_set = gail_misc_add_attribute (attrib_set, ATK_TEXT_ATTR_INVISIBLE, value);
1015         }
1016       temp_tags = temp_tags->next;
1017     }
1018   val_set = FALSE;
1019
1020   temp_tags = tags;
1021   while (temp_tags && !val_set)
1022     {
1023       GtkTextTag *tag = GTK_TEXT_TAG (temp_tags->data);
1024
1025       g_object_get (tag, "indent-set", &val_set, NULL);
1026       if (val_set)
1027         {
1028           gint indent;
1029           gchar *value;
1030           g_object_get (tag, "indent", &indent, NULL);
1031           value = g_strdup_printf ("%i", indent);
1032           attrib_set = gail_misc_add_attribute (attrib_set, ATK_TEXT_ATTR_INDENT, value);
1033         }
1034       temp_tags = temp_tags->next;
1035     }
1036   val_set = FALSE;
1037
1038   temp_tags = tags;
1039   while (temp_tags && !val_set)
1040     {
1041       GtkTextTag *tag = GTK_TEXT_TAG (temp_tags->data);
1042
1043       g_object_get (tag, "right-margin-set", &val_set, NULL);
1044       if (val_set)
1045         {
1046           gint margin;
1047           gchar *value;
1048           g_object_get (tag, "right-margin", &margin, NULL);
1049           value = g_strdup_printf ("%i", margin);
1050           attrib_set = gail_misc_add_attribute (attrib_set, ATK_TEXT_ATTR_RIGHT_MARGIN, value);
1051         }
1052       temp_tags = temp_tags->next;
1053     }
1054   val_set = FALSE;
1055
1056   temp_tags = tags;
1057   while (temp_tags && !val_set)
1058     {
1059       GtkTextTag *tag = GTK_TEXT_TAG (temp_tags->data);
1060
1061       g_object_get (tag, "left-margin-set", &val_set, NULL);
1062       if (val_set)
1063         {
1064           gint margin;
1065           gchar *value;
1066           g_object_get (tag, "left-margin", &margin, NULL);
1067           value = g_strdup_printf ("%i", margin);
1068           attrib_set = gail_misc_add_attribute (attrib_set, ATK_TEXT_ATTR_LEFT_MARGIN, value);
1069         }
1070       temp_tags = temp_tags->next;
1071     }
1072   val_set = FALSE;
1073
1074   g_slist_free (tags);
1075   return attrib_set;
1076 }