]> Pileus Git - ~andy/gtk/blob - gtk/a11y/gailmisc.c
Drop gail_misc_buffer_get_run_attributes
[~andy/gtk] / gtk / a11y / 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 }