]> Pileus Git - ~andy/gtk/blob - modules/other/gail/gailstatusbar.c
02168624187667ebfadbe7e85d62b522fc68f253
[~andy/gtk] / modules / other / gail / gailstatusbar.c
1 /* GAIL - The GNOME Accessibility Implementation Library
2  * Copyright 2001, 2002, 2003 Sun Microsystems Inc.
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Lesser General Public
6  * License as published by the Free Software Foundation; either
7  * version 2 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser General Public
15  * License along with this library; if not, write to the
16  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17  * Boston, MA 02111-1307, USA.
18  */
19
20 #include "config.h"
21
22 #include <string.h>
23 #include <gtk/gtk.h>
24 #include "gailstatusbar.h"
25 #include <libgail-util/gailmisc.h>
26
27 static void         gail_statusbar_class_init          (GailStatusbarClass *klass);
28 static void         gail_statusbar_init                (GailStatusbar      *bar);
29 static G_CONST_RETURN gchar* gail_statusbar_get_name   (AtkObject          *obj);
30 static gint         gail_statusbar_get_n_children      (AtkObject          *obj);
31 static AtkObject*   gail_statusbar_ref_child           (AtkObject          *obj,
32                                                         gint               i);
33 static void         gail_statusbar_real_initialize     (AtkObject          *obj,
34                                                         gpointer           data);
35
36 static gint         gail_statusbar_notify              (GObject            *obj,
37                                                         GParamSpec         *pspec,
38                                                         gpointer           user_data);
39 static void         gail_statusbar_finalize            (GObject            *object);
40 static void         gail_statusbar_init_textutil       (GailStatusbar      *statusbar,
41                                                         GtkWidget          *label);
42
43 /* atktext.h */ 
44 static void       atk_text_interface_init          (AtkTextIface        *iface);
45
46 static gchar*     gail_statusbar_get_text          (AtkText           *text,
47                                                     gint              start_pos,
48                                                     gint              end_pos);
49 static gunichar   gail_statusbar_get_character_at_offset
50                                                    (AtkText           *text,
51                                                     gint              offset);
52 static gchar*     gail_statusbar_get_text_before_offset
53                                                    (AtkText           *text,
54                                                     gint              offset,
55                                                     AtkTextBoundary   boundary_type,
56                                                     gint              *start_offset,
57                                                     gint              *end_offset);
58 static gchar*     gail_statusbar_get_text_at_offset(AtkText           *text,
59                                                     gint              offset,
60                                                     AtkTextBoundary   boundary_type,
61                                                     gint              *start_offset,
62                                                     gint              *end_offset);
63 static gchar*     gail_statusbar_get_text_after_offset
64                                                    (AtkText           *text,
65                                                     gint              offset,
66                                                     AtkTextBoundary   boundary_type,
67                                                     gint              *start_offset,
68                                                     gint              *end_offset);
69 static gint       gail_statusbar_get_character_count (AtkText         *text);
70 static void       gail_statusbar_get_character_extents
71                                                    (AtkText           *text,
72                                                     gint              offset,
73                                                     gint              *x,
74                                                     gint              *y,
75                                                     gint              *width,
76                                                     gint              *height,
77                                                     AtkCoordType      coords);
78 static gint      gail_statusbar_get_offset_at_point(AtkText           *text,
79                                                     gint              x,
80                                                     gint              y,
81                                                     AtkCoordType      coords);
82 static AtkAttributeSet* gail_statusbar_get_run_attributes 
83                                                    (AtkText           *text,
84                                                     gint              offset,
85                                                     gint              *start_offset,
86                                                     gint              *end_offset);
87 static AtkAttributeSet* gail_statusbar_get_default_attributes
88                                                    (AtkText           *text);
89 static GtkWidget* get_label_from_statusbar         (GtkWidget         *statusbar);
90
91 G_DEFINE_TYPE_WITH_CODE (GailStatusbar, gail_statusbar, GAIL_TYPE_CONTAINER,
92                          G_IMPLEMENT_INTERFACE (ATK_TYPE_TEXT, atk_text_interface_init))
93
94 static void
95 gail_statusbar_class_init (GailStatusbarClass *klass)
96 {
97   GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
98   AtkObjectClass  *class = ATK_OBJECT_CLASS (klass);
99   GailContainerClass *container_class;
100
101   container_class = (GailContainerClass*)klass;
102
103   gobject_class->finalize = gail_statusbar_finalize;
104
105   class->get_name = gail_statusbar_get_name;
106   class->get_n_children = gail_statusbar_get_n_children;
107   class->ref_child = gail_statusbar_ref_child;
108   class->initialize = gail_statusbar_real_initialize;
109   /*
110    * As we report the statusbar as having no children we are not interested
111    * in add and remove signals
112    */
113   container_class->add_gtk = NULL;
114   container_class->remove_gtk = NULL;
115 }
116
117 static void
118 gail_statusbar_init (GailStatusbar *bar)
119 {
120 }
121
122 static G_CONST_RETURN gchar*
123 gail_statusbar_get_name (AtkObject *obj)
124 {
125   G_CONST_RETURN gchar* name;
126
127   g_return_val_if_fail (GAIL_IS_STATUSBAR (obj), NULL);
128
129   name = ATK_OBJECT_CLASS (gail_statusbar_parent_class)->get_name (obj);
130   if (name != NULL)
131     return name;
132   else
133     {
134       /*
135        * Get the text on the label
136        */
137       GtkWidget *widget;
138       GtkWidget *label;
139
140       widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (obj));
141       if (widget == NULL)
142         /*
143          * State is defunct
144          */
145         return NULL;
146
147      g_return_val_if_fail (GTK_IS_STATUSBAR (widget), NULL);
148      label = get_label_from_statusbar (widget);
149      if (GTK_IS_LABEL (label))
150        return gtk_label_get_label (GTK_LABEL (label));
151      else 
152        return NULL;
153    }
154 }
155
156 static gint
157 gail_statusbar_get_n_children (AtkObject *obj)
158 {
159   GtkWidget *widget;
160   GList *children;
161   gint count = 0;
162
163   widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (obj));
164   if (widget == NULL)
165     return 0;
166
167   children = gtk_container_get_children (GTK_CONTAINER (widget));
168   if (children != NULL)
169     {
170       count = g_list_length (children);
171       g_list_free (children);
172     }
173
174   return count;
175 }
176
177 static AtkObject*
178 gail_statusbar_ref_child (AtkObject *obj,
179                           gint      i)
180 {
181   GList *children, *tmp_list;
182   AtkObject  *accessible;
183   GtkWidget *widget;
184
185   g_return_val_if_fail ((i >= 0), NULL);
186   widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (obj));
187   if (widget == NULL)
188     return NULL;
189
190   children = gtk_container_get_children (GTK_CONTAINER (widget));
191   if (children == NULL)
192     return NULL;
193
194   tmp_list = g_list_nth (children, i);
195   if (!tmp_list)
196     {
197       g_list_free (children);
198       return NULL;
199     }
200   accessible = gtk_widget_get_accessible (GTK_WIDGET (tmp_list->data));
201
202   g_list_free (children);
203   g_object_ref (accessible);
204   return accessible;
205 }
206
207 static void
208 gail_statusbar_real_initialize (AtkObject *obj,
209                                 gpointer  data)
210 {
211   GailStatusbar *statusbar = GAIL_STATUSBAR (obj);
212   GtkWidget *label;
213
214   ATK_OBJECT_CLASS (gail_statusbar_parent_class)->initialize (obj, data);
215
216   /*
217    * We get notified of changes to the label
218    */
219   label = get_label_from_statusbar (GTK_WIDGET (data));
220   if (GTK_IS_LABEL (label))
221     {
222       gail_statusbar_init_textutil (statusbar, label);
223     }
224
225   obj->role = ATK_ROLE_STATUSBAR;
226
227 }
228
229 static gint
230 gail_statusbar_notify (GObject    *obj, 
231                        GParamSpec *pspec,
232                        gpointer   user_data)
233 {
234   AtkObject *atk_obj = ATK_OBJECT (user_data);
235   GtkLabel *label;
236   GailStatusbar *statusbar;
237
238   if (strcmp (pspec->name, "label") == 0)
239     {
240       const gchar* label_text;
241
242       label = GTK_LABEL (obj);
243
244       label_text = gtk_label_get_text (label);
245
246       statusbar = GAIL_STATUSBAR (atk_obj);
247       gail_text_util_text_setup (statusbar->textutil, label_text);
248
249       if (atk_obj->name == NULL)
250       {
251         /*
252          * The label has changed so notify a change in accessible-name
253          */
254         g_object_notify (G_OBJECT (atk_obj), "accessible-name");
255       }
256       /*
257        * The label is the only property which can be changed
258        */
259       g_signal_emit_by_name (atk_obj, "visible_data_changed");
260     }
261   return 1;
262 }
263
264 static void
265 gail_statusbar_init_textutil (GailStatusbar *statusbar,
266                               GtkWidget     *label)
267 {
268   const gchar *label_text;
269
270   statusbar->textutil = gail_text_util_new ();
271   label_text = gtk_label_get_text (GTK_LABEL (label));
272   gail_text_util_text_setup (statusbar->textutil, label_text);
273   g_signal_connect (label,
274                     "notify",
275                     (GCallback) gail_statusbar_notify,
276                     statusbar);     
277 }
278
279 static void
280 gail_statusbar_finalize (GObject *object)
281 {
282   GailStatusbar *statusbar = GAIL_STATUSBAR (object);
283
284   if (statusbar->textutil)
285     {
286       g_object_unref (statusbar->textutil);
287     }
288   G_OBJECT_CLASS (gail_statusbar_parent_class)->finalize (object);
289 }
290
291 /* atktext.h */
292
293 static void
294 atk_text_interface_init (AtkTextIface *iface)
295 {
296   iface->get_text = gail_statusbar_get_text;
297   iface->get_character_at_offset = gail_statusbar_get_character_at_offset;
298   iface->get_text_before_offset = gail_statusbar_get_text_before_offset;
299   iface->get_text_at_offset = gail_statusbar_get_text_at_offset;
300   iface->get_text_after_offset = gail_statusbar_get_text_after_offset;
301   iface->get_character_count = gail_statusbar_get_character_count;
302   iface->get_character_extents = gail_statusbar_get_character_extents;
303   iface->get_offset_at_point = gail_statusbar_get_offset_at_point;
304   iface->get_run_attributes = gail_statusbar_get_run_attributes;
305   iface->get_default_attributes = gail_statusbar_get_default_attributes;
306 }
307
308 static gchar*
309 gail_statusbar_get_text (AtkText *text,
310                          gint    start_pos,
311                          gint    end_pos)
312 {
313   GtkWidget *widget;
314   GtkWidget *label;
315   GailStatusbar *statusbar;
316   const gchar *label_text;
317
318   widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (text));
319   if (widget == NULL)
320     /* State is defunct */
321     return NULL;
322
323   label = get_label_from_statusbar (widget);
324
325   if (!GTK_IS_LABEL (label))
326     return NULL;
327
328   statusbar = GAIL_STATUSBAR (text);
329   if (!statusbar->textutil) 
330     gail_statusbar_init_textutil (statusbar, label);
331
332   label_text = gtk_label_get_text (GTK_LABEL (label));
333
334   if (label_text == NULL)
335     return NULL;
336   else
337   {
338     return gail_text_util_get_substring (statusbar->textutil, 
339                                          start_pos, end_pos);
340   }
341 }
342
343 static gchar*
344 gail_statusbar_get_text_before_offset (AtkText         *text,
345                                        gint            offset,
346                                        AtkTextBoundary boundary_type,
347                                        gint            *start_offset,
348                                        gint            *end_offset)
349 {
350   GtkWidget *widget;
351   GtkWidget *label;
352   GailStatusbar *statusbar;
353   
354   widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (text));
355   
356   if (widget == NULL)
357     /* State is defunct */
358     return NULL;
359   
360   /* Get label */
361   label = get_label_from_statusbar (widget);
362
363   if (!GTK_IS_LABEL(label))
364     return NULL;
365
366   statusbar = GAIL_STATUSBAR (text);
367   if (!statusbar->textutil)
368     gail_statusbar_init_textutil (statusbar, label);
369
370   return gail_text_util_get_text (statusbar->textutil,
371                            gtk_label_get_layout (GTK_LABEL (label)), GAIL_BEFORE_OFFSET, 
372                            boundary_type, offset, start_offset, end_offset); 
373 }
374
375 static gchar*
376 gail_statusbar_get_text_at_offset (AtkText         *text,
377                                    gint            offset,
378                                    AtkTextBoundary boundary_type,
379                                    gint            *start_offset,
380                                    gint            *end_offset)
381 {
382   GtkWidget *widget;
383   GtkWidget *label;
384   GailStatusbar *statusbar;
385  
386   widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (text));
387   
388   if (widget == NULL)
389     /* State is defunct */
390     return NULL;
391   
392   /* Get label */
393   label = get_label_from_statusbar (widget);
394
395   if (!GTK_IS_LABEL(label))
396     return NULL;
397
398   statusbar = GAIL_STATUSBAR (text);
399   if (!statusbar->textutil)
400     gail_statusbar_init_textutil (statusbar, label);
401
402   return gail_text_util_get_text (statusbar->textutil,
403                               gtk_label_get_layout (GTK_LABEL (label)), GAIL_AT_OFFSET, 
404                               boundary_type, offset, start_offset, end_offset);
405 }
406
407 static gchar*
408 gail_statusbar_get_text_after_offset (AtkText         *text,
409                                       gint            offset,
410                                       AtkTextBoundary boundary_type,
411                                       gint            *start_offset,
412                                       gint            *end_offset)
413 {
414   GtkWidget *widget;
415   GtkWidget *label;
416   GailStatusbar *statusbar;
417
418   widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (text));
419   
420   if (widget == NULL)
421   {
422     /* State is defunct */
423     return NULL;
424   }
425   
426   /* Get label */
427   label = get_label_from_statusbar (widget);
428
429   if (!GTK_IS_LABEL(label))
430     return NULL;
431
432   statusbar = GAIL_STATUSBAR (text);
433   if (!statusbar->textutil)
434     gail_statusbar_init_textutil (statusbar, label);
435
436   return gail_text_util_get_text (statusbar->textutil,
437                            gtk_label_get_layout (GTK_LABEL (label)), GAIL_AFTER_OFFSET, 
438                            boundary_type, offset, start_offset, end_offset);
439 }
440
441 static gint
442 gail_statusbar_get_character_count (AtkText *text)
443 {
444   GtkWidget *widget;
445   GtkWidget *label;
446
447   widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (text));
448   if (widget == NULL)
449     /* State is defunct */
450     return 0;
451
452   label = get_label_from_statusbar (widget);
453
454   if (!GTK_IS_LABEL(label))
455     return 0;
456
457   return g_utf8_strlen (gtk_label_get_text (GTK_LABEL (label)), -1);
458 }
459
460 static void
461 gail_statusbar_get_character_extents (AtkText      *text,
462                                       gint         offset,
463                                       gint         *x,
464                                       gint         *y,
465                                       gint         *width,
466                                       gint         *height,
467                                       AtkCoordType coords)
468 {
469   GtkWidget *widget;
470   GtkWidget *label;
471   PangoRectangle char_rect;
472   gint index, x_layout, y_layout;
473   const gchar *label_text;
474  
475   widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (text));
476
477   if (widget == NULL)
478     /* State is defunct */
479     return;
480
481   label = get_label_from_statusbar (widget);
482
483   if (!GTK_IS_LABEL(label))
484     return;
485   
486   gtk_label_get_layout_offsets (GTK_LABEL (label), &x_layout, &y_layout);
487   label_text = gtk_label_get_text (GTK_LABEL (label));
488   index = g_utf8_offset_to_pointer (label_text, offset) - label_text;
489   pango_layout_index_to_pos (gtk_label_get_layout (GTK_LABEL (label)), index, &char_rect);
490   
491   gail_misc_get_extents_from_pango_rectangle (label, &char_rect, 
492                     x_layout, y_layout, x, y, width, height, coords);
493
494
495 static gint 
496 gail_statusbar_get_offset_at_point (AtkText      *text,
497                                     gint         x,
498                                     gint         y,
499                                     AtkCoordType coords)
500
501   GtkWidget *widget;
502   GtkWidget *label;
503   gint index, x_layout, y_layout;
504   const gchar *label_text;
505
506   widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (text));
507   if (widget == NULL)
508     /* State is defunct */
509     return -1;
510
511   label = get_label_from_statusbar (widget);
512
513   if (!GTK_IS_LABEL(label))
514     return -1;
515   
516   gtk_label_get_layout_offsets (GTK_LABEL (label), &x_layout, &y_layout);
517   
518   index = gail_misc_get_index_at_point_in_layout (label, 
519                                               gtk_label_get_layout (GTK_LABEL (label)), 
520                                               x_layout, y_layout, x, y, coords);
521   label_text = gtk_label_get_text (GTK_LABEL (label));
522   if (index == -1)
523     {
524       if (coords == ATK_XY_WINDOW || coords == ATK_XY_SCREEN)
525         return g_utf8_strlen (label_text, -1);
526
527       return index;  
528     }
529   else
530     return g_utf8_pointer_to_offset (label_text, label_text + index);  
531 }
532
533 static AtkAttributeSet*
534 gail_statusbar_get_run_attributes (AtkText *text,
535                                    gint    offset,
536                                    gint    *start_offset,
537                                    gint    *end_offset)
538 {
539   GtkWidget *widget;
540   GtkWidget *label;
541   AtkAttributeSet *at_set = NULL;
542   GtkJustification justify;
543   GtkTextDirection dir;
544
545   widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (text));
546   if (widget == NULL)
547     /* State is defunct */
548     return NULL;
549
550   label = get_label_from_statusbar (widget);
551
552   if (!GTK_IS_LABEL(label))
553     return NULL;
554   
555   /* Get values set for entire label, if any */
556   justify = gtk_label_get_justify (GTK_LABEL (label));
557   if (justify != GTK_JUSTIFY_CENTER)
558     {
559       at_set = gail_misc_add_attribute (at_set, 
560                                         ATK_TEXT_ATTR_JUSTIFICATION,
561      g_strdup (atk_text_attribute_get_value (ATK_TEXT_ATTR_JUSTIFICATION, justify)));
562     }
563   dir = gtk_widget_get_direction (label);
564   if (dir == GTK_TEXT_DIR_RTL)
565     {
566       at_set = gail_misc_add_attribute (at_set, 
567                                         ATK_TEXT_ATTR_DIRECTION,
568      g_strdup (atk_text_attribute_get_value (ATK_TEXT_ATTR_DIRECTION, dir)));
569     }
570
571   at_set = gail_misc_layout_get_run_attributes (at_set,
572                                                 gtk_label_get_layout (GTK_LABEL (label)),
573                                                 (gchar *) gtk_label_get_text (GTK_LABEL (label)),
574                                                 offset,
575                                                 start_offset,
576                                                 end_offset);
577   return at_set;
578 }
579
580 static AtkAttributeSet*
581 gail_statusbar_get_default_attributes (AtkText *text)
582 {
583   GtkWidget *widget;
584   GtkWidget *label;
585   AtkAttributeSet *at_set = NULL;
586
587   widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (text));
588   if (widget == NULL)
589     /* State is defunct */
590     return NULL;
591
592   label = get_label_from_statusbar (widget);
593
594   if (!GTK_IS_LABEL(label))
595     return NULL;
596
597   at_set = gail_misc_get_default_attributes (at_set,
598                                              gtk_label_get_layout (GTK_LABEL (label)),
599                                              widget);
600   return at_set;
601 }
602
603 static gunichar 
604 gail_statusbar_get_character_at_offset (AtkText *text,
605                                         gint    offset)
606 {
607   GtkWidget *widget;
608   GtkWidget *label;
609   const gchar *string;
610   gchar *index;
611
612   widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (text));
613   if (widget == NULL)
614     /* State is defunct */
615     return '\0';
616
617   label = get_label_from_statusbar (widget);
618
619   if (!GTK_IS_LABEL(label))
620     return '\0';
621   string = gtk_label_get_text (GTK_LABEL (label));
622   if (offset >= g_utf8_strlen (string, -1))
623     return '\0';
624   index = g_utf8_offset_to_pointer (string, offset);
625
626   return g_utf8_get_char (index);
627 }
628
629 static GtkWidget*
630 get_label_from_statusbar (GtkWidget *statusbar)
631 {
632   GtkWidget *message_area;
633   GList *children, *l;
634   GtkWidget *child;
635
636   message_area = gtk_statusbar_get_message_area (GTK_STATUSBAR (statusbar));
637
638   children = gtk_container_get_children (GTK_CONTAINER (message_area));
639   for (l = children; l; l = l->next)
640     {
641       child = l->data;
642       if (GTK_IS_LABEL (child))
643         break;
644       child = NULL;
645     }
646
647   g_list_free (children);
648
649   return child;
650 }