1 /*
2  * Copyright © 2003  Sun Microsystems Inc.
3  * Copyright © 2007  Christian Persch
4  *
5  * This library is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU General Public
7  * License as published by the Free Software Foundation; either
8  * version 3 of the License, or (at your option) any later version.
9  *
10  * This library is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public
16  * License along with this library; if not, write to the
17  * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
18  * Boston, MA 02110-1301, USA.
19  */
20 
21 #include <config.h>
22 
23 #include <string.h>
24 
25 #include <glib/gi18n-lib.h>
26 
27 #include <gtk/gtk.h>
28 
29 #include "gucharmap.h"
30 #include "gucharmap-chartable.h"
31 #include "gucharmap-chartable-accessible.h"
32 #include "gucharmap-chartable-cell-accessible.h"
33 #include "gucharmap-private.h"
34 
35 typedef struct
36 {
37   GtkAdjustment *vadjustment;
38   GPtrArray *cells;
39   AtkObject *focus_obj;
40 } GucharmapChartableAccessiblePrivate;
41 
42 #define GET_PRIVATE(inst) (G_TYPE_INSTANCE_GET_PRIVATE ((inst), gucharmap_chartable_accessible_get_type (), GucharmapChartableAccessiblePrivate))
43 
44 static gpointer gucharmap_chartable_accessible_parent_class;
45 
46 static void
set_cell_visibility(GucharmapChartable * chartable,GucharmapChartableCellAccessible * cell,gboolean emit_signal)47 set_cell_visibility (GucharmapChartable  *chartable,
48                      GucharmapChartableCellAccessible  *cell,
49                      gboolean emit_signal)
50 {
51   GucharmapChartablePrivate *chartable_priv = chartable->priv;
52   gucharmap_chartable_cell_accessible_add_state (cell, ATK_STATE_VISIBLE, emit_signal);
53 
54   if (cell->index >= chartable_priv->page_first_cell &&
55       cell->index < chartable_priv->page_first_cell
56                     + chartable_priv->rows * chartable_priv->cols)
57     {
58       gucharmap_chartable_cell_accessible_add_state (cell, ATK_STATE_SHOWING, emit_signal);
59     }
60   else
61     {
62       gucharmap_chartable_cell_accessible_remove_state (cell, ATK_STATE_SHOWING, emit_signal);
63     }
64 }
65 
66 static void
cell_destroyed(GucharmapChartableCellAccessible * cell)67 cell_destroyed (GucharmapChartableCellAccessible *cell)
68 {
69   GucharmapChartableAccessiblePrivate *priv;
70   AtkObject *parent;
71   GPtrArray *cells;
72   guint n_cells, n;
73   GucharmapChartableAccessible *accessible;
74 
75   parent = atk_object_get_parent (ATK_OBJECT (cell));
76   accessible = GUCHARMAP_CHARTABLE_ACCESSIBLE (parent);
77   priv = GET_PRIVATE (accessible);
78 
79   cells = priv->cells;
80   n_cells = cells->len;
81   for (n = 0; n < n_cells; ++n)
82     {
83       GucharmapChartableCellAccessible *another_cell = g_ptr_array_index (cells, n);
84 
85       if (another_cell == cell)
86         {
87           g_ptr_array_remove_index_fast (priv->cells, n);
88           return;
89         }
90     }
91 
92   g_warning ("Cell destroyed but was not in the cells cache?\n");
93 }
94 
95 static AtkObject*
gucharmap_chartable_accessible_ref_child(AtkObject * obj,int index)96 gucharmap_chartable_accessible_ref_child (AtkObject *obj,
97                                           int index)
98 {
99   GucharmapChartableAccessible *table;
100   GucharmapChartableAccessiblePrivate *priv;
101   GtkWidget *widget;
102   GucharmapChartable *chartable;
103   AtkObject *child;
104   gchar* name;
105   GPtrArray *cells;
106   guint n_cells, n;
107 
108   widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (obj));
109   if (widget == NULL)
110     /* State is defunct */
111     return NULL;
112 
113   if (index > UNICHAR_MAX)
114     return NULL;
115 
116   table = GUCHARMAP_CHARTABLE_ACCESSIBLE (obj);
117   priv = GET_PRIVATE (table);
118 
119   /* Check whether the child is cached */
120   cells = priv->cells;
121   n_cells = cells->len;
122   for (n = 0; n < n_cells; ++n)
123     {
124       GucharmapChartableCellAccessible *cell = g_ptr_array_index (cells, n);
125 
126       if (index == cell->index)
127         {
128           g_object_ref (cell);
129           return ATK_OBJECT (cell);
130         }
131     }
132 
133   /* Not cached, create a new cell accessible */
134   chartable = GUCHARMAP_CHARTABLE (widget);
135 
136   child = gucharmap_chartable_cell_accessible_new ();
137   gucharmap_chartable_cell_accessible_initialise (GUCHARMAP_CHARTABLE_CELL_ACCESSIBLE (child),
138                             GTK_WIDGET (chartable), obj, index);
139   /* Set the name of the cell */
140   name = g_strdup_printf("U+%4.4X %s", (unsigned int)index, gucharmap_get_unicode_name (index));
141   atk_object_set_name (child, name);
142   g_free (name);
143   set_cell_visibility (chartable, GUCHARMAP_CHARTABLE_CELL_ACCESSIBLE (child), FALSE);
144 
145   /* Store the cell in our cache */
146   g_ptr_array_add (priv->cells, child);
147   g_object_weak_ref (G_OBJECT (child),
148                      (GWeakNotify) cell_destroyed,
149                      child);
150 
151   return child;
152 }
153 
154 static AtkObject*
gucharmap_chartable_accessible_ref_at(AtkTable * table,gint row,gint column)155 gucharmap_chartable_accessible_ref_at (AtkTable *table,
156                              gint    row,
157                              gint    column)
158 {
159   GucharmapChartable *chartable;
160   GucharmapChartablePrivate *chartable_priv;
161   GtkWidget *widget;
162   AtkObject *child;
163   gint index;
164 
165   widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (table));
166   if (widget == NULL)
167     /* State is defunct */
168     return NULL;
169 
170   chartable = GUCHARMAP_CHARTABLE (widget);
171   chartable_priv = chartable->priv;
172 
173   index =  row * chartable_priv->cols + column;
174 
175   child = gucharmap_chartable_accessible_ref_child (ATK_OBJECT (table), index);
176 
177   return child;
178 }
179 
180 static AtkObject*
gucharmap_chartable_accessible_ref_accessible_at_point(AtkComponent * component,gint x,gint y,AtkCoordType coord_type)181 gucharmap_chartable_accessible_ref_accessible_at_point (AtkComponent *component,
182                                               gint x,
183                                               gint y,
184                                               AtkCoordType coord_type)
185 {
186   GtkWidget *widget;
187   GucharmapChartable *chartable;
188   GucharmapChartablePrivate *chartable_priv;
189   gint x_pos, y_pos;
190   gint row, col;
191 
192   widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (component));
193   if (widget == NULL)
194     /* State is defunct */
195     return NULL;
196 
197   chartable = GUCHARMAP_CHARTABLE (widget);
198   chartable_priv = chartable->priv;
199 
200   atk_component_get_extents (component, &x_pos, &y_pos,
201                              NULL, NULL, coord_type);
202 
203   /* Find cell at offset x - x_pos, y - y_pos */
204 
205   x_pos = x - x_pos;
206   y_pos = y - y_pos;
207 
208   for (col = 0; col < chartable_priv->cols; col++)
209     {
210       if (x_pos < _gucharmap_chartable_x_offset (chartable, col))
211         {
212           col--;
213           break;
214         }
215     }
216   if (col == chartable_priv->cols || col < 0)
217     return NULL;
218 
219   for (row = 0; row < chartable_priv->rows; row++)
220     {
221       if (y_pos < _gucharmap_chartable_y_offset (chartable, row))
222         {
223           row--;
224           break;
225         }
226     }
227   if (row == chartable_priv->rows || row < 0)
228     return NULL;
229 
230   row += chartable_priv->page_first_cell / chartable_priv->cols;
231 
232   return gucharmap_chartable_accessible_ref_at (ATK_TABLE (component), row, col);
233 }
234 
235 static void
gucharmap_chartable_accessible_component_interface_init(AtkComponentIface * iface)236 gucharmap_chartable_accessible_component_interface_init (AtkComponentIface *iface)
237 {
238   g_return_if_fail (iface != NULL);
239 
240   iface->ref_accessible_at_point = gucharmap_chartable_accessible_ref_accessible_at_point;
241 }
242 
243 static AtkStateSet*
gucharmap_chartable_accessible_ref_state_set(AtkObject * obj)244 gucharmap_chartable_accessible_ref_state_set (AtkObject *obj)
245 {
246   AtkStateSet *state_set;
247   GtkWidget *widget;
248 
249   state_set = ATK_OBJECT_CLASS (gucharmap_chartable_accessible_parent_class)->ref_state_set (obj);
250   widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (obj));
251 
252   if (widget != NULL)
253     atk_state_set_add_state (state_set, ATK_STATE_MANAGES_DESCENDANTS);
254 
255   /* FIXME: reference count ? */
256   return state_set;
257 }
258 
259 /* FIXMEchpe: shouldn't this get the number from the chartable's codepoint list instead?? */
260 static gint
gucharmap_chartable_accessible_get_n_children(AtkObject * obj)261 gucharmap_chartable_accessible_get_n_children (AtkObject *obj)
262 {
263   GtkWidget *widget;
264 
265   widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (obj));
266   if (widget == NULL)
267     /* State is defunct */
268     return 0;
269 
270   return UNICHAR_MAX + 1;
271 }
272 
273 static void
gucharmap_chartable_accessible_init(GucharmapChartableAccessible * accessible)274 gucharmap_chartable_accessible_init (GucharmapChartableAccessible *accessible)
275 {
276   GucharmapChartableAccessiblePrivate *priv = GET_PRIVATE (accessible);
277 
278   priv->cells = g_ptr_array_sized_new (512);
279 }
280 
281 static void
gucharmap_chartable_accessible_finalize(GObject * obj)282 gucharmap_chartable_accessible_finalize (GObject *obj)
283 {
284   GucharmapChartableAccessible *accessible = GUCHARMAP_CHARTABLE_ACCESSIBLE (obj);
285   GucharmapChartableAccessiblePrivate *priv = GET_PRIVATE (accessible);
286   GPtrArray *cells;
287   guint n_cells, n;
288 
289   if (priv->focus_obj)
290     g_object_unref (priv->focus_obj);
291 
292   /* Remove the weak ref notifications */
293   cells = priv->cells;
294   n_cells = cells->len;
295   for (n = 0; n < n_cells; ++n)
296     {
297       GucharmapChartableCellAccessible *cell = g_ptr_array_index (cells, n);
298 
299       g_object_weak_unref (G_OBJECT (cell),
300                            (GWeakNotify) cell_destroyed,
301                            cell);
302     }
303 
304   g_ptr_array_free (priv->cells, TRUE);
305 
306   G_OBJECT_CLASS (gucharmap_chartable_accessible_parent_class)->finalize (obj);
307 }
308 
309 static void
gucharmap_chartable_accessible_update_all_cells(AtkObject * obj)310 gucharmap_chartable_accessible_update_all_cells (AtkObject *obj)
311 {
312   GucharmapChartableAccessible *accessible;
313   GucharmapChartableAccessiblePrivate *priv;
314   GtkWidget *widget;
315   GucharmapChartable *chartable;
316   GPtrArray *cells;
317   guint n_cells, n;
318 
319   widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (obj));
320   if (!widget)
321     /* Widget is being deleted */
322     return;
323 
324   accessible = GUCHARMAP_CHARTABLE_ACCESSIBLE (obj);
325   priv = GET_PRIVATE (accessible);
326 
327   chartable = GUCHARMAP_CHARTABLE (widget);
328 
329   cells = priv->cells;
330   n_cells = cells->len;
331   for (n = 0; n < n_cells; ++n)
332     {
333       GucharmapChartableCellAccessible *cell = g_ptr_array_index (cells, n);
334 
335       set_cell_visibility (chartable, GUCHARMAP_CHARTABLE_CELL_ACCESSIBLE (cell), TRUE);
336     }
337 
338   g_signal_emit_by_name (obj, "visible-data-changed");
339 }
340 
341 static void
adjustment_changed(GtkAdjustment * adj,AtkObject * obj)342 adjustment_changed (GtkAdjustment *adj,
343                     AtkObject     *obj)
344 {
345   gucharmap_chartable_accessible_update_all_cells (obj);
346 }
347 
348 static void
size_allocated(GtkWidget * widget,GtkAllocation * alloc,gpointer data)349 size_allocated (GtkWidget     *widget,
350                 GtkAllocation *alloc,
351                 gpointer      data)
352 {
353   gucharmap_chartable_accessible_update_all_cells (ATK_OBJECT (data));
354 }
355 
356 static AtkObject* /* reference */
find_object(GucharmapChartable * chartable,gunichar uc,AtkObject * obj)357 find_object (GucharmapChartable   *chartable,
358              gunichar  uc,
359              AtkObject *obj)
360 {
361   GucharmapChartablePrivate *chartable_priv = chartable->priv;
362   gint row, column;
363 
364   row = uc / chartable_priv->cols;
365   column = _gucharmap_chartable_cell_column (chartable, uc);
366 
367   return atk_table_ref_at (ATK_TABLE (obj), row, column);
368 }
369 
370 static void
sync_active_char(GucharmapChartable * chartable,GParamSpec * pspec,GucharmapChartableAccessible * accessible)371 sync_active_char (GucharmapChartable  *chartable,
372                   GParamSpec *pspec,
373                   GucharmapChartableAccessible *accessible)
374 {
375   GucharmapChartableAccessiblePrivate *priv = GET_PRIVATE (accessible);
376   gunichar uc;
377   AtkObject *child;
378   AtkObject *focus_obj;
379 
380   uc = gucharmap_chartable_get_active_character (chartable);
381 
382   child = find_object (chartable, uc, ATK_OBJECT (accessible));
383   focus_obj = priv->focus_obj;
384   if (focus_obj != child)
385     {
386       if (focus_obj)
387         gucharmap_chartable_cell_accessible_remove_state (GUCHARMAP_CHARTABLE_CELL_ACCESSIBLE (focus_obj), ATK_STATE_FOCUSED, FALSE);
388 
389       gucharmap_chartable_cell_accessible_add_state (GUCHARMAP_CHARTABLE_CELL_ACCESSIBLE (child), ATK_STATE_FOCUSED, FALSE);
390     }
391 
392   if (focus_obj)
393     g_object_unref (focus_obj);
394 
395   priv->focus_obj = child; /* adopts the reference from find_object */
396 
397   g_signal_emit_by_name (accessible, "active-descendant-changed", child);
398 }
399 
400 static void
gucharmap_chartable_accessible_set_scroll_adjustments(GucharmapChartable * chartable,GtkAdjustment * hadjustment,GtkAdjustment * vadjustment,AtkObject * obj)401 gucharmap_chartable_accessible_set_scroll_adjustments (GucharmapChartable *chartable,
402                                                        GtkAdjustment *hadjustment,
403                                                        GtkAdjustment *vadjustment,
404                                                        AtkObject *obj)
405 {
406   GucharmapChartableAccessible *accessible = GUCHARMAP_CHARTABLE_ACCESSIBLE (obj);
407   GucharmapChartableAccessiblePrivate *priv = GET_PRIVATE (accessible);
408 
409   if (priv->vadjustment != vadjustment)
410     {
411       GtkAdjustment **adjustment_ptr = &priv->vadjustment;
412       g_object_remove_weak_pointer (G_OBJECT (priv->vadjustment),
413                                     (gpointer *) adjustment_ptr);
414       g_signal_handlers_disconnect_by_func (priv->vadjustment,
415                                             G_CALLBACK (adjustment_changed),
416                                             obj);
417       priv->vadjustment = vadjustment;
418       g_object_add_weak_pointer (G_OBJECT (priv->vadjustment),
419                                  (gpointer *) adjustment_ptr);
420       g_signal_connect (vadjustment, "value-changed",
421                         G_CALLBACK (adjustment_changed), obj);
422     }
423 }
424 
425 static void
sync_adjustment(GucharmapChartable * chartable,GParamSpec * pspec,AtkObject * accessible)426 sync_adjustment (GucharmapChartable *chartable,
427                  GParamSpec         *pspec,
428                  AtkObject          *accessible)
429 {
430   GtkAdjustment *hadjustment, *vadjustment;
431 
432   g_object_get (chartable,
433                 "hadjustment", &hadjustment,
434                 "vadjustment", &vadjustment,
435                 NULL);
436   /* hadjustment and vadjustment are set to NULL in
437      gtk_scrolled_window_remove() */
438   if (hadjustment && vadjustment)
439     gucharmap_chartable_accessible_set_scroll_adjustments (chartable,
440                                                            hadjustment,
441                                                            vadjustment,
442                                                            accessible);
443 }
444 
445 static void
gucharmap_chartable_accessible_initialize(AtkObject * obj,gpointer data)446 gucharmap_chartable_accessible_initialize (AtkObject *obj,
447                                            gpointer  data)
448 {
449   GtkWidget *widget;
450   AtkObject *focus_obj, *old_focus_obj;
451   GucharmapChartableAccessible *accessible;
452   GucharmapChartableAccessiblePrivate *priv;
453   GucharmapChartable *chartable;
454   GucharmapChartablePrivate *chartable_priv;
455 
456   ATK_OBJECT_CLASS (gucharmap_chartable_accessible_parent_class)->initialize (obj, data);
457 
458   widget = GTK_WIDGET (data);
459   accessible = GUCHARMAP_CHARTABLE_ACCESSIBLE (obj);
460   priv = GET_PRIVATE (accessible);
461   chartable = GUCHARMAP_CHARTABLE (widget);
462   chartable_priv = chartable->priv;
463 
464   if (chartable_priv->vadjustment)
465     {
466       GtkAdjustment **adjustment_ptr = &priv->vadjustment;
467 
468       priv->vadjustment = chartable_priv->vadjustment;
469       g_object_add_weak_pointer (G_OBJECT (priv->vadjustment),
470                                  (gpointer *) adjustment_ptr);
471       g_signal_connect (chartable_priv->vadjustment, "value-changed",
472                         G_CALLBACK (adjustment_changed), obj);
473     }
474 
475   g_signal_connect_after (chartable, "notify::hadjustment",
476                           G_CALLBACK (sync_adjustment), obj);
477   g_signal_connect_after (chartable, "notify::vadjustment",
478                           G_CALLBACK (sync_adjustment), obj);
479   g_signal_connect (widget, "size-allocate",
480                     G_CALLBACK (size_allocated), obj);
481   g_signal_connect (chartable, "notify::active-character",
482                     G_CALLBACK (sync_active_char), obj);
483 
484   focus_obj = find_object (chartable, chartable_priv->active_cell, obj);
485   old_focus_obj = priv->focus_obj;
486   priv->focus_obj = focus_obj; /* adopts the reference from find_object */
487   if (old_focus_obj)
488     g_object_unref (old_focus_obj);
489 }
490 
491 static void
gucharmap_chartable_accessible_destroyed(GtkWidget * widget,AtkObject * obj)492 gucharmap_chartable_accessible_destroyed (GtkWidget *widget,
493                                           AtkObject *obj)
494 {
495   GucharmapChartableAccessible *accessible = GUCHARMAP_CHARTABLE_ACCESSIBLE (obj);
496   GucharmapChartableAccessiblePrivate *priv = GET_PRIVATE (accessible);
497 
498   if (priv->vadjustment)
499     {
500       GtkAdjustment **adjustment_ptr = &priv->vadjustment;
501 
502       g_object_remove_weak_pointer (G_OBJECT (priv->vadjustment),
503                                     (gpointer *) adjustment_ptr);
504 
505       g_signal_handlers_disconnect_by_func (priv->vadjustment,
506                                             G_CALLBACK (adjustment_changed),
507                                             obj);
508       priv->vadjustment = NULL;
509     }
510 
511   g_signal_handlers_disconnect_by_func (widget,
512                                         G_CALLBACK (gucharmap_chartable_accessible_set_scroll_adjustments),
513                                         obj);
514   g_signal_handlers_disconnect_by_func (widget,
515 					G_CALLBACK (sync_adjustment),
516 					obj);
517   g_signal_handlers_disconnect_by_func (widget,
518                                         G_CALLBACK (size_allocated),
519                                         obj);
520   g_signal_handlers_disconnect_by_func (widget,
521                                         G_CALLBACK (sync_active_char),
522                                         obj);
523 }
524 
525 static void
gucharmap_chartable_accessible_connect_widget_destroyed(GtkAccessible * accessible)526 gucharmap_chartable_accessible_connect_widget_destroyed (GtkAccessible *accessible)
527 {
528   if (gtk_accessible_get_widget (accessible))
529     {
530       g_signal_connect_after (gtk_accessible_get_widget (accessible),
531                               "destroy",
532                               G_CALLBACK (gucharmap_chartable_accessible_destroyed),
533                               accessible);
534     }
535 
536   GTK_ACCESSIBLE_CLASS (gucharmap_chartable_accessible_parent_class)->connect_widget_destroyed (accessible);
537 }
538 
539 static void
gucharmap_chartable_accessible_class_init(GucharmapChartableAccessibleClass * klass)540 gucharmap_chartable_accessible_class_init (GucharmapChartableAccessibleClass *klass)
541 {
542   GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
543   AtkObjectClass *atk_object_class = ATK_OBJECT_CLASS (klass);
544 
545   gucharmap_chartable_accessible_parent_class = g_type_class_peek_parent (klass);
546 
547   gobject_class->finalize = gucharmap_chartable_accessible_finalize;
548 
549   /* This is normally true, except during introspection dump */
550   if (GTK_IS_ACCESSIBLE_CLASS (klass)) {
551     GtkAccessibleClass *accessible_class = GTK_ACCESSIBLE_CLASS (klass);
552     accessible_class->connect_widget_destroyed = gucharmap_chartable_accessible_connect_widget_destroyed;
553   }
554 
555   atk_object_class->get_n_children = gucharmap_chartable_accessible_get_n_children;
556   atk_object_class->ref_child = gucharmap_chartable_accessible_ref_child;
557   atk_object_class->ref_state_set = gucharmap_chartable_accessible_ref_state_set;
558   atk_object_class->initialize = gucharmap_chartable_accessible_initialize;
559 
560   g_type_class_add_private (gobject_class, sizeof (GucharmapChartableAccessiblePrivate));
561 }
562 
563 static gint
gucharmap_chartable_accessible_get_n_columns(AtkTable * table)564 gucharmap_chartable_accessible_get_n_columns (AtkTable *table)
565 {
566   GtkWidget *widget;
567   GucharmapChartable *chartable;
568   GucharmapChartablePrivate *chartable_priv;
569 
570   widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (table));
571   if (widget == NULL)
572     /* State is defunct */
573     return 0;
574 
575   chartable = GUCHARMAP_CHARTABLE (widget);
576   chartable_priv = chartable->priv;
577 
578   return chartable_priv->cols;
579 }
580 
581 
582 static gint
gucharmap_chartable_accessible_get_column_extent_at(AtkTable * table,gint row,gint column)583 gucharmap_chartable_accessible_get_column_extent_at (AtkTable       *table,
584                                            gint           row,
585                                            gint           column)
586 {
587   GtkWidget *widget;
588 
589   widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (table));
590   if (widget == NULL)
591     /* State is defunct */
592     return 0;
593 
594   return 1;
595 }
596 
597 
598 static gint
gucharmap_chartable_accessible_get_n_rows(AtkTable * table)599 gucharmap_chartable_accessible_get_n_rows (AtkTable *table)
600 {
601   GtkWidget *widget;
602   GucharmapChartable *chartable;
603   GucharmapChartablePrivate *chartable_priv;
604   gint n_rows;
605 
606   widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (table));
607   if (widget == NULL)
608     /* State is defunct */
609     return 0;
610 
611   chartable = GUCHARMAP_CHARTABLE (widget);
612   chartable_priv = chartable->priv;
613 
614   n_rows = UNICHAR_MAX / chartable_priv->cols + 1;
615 
616   return n_rows;
617 }
618 
619 
620 static gint
gucharmap_chartable_accessible_get_row_extent_at(AtkTable * table,gint row,gint column)621 gucharmap_chartable_accessible_get_row_extent_at (AtkTable *table,
622                                         gint    row,
623                                         gint    column)
624 {
625   GtkWidget *widget;
626 
627   widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (table));
628   if (widget == NULL)
629     /* State is defunct */
630     return 0;
631 
632   return 1;
633 }
634 
635 
636 static gint
gucharmap_chartable_accessible_get_index_at(AtkTable * table,gint row,gint column)637 gucharmap_chartable_accessible_get_index_at (AtkTable *table,
638                                    gint     row,
639                                    gint     column)
640 {
641   GtkWidget *widget;
642   GucharmapChartable *chartable;
643   GucharmapChartablePrivate *chartable_priv;
644 
645   widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (table));
646   if (widget == NULL)
647     /* State is defunct */
648     return -1;
649 
650   chartable = GUCHARMAP_CHARTABLE (widget);
651   chartable_priv = chartable->priv;
652 
653   return row * chartable_priv->cols + column;
654 }
655 
656 
657 static gint
gucharmap_chartable_accessible_get_column_at_index(AtkTable * table,gint index)658 gucharmap_chartable_accessible_get_column_at_index (AtkTable *table,
659                                           gint     index)
660 {
661   GtkWidget *widget;
662   GucharmapChartable *chartable;
663   GucharmapChartablePrivate *chartable_priv;
664 
665   widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (table));
666   if (widget == NULL)
667     /* State is defunct */
668     return -1;
669 
670   chartable = GUCHARMAP_CHARTABLE (widget);
671   chartable_priv = chartable->priv;
672 
673   return index % chartable_priv->cols;
674 }
675 
676 
677 static gint
gucharmap_chartable_accessible_get_row_at_index(AtkTable * table,gint index)678 gucharmap_chartable_accessible_get_row_at_index (AtkTable *table,
679                                                  gint     index)
680 {
681   GtkWidget *widget;
682   GucharmapChartable *chartable;
683   GucharmapChartablePrivate *chartable_priv;
684 
685   widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (table));
686   if (widget == NULL)
687     /* State is defunct */
688     return -1;
689 
690   chartable = GUCHARMAP_CHARTABLE (widget);
691   chartable_priv = chartable->priv;
692 
693   return index / chartable_priv->cols;
694 }
695 
696 
697 static void
gucharmap_chartable_accessible_table_interface_init(AtkTableIface * iface)698 gucharmap_chartable_accessible_table_interface_init (AtkTableIface *iface)
699 {
700   iface->ref_at = gucharmap_chartable_accessible_ref_at;
701   iface->get_n_columns = gucharmap_chartable_accessible_get_n_columns;
702   iface->get_column_extent_at = gucharmap_chartable_accessible_get_column_extent_at;
703   iface->get_n_rows = gucharmap_chartable_accessible_get_n_rows;
704   iface->get_row_extent_at = gucharmap_chartable_accessible_get_row_extent_at;
705   iface->get_index_at = gucharmap_chartable_accessible_get_index_at;
706   iface->get_column_at_index = gucharmap_chartable_accessible_get_column_at_index;
707   iface->get_row_at_index = gucharmap_chartable_accessible_get_row_at_index;
708 }
709 
710 #if 0
711 /* See http://bugzilla.gnome.org/show_bug.cgi?id=502840 */
712 #include <atk/atktype.h>
713 
714 ATK_DEFINE_TYPE_WITH_CODE (GucharmapChartableAccessible,
715                            gucharmap_chartable_accessible,
716                            GUCHARMAP_TYPE_CHARTABLE,
717                            G_IMPLEMENT_INTERFACE (ATK_TYPE_TABLE,
718                                                   gucharmap_chartable_accessible_table_interface_init)
719                            G_IMPLEMENT_INTERFACE (ATK_TYPE_COMPONENT,
720                                                   gucharmap_chartable_accessible_component_interface_init))
721 
722 #else
723 
724 GType
gucharmap_chartable_accessible_get_type(void)725 gucharmap_chartable_accessible_get_type (void)
726 {
727   static volatile gsize type__volatile = 0;
728 
729   if (g_once_init_enter (&type__volatile))
730     {
731       GTypeInfo typeinfo =
732       {
733         0 /* filled in by the code below */,
734         (GBaseInitFunc) NULL, /* base init */
735         (GBaseFinalizeFunc) NULL, /* base finalize */
736         (GClassInitFunc) gucharmap_chartable_accessible_class_init, /* class init */
737         (GClassFinalizeFunc) NULL, /* class finalize */
738         NULL, /* class data */
739         0 /* filled in by the code below */,
740         0, /* nb preallocs */
741         (GInstanceInitFunc) gucharmap_chartable_accessible_init, /* instance init */
742         NULL /* value table */
743       };
744       const GInterfaceInfo atk_table_info =
745       {
746           (GInterfaceInitFunc) gucharmap_chartable_accessible_table_interface_init,
747           (GInterfaceFinalizeFunc) NULL,
748           NULL
749       };
750       const GInterfaceInfo atk_component_info =
751       {
752           (GInterfaceInitFunc) gucharmap_chartable_accessible_component_interface_init,
753           (GInterfaceFinalizeFunc) NULL,
754           NULL
755       };
756       AtkObjectFactory *factory;
757       GType derived_type;
758       GTypeQuery query;
759       GType derived_atk_type;
760       GType type;
761 
762       /* Figure out the size of the class and instance we are deriving from */
763       derived_type = g_type_parent (GUCHARMAP_TYPE_CHARTABLE);
764       factory = atk_registry_get_factory (atk_get_default_registry (),
765                                           derived_type);
766       derived_atk_type = atk_object_factory_get_accessible_type (factory);
767       g_type_query (derived_atk_type, &query);
768       typeinfo.class_size = query.class_size;
769       typeinfo.instance_size = query.instance_size;
770 
771       type = g_type_register_static (derived_atk_type,
772                                      "GucharmapChartableAccessible",
773                                      &typeinfo, 0);
774 
775       g_type_add_interface_static (type, ATK_TYPE_TABLE,
776                                    &atk_table_info);
777       g_type_add_interface_static (type, ATK_TYPE_COMPONENT,
778                                    &atk_component_info);
779 
780       g_once_init_leave (&type__volatile, type);
781     }
782 
783   return type__volatile;
784 }
785 #endif
786 
787 /* API */
788 
789 AtkObject*
gucharmap_chartable_accessible_new(GucharmapChartable * chartable)790 gucharmap_chartable_accessible_new (GucharmapChartable *chartable)
791 {
792   GObject *object;
793   AtkObject *accessible;
794 
795   object = g_object_new (gucharmap_chartable_accessible_get_type (), NULL);
796   accessible = ATK_OBJECT (object);
797 
798   /* atk is fucked up... */
799   atk_object_initialize (accessible, GTK_WIDGET (chartable));
800   accessible->role = ATK_ROLE_TABLE;
801   atk_object_set_name (accessible, _("Character Table"));
802 
803   return accessible;
804 }
805