7ba03f24a32f2b4fbda9396d58c1c1e3cc32d99b
[platform/core/uifw/at-spi2-atk.git] / atk-adaptor / 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 "accessible-marshaller.h"
29 #include "spi-common/spi-dbus.h"
30
31 static dbus_bool_t
32 impl_get_nRows (DBusMessageIter * iter, void *user_data)
33 {
34   AtkTable *table = (AtkTable *) user_data;
35   g_return_val_if_fail (ATK_IS_TABLE (user_data), FALSE);
36   return droute_return_v_int32 (iter, atk_table_get_n_rows (table));
37 }
38
39 static dbus_bool_t
40 impl_get_nColumns (DBusMessageIter * iter, void *user_data)
41 {
42   AtkTable *table = (AtkTable *) user_data;
43   g_return_val_if_fail (ATK_IS_TABLE (user_data), FALSE);
44   return droute_return_v_int32 (iter, atk_table_get_n_columns (table));
45 }
46
47 static dbus_bool_t
48 impl_get_caption (DBusMessageIter * iter, void *user_data)
49 {
50   AtkTable *table = (AtkTable *) user_data;
51   g_return_val_if_fail (ATK_IS_TABLE (user_data), FALSE);
52   return spi_dbus_return_v_object (iter, atk_table_get_caption (table),
53                                    FALSE);
54 }
55
56 static dbus_bool_t
57 impl_get_summary (DBusMessageIter * iter, void *user_data)
58 {
59   AtkTable *table = (AtkTable *) user_data;
60   g_return_val_if_fail (ATK_IS_TABLE (user_data), FALSE);
61   return spi_dbus_return_v_object (iter, atk_table_get_summary (table),
62                                    FALSE);
63 }
64
65 static dbus_bool_t
66 impl_get_nSelectedRows (DBusMessageIter * iter,
67                         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,
81                            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   DBusError error;
100   AtkObject *obj;
101
102   g_return_val_if_fail (ATK_IS_TABLE (user_data),
103                         droute_not_yet_handled_error (message));
104   dbus_error_init (&error);
105   if (!dbus_message_get_args
106       (message, &error, DBUS_TYPE_INT32, &row, DBUS_TYPE_INT32, &column,
107        DBUS_TYPE_INVALID))
108     {
109       return droute_invalid_arguments_error (message);
110     }
111   obj = atk_table_ref_at (table, row, column);
112   return spi_dbus_return_object (message, obj, TRUE);
113 }
114
115 static DBusMessage *
116 impl_getIndexAt (DBusConnection * bus, DBusMessage * message, void *user_data)
117 {
118   AtkTable *table = (AtkTable *) user_data;
119   dbus_int32_t row, column;
120   dbus_int32_t index;
121   DBusError error;
122   DBusMessage *reply;
123
124   g_return_val_if_fail (ATK_IS_TABLE (user_data),
125                         droute_not_yet_handled_error (message));
126   dbus_error_init (&error);
127   if (!dbus_message_get_args
128       (message, &error, 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   DBusError error;
151   DBusMessage *reply;
152
153   g_return_val_if_fail (ATK_IS_TABLE (user_data),
154                         droute_not_yet_handled_error (message));
155   dbus_error_init (&error);
156   if (!dbus_message_get_args
157       (message, &error, DBUS_TYPE_INT32, &index, DBUS_TYPE_INVALID))
158     {
159       return droute_invalid_arguments_error (message);
160     }
161   row = atk_table_get_row_at_index (table, index);
162   reply = dbus_message_new_method_return (message);
163   if (reply)
164     {
165       dbus_message_append_args (reply, DBUS_TYPE_INT32, &row,
166                                 DBUS_TYPE_INVALID);
167     }
168   return reply;
169 }
170
171 static DBusMessage *
172 impl_getColumnAtIndex (DBusConnection * bus, DBusMessage * message,
173                        void *user_data)
174 {
175   AtkTable *table = (AtkTable *) user_data;
176   dbus_int32_t index;
177   dbus_int32_t column;
178   DBusError error;
179   DBusMessage *reply;
180
181   g_return_val_if_fail (ATK_IS_TABLE (user_data),
182                         droute_not_yet_handled_error (message));
183   dbus_error_init (&error);
184   if (!dbus_message_get_args
185       (message, &error, DBUS_TYPE_INT32, &index, DBUS_TYPE_INVALID))
186     {
187       return droute_invalid_arguments_error (message);
188     }
189   column = atk_table_get_column_at_index (table, index);
190   reply = dbus_message_new_method_return (message);
191   if (reply)
192     {
193       dbus_message_append_args (reply, DBUS_TYPE_INT32, &column,
194                                 DBUS_TYPE_INVALID);
195     }
196   return reply;
197 }
198
199 static DBusMessage *
200 impl_getRowDescription (DBusConnection * bus, DBusMessage * message,
201                         void *user_data)
202 {
203   dbus_int32_t row;
204   AtkTable *table = (AtkTable *) user_data;
205   const gchar *description;
206   DBusError error;
207   DBusMessage *reply;
208
209   g_return_val_if_fail (ATK_IS_TABLE (user_data),
210                         droute_not_yet_handled_error (message));
211   dbus_error_init (&error);
212   if (!dbus_message_get_args
213       (message, &error, DBUS_TYPE_INT32, &row, DBUS_TYPE_INVALID))
214     {
215       return droute_invalid_arguments_error (message);
216     }
217   description = atk_table_get_row_description (table, row);
218   if (!description)
219     description = "";
220   reply = dbus_message_new_method_return (message);
221   if (reply)
222     {
223       dbus_message_append_args (reply, DBUS_TYPE_STRING, &description,
224                                 DBUS_TYPE_INVALID);
225     }
226   return reply;
227 }
228
229 static DBusMessage *
230 impl_getColumnDescription (DBusConnection * bus, DBusMessage * message,
231                            void *user_data)
232 {
233   AtkTable *table = (AtkTable *) user_data;
234   dbus_int32_t column;
235   const char *description;
236   DBusError error;
237   DBusMessage *reply;
238
239   g_return_val_if_fail (ATK_IS_TABLE (user_data),
240                         droute_not_yet_handled_error (message));
241   dbus_error_init (&error);
242   if (!dbus_message_get_args
243       (message, &error, DBUS_TYPE_INT32, &column, DBUS_TYPE_INVALID))
244     {
245       return droute_invalid_arguments_error (message);
246     }
247   description = atk_table_get_column_description (table, column);
248   if (!description)
249     description = "";
250   reply = dbus_message_new_method_return (message);
251   if (reply)
252     {
253       dbus_message_append_args (reply, DBUS_TYPE_STRING, &description,
254                                 DBUS_TYPE_INVALID);
255     }
256   return reply;
257 }
258
259 static DBusMessage *
260 impl_getRowExtentAt (DBusConnection * bus, DBusMessage * message,
261                      void *user_data)
262 {
263   AtkTable *table = (AtkTable *) user_data;
264   dbus_int32_t row, column;
265   dbus_int32_t extent;
266   DBusError error;
267   DBusMessage *reply;
268
269   g_return_val_if_fail (ATK_IS_TABLE (user_data),
270                         droute_not_yet_handled_error (message));
271   dbus_error_init (&error);
272   if (!dbus_message_get_args
273       (message, &error, DBUS_TYPE_INT32, &row, DBUS_TYPE_INT32, &column,
274        DBUS_TYPE_INVALID))
275     {
276       return droute_invalid_arguments_error (message);
277     }
278   extent = atk_table_get_row_extent_at (table, row, column);
279   reply = dbus_message_new_method_return (message);
280   if (reply)
281     {
282       dbus_message_append_args (reply, DBUS_TYPE_INT32, &extent,
283                                 DBUS_TYPE_INVALID);
284     }
285   return reply;
286 }
287
288 static DBusMessage *
289 impl_getColumnExtentAt (DBusConnection * bus, DBusMessage * message,
290                         void *user_data)
291 {
292   AtkTable *table = (AtkTable *) user_data;
293   dbus_int32_t row, column;
294   dbus_int32_t extent;
295   DBusError error;
296   DBusMessage *reply;
297
298   g_return_val_if_fail (ATK_IS_TABLE (user_data),
299                         droute_not_yet_handled_error (message));
300   dbus_error_init (&error);
301   if (!dbus_message_get_args
302       (message, &error, 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   DBusError error;
324   AtkObject *obj;
325
326   g_return_val_if_fail (ATK_IS_TABLE (user_data),
327                         droute_not_yet_handled_error (message));
328   dbus_error_init (&error);
329   if (!dbus_message_get_args
330       (message, &error, DBUS_TYPE_INT32, &row, DBUS_TYPE_INVALID))
331     {
332       return droute_invalid_arguments_error (message);
333     }
334   obj = atk_table_get_row_header (table, row);
335   return spi_dbus_return_object (message, obj, FALSE);
336 }
337
338 static DBusMessage *
339 impl_getColumnHeader (DBusConnection * bus, DBusMessage * message,
340                       void *user_data)
341 {
342   AtkTable *table = (AtkTable *) user_data;
343   dbus_int32_t column;
344   DBusError error;
345   AtkObject *obj;
346
347   g_return_val_if_fail (ATK_IS_TABLE (user_data),
348                         droute_not_yet_handled_error (message));
349   dbus_error_init (&error);
350   if (!dbus_message_get_args
351       (message, &error, DBUS_TYPE_INT32, &column, DBUS_TYPE_INVALID))
352     {
353       return droute_invalid_arguments_error (message);
354     }
355   obj = atk_table_get_column_header (table, column);
356   return spi_dbus_return_object (message, obj, FALSE);
357 }
358
359 static DBusMessage *
360 impl_getSelectedRows (DBusConnection * bus, DBusMessage * message,
361                       void *user_data)
362 {
363   AtkTable *table = (AtkTable *) user_data;
364   gint *selected_rows = NULL;
365   gint count;
366   DBusMessage *reply;
367
368   g_return_val_if_fail (ATK_IS_TABLE (user_data),
369                         droute_not_yet_handled_error (message));
370   count = atk_table_get_selected_rows (table, &selected_rows);
371   if (!selected_rows)
372     count = 0;
373   reply = dbus_message_new_method_return (message);
374   if (reply)
375     {
376       /* tbd - figure out if this is safe for a 0-length array */
377       dbus_message_append_args (reply, DBUS_TYPE_ARRAY, DBUS_TYPE_INT32,
378                                 &selected_rows, count, DBUS_TYPE_INVALID);
379     }
380   if (selected_rows)
381     g_free (selected_rows);
382   return reply;
383 }
384
385 static DBusMessage *
386 impl_getSelectedColumns (DBusConnection * bus, DBusMessage * message,
387                          void *user_data)
388 {
389   AtkTable *table = (AtkTable *) user_data;
390   gint *selected_columns = NULL;
391   gint count;
392   DBusMessage *reply;
393
394   g_return_val_if_fail (ATK_IS_TABLE (user_data),
395                         droute_not_yet_handled_error (message));
396   count = atk_table_get_selected_columns (table, &selected_columns);
397   if (!selected_columns)
398     count = 0;
399   reply = dbus_message_new_method_return (message);
400   if (reply)
401     {
402       /* tbd - figure out if this is safe for a 0-length array */
403       dbus_message_append_args (reply, DBUS_TYPE_ARRAY, DBUS_TYPE_INT32,
404                                 &selected_columns, count, DBUS_TYPE_INVALID);
405     }
406   if (selected_columns)
407     g_free (selected_columns);
408   return reply;
409 }
410
411 static DBusMessage *
412 impl_isRowSelected (DBusConnection * bus, DBusMessage * message,
413                     void *user_data)
414 {
415   AtkTable *table = (AtkTable *) user_data;
416   dbus_int32_t row;
417   DBusError error;
418   DBusMessage *reply;
419   dbus_bool_t ret;
420
421   g_return_val_if_fail (ATK_IS_TABLE (user_data),
422                         droute_not_yet_handled_error (message));
423   dbus_error_init (&error);
424   if (!dbus_message_get_args
425       (message, &error, DBUS_TYPE_INT32, &row, DBUS_TYPE_INVALID))
426     {
427       return droute_invalid_arguments_error (message);
428     }
429   ret = atk_table_is_row_selected (table, row);
430   reply = dbus_message_new_method_return (message);
431   if (reply)
432     {
433       dbus_message_append_args (reply, DBUS_TYPE_BOOLEAN, &ret,
434                                 DBUS_TYPE_INVALID);
435     }
436   return reply;
437 }
438
439 static DBusMessage *
440 impl_isColumnSelected (DBusConnection * bus, DBusMessage * message,
441                        void *user_data)
442 {
443   AtkTable *table = (AtkTable *) user_data;
444   dbus_int32_t column;
445   DBusError error;
446   DBusMessage *reply;
447   dbus_bool_t ret;
448
449   g_return_val_if_fail (ATK_IS_TABLE (user_data),
450                         droute_not_yet_handled_error (message));
451   dbus_error_init (&error);
452   if (!dbus_message_get_args
453       (message, &error, DBUS_TYPE_INT32, &column, DBUS_TYPE_INVALID))
454     {
455       return droute_invalid_arguments_error (message);
456     }
457   ret = atk_table_is_column_selected (table, column);
458   reply = dbus_message_new_method_return (message);
459   if (reply)
460     {
461       dbus_message_append_args (reply, DBUS_TYPE_BOOLEAN, &ret,
462                                 DBUS_TYPE_INVALID);
463     }
464   return reply;
465 }
466
467 static DBusMessage *
468 impl_isSelected (DBusConnection * bus, DBusMessage * message, void *user_data)
469 {
470   AtkTable *table = (AtkTable *) user_data;
471   dbus_int32_t row, column;
472   DBusError error;
473   DBusMessage *reply;
474   dbus_bool_t ret;
475
476   g_return_val_if_fail (ATK_IS_TABLE (user_data),
477                         droute_not_yet_handled_error (message));
478   dbus_error_init (&error);
479   if (!dbus_message_get_args
480       (message, &error, DBUS_TYPE_INT32, &row, DBUS_TYPE_INT32, &column,
481        DBUS_TYPE_INVALID))
482     {
483       return droute_invalid_arguments_error (message);
484     }
485   ret = atk_table_is_selected (table, row, column);
486   reply = dbus_message_new_method_return (message);
487   if (reply)
488     {
489       dbus_message_append_args (reply, DBUS_TYPE_BOOLEAN, &ret,
490                                 DBUS_TYPE_INVALID);
491     }
492   return reply;
493 }
494
495 static DBusMessage *
496 impl_addRowSelection (DBusConnection * bus, DBusMessage * message,
497                       void *user_data)
498 {
499   AtkTable *table = (AtkTable *) user_data;
500   dbus_int32_t row;
501   DBusError error;
502   DBusMessage *reply;
503   dbus_bool_t ret;
504
505   g_return_val_if_fail (ATK_IS_TABLE (user_data),
506                         droute_not_yet_handled_error (message));
507   dbus_error_init (&error);
508   if (!dbus_message_get_args
509       (message, &error, DBUS_TYPE_INT32, &row, DBUS_TYPE_INVALID))
510     {
511       return droute_invalid_arguments_error (message);
512     }
513   ret = atk_table_add_row_selection (table, row);
514   reply = dbus_message_new_method_return (message);
515   if (reply)
516     {
517       dbus_message_append_args (reply, DBUS_TYPE_BOOLEAN, &ret,
518                                 DBUS_TYPE_INVALID);
519     }
520   return reply;
521 }
522
523 static DBusMessage *
524 impl_addColumnSelection (DBusConnection * bus, DBusMessage * message,
525                          void *user_data)
526 {
527   AtkTable *table = (AtkTable *) user_data;
528   dbus_int32_t column;
529   DBusError error;
530   DBusMessage *reply;
531   dbus_bool_t ret;
532
533   g_return_val_if_fail (ATK_IS_TABLE (user_data),
534                         droute_not_yet_handled_error (message));
535   dbus_error_init (&error);
536   if (!dbus_message_get_args
537       (message, &error, DBUS_TYPE_INT32, &column, DBUS_TYPE_INVALID))
538     {
539       return droute_invalid_arguments_error (message);
540     }
541   ret = atk_table_add_column_selection (table, column);
542   reply = dbus_message_new_method_return (message);
543   if (reply)
544     {
545       dbus_message_append_args (reply, DBUS_TYPE_BOOLEAN, &ret,
546                                 DBUS_TYPE_INVALID);
547     }
548   return reply;
549 }
550
551 static DBusMessage *
552 impl_removeRowSelection (DBusConnection * bus, DBusMessage * message,
553                          void *user_data)
554 {
555   AtkTable *table = (AtkTable *) user_data;
556   dbus_int32_t row;
557   DBusError error;
558   DBusMessage *reply;
559   dbus_bool_t ret;
560
561   g_return_val_if_fail (ATK_IS_TABLE (user_data),
562                         droute_not_yet_handled_error (message));
563   dbus_error_init (&error);
564   if (!dbus_message_get_args
565       (message, &error, DBUS_TYPE_INT32, &row, DBUS_TYPE_INVALID))
566     {
567       return droute_invalid_arguments_error (message);
568     }
569   ret = atk_table_remove_row_selection (table, row);
570   reply = dbus_message_new_method_return (message);
571   if (reply)
572     {
573       dbus_message_append_args (reply, DBUS_TYPE_BOOLEAN, &ret,
574                                 DBUS_TYPE_INVALID);
575     }
576   return reply;
577 }
578
579 static DBusMessage *
580 impl_removeColumnSelection (DBusConnection * bus, DBusMessage * message,
581                             void *user_data)
582 {
583   AtkTable *table = (AtkTable *) user_data;
584   dbus_int32_t column;
585   DBusError error;
586   DBusMessage *reply;
587   dbus_bool_t ret;
588
589   g_return_val_if_fail (ATK_IS_TABLE (user_data),
590                         droute_not_yet_handled_error (message));
591   dbus_error_init (&error);
592   if (!dbus_message_get_args
593       (message, &error, DBUS_TYPE_INT32, &column, DBUS_TYPE_INVALID))
594     {
595       return droute_invalid_arguments_error (message);
596     }
597   ret = atk_table_remove_column_selection (table, column);
598   reply = dbus_message_new_method_return (message);
599   if (reply)
600     {
601       dbus_message_append_args (reply, DBUS_TYPE_BOOLEAN, &ret,
602                                 DBUS_TYPE_INVALID);
603     }
604   return reply;
605 }
606
607 static DBusMessage *
608 impl_getRowColumnExtentsAtIndex (DBusConnection * bus, DBusMessage * message,
609                                  void *user_data)
610 {
611   AtkTable *table = (AtkTable *) user_data;
612   dbus_int32_t index;
613   DBusError error;
614   dbus_int32_t row, column, row_extents, col_extents;
615   dbus_bool_t is_selected;
616   dbus_bool_t ret;
617   DBusMessage *reply;
618
619   AtkObject *cell;
620   AtkRole role;
621
622   g_return_val_if_fail (ATK_IS_TABLE (user_data),
623                         droute_not_yet_handled_error (message));
624   dbus_error_init (&error);
625   if (!dbus_message_get_args
626       (message, &error, DBUS_TYPE_INT32, &index, DBUS_TYPE_INVALID))
627     {
628       return droute_invalid_arguments_error (message);
629     }
630   column = atk_table_get_column_at_index (table, index);
631   row = atk_table_get_row_at_index (table, index);
632   row_extents = atk_table_get_row_extent_at (table, row, column);
633   col_extents = atk_table_get_column_extent_at (table, row, column);
634   is_selected = atk_table_is_selected (table, row, column);
635   cell = atk_table_ref_at (table, row, column);
636   role = atk_object_get_role (cell);
637   g_object_unref (cell);
638   ret = (role == ATK_ROLE_TABLE_CELL ? TRUE : FALSE);
639   reply = dbus_message_new_method_return (message);
640   if (reply)
641     {
642       dbus_message_append_args (reply, DBUS_TYPE_INT32, row, DBUS_TYPE_INT32,
643                                 column, DBUS_TYPE_INT32, row_extents,
644                                 DBUS_TYPE_INT32, col_extents,
645                                 DBUS_TYPE_BOOLEAN, is_selected,
646                                 DBUS_TYPE_BOOLEAN, &ret, DBUS_TYPE_INVALID);
647     }
648   return reply;
649 }
650
651 static DRouteMethod methods[] = {
652   {impl_getAccessibleAt, "getAccessibleAt"},
653   {impl_getIndexAt, "getIndexAt"},
654   {impl_getRowAtIndex, "getRowAtIndex"},
655   {impl_getColumnAtIndex, "getColumnAtIndex"},
656   {impl_getRowDescription, "getRowDescription"},
657   {impl_getColumnDescription, "getColumnDescription"},
658   {impl_getRowExtentAt, "getRowExtentAt"},
659   {impl_getColumnExtentAt, "getColumnExtentAt"},
660   {impl_getRowHeader, "getRowHeader"},
661   {impl_getColumnHeader, "getColumnHeader"},
662   {impl_getSelectedRows, "getSelectedRows"},
663   {impl_getSelectedColumns, "getSelectedColumns"},
664   {impl_isRowSelected, "isRowSelected"},
665   {impl_isColumnSelected, "isColumnSelected"},
666   {impl_isSelected, "isSelected"},
667   {impl_addRowSelection, "addRowSelection"},
668   {impl_addColumnSelection, "addColumnSelection"},
669   {impl_removeRowSelection, "removeRowSelection"},
670   {impl_removeColumnSelection, "removeColumnSelection"},
671   {impl_getRowColumnExtentsAtIndex, "getRowColumnExtentsAtIndex"},
672   {NULL, NULL}
673 };
674
675 static DRouteProperty properties[] = {
676   {impl_get_nRows, NULL, "nRows"},
677   {impl_get_nColumns, NULL, "nColumns"},
678   {impl_get_caption, NULL, "caption"},
679   {impl_get_summary, NULL, "summary"},
680   {impl_get_nSelectedRows, NULL, "nSelectedRows"},
681   {impl_get_nSelectedColumns, NULL, "nSelectedColumns"},
682   {NULL, NULL, NULL}
683 };
684
685 void
686 spi_initialize_table (DRoutePath *path)
687 {
688   droute_path_add_interface (path,
689                              SPI_DBUS_INTERFACE_TABLE,
690                              methods,
691                              properties);
692 };