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