Support sending data with events
[platform/core/uifw/at-spi2-atk.git] / atk-adaptor / adaptors / table-adaptor.c
1 /*
2  * AT-SPI - Assistive Technology Service Provider Interface
3  * (Gnome Accessibility Project; http://developer.gnome.org/projects/gap)
4  *
5  * Copyright 2008 Novell, Inc.
6  * Copyright 2001, 2002 Sun Microsystems Inc.,
7  * Copyright 2001, 2002 Ximian, Inc.
8  *
9  * This library is free software; you can redistribute it and/or
10  * modify it under the terms of the GNU Library General Public
11  * License as published by the Free Software Foundation; either
12  * version 2 of the License, or (at your option) any later version.
13  *
14  * This library is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17  * Library General Public License for more details.
18  *
19  * You should have received a copy of the GNU Library General Public
20  * License along with this library; if not, write to the
21  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
22  * Boston, MA 02111-1307, USA.
23  */
24
25 #include <atk/atk.h>
26 #include <droute/droute.h>
27 #include "bridge.h"
28
29 #include "spi-dbus.h"
30 #include "object.h"
31 #include "introspection.h"
32
33 static dbus_bool_t
34 impl_get_NRows (DBusMessageIter * iter, void *user_data)
35 {
36   AtkTable *table = (AtkTable *) user_data;
37   g_return_val_if_fail (ATK_IS_TABLE (user_data), FALSE);
38   return droute_return_v_int32 (iter, atk_table_get_n_rows (table));
39 }
40
41 static dbus_bool_t
42 impl_get_NColumns (DBusMessageIter * iter, void *user_data)
43 {
44   AtkTable *table = (AtkTable *) user_data;
45   g_return_val_if_fail (ATK_IS_TABLE (user_data), FALSE);
46   return droute_return_v_int32 (iter, atk_table_get_n_columns (table));
47 }
48
49 static dbus_bool_t
50 impl_get_Caption (DBusMessageIter * iter, void *user_data)
51 {
52   AtkTable *table = (AtkTable *) user_data;
53   g_return_val_if_fail (ATK_IS_TABLE (user_data), FALSE);
54   spi_object_append_v_reference (iter, atk_table_get_caption (table));
55   return TRUE;
56 }
57
58 static dbus_bool_t
59 impl_get_Summary (DBusMessageIter * iter, void *user_data)
60 {
61   AtkTable *table = (AtkTable *) user_data;
62   g_return_val_if_fail (ATK_IS_TABLE (user_data), FALSE);
63   spi_object_append_v_reference (iter, atk_table_get_summary (table));
64   return TRUE;
65 }
66
67 static dbus_bool_t
68 impl_get_NSelectedRows (DBusMessageIter * iter, void *user_data)
69 {
70   AtkTable *table = (AtkTable *) user_data;
71   gint *selected_rows = NULL;
72   int count;
73   g_return_val_if_fail (ATK_IS_TABLE (user_data), FALSE);
74   count = atk_table_get_selected_rows (table, &selected_rows);
75   if (selected_rows)
76     g_free (selected_rows);
77   return droute_return_v_int32 (iter, count);
78 }
79
80 static dbus_bool_t
81 impl_get_NSelectedColumns (DBusMessageIter * iter, void *user_data)
82 {
83   AtkTable *table = (AtkTable *) user_data;
84   gint *selected_columns = NULL;
85   int count;
86   g_return_val_if_fail (ATK_IS_TABLE (user_data), FALSE);
87   count = atk_table_get_selected_columns (table, &selected_columns);
88   if (selected_columns)
89     g_free (selected_columns);
90   return droute_return_v_int32 (iter, count);
91 }
92
93 static DBusMessage *
94 impl_GetAccessibleAt (DBusConnection * bus, DBusMessage * message,
95                       void *user_data)
96 {
97   AtkTable *table = (AtkTable *) user_data;
98   dbus_int32_t row, column;
99   DBusMessage *reply;
100   AtkObject *obj;
101
102   g_return_val_if_fail (ATK_IS_TABLE (user_data),
103                         droute_not_yet_handled_error (message));
104   if (!dbus_message_get_args
105       (message, NULL, DBUS_TYPE_INT32, &row, DBUS_TYPE_INT32, &column,
106        DBUS_TYPE_INVALID))
107     {
108       return droute_invalid_arguments_error (message);
109     }
110   obj = atk_table_ref_at (table, row, column);
111   reply = spi_object_return_reference (message, obj);
112   if (obj)
113     g_object_unref (obj);
114
115   return reply;
116 }
117
118 static DBusMessage *
119 impl_GetIndexAt (DBusConnection * bus, DBusMessage * message, void *user_data)
120 {
121   AtkTable *table = (AtkTable *) user_data;
122   dbus_int32_t row, column;
123   dbus_int32_t index;
124   DBusMessage *reply;
125
126   g_return_val_if_fail (ATK_IS_TABLE (user_data),
127                         droute_not_yet_handled_error (message));
128   if (!dbus_message_get_args
129       (message, NULL, DBUS_TYPE_INT32, &row, DBUS_TYPE_INT32, &column,
130        DBUS_TYPE_INVALID))
131     {
132       return droute_invalid_arguments_error (message);
133     }
134   index = atk_table_get_index_at (table, row, column);
135   reply = dbus_message_new_method_return (message);
136   if (reply)
137     {
138       dbus_message_append_args (reply, DBUS_TYPE_INT32, &index,
139                                 DBUS_TYPE_INVALID);
140     }
141   return reply;
142 }
143
144 static DBusMessage *
145 impl_GetRowAtIndex (DBusConnection * bus, DBusMessage * message,
146                     void *user_data)
147 {
148   AtkTable *table = (AtkTable *) user_data;
149   dbus_int32_t index;
150   dbus_int32_t row;
151   DBusMessage *reply;
152
153   g_return_val_if_fail (ATK_IS_TABLE (user_data),
154                         droute_not_yet_handled_error (message));
155   if (!dbus_message_get_args
156       (message, NULL, DBUS_TYPE_INT32, &index, DBUS_TYPE_INVALID))
157     {
158       return droute_invalid_arguments_error (message);
159     }
160   row = atk_table_get_row_at_index (table, index);
161   reply = dbus_message_new_method_return (message);
162   if (reply)
163     {
164       dbus_message_append_args (reply, DBUS_TYPE_INT32, &row,
165                                 DBUS_TYPE_INVALID);
166     }
167   return reply;
168 }
169
170 static DBusMessage *
171 impl_GetColumnAtIndex (DBusConnection * bus, DBusMessage * message,
172                        void *user_data)
173 {
174   AtkTable *table = (AtkTable *) user_data;
175   dbus_int32_t index;
176   dbus_int32_t column;
177   DBusMessage *reply;
178
179   g_return_val_if_fail (ATK_IS_TABLE (user_data),
180                         droute_not_yet_handled_error (message));
181   if (!dbus_message_get_args
182       (message, NULL, DBUS_TYPE_INT32, &index, DBUS_TYPE_INVALID))
183     {
184       return droute_invalid_arguments_error (message);
185     }
186   column = atk_table_get_column_at_index (table, index);
187   reply = dbus_message_new_method_return (message);
188   if (reply)
189     {
190       dbus_message_append_args (reply, DBUS_TYPE_INT32, &column,
191                                 DBUS_TYPE_INVALID);
192     }
193   return reply;
194 }
195
196 static const gchar *
197 validate_unallocated_string (const gchar *str)
198 {
199   if (!str)
200     return "";
201   if (!g_utf8_validate (str, -1, NULL))
202     {
203       g_warning ("atk-bridge: received bad UTF-8 string from a table function");
204       return "";
205     }
206   return str;
207 }
208
209 static DBusMessage *
210 impl_GetRowDescription (DBusConnection * bus, DBusMessage * message,
211                         void *user_data)
212 {
213   dbus_int32_t row;
214   AtkTable *table = (AtkTable *) user_data;
215   const gchar *description;
216   DBusMessage *reply;
217
218   g_return_val_if_fail (ATK_IS_TABLE (user_data),
219                         droute_not_yet_handled_error (message));
220   if (!dbus_message_get_args
221       (message, NULL, DBUS_TYPE_INT32, &row, DBUS_TYPE_INVALID))
222     {
223       return droute_invalid_arguments_error (message);
224     }
225   description = atk_table_get_row_description (table, row);
226   description = validate_unallocated_string (description);
227   reply = dbus_message_new_method_return (message);
228   if (reply)
229     {
230       dbus_message_append_args (reply, DBUS_TYPE_STRING, &description,
231                                 DBUS_TYPE_INVALID);
232     }
233   return reply;
234 }
235
236 static DBusMessage *
237 impl_GetColumnDescription (DBusConnection * bus, DBusMessage * message,
238                            void *user_data)
239 {
240   AtkTable *table = (AtkTable *) user_data;
241   dbus_int32_t column;
242   const char *description;
243   DBusMessage *reply;
244
245   g_return_val_if_fail (ATK_IS_TABLE (user_data),
246                         droute_not_yet_handled_error (message));
247   if (!dbus_message_get_args
248       (message, NULL, DBUS_TYPE_INT32, &column, DBUS_TYPE_INVALID))
249     {
250       return droute_invalid_arguments_error (message);
251     }
252   description = atk_table_get_column_description (table, column);
253   description = validate_unallocated_string (description);
254   reply = dbus_message_new_method_return (message);
255   if (reply)
256     {
257       dbus_message_append_args (reply, DBUS_TYPE_STRING, &description,
258                                 DBUS_TYPE_INVALID);
259     }
260   return reply;
261 }
262
263 static DBusMessage *
264 impl_GetRowExtentAt (DBusConnection * bus, DBusMessage * message,
265                      void *user_data)
266 {
267   AtkTable *table = (AtkTable *) user_data;
268   dbus_int32_t row, column;
269   dbus_int32_t extent;
270   DBusMessage *reply;
271
272   g_return_val_if_fail (ATK_IS_TABLE (user_data),
273                         droute_not_yet_handled_error (message));
274   if (!dbus_message_get_args
275       (message, NULL, DBUS_TYPE_INT32, &row, DBUS_TYPE_INT32, &column,
276        DBUS_TYPE_INVALID))
277     {
278       return droute_invalid_arguments_error (message);
279     }
280   extent = atk_table_get_row_extent_at (table, row, column);
281   reply = dbus_message_new_method_return (message);
282   if (reply)
283     {
284       dbus_message_append_args (reply, DBUS_TYPE_INT32, &extent,
285                                 DBUS_TYPE_INVALID);
286     }
287   return reply;
288 }
289
290 static DBusMessage *
291 impl_GetColumnExtentAt (DBusConnection * bus, DBusMessage * message,
292                         void *user_data)
293 {
294   AtkTable *table = (AtkTable *) user_data;
295   dbus_int32_t row, column;
296   dbus_int32_t extent;
297   DBusMessage *reply;
298
299   g_return_val_if_fail (ATK_IS_TABLE (user_data),
300                         droute_not_yet_handled_error (message));
301   if (!dbus_message_get_args
302       (message, NULL, DBUS_TYPE_INT32, &row, DBUS_TYPE_INT32, &column,
303        DBUS_TYPE_INVALID))
304     {
305       return droute_invalid_arguments_error (message);
306     }
307   extent = atk_table_get_column_extent_at (table, row, column);
308   reply = dbus_message_new_method_return (message);
309   if (reply)
310     {
311       dbus_message_append_args (reply, DBUS_TYPE_INT32, &extent,
312                                 DBUS_TYPE_INVALID);
313     }
314   return reply;
315 }
316
317 static DBusMessage *
318 impl_GetRowHeader (DBusConnection * bus, DBusMessage * message,
319                    void *user_data)
320 {
321   AtkTable *table = (AtkTable *) user_data;
322   dbus_int32_t row;
323   AtkObject *obj = NULL;
324
325   g_return_val_if_fail (ATK_IS_TABLE (user_data),
326                         droute_not_yet_handled_error (message));
327   if (!dbus_message_get_args
328       (message, NULL, DBUS_TYPE_INT32, &row, DBUS_TYPE_INVALID))
329     {
330       return droute_invalid_arguments_error (message);
331     }
332   obj = atk_table_get_row_header (table, row);
333   return spi_object_return_reference (message, obj);
334 }
335
336 static DBusMessage *
337 impl_GetColumnHeader (DBusConnection * bus, DBusMessage * message,
338                       void *user_data)
339 {
340   AtkTable *table = (AtkTable *) user_data;
341   dbus_int32_t column;
342   AtkObject *obj;
343
344   g_return_val_if_fail (ATK_IS_TABLE (user_data),
345                         droute_not_yet_handled_error (message));
346   if (!dbus_message_get_args
347       (message, NULL, DBUS_TYPE_INT32, &column, DBUS_TYPE_INVALID))
348     {
349       return droute_invalid_arguments_error (message);
350     }
351   obj = atk_table_get_column_header (table, column);
352   return spi_object_return_reference (message, obj);
353 }
354
355 static DBusMessage *
356 impl_GetSelectedRows (DBusConnection * bus, DBusMessage * message,
357                       void *user_data)
358 {
359   AtkTable *table = (AtkTable *) user_data;
360   gint *selected_rows = NULL;
361   gint count;
362   DBusMessage *reply;
363
364   g_return_val_if_fail (ATK_IS_TABLE (user_data),
365                         droute_not_yet_handled_error (message));
366   count = atk_table_get_selected_rows (table, &selected_rows);
367   if (!selected_rows)
368     count = 0;
369   reply = dbus_message_new_method_return (message);
370   if (reply)
371     {
372       /* tbd - figure out if this is safe for a 0-length array */
373       dbus_message_append_args (reply, DBUS_TYPE_ARRAY, DBUS_TYPE_INT32,
374                                 &selected_rows, count, DBUS_TYPE_INVALID);
375     }
376   if (selected_rows)
377     g_free (selected_rows);
378   return reply;
379 }
380
381 static DBusMessage *
382 impl_GetSelectedColumns (DBusConnection * bus, DBusMessage * message,
383                          void *user_data)
384 {
385   AtkTable *table = (AtkTable *) user_data;
386   gint *selected_columns = NULL;
387   gint count;
388   DBusMessage *reply;
389
390   g_return_val_if_fail (ATK_IS_TABLE (user_data),
391                         droute_not_yet_handled_error (message));
392   count = atk_table_get_selected_columns (table, &selected_columns);
393   if (!selected_columns)
394     count = 0;
395   reply = dbus_message_new_method_return (message);
396   if (reply)
397     {
398       /* tbd - figure out if this is safe for a 0-length array */
399       dbus_message_append_args (reply, DBUS_TYPE_ARRAY, DBUS_TYPE_INT32,
400                                 &selected_columns, count, DBUS_TYPE_INVALID);
401     }
402   if (selected_columns)
403     g_free (selected_columns);
404   return reply;
405 }
406
407 static DBusMessage *
408 impl_IsRowSelected (DBusConnection * bus, DBusMessage * message,
409                     void *user_data)
410 {
411   AtkTable *table = (AtkTable *) user_data;
412   dbus_int32_t row;
413   DBusMessage *reply;
414   dbus_bool_t ret;
415
416   g_return_val_if_fail (ATK_IS_TABLE (user_data),
417                         droute_not_yet_handled_error (message));
418   if (!dbus_message_get_args
419       (message, NULL, DBUS_TYPE_INT32, &row, DBUS_TYPE_INVALID))
420     {
421       return droute_invalid_arguments_error (message);
422     }
423   ret = atk_table_is_row_selected (table, row);
424   reply = dbus_message_new_method_return (message);
425   if (reply)
426     {
427       dbus_message_append_args (reply, DBUS_TYPE_BOOLEAN, &ret,
428                                 DBUS_TYPE_INVALID);
429     }
430   return reply;
431 }
432
433 static DBusMessage *
434 impl_IsColumnSelected (DBusConnection * bus, DBusMessage * message,
435                        void *user_data)
436 {
437   AtkTable *table = (AtkTable *) user_data;
438   dbus_int32_t column;
439   DBusMessage *reply;
440   dbus_bool_t ret;
441
442   g_return_val_if_fail (ATK_IS_TABLE (user_data),
443                         droute_not_yet_handled_error (message));
444   if (!dbus_message_get_args
445       (message, NULL, DBUS_TYPE_INT32, &column, DBUS_TYPE_INVALID))
446     {
447       return droute_invalid_arguments_error (message);
448     }
449   ret = atk_table_is_column_selected (table, column);
450   reply = dbus_message_new_method_return (message);
451   if (reply)
452     {
453       dbus_message_append_args (reply, DBUS_TYPE_BOOLEAN, &ret,
454                                 DBUS_TYPE_INVALID);
455     }
456   return reply;
457 }
458
459 static DBusMessage *
460 impl_IsSelected (DBusConnection * bus, DBusMessage * message, void *user_data)
461 {
462   AtkTable *table = (AtkTable *) user_data;
463   dbus_int32_t row, column;
464   DBusMessage *reply;
465   dbus_bool_t ret;
466
467   g_return_val_if_fail (ATK_IS_TABLE (user_data),
468                         droute_not_yet_handled_error (message));
469   if (!dbus_message_get_args
470       (message, NULL, DBUS_TYPE_INT32, &row, DBUS_TYPE_INT32, &column,
471        DBUS_TYPE_INVALID))
472     {
473       return droute_invalid_arguments_error (message);
474     }
475   ret = atk_table_is_selected (table, row, column);
476   reply = dbus_message_new_method_return (message);
477   if (reply)
478     {
479       dbus_message_append_args (reply, DBUS_TYPE_BOOLEAN, &ret,
480                                 DBUS_TYPE_INVALID);
481     }
482   return reply;
483 }
484
485 static DBusMessage *
486 impl_AddRowSelection (DBusConnection * bus, DBusMessage * message,
487                       void *user_data)
488 {
489   AtkTable *table = (AtkTable *) user_data;
490   dbus_int32_t row;
491   DBusMessage *reply;
492   dbus_bool_t ret;
493
494   g_return_val_if_fail (ATK_IS_TABLE (user_data),
495                         droute_not_yet_handled_error (message));
496   if (!dbus_message_get_args
497       (message, NULL, DBUS_TYPE_INT32, &row, DBUS_TYPE_INVALID))
498     {
499       return droute_invalid_arguments_error (message);
500     }
501   ret = atk_table_add_row_selection (table, row);
502   reply = dbus_message_new_method_return (message);
503   if (reply)
504     {
505       dbus_message_append_args (reply, DBUS_TYPE_BOOLEAN, &ret,
506                                 DBUS_TYPE_INVALID);
507     }
508   return reply;
509 }
510
511 static DBusMessage *
512 impl_AddColumnSelection (DBusConnection * bus, DBusMessage * message,
513                          void *user_data)
514 {
515   AtkTable *table = (AtkTable *) user_data;
516   dbus_int32_t column;
517   DBusMessage *reply;
518   dbus_bool_t ret;
519
520   g_return_val_if_fail (ATK_IS_TABLE (user_data),
521                         droute_not_yet_handled_error (message));
522   if (!dbus_message_get_args
523       (message, NULL, DBUS_TYPE_INT32, &column, DBUS_TYPE_INVALID))
524     {
525       return droute_invalid_arguments_error (message);
526     }
527   ret = atk_table_add_column_selection (table, column);
528   reply = dbus_message_new_method_return (message);
529   if (reply)
530     {
531       dbus_message_append_args (reply, DBUS_TYPE_BOOLEAN, &ret,
532                                 DBUS_TYPE_INVALID);
533     }
534   return reply;
535 }
536
537 static DBusMessage *
538 impl_RemoveRowSelection (DBusConnection * bus, DBusMessage * message,
539                          void *user_data)
540 {
541   AtkTable *table = (AtkTable *) user_data;
542   dbus_int32_t row;
543   DBusMessage *reply;
544   dbus_bool_t ret;
545
546   g_return_val_if_fail (ATK_IS_TABLE (user_data),
547                         droute_not_yet_handled_error (message));
548   if (!dbus_message_get_args
549       (message, NULL, DBUS_TYPE_INT32, &row, DBUS_TYPE_INVALID))
550     {
551       return droute_invalid_arguments_error (message);
552     }
553   ret = atk_table_remove_row_selection (table, row);
554   reply = dbus_message_new_method_return (message);
555   if (reply)
556     {
557       dbus_message_append_args (reply, DBUS_TYPE_BOOLEAN, &ret,
558                                 DBUS_TYPE_INVALID);
559     }
560   return reply;
561 }
562
563 static DBusMessage *
564 impl_RemoveColumnSelection (DBusConnection * bus, DBusMessage * message,
565                             void *user_data)
566 {
567   AtkTable *table = (AtkTable *) user_data;
568   dbus_int32_t column;
569   DBusMessage *reply;
570   dbus_bool_t ret;
571
572   g_return_val_if_fail (ATK_IS_TABLE (user_data),
573                         droute_not_yet_handled_error (message));
574   if (!dbus_message_get_args
575       (message, NULL, DBUS_TYPE_INT32, &column, DBUS_TYPE_INVALID))
576     {
577       return droute_invalid_arguments_error (message);
578     }
579   ret = atk_table_remove_column_selection (table, column);
580   reply = dbus_message_new_method_return (message);
581   if (reply)
582     {
583       dbus_message_append_args (reply, DBUS_TYPE_BOOLEAN, &ret,
584                                 DBUS_TYPE_INVALID);
585     }
586   return reply;
587 }
588
589 static DBusMessage *
590 impl_GetRowColumnExtentsAtIndex (DBusConnection * bus, DBusMessage * message,
591                                  void *user_data)
592 {
593   AtkTable *table = (AtkTable *) user_data;
594   dbus_int32_t index;
595   dbus_int32_t row, column, row_extents, col_extents;
596   dbus_bool_t is_selected;
597   dbus_bool_t ret;
598   DBusMessage *reply;
599   AtkObject *cell;
600   AtkRole role = ATK_ROLE_INVALID;
601
602   g_return_val_if_fail (ATK_IS_TABLE (user_data),
603                         droute_not_yet_handled_error (message));
604   if (!dbus_message_get_args
605       (message, NULL, DBUS_TYPE_INT32, &index, DBUS_TYPE_INVALID))
606     {
607       return droute_invalid_arguments_error (message);
608     }
609   column = atk_table_get_column_at_index (table, index);
610   row = atk_table_get_row_at_index (table, index);
611   row_extents = atk_table_get_row_extent_at (table, row, column);
612   col_extents = atk_table_get_column_extent_at (table, row, column);
613   is_selected = atk_table_is_selected (table, row, column);
614   cell = atk_table_ref_at (table, row, column);
615   if (cell)
616   {
617     role = atk_object_get_role (cell);
618     g_object_unref (cell);
619   }
620   ret = (role == ATK_ROLE_TABLE_CELL ? TRUE : FALSE);
621   reply = dbus_message_new_method_return (message);
622   if (reply)
623     {
624       dbus_message_append_args (reply, DBUS_TYPE_BOOLEAN, &ret,
625                                 DBUS_TYPE_INT32, &row, DBUS_TYPE_INT32,
626                                 &column, DBUS_TYPE_INT32, &row_extents,
627                                 DBUS_TYPE_INT32, &col_extents,
628                                 DBUS_TYPE_BOOLEAN, &is_selected,
629                                 DBUS_TYPE_INVALID);
630     }
631   return reply;
632 }
633
634 static DRouteMethod methods[] = {
635   {impl_GetAccessibleAt, "GetAccessibleAt"},
636   {impl_GetIndexAt, "GetIndexAt"},
637   {impl_GetRowAtIndex, "GetRowAtIndex"},
638   {impl_GetColumnAtIndex, "GetColumnAtIndex"},
639   {impl_GetRowDescription, "GetRowDescription"},
640   {impl_GetColumnDescription, "GetColumnDescription"},
641   {impl_GetRowExtentAt, "GetRowExtentAt"},
642   {impl_GetColumnExtentAt, "GetColumnExtentAt"},
643   {impl_GetRowHeader, "GetRowHeader"},
644   {impl_GetColumnHeader, "GetColumnHeader"},
645   {impl_GetSelectedRows, "GetSelectedRows"},
646   {impl_GetSelectedColumns, "GetSelectedColumns"},
647   {impl_IsRowSelected, "IsRowSelected"},
648   {impl_IsColumnSelected, "IsColumnSelected"},
649   {impl_IsSelected, "IsSelected"},
650   {impl_AddRowSelection, "AddRowSelection"},
651   {impl_AddColumnSelection, "AddColumnSelection"},
652   {impl_RemoveRowSelection, "RemoveRowSelection"},
653   {impl_RemoveColumnSelection, "RemoveColumnSelection"},
654   {impl_GetRowColumnExtentsAtIndex, "GetRowColumnExtentsAtIndex"},
655   {NULL, NULL}
656 };
657
658 static DRouteProperty properties[] = {
659   {impl_get_NRows, NULL, "NRows"},
660   {impl_get_NColumns, NULL, "NColumns"},
661   {impl_get_Caption, NULL, "Caption"},
662   {impl_get_Summary, NULL, "Summary"},
663   {impl_get_NSelectedRows, NULL, "NSelectedRows"},
664   {impl_get_NSelectedColumns, NULL, "NSelectedColumns"},
665   {NULL, NULL, NULL}
666 };
667
668 void
669 spi_initialize_table (DRoutePath * path)
670 {
671   spi_atk_add_interface (path,
672                          ATSPI_DBUS_INTERFACE_TABLE, spi_org_a11y_atspi_Table, methods, properties);
673 };