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