Fix error where null objects were sent with wrong address.
[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 "common/spi-dbus.h"
29 #include "object.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   spi_object_append_v_reference (iter, atk_table_get_caption (table));
53   return TRUE;
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   spi_object_append_v_reference (iter, atk_table_get_summary (table));
62   return TRUE;
63 }
64
65 static dbus_bool_t
66 impl_get_NSelectedRows (DBusMessageIter * iter, void *user_data)
67 {
68   AtkTable *table = (AtkTable *) user_data;
69   gint *selected_rows = NULL;
70   int count;
71   g_return_val_if_fail (ATK_IS_TABLE (user_data), FALSE);
72   count = atk_table_get_selected_rows (table, &selected_rows);
73   if (selected_rows)
74     g_free (selected_rows);
75   return droute_return_v_int32 (iter, count);
76 }
77
78 static dbus_bool_t
79 impl_get_NSelectedColumns (DBusMessageIter * iter, void *user_data)
80 {
81   AtkTable *table = (AtkTable *) user_data;
82   gint *selected_columns = NULL;
83   int count;
84   g_return_val_if_fail (ATK_IS_TABLE (user_data), FALSE);
85   count = atk_table_get_selected_columns (table, &selected_columns);
86   if (selected_columns)
87     g_free (selected_columns);
88   return droute_return_v_int32 (iter, count);
89 }
90
91 static DBusMessage *
92 impl_GetAccessibleAt (DBusConnection * bus, DBusMessage * message,
93                       void *user_data)
94 {
95   AtkTable *table = (AtkTable *) user_data;
96   dbus_int32_t row, column;
97   DBusError error;
98   AtkObject *obj;
99
100   g_return_val_if_fail (ATK_IS_TABLE (user_data),
101                         droute_not_yet_handled_error (message));
102   dbus_error_init (&error);
103   if (!dbus_message_get_args
104       (message, &error, 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   return spi_object_return_reference (message, obj);
111 }
112
113 static DBusMessage *
114 impl_GetIndexAt (DBusConnection * bus, DBusMessage * message, void *user_data)
115 {
116   AtkTable *table = (AtkTable *) user_data;
117   dbus_int32_t row, column;
118   dbus_int32_t index;
119   DBusError error;
120   DBusMessage *reply;
121
122   g_return_val_if_fail (ATK_IS_TABLE (user_data),
123                         droute_not_yet_handled_error (message));
124   dbus_error_init (&error);
125   if (!dbus_message_get_args
126       (message, &error, DBUS_TYPE_INT32, &row, DBUS_TYPE_INT32, &column,
127        DBUS_TYPE_INVALID))
128     {
129       return droute_invalid_arguments_error (message);
130     }
131   index = atk_table_get_index_at (table, row, column);
132   reply = dbus_message_new_method_return (message);
133   if (reply)
134     {
135       dbus_message_append_args (reply, DBUS_TYPE_INT32, &index,
136                                 DBUS_TYPE_INVALID);
137     }
138   return reply;
139 }
140
141 static DBusMessage *
142 impl_GetRowAtIndex (DBusConnection * bus, DBusMessage * message,
143                     void *user_data)
144 {
145   AtkTable *table = (AtkTable *) user_data;
146   dbus_int32_t index;
147   dbus_int32_t row;
148   DBusError error;
149   DBusMessage *reply;
150
151   g_return_val_if_fail (ATK_IS_TABLE (user_data),
152                         droute_not_yet_handled_error (message));
153   dbus_error_init (&error);
154   if (!dbus_message_get_args
155       (message, &error, 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   DBusError error;
177   DBusMessage *reply;
178
179   g_return_val_if_fail (ATK_IS_TABLE (user_data),
180                         droute_not_yet_handled_error (message));
181   dbus_error_init (&error);
182   if (!dbus_message_get_args
183       (message, &error, DBUS_TYPE_INT32, &index, DBUS_TYPE_INVALID))
184     {
185       return droute_invalid_arguments_error (message);
186     }
187   column = atk_table_get_column_at_index (table, index);
188   reply = dbus_message_new_method_return (message);
189   if (reply)
190     {
191       dbus_message_append_args (reply, DBUS_TYPE_INT32, &column,
192                                 DBUS_TYPE_INVALID);
193     }
194   return reply;
195 }
196
197 static DBusMessage *
198 impl_GetRowDescription (DBusConnection * bus, DBusMessage * message,
199                         void *user_data)
200 {
201   dbus_int32_t row;
202   AtkTable *table = (AtkTable *) user_data;
203   const gchar *description;
204   DBusError error;
205   DBusMessage *reply;
206
207   g_return_val_if_fail (ATK_IS_TABLE (user_data),
208                         droute_not_yet_handled_error (message));
209   dbus_error_init (&error);
210   if (!dbus_message_get_args
211       (message, &error, DBUS_TYPE_INT32, &row, DBUS_TYPE_INVALID))
212     {
213       return droute_invalid_arguments_error (message);
214     }
215   description = atk_table_get_row_description (table, row);
216   if (!description)
217     description = "";
218   reply = dbus_message_new_method_return (message);
219   if (reply)
220     {
221       dbus_message_append_args (reply, DBUS_TYPE_STRING, &description,
222                                 DBUS_TYPE_INVALID);
223     }
224   return reply;
225 }
226
227 static DBusMessage *
228 impl_GetColumnDescription (DBusConnection * bus, DBusMessage * message,
229                            void *user_data)
230 {
231   AtkTable *table = (AtkTable *) user_data;
232   dbus_int32_t column;
233   const char *description;
234   DBusError error;
235   DBusMessage *reply;
236
237   g_return_val_if_fail (ATK_IS_TABLE (user_data),
238                         droute_not_yet_handled_error (message));
239   dbus_error_init (&error);
240   if (!dbus_message_get_args
241       (message, &error, DBUS_TYPE_INT32, &column, DBUS_TYPE_INVALID))
242     {
243       return droute_invalid_arguments_error (message);
244     }
245   description = atk_table_get_column_description (table, column);
246   if (!description)
247     description = "";
248   reply = dbus_message_new_method_return (message);
249   if (reply)
250     {
251       dbus_message_append_args (reply, DBUS_TYPE_STRING, &description,
252                                 DBUS_TYPE_INVALID);
253     }
254   return reply;
255 }
256
257 static DBusMessage *
258 impl_GetRowExtentAt (DBusConnection * bus, DBusMessage * message,
259                      void *user_data)
260 {
261   AtkTable *table = (AtkTable *) user_data;
262   dbus_int32_t row, column;
263   dbus_int32_t extent;
264   DBusError error;
265   DBusMessage *reply;
266
267   g_return_val_if_fail (ATK_IS_TABLE (user_data),
268                         droute_not_yet_handled_error (message));
269   dbus_error_init (&error);
270   if (!dbus_message_get_args
271       (message, &error, DBUS_TYPE_INT32, &row, DBUS_TYPE_INT32, &column,
272        DBUS_TYPE_INVALID))
273     {
274       return droute_invalid_arguments_error (message);
275     }
276   extent = atk_table_get_row_extent_at (table, row, column);
277   reply = dbus_message_new_method_return (message);
278   if (reply)
279     {
280       dbus_message_append_args (reply, DBUS_TYPE_INT32, &extent,
281                                 DBUS_TYPE_INVALID);
282     }
283   return reply;
284 }
285
286 static DBusMessage *
287 impl_GetColumnExtentAt (DBusConnection * bus, DBusMessage * message,
288                         void *user_data)
289 {
290   AtkTable *table = (AtkTable *) user_data;
291   dbus_int32_t row, column;
292   dbus_int32_t extent;
293   DBusError error;
294   DBusMessage *reply;
295
296   g_return_val_if_fail (ATK_IS_TABLE (user_data),
297                         droute_not_yet_handled_error (message));
298   dbus_error_init (&error);
299   if (!dbus_message_get_args
300       (message, &error, DBUS_TYPE_INT32, &row, DBUS_TYPE_INT32, &column,
301        DBUS_TYPE_INVALID))
302     {
303       return droute_invalid_arguments_error (message);
304     }
305   extent = atk_table_get_column_extent_at (table, row, column);
306   reply = dbus_message_new_method_return (message);
307   if (reply)
308     {
309       dbus_message_append_args (reply, DBUS_TYPE_INT32, &extent,
310                                 DBUS_TYPE_INVALID);
311     }
312   return reply;
313 }
314
315 static DBusMessage *
316 impl_GetRowHeader (DBusConnection * bus, DBusMessage * message,
317                    void *user_data)
318 {
319   AtkTable *table = (AtkTable *) user_data;
320   dbus_int32_t row;
321   DBusError error;
322   AtkObject *obj = NULL;
323
324   g_return_val_if_fail (ATK_IS_TABLE (user_data),
325                         droute_not_yet_handled_error (message));
326   dbus_error_init (&error);
327   if (!dbus_message_get_args
328       (message, &error, 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   DBusError error;
343   AtkObject *obj;
344
345   g_return_val_if_fail (ATK_IS_TABLE (user_data),
346                         droute_not_yet_handled_error (message));
347   dbus_error_init (&error);
348   if (!dbus_message_get_args
349       (message, &error, DBUS_TYPE_INT32, &column, DBUS_TYPE_INVALID))
350     {
351       return droute_invalid_arguments_error (message);
352     }
353   obj = atk_table_get_column_header (table, column);
354   obj = atk_table_get_column_header (table, column);
355   return spi_object_return_reference (message, obj);
356 }
357
358 static DBusMessage *
359 impl_GetSelectedRows (DBusConnection * bus, DBusMessage * message,
360                       void *user_data)
361 {
362   AtkTable *table = (AtkTable *) user_data;
363   gint *selected_rows = NULL;
364   gint count;
365   DBusMessage *reply;
366
367   g_return_val_if_fail (ATK_IS_TABLE (user_data),
368                         droute_not_yet_handled_error (message));
369   count = atk_table_get_selected_rows (table, &selected_rows);
370   if (!selected_rows)
371     count = 0;
372   reply = dbus_message_new_method_return (message);
373   if (reply)
374     {
375       /* tbd - figure out if this is safe for a 0-length array */
376       dbus_message_append_args (reply, DBUS_TYPE_ARRAY, DBUS_TYPE_INT32,
377                                 &selected_rows, count, DBUS_TYPE_INVALID);
378     }
379   if (selected_rows)
380     g_free (selected_rows);
381   return reply;
382 }
383
384 static DBusMessage *
385 impl_GetSelectedColumns (DBusConnection * bus, DBusMessage * message,
386                          void *user_data)
387 {
388   AtkTable *table = (AtkTable *) user_data;
389   gint *selected_columns = NULL;
390   gint count;
391   DBusMessage *reply;
392
393   g_return_val_if_fail (ATK_IS_TABLE (user_data),
394                         droute_not_yet_handled_error (message));
395   count = atk_table_get_selected_columns (table, &selected_columns);
396   if (!selected_columns)
397     count = 0;
398   reply = dbus_message_new_method_return (message);
399   if (reply)
400     {
401       /* tbd - figure out if this is safe for a 0-length array */
402       dbus_message_append_args (reply, DBUS_TYPE_ARRAY, DBUS_TYPE_INT32,
403                                 &selected_columns, count, DBUS_TYPE_INVALID);
404     }
405   if (selected_columns)
406     g_free (selected_columns);
407   return reply;
408 }
409
410 static DBusMessage *
411 impl_IsRowSelected (DBusConnection * bus, DBusMessage * message,
412                     void *user_data)
413 {
414   AtkTable *table = (AtkTable *) user_data;
415   dbus_int32_t row;
416   DBusError error;
417   DBusMessage *reply;
418   dbus_bool_t ret;
419
420   g_return_val_if_fail (ATK_IS_TABLE (user_data),
421                         droute_not_yet_handled_error (message));
422   dbus_error_init (&error);
423   if (!dbus_message_get_args
424       (message, &error, DBUS_TYPE_INT32, &row, DBUS_TYPE_INVALID))
425     {
426       return droute_invalid_arguments_error (message);
427     }
428   ret = atk_table_is_row_selected (table, row);
429   reply = dbus_message_new_method_return (message);
430   if (reply)
431     {
432       dbus_message_append_args (reply, DBUS_TYPE_BOOLEAN, &ret,
433                                 DBUS_TYPE_INVALID);
434     }
435   return reply;
436 }
437
438 static DBusMessage *
439 impl_IsColumnSelected (DBusConnection * bus, DBusMessage * message,
440                        void *user_data)
441 {
442   AtkTable *table = (AtkTable *) user_data;
443   dbus_int32_t column;
444   DBusError error;
445   DBusMessage *reply;
446   dbus_bool_t ret;
447
448   g_return_val_if_fail (ATK_IS_TABLE (user_data),
449                         droute_not_yet_handled_error (message));
450   dbus_error_init (&error);
451   if (!dbus_message_get_args
452       (message, &error, DBUS_TYPE_INT32, &column, DBUS_TYPE_INVALID))
453     {
454       return droute_invalid_arguments_error (message);
455     }
456   ret = atk_table_is_column_selected (table, column);
457   reply = dbus_message_new_method_return (message);
458   if (reply)
459     {
460       dbus_message_append_args (reply, DBUS_TYPE_BOOLEAN, &ret,
461                                 DBUS_TYPE_INVALID);
462     }
463   return reply;
464 }
465
466 static DBusMessage *
467 impl_IsSelected (DBusConnection * bus, DBusMessage * message, void *user_data)
468 {
469   AtkTable *table = (AtkTable *) user_data;
470   dbus_int32_t row, column;
471   DBusError error;
472   DBusMessage *reply;
473   dbus_bool_t ret;
474
475   g_return_val_if_fail (ATK_IS_TABLE (user_data),
476                         droute_not_yet_handled_error (message));
477   dbus_error_init (&error);
478   if (!dbus_message_get_args
479       (message, &error, DBUS_TYPE_INT32, &row, DBUS_TYPE_INT32, &column,
480        DBUS_TYPE_INVALID))
481     {
482       return droute_invalid_arguments_error (message);
483     }
484   ret = atk_table_is_selected (table, row, column);
485   reply = dbus_message_new_method_return (message);
486   if (reply)
487     {
488       dbus_message_append_args (reply, DBUS_TYPE_BOOLEAN, &ret,
489                                 DBUS_TYPE_INVALID);
490     }
491   return reply;
492 }
493
494 static DBusMessage *
495 impl_AddRowSelection (DBusConnection * bus, DBusMessage * message,
496                       void *user_data)
497 {
498   AtkTable *table = (AtkTable *) user_data;
499   dbus_int32_t row;
500   DBusError error;
501   DBusMessage *reply;
502   dbus_bool_t ret;
503
504   g_return_val_if_fail (ATK_IS_TABLE (user_data),
505                         droute_not_yet_handled_error (message));
506   dbus_error_init (&error);
507   if (!dbus_message_get_args
508       (message, &error, DBUS_TYPE_INT32, &row, DBUS_TYPE_INVALID))
509     {
510       return droute_invalid_arguments_error (message);
511     }
512   ret = atk_table_add_row_selection (table, row);
513   reply = dbus_message_new_method_return (message);
514   if (reply)
515     {
516       dbus_message_append_args (reply, DBUS_TYPE_BOOLEAN, &ret,
517                                 DBUS_TYPE_INVALID);
518     }
519   return reply;
520 }
521
522 static DBusMessage *
523 impl_AddColumnSelection (DBusConnection * bus, DBusMessage * message,
524                          void *user_data)
525 {
526   AtkTable *table = (AtkTable *) user_data;
527   dbus_int32_t column;
528   DBusError error;
529   DBusMessage *reply;
530   dbus_bool_t ret;
531
532   g_return_val_if_fail (ATK_IS_TABLE (user_data),
533                         droute_not_yet_handled_error (message));
534   dbus_error_init (&error);
535   if (!dbus_message_get_args
536       (message, &error, DBUS_TYPE_INT32, &column, DBUS_TYPE_INVALID))
537     {
538       return droute_invalid_arguments_error (message);
539     }
540   ret = atk_table_add_column_selection (table, column);
541   reply = dbus_message_new_method_return (message);
542   if (reply)
543     {
544       dbus_message_append_args (reply, DBUS_TYPE_BOOLEAN, &ret,
545                                 DBUS_TYPE_INVALID);
546     }
547   return reply;
548 }
549
550 static DBusMessage *
551 impl_RemoveRowSelection (DBusConnection * bus, DBusMessage * message,
552                          void *user_data)
553 {
554   AtkTable *table = (AtkTable *) user_data;
555   dbus_int32_t row;
556   DBusError error;
557   DBusMessage *reply;
558   dbus_bool_t ret;
559
560   g_return_val_if_fail (ATK_IS_TABLE (user_data),
561                         droute_not_yet_handled_error (message));
562   dbus_error_init (&error);
563   if (!dbus_message_get_args
564       (message, &error, DBUS_TYPE_INT32, &row, DBUS_TYPE_INVALID))
565     {
566       return droute_invalid_arguments_error (message);
567     }
568   ret = atk_table_remove_row_selection (table, row);
569   reply = dbus_message_new_method_return (message);
570   if (reply)
571     {
572       dbus_message_append_args (reply, DBUS_TYPE_BOOLEAN, &ret,
573                                 DBUS_TYPE_INVALID);
574     }
575   return reply;
576 }
577
578 static DBusMessage *
579 impl_RemoveColumnSelection (DBusConnection * bus, DBusMessage * message,
580                             void *user_data)
581 {
582   AtkTable *table = (AtkTable *) user_data;
583   dbus_int32_t column;
584   DBusError error;
585   DBusMessage *reply;
586   dbus_bool_t ret;
587
588   g_return_val_if_fail (ATK_IS_TABLE (user_data),
589                         droute_not_yet_handled_error (message));
590   dbus_error_init (&error);
591   if (!dbus_message_get_args
592       (message, &error, DBUS_TYPE_INT32, &column, DBUS_TYPE_INVALID))
593     {
594       return droute_invalid_arguments_error (message);
595     }
596   ret = atk_table_remove_column_selection (table, column);
597   reply = dbus_message_new_method_return (message);
598   if (reply)
599     {
600       dbus_message_append_args (reply, DBUS_TYPE_BOOLEAN, &ret,
601                                 DBUS_TYPE_INVALID);
602     }
603   return reply;
604 }
605
606 static DBusMessage *
607 impl_GetRowColumnExtentsAtIndex (DBusConnection * bus, DBusMessage * message,
608                                  void *user_data)
609 {
610   AtkTable *table = (AtkTable *) user_data;
611   dbus_int32_t index;
612   DBusError error;
613   dbus_int32_t row, column, row_extents, col_extents;
614   dbus_bool_t is_selected;
615   dbus_bool_t ret;
616   DBusMessage *reply;
617
618   AtkObject *cell;
619   AtkRole role;
620
621   g_return_val_if_fail (ATK_IS_TABLE (user_data),
622                         droute_not_yet_handled_error (message));
623   dbus_error_init (&error);
624   if (!dbus_message_get_args
625       (message, &error, DBUS_TYPE_INT32, &index, DBUS_TYPE_INVALID))
626     {
627       return droute_invalid_arguments_error (message);
628     }
629   column = atk_table_get_column_at_index (table, index);
630   row = atk_table_get_row_at_index (table, index);
631   row_extents = atk_table_get_row_extent_at (table, row, column);
632   col_extents = atk_table_get_column_extent_at (table, row, column);
633   is_selected = atk_table_is_selected (table, row, column);
634   cell = atk_table_ref_at (table, row, column);
635   role = atk_object_get_role (cell);
636   g_object_unref (cell);
637   ret = (role == ATK_ROLE_TABLE_CELL ? TRUE : FALSE);
638   reply = dbus_message_new_method_return (message);
639   if (reply)
640     {
641       dbus_message_append_args (reply, DBUS_TYPE_BOOLEAN, &ret,
642                                 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_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, methods, properties);
690 };