source: trunk/third/gail/gail/gailwidget.c @ 20902

Revision 20902, 31.9 KB checked in by ghudson, 20 years ago (diff)
This commit was generated by cvs2svn to compensate for changes in r20901, which included commits to RCS files with non-trunk default branches.
Line 
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 "gailwidget.h"
23#include "gailnotebookpage.h"
24#include "gailcanvaswidget.h"
25
26static void gail_widget_class_init (GailWidgetClass *klass);
27
28static void gail_widget_connect_widget_destroyed (GtkAccessible    *accessible);
29static void gail_widget_destroyed                (GtkWidget        *widget,
30                                                  GtkAccessible    *accessible);
31
32static G_CONST_RETURN gchar* gail_widget_get_description (AtkObject *accessible);
33static AtkObject* gail_widget_get_parent (AtkObject *accessible);
34static AtkStateSet* gail_widget_ref_state_set (AtkObject *accessible);
35static AtkRelationSet* gail_widget_ref_relation_set (AtkObject *accessible);
36static gint gail_widget_get_index_in_parent (AtkObject *accessible);
37
38static void atk_component_interface_init (AtkComponentIface *iface);
39
40static guint    gail_widget_add_focus_handler
41                                           (AtkComponent    *component,
42                                            AtkFocusHandler handler);
43
44static void     gail_widget_get_extents    (AtkComponent    *component,
45                                            gint            *x,
46                                            gint            *y,
47                                            gint            *width,
48                                            gint            *height,
49                                            AtkCoordType    coord_type);
50
51static void     gail_widget_get_size       (AtkComponent    *component,
52                                            gint            *width,
53                                            gint            *height);
54
55static AtkLayer gail_widget_get_layer      (AtkComponent *component);
56
57static gboolean gail_widget_grab_focus     (AtkComponent    *component);
58
59
60static void     gail_widget_remove_focus_handler
61                                           (AtkComponent    *component,
62                                            guint           handler_id);
63
64static gboolean gail_widget_set_extents    (AtkComponent    *component,
65                                            gint            x,
66                                            gint            y,
67                                            gint            width,
68                                            gint            height,
69                                            AtkCoordType    coord_type);
70
71static gboolean gail_widget_set_position   (AtkComponent    *component,
72                                            gint            x,
73                                            gint            y,
74                                            AtkCoordType    coord_type);
75
76static gboolean gail_widget_set_size       (AtkComponent    *component,
77                                            gint            width,
78                                            gint            height);
79
80#if 0
81/*
82 * We will get the parent from the widget structure rather than
83 * use this function
84 */
85static GtkWidget* _gail_widget_get_parent        (GtkWidget     *widget);
86#endif
87
88static gint       gail_widget_map_gtk            (GtkWidget     *widget);
89static void       gail_widget_real_notify_gtk    (GObject       *obj,
90                                                  GParamSpec    *pspec);
91static void       gail_widget_notify_gtk         (GObject       *obj,
92                                                  GParamSpec    *pspec);
93static gboolean   gail_widget_focus_gtk          (GtkWidget     *widget,
94                                                  GdkEventFocus *event);
95static gboolean   gail_widget_real_focus_gtk     (GtkWidget     *widget,
96                                                  GdkEventFocus *event);
97static void       gail_widget_size_allocate_gtk  (GtkWidget     *widget,
98                                                  GtkAllocation *allocation);
99
100static void       gail_widget_focus_event        (AtkObject     *obj,
101                                                  gboolean      focus_in);
102
103static void       gail_widget_real_initialize    (AtkObject     *obj,
104                                                  gpointer      data);
105static GtkWidget* gail_widget_find_viewport      (GtkWidget     *widget);
106static gboolean   gail_widget_on_screen          (GtkWidget     *widget);
107
108static gpointer parent_class = NULL;
109
110GType
111gail_widget_get_type (void)
112{
113  static GType type = 0;
114
115  if (!type)
116    {
117      static const GTypeInfo tinfo =
118      {
119        sizeof (GailWidgetClass),
120        (GBaseInitFunc) NULL, /* base init */
121        (GBaseFinalizeFunc) NULL, /* base finalize */
122        (GClassInitFunc) gail_widget_class_init, /* class init */
123        (GClassFinalizeFunc) NULL, /* class finalize */
124        NULL, /* class data */
125        sizeof (GailWidget), /* instance size */
126        0, /* nb preallocs */
127        (GInstanceInitFunc) NULL, /* instance init */
128        NULL /* value table */
129      };
130
131      static const GInterfaceInfo atk_component_info =
132      {
133        (GInterfaceInitFunc) atk_component_interface_init,
134        (GInterfaceFinalizeFunc) NULL,
135        NULL
136      };
137
138      type = g_type_register_static (GTK_TYPE_ACCESSIBLE,
139                                     "GailWidget", &tinfo, 0);
140      g_type_add_interface_static (type, ATK_TYPE_COMPONENT,
141                                   &atk_component_info);
142    }
143
144  return type;
145}
146
147static void
148gail_widget_class_init (GailWidgetClass *klass)
149{
150  AtkObjectClass *class = ATK_OBJECT_CLASS (klass);
151  GtkAccessibleClass *accessible_class = GTK_ACCESSIBLE_CLASS (klass);
152
153  parent_class = g_type_class_peek_parent (klass);
154
155  klass->notify_gtk = gail_widget_real_notify_gtk;
156  klass->focus_gtk = gail_widget_real_focus_gtk;
157
158  accessible_class->connect_widget_destroyed = gail_widget_connect_widget_destroyed;
159
160  class->get_description = gail_widget_get_description;
161  class->get_parent = gail_widget_get_parent;
162  class->ref_relation_set = gail_widget_ref_relation_set;
163  class->ref_state_set = gail_widget_ref_state_set;
164  class->get_index_in_parent = gail_widget_get_index_in_parent;
165  class->initialize = gail_widget_real_initialize;
166}
167
168/**
169 * This function  specifies the GtkWidget for which the GailWidget was created
170 * and specifies a handler to be called when the GtkWidget is destroyed.
171 **/
172static void
173gail_widget_real_initialize (AtkObject *obj,
174                             gpointer  data)
175{
176  GtkAccessible *accessible;
177  GtkWidget *widget;
178
179  g_return_if_fail (GTK_IS_WIDGET (data));
180
181  widget = GTK_WIDGET (data);
182
183  accessible = GTK_ACCESSIBLE (obj);
184  accessible->widget = widget;
185  gtk_accessible_connect_widget_destroyed (accessible);
186  g_signal_connect_after (widget,
187                          "focus-in-event",
188                          G_CALLBACK (gail_widget_focus_gtk),
189                          NULL);
190  g_signal_connect_after (widget,
191                          "focus-out-event",
192                          G_CALLBACK (gail_widget_focus_gtk),
193                          NULL);
194  g_signal_connect (widget,
195                    "notify",
196                    G_CALLBACK (gail_widget_notify_gtk),
197                    NULL);
198  g_signal_connect (widget,
199                    "size_allocate",
200                    G_CALLBACK (gail_widget_size_allocate_gtk),
201                    NULL);
202  atk_component_add_focus_handler (ATK_COMPONENT (accessible),
203                                   gail_widget_focus_event);
204  /*
205   * Add signal handlers for GTK signals required to support property changes
206   */
207  g_signal_connect (widget,
208                    "map",
209                    G_CALLBACK (gail_widget_map_gtk),
210                    NULL);
211  g_signal_connect (widget,
212                    "unmap",
213                    G_CALLBACK (gail_widget_map_gtk),
214                    NULL);
215  g_object_set_data (G_OBJECT (obj), "atk-component-layer",
216                     GINT_TO_POINTER (ATK_LAYER_WIDGET));
217
218  obj->role = ATK_ROLE_UNKNOWN;
219}
220
221AtkObject*
222gail_widget_new (GtkWidget *widget)
223{
224  GObject *object;
225  AtkObject *accessible;
226
227  g_return_val_if_fail (GTK_IS_WIDGET (widget), NULL);
228
229  object = g_object_new (GAIL_TYPE_WIDGET, NULL);
230
231  accessible = ATK_OBJECT (object);
232  atk_object_initialize (accessible, widget);
233
234  return accessible;
235}
236
237/*
238 * This function specifies the function to be called when the widget
239 * is destroyed
240 */
241static void
242gail_widget_connect_widget_destroyed (GtkAccessible *accessible)
243{
244  if (accessible->widget)
245    {
246      g_signal_connect_after (accessible->widget,
247                              "destroy",
248                              G_CALLBACK (gail_widget_destroyed),
249                              accessible);
250    }
251}
252
253/*
254 * This function is called when the widget is destroyed.
255 * It sets the widget field in the GtkAccessible structure to NULL
256 * and emits a state-change signal for the state ATK_STATE_DEFUNCT
257 */
258static void
259gail_widget_destroyed (GtkWidget     *widget,
260                       GtkAccessible *accessible)
261{
262  accessible->widget = NULL;
263  atk_object_notify_state_change (ATK_OBJECT (accessible), ATK_STATE_DEFUNCT,
264                                  TRUE);
265}
266
267static G_CONST_RETURN gchar*
268gail_widget_get_description (AtkObject *accessible)
269{
270  if (accessible->description)
271    return accessible->description;
272  else
273    {
274      /* Get the tooltip from the widget */
275      GtkAccessible *obj = GTK_ACCESSIBLE (accessible);
276      GtkTooltipsData *data;
277
278      g_return_val_if_fail (obj, NULL);
279
280      if (obj->widget == NULL)
281        /*
282         * Object is defunct
283         */
284        return NULL;
285 
286      g_return_val_if_fail (GTK_WIDGET (obj->widget), NULL);
287   
288      data = gtk_tooltips_data_get (obj->widget);
289      if (data == NULL)
290        return NULL;
291
292      return data->tip_text;
293    }
294}
295
296static AtkObject*
297gail_widget_get_parent (AtkObject *accessible)
298{
299  AtkObject *parent;
300
301  parent = accessible->accessible_parent;
302
303  if (parent != NULL)
304    g_return_val_if_fail (ATK_IS_OBJECT (parent), NULL);
305  else
306    {
307      GtkWidget *widget, *parent_widget;
308
309      widget = GTK_ACCESSIBLE (accessible)->widget;
310      if (widget == NULL)
311        /*
312         * State is defunct
313         */
314        return NULL;
315      g_return_val_if_fail (GTK_IS_WIDGET (widget), NULL);
316
317      parent_widget = widget->parent;
318      if (parent_widget == NULL)
319        return NULL;
320
321      /*
322       * For a widget whose parent is a GtkNoteBook, we return the
323       * accessible object corresponding the GtkNotebookPage containing
324       * the widget as the accessible parent.
325       */
326      if (GTK_IS_NOTEBOOK (parent_widget))
327        {
328          gint page_num;
329          GtkWidget *child;
330          GtkNotebook *notebook;
331
332          page_num = 0;
333          notebook = GTK_NOTEBOOK (parent_widget);
334          while (TRUE)
335            {
336              child = gtk_notebook_get_nth_page (notebook, page_num);
337              if (!child)
338                break;
339              if (child == widget)
340                {
341                  parent = gtk_widget_get_accessible (parent_widget);
342                  parent = atk_object_ref_accessible_child (parent, page_num);
343                  g_object_unref (parent);
344                  return parent;
345                }
346              page_num++;
347            }
348        }
349
350      parent = gtk_widget_get_accessible (parent_widget);
351    }
352  return parent;
353}
354
355static GtkWidget*
356find_label (GtkWidget *widget)
357{
358  GList *labels;
359  GtkWidget *label;
360  GtkWidget *temp_widget;
361
362  labels = gtk_widget_list_mnemonic_labels (widget);
363  label = NULL;
364  if (labels)
365    {
366      if (labels->data)
367        {
368          if (labels->next)
369            {
370              g_warning ("Widget (%s) has more than one label", G_OBJECT_TYPE_NAME (widget));
371             
372            }
373          else
374            {
375              label = labels->data;
376            }
377        }
378      g_list_free (labels);
379    }
380
381  /*
382   * Ignore a label within a button; bug #136602
383   */
384  if (label && GTK_IS_BUTTON (widget))
385    {
386      temp_widget = label;
387      while (temp_widget)
388        {
389          if (temp_widget == widget)
390            {
391              label = NULL;
392              break;
393            }
394          temp_widget = gtk_widget_get_parent (temp_widget);
395        }
396    }
397  return label;
398}
399
400static AtkRelationSet*
401gail_widget_ref_relation_set (AtkObject *obj)
402{
403  GtkWidget *widget;
404  AtkRelationSet *relation_set;
405  GtkWidget *label;
406  AtkObject *array[1];
407  AtkRelation* relation;
408
409  g_return_val_if_fail (GAIL_IS_WIDGET (obj), NULL);
410
411  widget = GTK_ACCESSIBLE (obj)->widget;
412  if (widget == NULL)
413    /*
414     * State is defunct
415     */
416    return NULL;
417
418  relation_set = ATK_OBJECT_CLASS (parent_class)->ref_relation_set (obj);
419
420  if (GTK_IS_BOX (widget) && !GTK_IS_COMBO (widget))
421      /*
422       * Do not report labelled-by for a GtkBox which could be a
423       * GnomeFileEntry.
424       */
425    return relation_set;
426
427  if (!atk_relation_set_contains (relation_set, ATK_RELATION_LABELLED_BY))
428    {
429      label = find_label (widget);
430      if (label == NULL)
431        {
432          if (GTK_IS_BUTTON (widget))
433            /*
434             * Handle the case where GnomeIconEntry is the mnemonic widget.
435             * The GtkButton which is a grandchild of the GnomeIconEntry
436             * should really be the mnemonic widget. See bug #133967.
437             */
438            {
439              GtkWidget *temp_widget;
440
441              temp_widget = gtk_widget_get_parent (widget);
442
443              if (GTK_IS_ALIGNMENT (temp_widget))
444                {
445                  temp_widget = gtk_widget_get_parent (temp_widget);
446                  if (GTK_IS_BOX (temp_widget))
447                    {
448                      label = find_label (temp_widget);
449                 
450                      if (!label)
451                        label = find_label (gtk_widget_get_parent (temp_widget));
452                    }
453                }
454            }
455          else if (GTK_IS_COMBO (widget))
456            /*
457             * Handle the case when GnomeFileEntry is the mnemonic widget.
458             * The GnomeEntry which is a grandchild of the GnomeFileEntry
459             * should be the mnemonic widget. See bug #137584.
460             */
461            {
462              GtkWidget *temp_widget;
463
464              temp_widget = gtk_widget_get_parent (widget);
465
466              if (GTK_IS_HBOX (temp_widget))
467                {
468                  temp_widget = gtk_widget_get_parent (temp_widget);
469                  if (GTK_IS_BOX (temp_widget))
470                    {
471                      label = find_label (temp_widget);
472                    }
473                }
474            }
475        }
476
477      if (label)
478        {
479          array [0] = gtk_widget_get_accessible (label);
480
481          relation = atk_relation_new (array, 1, ATK_RELATION_LABELLED_BY);
482          atk_relation_set_add (relation_set, relation);
483          g_object_unref (relation);
484        }
485    }
486
487  return relation_set;
488}
489
490static AtkStateSet*
491gail_widget_ref_state_set (AtkObject *accessible)
492{
493  GtkWidget *widget = GTK_ACCESSIBLE (accessible)->widget;
494  AtkStateSet *state_set;
495
496  state_set = ATK_OBJECT_CLASS (parent_class)->ref_state_set (accessible);
497
498  if (widget == NULL)
499    {
500      atk_state_set_add_state (state_set, ATK_STATE_DEFUNCT);
501    }
502  else
503    {
504      if (GTK_WIDGET_IS_SENSITIVE (widget))
505        {
506          atk_state_set_add_state (state_set, ATK_STATE_SENSITIVE);
507          atk_state_set_add_state (state_set, ATK_STATE_ENABLED);
508        }
509 
510      if (GTK_WIDGET_CAN_FOCUS (widget))
511        {
512          atk_state_set_add_state (state_set, ATK_STATE_FOCUSABLE);
513        }
514      /*
515       * We do not currently generate notifications when an ATK object
516       * corresponding to a GtkWidget changes visibility by being scrolled
517       * on or off the screen.  The testcase for this is the main window
518       * of the testgtk application in which a set of buttons in a GtkVBox
519       * is in a scrooled window with a viewport.
520       *
521       * To generate the notifications we would need to do the following:
522       * 1) Find the GtkViewPort among the antecendents of the objects
523       * 2) Create an accesible for the GtkViewPort
524       * 3) Connect to the value-changed signal on the viewport
525       * 4) When the signal is received we need to traverse the children
526       * of the viewport and check whether the children are visible or not
527       * visible; we may want to restrict this to the widgets for which
528       * accessible objects have been created.
529       * 5) We probably need to store a variable on_screen in the
530       * GailWidget data structure so we can determine whether the value has
531       * changed.
532       */
533      if (gail_widget_on_screen (widget))
534        {
535          if (GTK_WIDGET_VISIBLE (widget))
536            {
537              atk_state_set_add_state (state_set, ATK_STATE_VISIBLE);
538
539              if (GTK_WIDGET_MAPPED (widget))
540                {
541                  atk_state_set_add_state (state_set, ATK_STATE_SHOWING);
542                }
543            }
544        }
545 
546      if (GTK_WIDGET_HAS_FOCUS (widget))
547        {
548          AtkObject *focus_obj;
549
550          focus_obj = g_object_get_data (G_OBJECT (accessible), "gail-focus-object");
551          if (focus_obj == NULL)
552            atk_state_set_add_state (state_set, ATK_STATE_FOCUSED);
553        }
554    }
555  return state_set;
556}
557
558static gint
559gail_widget_get_index_in_parent (AtkObject *accessible)
560{
561  GtkWidget *widget;
562  GtkWidget *parent_widget;
563  gint index;
564  GList *children;
565
566  widget = GTK_ACCESSIBLE (accessible)->widget;
567
568  if (widget == NULL)
569    /*
570     * State is defunct
571     */
572    return -1;
573
574  if (accessible->accessible_parent)
575    {
576      AtkObject *parent;
577
578      parent = accessible->accessible_parent;
579
580      if (GAIL_IS_NOTEBOOK_PAGE (parent) ||
581          GAIL_IS_CANVAS_WIDGET (parent))
582        return 0;
583      else
584        {
585          gint n_children, i;
586          gboolean found = FALSE;
587
588          n_children = atk_object_get_n_accessible_children (parent);
589          for (i = 0; i < n_children; i++)
590            {
591              AtkObject *child;
592
593              child = atk_object_ref_accessible_child (parent, i);
594              if (child == accessible)
595                found = TRUE;
596
597              g_object_unref (child);
598              if (found)
599                return i;
600            }
601        }
602    }
603
604  g_return_val_if_fail (GTK_IS_WIDGET (widget), -1);
605  parent_widget = widget->parent;
606  if (parent_widget == NULL)
607    return -1;
608  g_return_val_if_fail (GTK_IS_CONTAINER (parent_widget), -1);
609
610  children = gtk_container_get_children (GTK_CONTAINER (parent_widget));
611
612  index = g_list_index (children, widget);
613  g_list_free (children);
614  return index; 
615}
616
617static void
618atk_component_interface_init (AtkComponentIface *iface)
619{
620  g_return_if_fail (iface != NULL);
621
622  /*
623   * Use default implementation for contains and get_position
624   */
625  iface->add_focus_handler = gail_widget_add_focus_handler;
626  iface->get_extents = gail_widget_get_extents;
627  iface->get_size = gail_widget_get_size;
628  iface->get_layer = gail_widget_get_layer;
629  iface->grab_focus = gail_widget_grab_focus;
630  iface->remove_focus_handler = gail_widget_remove_focus_handler;
631  iface->set_extents = gail_widget_set_extents;
632  iface->set_position = gail_widget_set_position;
633  iface->set_size = gail_widget_set_size;
634}
635
636static guint
637gail_widget_add_focus_handler (AtkComponent    *component,
638                               AtkFocusHandler handler)
639{
640  GSignalMatchType match_type;
641  gulong ret;
642  guint signal_id;
643
644  match_type = G_SIGNAL_MATCH_ID | G_SIGNAL_MATCH_FUNC;
645  signal_id = g_signal_lookup ("focus-event", ATK_TYPE_OBJECT);
646
647  ret = g_signal_handler_find (component, match_type, signal_id, 0, NULL,
648                               (gpointer) handler, NULL);
649  if (!ret)
650    {
651      return g_signal_connect_closure_by_id (component,
652                                             signal_id, 0,
653                                             g_cclosure_new (
654                                             G_CALLBACK (handler), NULL,
655                                             (GClosureNotify) NULL),
656                                             FALSE);
657    }
658  else
659    {
660      return 0;
661    }
662}
663
664static void
665gail_widget_get_extents (AtkComponent   *component,
666                         gint           *x,
667                         gint           *y,
668                         gint           *width,
669                         gint           *height,
670                         AtkCoordType   coord_type)
671{
672  GdkWindow *window;
673  gint x_window, y_window;
674  gint x_toplevel, y_toplevel;
675  GtkWidget *widget = GTK_ACCESSIBLE (component)->widget;
676
677  if (widget == NULL)
678    /*
679     * Object is defunct
680     */
681    return;
682
683  g_return_if_fail (GTK_IS_WIDGET (widget));
684
685  *width = widget->allocation.width;
686  *height = widget->allocation.height;
687  if (!gail_widget_on_screen (widget) || (!GTK_WIDGET_DRAWABLE (widget)))
688    {
689      *x = G_MININT;
690      *y = G_MININT;
691      return;
692    }
693
694  if (widget->parent)
695    {
696      *x = widget->allocation.x;
697      *y = widget->allocation.y;
698      window = gtk_widget_get_parent_window (widget);
699    }
700  else
701    {
702      *x = 0;
703      *y = 0;
704      window = widget->window;
705    }
706  gdk_window_get_origin (window, &x_window, &y_window);
707  *x += x_window;
708  *y += y_window;
709
710 
711 if (coord_type == ATK_XY_WINDOW)
712    {
713      window = gdk_window_get_toplevel (widget->window);
714      gdk_window_get_origin (window, &x_toplevel, &y_toplevel);
715
716      *x -= x_toplevel;
717      *y -= y_toplevel;
718    }
719}
720
721static void
722gail_widget_get_size (AtkComponent   *component,
723                      gint           *width,
724                      gint           *height)
725{
726  GtkWidget *widget = GTK_ACCESSIBLE (component)->widget;
727
728  if (widget == NULL)
729    /*
730     * Object is defunct
731     */
732    return;
733
734  g_return_if_fail (GTK_IS_WIDGET (widget));
735
736  *width = widget->allocation.width;
737  *height = widget->allocation.height;
738}
739
740static AtkLayer
741gail_widget_get_layer (AtkComponent *component)
742{
743  gint layer;
744  layer = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (component), "atk-component-layer"));
745
746  return (AtkLayer) layer;
747}
748
749static gboolean
750gail_widget_grab_focus (AtkComponent   *component)
751{
752  GtkWidget *widget = GTK_ACCESSIBLE (component)->widget;
753  GtkWidget *toplevel;
754
755  g_return_val_if_fail (GTK_IS_WIDGET (widget), FALSE);
756  if (GTK_WIDGET_CAN_FOCUS (widget))
757    {
758      gtk_widget_grab_focus (widget);
759      toplevel = gtk_widget_get_toplevel (widget);
760      if (GTK_WIDGET_TOPLEVEL (toplevel))
761        gtk_window_present (GTK_WINDOW (toplevel));
762      return TRUE;
763    }
764  else
765    return FALSE;
766}
767
768static void
769gail_widget_remove_focus_handler (AtkComponent   *component,
770                                  guint          handler_id)
771{
772  g_signal_handler_disconnect (component, handler_id);
773}
774
775static gboolean
776gail_widget_set_extents (AtkComponent   *component,
777                         gint           x,
778                         gint           y,
779                         gint           width,
780                         gint           height,
781                         AtkCoordType   coord_type)
782{
783  GtkWidget *widget = GTK_ACCESSIBLE (component)->widget;
784
785  if (widget == NULL)
786    /*
787     * Object is defunct
788     */
789    return FALSE;
790  g_return_val_if_fail (GTK_IS_WIDGET (widget), FALSE);
791
792  if (GTK_WIDGET_TOPLEVEL (widget))
793    {
794      if (coord_type == ATK_XY_WINDOW)
795        {
796          gint x_current, y_current;
797          GdkWindow *window = widget->window;
798
799          gdk_window_get_origin (window, &x_current, &y_current);
800          x_current += x;
801          y_current += y;
802          if (x_current < 0 || y_current < 0)
803            return FALSE;
804          else
805            {
806              gtk_widget_set_uposition (widget, x_current, y_current);
807              gtk_widget_set_usize (widget, width, height);
808              return TRUE;
809            }
810        }
811      else if (coord_type == ATK_XY_SCREEN)
812        { 
813          gtk_widget_set_uposition (widget, x, y);
814          gtk_widget_set_usize (widget, width, height);
815          return TRUE;
816        }
817    }
818  return FALSE;
819}
820
821static gboolean
822gail_widget_set_position (AtkComponent   *component,
823                          gint           x,
824                          gint           y,
825                          AtkCoordType   coord_type)
826{
827  GtkWidget *widget = GTK_ACCESSIBLE (component)->widget;
828
829  if (widget == NULL)
830    /*
831     * Object is defunct
832     */
833    return FALSE;
834  g_return_val_if_fail (GTK_IS_WIDGET (widget), FALSE);
835
836  if (GTK_WIDGET_TOPLEVEL (widget))
837    {
838      if (coord_type == ATK_XY_WINDOW)
839        {
840          gint x_current, y_current;
841          GdkWindow *window = widget->window;
842
843          gdk_window_get_origin (window, &x_current, &y_current);
844          x_current += x;
845          y_current += y;
846          if (x_current < 0 || y_current < 0)
847            return FALSE;
848          else
849            {
850              gtk_widget_set_uposition (widget, x_current, y_current);
851              return TRUE;
852            }
853        }
854      else if (coord_type == ATK_XY_SCREEN)
855        { 
856          gtk_widget_set_uposition (widget, x, y);
857          return TRUE;
858        }
859    }
860  return FALSE;
861}
862
863static gboolean
864gail_widget_set_size (AtkComponent   *component,
865                      gint           width,
866                      gint           height)
867{
868  GtkWidget *widget = GTK_ACCESSIBLE (component)->widget;
869
870  if (widget == NULL)
871    /*
872     * Object is defunct
873     */
874    return FALSE;
875  g_return_val_if_fail (GTK_IS_WIDGET (widget), FALSE);
876
877  if (GTK_WIDGET_TOPLEVEL (widget))
878    {
879      gtk_widget_set_usize (widget, width, height);
880      return TRUE;
881    }
882  else
883   return FALSE;
884}
885
886#if 0
887static GtkWidget*
888_gail_widget_get_parent (GtkWidget* widget)
889{
890  GtkWidget *parent_widget;
891  gpointer pointer;
892  GValue value = { 0, };
893
894  g_return_val_if_fail (GTK_WIDGET (widget), NULL);
895
896  g_value_init (&value, G_TYPE_OBJECT);
897  g_object_get_property (G_OBJECT (widget), "parent", &value);
898  pointer = g_value_get_object (&value);
899 
900  g_return_val_if_fail (GTK_IS_WIDGET (pointer), NULL);
901
902  return GTK_WIDGET (pointer);
903}
904#endif
905
906/*
907 * This function is a signal handler for notify_in_event and focus_out_event
908 * signal which gets emitted on a GtkWidget.
909 */
910static gboolean
911gail_widget_focus_gtk (GtkWidget     *widget,
912                       GdkEventFocus *event)
913{
914  GailWidget *gail_widget;
915  GailWidgetClass *klass;
916
917  gail_widget = GAIL_WIDGET (gtk_widget_get_accessible (widget));
918  klass = GAIL_WIDGET_GET_CLASS (gail_widget);
919  if (klass->focus_gtk)
920    return klass->focus_gtk (widget, event);
921  else
922    return FALSE;
923}
924
925/*
926 * This function is the signal handler defined for focus_in_event and
927 * focus_out_event got GailWidget.
928 *
929 * It emits a focus-event signal on the GailWidget.
930 */
931static gboolean
932gail_widget_real_focus_gtk (GtkWidget     *widget,
933                            GdkEventFocus *event)
934{
935  AtkObject* accessible;
936  gboolean return_val;
937  return_val = FALSE;
938
939  accessible = gtk_widget_get_accessible (widget);
940  g_signal_emit_by_name (accessible, "focus_event", event->in, &return_val);
941  return FALSE;
942}
943
944static void
945gail_widget_size_allocate_gtk (GtkWidget     *widget,
946                               GtkAllocation *allocation)
947{
948  AtkObject* accessible;
949  AtkRectangle rect;
950
951  accessible = gtk_widget_get_accessible (widget);
952  if (ATK_IS_COMPONENT (accessible))
953    {
954      rect.x = allocation->x;
955      rect.y = allocation->y;
956      rect.width = allocation->width;
957      rect.height = allocation->height;
958      g_signal_emit_by_name (accessible, "bounds_changed", &rect);
959    }
960}
961
962/*
963 * This function is the signal handler defined for map and unmap signals.
964 */
965static gint
966gail_widget_map_gtk (GtkWidget     *widget)
967{
968  AtkObject* accessible;
969
970  accessible = gtk_widget_get_accessible (widget);
971  atk_object_notify_state_change (accessible, ATK_STATE_SHOWING,
972                                  GTK_WIDGET_MAPPED (widget));
973  return 1;
974}
975
976/*
977 * This function is a signal handler for notify signal which gets emitted
978 * when a property changes value on the GtkWidget associated with the object.
979 *
980 * It calls a function for the GailWidget type
981 */
982static void
983gail_widget_notify_gtk (GObject     *obj,
984                        GParamSpec  *pspec)
985{
986  GailWidget *widget;
987  GailWidgetClass *klass;
988
989  widget = GAIL_WIDGET (gtk_widget_get_accessible (GTK_WIDGET (obj)));
990  klass = GAIL_WIDGET_GET_CLASS (widget);
991  if (klass->notify_gtk)
992    klass->notify_gtk (obj, pspec);
993}
994
995/*
996 * This function is a signal handler for notify signal which gets emitted
997 * when a property changes value on the GtkWidget associated with a GailWidget.
998 *
999 * It constructs an AtkPropertyValues structure and emits a "property_changed"
1000 * signal which causes the user specified AtkPropertyChangeHandler
1001 * to be called.
1002 */
1003static void
1004gail_widget_real_notify_gtk (GObject     *obj,
1005                             GParamSpec  *pspec)
1006{
1007  GtkWidget* widget = GTK_WIDGET (obj);
1008  AtkObject* atk_obj = gtk_widget_get_accessible (widget);
1009  AtkState state;
1010  gboolean value;
1011
1012  if (strcmp (pspec->name, "has-focus") == 0)
1013    /*
1014     * We use focus-in-event and focus-out-event signals to catch
1015     * focus changes so we ignore this.
1016     */
1017    return;
1018  else if (strcmp (pspec->name, "visible") == 0)
1019    {
1020      state = ATK_STATE_VISIBLE;
1021      value = GTK_WIDGET_VISIBLE (widget);
1022    }
1023  else if (strcmp (pspec->name, "sensitive") == 0)
1024    {
1025      state = ATK_STATE_SENSITIVE;
1026      value = GTK_WIDGET_SENSITIVE (widget);
1027    }
1028  else
1029    return;
1030
1031  atk_object_notify_state_change (atk_obj, state, value);
1032}
1033
1034static void
1035gail_widget_focus_event (AtkObject   *obj,
1036                         gboolean    focus_in)
1037{
1038  AtkObject *focus_obj;
1039
1040  focus_obj = g_object_get_data (G_OBJECT (obj), "gail-focus-object");
1041  if (focus_obj == NULL)
1042    focus_obj = obj;
1043  atk_object_notify_state_change (focus_obj, ATK_STATE_FOCUSED, focus_in);
1044}
1045
1046static GtkWidget*
1047gail_widget_find_viewport (GtkWidget *widget)
1048{
1049  /*
1050   * Find an antecedent which is a GtkViewPort
1051   */
1052  GtkWidget *parent;
1053
1054  parent = widget->parent;
1055  while (parent != NULL)
1056    {
1057      if (GTK_IS_VIEWPORT (parent))
1058        break;
1059      parent = parent->parent;
1060    }
1061  return parent;
1062}
1063
1064/*
1065 * This function checks whether the widget has an antecedent which is
1066 * a GtkViewport and, if so, whether any part of the widget intersects
1067 * the visible rectangle of the GtkViewport.
1068 */
1069static gboolean gail_widget_on_screen (GtkWidget *widget)
1070{
1071  GtkWidget *viewport;
1072  gboolean return_value;
1073
1074  viewport = gail_widget_find_viewport (widget);
1075  if (viewport)
1076    {
1077      GtkAdjustment *adjustment;
1078      GdkRectangle visible_rect;
1079
1080      adjustment = gtk_viewport_get_vadjustment (GTK_VIEWPORT (viewport));
1081      visible_rect.y = adjustment->value;
1082      adjustment = gtk_viewport_get_hadjustment (GTK_VIEWPORT (viewport));
1083      visible_rect.x = adjustment->value;
1084      visible_rect.width = viewport->allocation.width;
1085      visible_rect.height = viewport->allocation.height;
1086             
1087      if (((widget->allocation.x + widget->allocation.width) < visible_rect.x) ||
1088         ((widget->allocation.y + widget->allocation.height) < visible_rect.y) ||
1089         (widget->allocation.x > (visible_rect.x + visible_rect.width)) ||
1090         (widget->allocation.y > (visible_rect.y + visible_rect.height)))
1091        return_value = FALSE;
1092      else
1093        return_value = TRUE;
1094    }
1095  else
1096    {
1097      /*
1098       * Check whether the widget has been placed of the screen. The
1099       * widget may be MAPPED as when toolbar items do not fit on the toolbar.
1100       */
1101      if (widget->allocation.x + widget->allocation.width <= 0 &&
1102          widget->allocation.y + widget->allocation.height <= 0)
1103        return_value = FALSE;
1104      else
1105        return_value = TRUE;
1106    }
1107
1108  return return_value;
1109}
Note: See TracBrowser for help on using the repository browser.