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 Lesser General Public
11
 * License as published by the Free Software Foundation; either
12
 * version 2.1 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
 * Lesser General Public License for more details.
18
 *
19
 * You should have received a copy of the GNU Lesser General Public
20
 * License along with this library; if not, write to the
21
 * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
22
 * Boston, MA 02110-1301, USA.
23
 */
24

            
25
#include <string.h>
26

            
27
#define ATK_DISABLE_DEPRECATION_WARNINGS
28
#include "bridge.h"
29
#include <atk/atk.h>
30
#include <droute/droute.h>
31

            
32
#include "spi-dbus.h"
33

            
34
#include "introspection.h"
35
#include "object.h"
36

            
37
static dbus_bool_t
38
impl_get_Version (DBusMessageIter *iter, void *user_data)
39
{
40
  return droute_return_v_uint32 (iter, SPI_DBUS_TEXT_VERSION);
41
}
42

            
43
static dbus_bool_t
44
1
impl_get_CharacterCount (DBusMessageIter *iter, void *user_data)
45
{
46
1
  AtkText *text = (AtkText *) user_data;
47
1
  g_return_val_if_fail (ATK_IS_TEXT (user_data), FALSE);
48
1
  return droute_return_v_int32 (iter, atk_text_get_character_count (text));
49
}
50

            
51
static dbus_bool_t
52
2
impl_get_CaretOffset (DBusMessageIter *iter, void *user_data)
53
{
54
2
  AtkText *text = (AtkText *) user_data;
55
2
  g_return_val_if_fail (ATK_IS_TEXT (user_data), FALSE);
56
2
  return droute_return_v_int32 (iter, atk_text_get_caret_offset (text));
57
}
58

            
59
static gchar *
60
7
validate_allocated_string (gchar *str)
61
{
62
7
  if (!str)
63
    return g_strdup ("");
64
7
  if (!g_utf8_validate (str, -1, NULL))
65
    {
66
      g_warning ("atk-bridge: received bad UTF-8 string from a get_text function");
67
      g_free (str);
68
      return g_strdup ("");
69
    }
70
7
  return str;
71
}
72

            
73
static DBusMessage *
74
2
impl_GetText (DBusConnection *bus, DBusMessage *message, void *user_data)
75
{
76
2
  AtkText *text = (AtkText *) user_data;
77
  dbus_int32_t startOffset, endOffset;
78
  gchar *txt;
79
  DBusMessage *reply;
80

            
81
2
  g_return_val_if_fail (ATK_IS_TEXT (user_data),
82
                        droute_not_yet_handled_error (message));
83
2
  if (!dbus_message_get_args (message, NULL, DBUS_TYPE_INT32, &startOffset, DBUS_TYPE_INT32,
84
                              &endOffset, DBUS_TYPE_INVALID))
85
    {
86
      return droute_invalid_arguments_error (message);
87
    }
88
2
  txt = atk_text_get_text (text, startOffset, endOffset);
89
2
  txt = validate_allocated_string (txt);
90
2
  reply = dbus_message_new_method_return (message);
91
2
  if (reply)
92
    {
93
2
      dbus_message_append_args (reply, DBUS_TYPE_STRING, &txt,
94
                                DBUS_TYPE_INVALID);
95
    }
96
2
  g_free (txt);
97
2
  return reply;
98
}
99

            
100
static DBusMessage *
101
2
impl_SetCaretOffset (DBusConnection *bus, DBusMessage *message, void *user_data)
102
{
103
2
  AtkText *text = (AtkText *) user_data;
104
  dbus_int32_t offset;
105
  dbus_bool_t rv;
106
  DBusMessage *reply;
107

            
108
2
  g_return_val_if_fail (ATK_IS_TEXT (user_data),
109
                        droute_not_yet_handled_error (message));
110
2
  if (!dbus_message_get_args (message, NULL, DBUS_TYPE_INT32, &offset, DBUS_TYPE_INVALID))
111
    {
112
      return droute_invalid_arguments_error (message);
113
    }
114
2
  rv = atk_text_set_caret_offset (text, offset);
115
2
  reply = dbus_message_new_method_return (message);
116
2
  if (reply)
117
    {
118
2
      dbus_message_append_args (reply, DBUS_TYPE_BOOLEAN, &rv,
119
                                DBUS_TYPE_INVALID);
120
    }
121
2
  return reply;
122
}
123

            
124
static DBusMessage *
125
impl_GetTextBeforeOffset (DBusConnection *bus, DBusMessage *message, void *user_data)
126
{
127
  AtkText *text = (AtkText *) user_data;
128
  dbus_int32_t offset;
129
  dbus_uint32_t type;
130
  gchar *txt;
131
  dbus_int32_t startOffset, endOffset;
132
  gint intstart_offset = 0, intend_offset = 0;
133
  DBusMessage *reply;
134

            
135
  g_return_val_if_fail (ATK_IS_TEXT (user_data),
136
                        droute_not_yet_handled_error (message));
137
  if (!dbus_message_get_args (message, NULL, DBUS_TYPE_INT32, &offset, DBUS_TYPE_UINT32, &type,
138
                              DBUS_TYPE_INVALID))
139
    {
140
      return droute_invalid_arguments_error (message);
141
    }
142
  txt =
143
      atk_text_get_text_before_offset (text, offset, (AtkTextBoundary) type,
144
                                       &intstart_offset, &intend_offset);
145
  startOffset = intstart_offset;
146
  endOffset = intend_offset;
147
  txt = validate_allocated_string (txt);
148
  reply = dbus_message_new_method_return (message);
149
  if (reply)
150
    {
151
      dbus_message_append_args (reply, DBUS_TYPE_STRING, &txt,
152
                                DBUS_TYPE_INT32, &startOffset,
153
                                DBUS_TYPE_INT32, &endOffset,
154
                                DBUS_TYPE_INVALID);
155
    }
156
  g_free (txt);
157
  return reply;
158
}
159

            
160
static DBusMessage *
161
impl_GetTextAtOffset (DBusConnection *bus, DBusMessage *message, void *user_data)
162
{
163
  AtkText *text = (AtkText *) user_data;
164
  dbus_int32_t offset, type;
165
  gchar *txt;
166
  dbus_int32_t startOffset, endOffset;
167
  gint intstart_offset = 0, intend_offset = 0;
168
  DBusMessage *reply;
169

            
170
  g_return_val_if_fail (ATK_IS_TEXT (user_data),
171
                        droute_not_yet_handled_error (message));
172
  if (!dbus_message_get_args (message, NULL, DBUS_TYPE_INT32, &offset, DBUS_TYPE_UINT32, &type,
173
                              DBUS_TYPE_INVALID))
174
    {
175
      return droute_invalid_arguments_error (message);
176
    }
177
  txt =
178
      atk_text_get_text_at_offset (text, offset, (AtkTextBoundary) type,
179
                                   &intstart_offset, &intend_offset);
180
  startOffset = intstart_offset;
181
  endOffset = intend_offset;
182
  txt = validate_allocated_string (txt);
183
  reply = dbus_message_new_method_return (message);
184
  if (reply)
185
    {
186
      dbus_message_append_args (reply, DBUS_TYPE_STRING, &txt,
187
                                DBUS_TYPE_INT32, &startOffset,
188
                                DBUS_TYPE_INT32, &endOffset,
189
                                DBUS_TYPE_INVALID);
190
    }
191
  g_free (txt);
192
  return reply;
193
}
194

            
195
static DBusMessage *
196
impl_GetTextAfterOffset (DBusConnection *bus, DBusMessage *message, void *user_data)
197
{
198
  AtkText *text = (AtkText *) user_data;
199
  dbus_int32_t offset;
200
  dbus_uint32_t type;
201
  gchar *txt;
202
  dbus_int32_t startOffset, endOffset;
203
  gint intstart_offset = 0, intend_offset = 0;
204
  DBusMessage *reply;
205

            
206
  g_return_val_if_fail (ATK_IS_TEXT (user_data),
207
                        droute_not_yet_handled_error (message));
208
  if (!dbus_message_get_args (message, NULL, DBUS_TYPE_INT32, &offset, DBUS_TYPE_UINT32, &type,
209
                              DBUS_TYPE_INVALID))
210
    {
211
      return droute_invalid_arguments_error (message);
212
    }
213
  txt =
214
      atk_text_get_text_after_offset (text, offset, (AtkTextBoundary) type,
215
                                      &intstart_offset, &intend_offset);
216
  startOffset = intstart_offset;
217
  endOffset = intend_offset;
218
  txt = validate_allocated_string (txt);
219
  reply = dbus_message_new_method_return (message);
220
  if (reply)
221
    {
222
      dbus_message_append_args (reply, DBUS_TYPE_STRING, &txt,
223
                                DBUS_TYPE_INT32, &startOffset,
224
                                DBUS_TYPE_INT32, &endOffset,
225
                                DBUS_TYPE_INVALID);
226
    }
227
  g_free (txt);
228
  return reply;
229
}
230

            
231
static DBusMessage *
232
1
impl_GetCharacterAtOffset (DBusConnection *bus, DBusMessage *message, void *user_data)
233
{
234
1
  AtkText *text = (AtkText *) user_data;
235
  dbus_int32_t offset;
236
  dbus_int32_t ch;
237
  DBusMessage *reply;
238

            
239
1
  g_return_val_if_fail (ATK_IS_TEXT (user_data),
240
                        droute_not_yet_handled_error (message));
241
1
  if (!dbus_message_get_args (message, NULL, DBUS_TYPE_INT32, &offset, DBUS_TYPE_INVALID))
242
    {
243
      return droute_invalid_arguments_error (message);
244
    }
245
1
  ch = atk_text_get_character_at_offset (text, offset);
246
1
  reply = dbus_message_new_method_return (message);
247
1
  if (reply)
248
    {
249
1
      dbus_message_append_args (reply, DBUS_TYPE_INT32, &ch,
250
                                DBUS_TYPE_INVALID);
251
    }
252
1
  return reply;
253
}
254

            
255
static gchar *
256
get_text_for_legacy_implementations (AtkText *text,
257
                                     gint offset,
258
                                     AtkTextGranularity granularity,
259
                                     gint *start_offset,
260
                                     gint *end_offset)
261
{
262
  gchar *txt = 0;
263
  AtkTextBoundary boundary = 0;
264
  switch (granularity)
265
    {
266
    case ATK_TEXT_GRANULARITY_CHAR:
267
      boundary = ATK_TEXT_BOUNDARY_CHAR;
268
      break;
269

            
270
    case ATK_TEXT_GRANULARITY_WORD:
271
      boundary = ATK_TEXT_BOUNDARY_WORD_START;
272
      break;
273

            
274
    case ATK_TEXT_GRANULARITY_SENTENCE:
275
      boundary = ATK_TEXT_BOUNDARY_SENTENCE_START;
276
      break;
277

            
278
    case ATK_TEXT_GRANULARITY_LINE:
279
      boundary = ATK_TEXT_BOUNDARY_LINE_START;
280
      break;
281

            
282
    case ATK_TEXT_GRANULARITY_PARAGRAPH:
283
      /* This is not implemented in previous versions of ATK */
284
      txt = g_strdup ("");
285
      break;
286

            
287
    default:
288
      g_assert_not_reached ();
289
    }
290

            
291
  if (!txt)
292
    {
293
      txt =
294
          atk_text_get_text_at_offset (text, offset, boundary,
295
                                       start_offset, end_offset);
296
    }
297

            
298
  return txt;
299
}
300

            
301
static DBusMessage *
302
5
impl_GetStringAtOffset (DBusConnection *bus, DBusMessage *message, void *user_data)
303
{
304
5
  AtkText *text = (AtkText *) user_data;
305
  dbus_int32_t offset;
306
  dbus_uint32_t granularity;
307
5
  gchar *txt = 0;
308
  dbus_int32_t startOffset, endOffset;
309
5
  gint intstart_offset = 0, intend_offset = 0;
310
  DBusMessage *reply;
311

            
312
5
  g_return_val_if_fail (ATK_IS_TEXT (user_data),
313
                        droute_not_yet_handled_error (message));
314
5
  if (!dbus_message_get_args (message, NULL, DBUS_TYPE_INT32, &offset, DBUS_TYPE_UINT32, &granularity,
315
                              DBUS_TYPE_INVALID))
316
    {
317
      return droute_invalid_arguments_error (message);
318
    }
319

            
320
5
  txt =
321
5
      atk_text_get_string_at_offset (text, offset, (AtkTextGranularity) granularity,
322
                                     &intstart_offset, &intend_offset);
323

            
324
  /* Accessibility layers implementing an older version of ATK (even if
325
   * a new enough version of libatk is installed) might return NULL due
326
   * not to provide an implementation for get_string_at_offset(), so we
327
   * try with the legacy implementation if that's the case. */
328
5
  if (!txt)
329
    txt = get_text_for_legacy_implementations (text, offset,
330
                                               (AtkTextGranularity) granularity,
331
                                               &intstart_offset, &intend_offset);
332

            
333
5
  startOffset = intstart_offset;
334
5
  endOffset = intend_offset;
335
5
  txt = validate_allocated_string (txt);
336
5
  reply = dbus_message_new_method_return (message);
337
5
  if (reply)
338
    {
339
5
      dbus_message_append_args (reply, DBUS_TYPE_STRING, &txt,
340
                                DBUS_TYPE_INT32, &startOffset,
341
                                DBUS_TYPE_INT32, &endOffset,
342
                                DBUS_TYPE_INVALID);
343
    }
344
5
  g_free (txt);
345
5
  return reply;
346
}
347

            
348
static DBusMessage *
349
2
impl_GetAttributeValue (DBusConnection *bus, DBusMessage *message, void *user_data)
350
{
351
2
  AtkText *text = (AtkText *) user_data;
352
  dbus_int32_t offset;
353
  char *attributeName;
354
2
  gint intstart_offset = 0, intend_offset = 0;
355
2
  char *rv = NULL;
356
  DBusMessage *reply;
357
  AtkAttributeSet *set;
358
  GSList *cur_attr;
359
  AtkAttribute *at;
360

            
361
2
  g_return_val_if_fail (ATK_IS_TEXT (user_data),
362
                        droute_not_yet_handled_error (message));
363
2
  if (!dbus_message_get_args (message, NULL, DBUS_TYPE_INT32, &offset, DBUS_TYPE_STRING,
364
                              &attributeName, DBUS_TYPE_INVALID))
365
    {
366
      return droute_invalid_arguments_error (message);
367
    }
368

            
369
2
  set = atk_text_get_run_attributes (text, offset,
370
                                     &intstart_offset, &intend_offset);
371
2
  cur_attr = (GSList *) set;
372
3
  while (cur_attr)
373
    {
374
3
      at = (AtkAttribute *) cur_attr->data;
375
3
      if (!strcmp (at->name, attributeName))
376
        {
377
2
          rv = at->value;
378
2
          break;
379
        }
380
1
      cur_attr = cur_attr->next;
381
    }
382
2
  if (!rv)
383
    rv = "";
384
2
  reply = dbus_message_new_method_return (message);
385
2
  if (reply)
386
    {
387
2
      dbus_message_append_args (reply, DBUS_TYPE_STRING, &rv, DBUS_TYPE_INVALID);
388
    }
389
2
  atk_attribute_set_free (set);
390
2
  return reply;
391
}
392

            
393
static DBusMessage *
394
1
impl_GetAttributes (DBusConnection *bus, DBusMessage *message, void *user_data)
395
{
396
1
  AtkText *text = (AtkText *) user_data;
397
  dbus_int32_t offset;
398
  dbus_int32_t startOffset, endOffset;
399
  gint intstart_offset, intend_offset;
400
  DBusMessage *reply;
401
  AtkAttributeSet *set;
402
  DBusMessageIter iter;
403

            
404
1
  g_return_val_if_fail (ATK_IS_TEXT (user_data),
405
                        droute_not_yet_handled_error (message));
406
1
  if (!dbus_message_get_args (message, NULL, DBUS_TYPE_INT32, &offset, DBUS_TYPE_INVALID))
407
    {
408
      return droute_invalid_arguments_error (message);
409
    }
410

            
411
1
  set = atk_text_get_run_attributes (text, offset,
412
                                     &intstart_offset, &intend_offset);
413

            
414
1
  startOffset = intstart_offset;
415
1
  endOffset = intend_offset;
416
1
  reply = dbus_message_new_method_return (message);
417
1
  if (reply)
418
    {
419
1
      dbus_message_iter_init_append (reply, &iter);
420
1
      spi_object_append_attribute_set (&iter, set);
421
1
      dbus_message_append_args (reply, DBUS_TYPE_INT32, &startOffset,
422
                                DBUS_TYPE_INT32, &endOffset,
423
                                DBUS_TYPE_INVALID);
424
    }
425
1
  atk_attribute_set_free (set);
426
1
  return reply;
427
}
428

            
429
static DBusMessage *
430
1
impl_GetDefaultAttributes (DBusConnection *bus, DBusMessage *message, void *user_data)
431
{
432
1
  AtkText *text = (AtkText *) user_data;
433
  DBusMessage *reply;
434
  AtkAttributeSet *set;
435
  DBusMessageIter iter;
436

            
437
1
  g_return_val_if_fail (ATK_IS_TEXT (user_data),
438
                        droute_not_yet_handled_error (message));
439

            
440
1
  set = atk_text_get_default_attributes (text);
441
1
  reply = dbus_message_new_method_return (message);
442
1
  if (reply)
443
    {
444
1
      dbus_message_iter_init_append (reply, &iter);
445
1
      spi_object_append_attribute_set (&iter, set);
446
    }
447
1
  atk_attribute_set_free (set);
448
1
  return reply;
449
}
450

            
451
static DBusMessage *
452
1
impl_GetCharacterExtents (DBusConnection *bus, DBusMessage *message, void *user_data)
453
{
454
1
  AtkText *text = (AtkText *) user_data;
455
  dbus_int32_t offset;
456
  dbus_uint32_t coordType;
457
  dbus_int32_t x, y, width, height;
458
1
  gint ix = 0, iy = 0, iw = 0, ih = 0;
459
  DBusMessage *reply;
460

            
461
1
  g_return_val_if_fail (ATK_IS_TEXT (user_data),
462
                        droute_not_yet_handled_error (message));
463
1
  if (!dbus_message_get_args (message, NULL, DBUS_TYPE_INT32, &offset, DBUS_TYPE_UINT32,
464
                              &coordType, DBUS_TYPE_INVALID))
465
    {
466
      return droute_invalid_arguments_error (message);
467
    }
468
1
  atk_text_get_character_extents (text, offset, &ix, &iy, &iw, &ih,
469
                                  (AtkCoordType) coordType);
470
1
  x = ix;
471
1
  y = iy;
472
1
  width = iw;
473
1
  height = ih;
474
1
  reply = dbus_message_new_method_return (message);
475
1
  if (reply)
476
    {
477
1
      dbus_message_append_args (reply, DBUS_TYPE_INT32, &x, DBUS_TYPE_INT32,
478
                                &y, DBUS_TYPE_INT32, &width, DBUS_TYPE_INT32,
479
                                &height, DBUS_TYPE_INVALID);
480
    }
481
1
  return reply;
482
}
483

            
484
static DBusMessage *
485
1
impl_GetOffsetAtPoint (DBusConnection *bus, DBusMessage *message, void *user_data)
486
{
487
1
  AtkText *text = (AtkText *) user_data;
488
  dbus_int32_t x, y;
489
  dbus_uint32_t coordType;
490
  dbus_int32_t rv;
491
  DBusMessage *reply;
492

            
493
1
  g_return_val_if_fail (ATK_IS_TEXT (user_data),
494
                        droute_not_yet_handled_error (message));
495
1
  if (!dbus_message_get_args (message, NULL, DBUS_TYPE_INT32, &x, DBUS_TYPE_INT32, &y,
496
                              DBUS_TYPE_UINT32, &coordType, DBUS_TYPE_INVALID))
497
    {
498
      return droute_invalid_arguments_error (message);
499
    }
500
1
  rv = atk_text_get_offset_at_point (text, x, y, coordType);
501
1
  reply = dbus_message_new_method_return (message);
502
1
  if (reply)
503
    {
504
1
      dbus_message_append_args (reply, DBUS_TYPE_INT32, &rv,
505
                                DBUS_TYPE_INVALID);
506
    }
507
1
  return reply;
508
}
509

            
510
static DBusMessage *
511
6
impl_GetNSelections (DBusConnection *bus, DBusMessage *message, void *user_data)
512
{
513
6
  AtkText *text = (AtkText *) user_data;
514
  dbus_int32_t rv;
515
  DBusMessage *reply;
516

            
517
6
  g_return_val_if_fail (ATK_IS_TEXT (user_data),
518
                        droute_not_yet_handled_error (message));
519
6
  rv = atk_text_get_n_selections (text);
520
6
  reply = dbus_message_new_method_return (message);
521
6
  if (reply)
522
    {
523
6
      dbus_message_append_args (reply, DBUS_TYPE_INT32, &rv,
524
                                DBUS_TYPE_INVALID);
525
    }
526
6
  return reply;
527
}
528

            
529
static DBusMessage *
530
4
impl_GetSelection (DBusConnection *bus, DBusMessage *message, void *user_data)
531
{
532
4
  AtkText *text = (AtkText *) user_data;
533
  dbus_int32_t selectionNum;
534
  dbus_int32_t startOffset, endOffset;
535
4
  gint intstart_offset = 0, intend_offset = 0;
536
  DBusMessage *reply;
537

            
538
4
  g_return_val_if_fail (ATK_IS_TEXT (user_data),
539
                        droute_not_yet_handled_error (message));
540
4
  if (!dbus_message_get_args (message, NULL, DBUS_TYPE_INT32, &selectionNum, DBUS_TYPE_INVALID))
541
    {
542
      return droute_invalid_arguments_error (message);
543
    }
544
  /* atk_text_get_selection returns gchar * which we discard */
545
4
  g_free (atk_text_get_selection (text, selectionNum, &intstart_offset, &intend_offset));
546
4
  startOffset = intstart_offset;
547
4
  endOffset = intend_offset;
548
4
  reply = dbus_message_new_method_return (message);
549
4
  if (reply)
550
    {
551
4
      dbus_message_append_args (reply, DBUS_TYPE_INT32, &startOffset,
552
                                DBUS_TYPE_INT32, &endOffset,
553
                                DBUS_TYPE_INVALID);
554
    }
555
4
  return reply;
556
}
557

            
558
static DBusMessage *
559
10
impl_AddSelection (DBusConnection *bus, DBusMessage *message, void *user_data)
560
{
561
10
  AtkText *text = (AtkText *) user_data;
562
  dbus_int32_t startOffset, endOffset;
563
  dbus_bool_t rv;
564
  DBusMessage *reply;
565

            
566
10
  g_return_val_if_fail (ATK_IS_TEXT (user_data),
567
                        droute_not_yet_handled_error (message));
568
10
  if (!dbus_message_get_args (message, NULL, DBUS_TYPE_INT32, &startOffset, DBUS_TYPE_INT32,
569
                              &endOffset, DBUS_TYPE_INVALID))
570
    {
571
      return droute_invalid_arguments_error (message);
572
    }
573
10
  rv = atk_text_add_selection (text, startOffset, endOffset);
574
10
  reply = dbus_message_new_method_return (message);
575
10
  if (reply)
576
    {
577
10
      dbus_message_append_args (reply, DBUS_TYPE_BOOLEAN, &rv,
578
                                DBUS_TYPE_INVALID);
579
    }
580
10
  return reply;
581
}
582

            
583
static DBusMessage *
584
2
impl_RemoveSelection (DBusConnection *bus, DBusMessage *message, void *user_data)
585
{
586
2
  AtkText *text = (AtkText *) user_data;
587
  dbus_int32_t selectionNum;
588
  dbus_bool_t rv;
589
  DBusMessage *reply;
590

            
591
2
  g_return_val_if_fail (ATK_IS_TEXT (user_data),
592
                        droute_not_yet_handled_error (message));
593
2
  if (!dbus_message_get_args (message, NULL, DBUS_TYPE_INT32, &selectionNum, DBUS_TYPE_INVALID))
594
    {
595
      return droute_invalid_arguments_error (message);
596
    }
597
2
  rv = atk_text_remove_selection (text, selectionNum);
598
2
  reply = dbus_message_new_method_return (message);
599
2
  if (reply)
600
    {
601
2
      dbus_message_append_args (reply, DBUS_TYPE_BOOLEAN, &rv,
602
                                DBUS_TYPE_INVALID);
603
    }
604
2
  return reply;
605
}
606

            
607
static DBusMessage *
608
2
impl_SetSelection (DBusConnection *bus, DBusMessage *message, void *user_data)
609
{
610
2
  AtkText *text = (AtkText *) user_data;
611
  dbus_int32_t selectionNum, startOffset, endOffset;
612
  dbus_bool_t rv;
613
  DBusMessage *reply;
614

            
615
2
  g_return_val_if_fail (ATK_IS_TEXT (user_data),
616
                        droute_not_yet_handled_error (message));
617
2
  if (!dbus_message_get_args (message, NULL, DBUS_TYPE_INT32, &selectionNum, DBUS_TYPE_INT32,
618
                              &startOffset, DBUS_TYPE_INT32, &endOffset, DBUS_TYPE_INVALID))
619
    {
620
      return droute_invalid_arguments_error (message);
621
    }
622
2
  rv = atk_text_set_selection (text, selectionNum, startOffset, endOffset);
623
2
  reply = dbus_message_new_method_return (message);
624
2
  if (reply)
625
    {
626
2
      dbus_message_append_args (reply, DBUS_TYPE_BOOLEAN, &rv,
627
                                DBUS_TYPE_INVALID);
628
    }
629
2
  return reply;
630
}
631

            
632
static DBusMessage *
633
1
impl_GetRangeExtents (DBusConnection *bus, DBusMessage *message, void *user_data)
634
{
635
1
  AtkText *text = (AtkText *) user_data;
636
  dbus_int32_t startOffset, endOffset;
637
  dbus_uint32_t coordType;
638
  AtkTextRectangle rect;
639
  dbus_int32_t x, y, width, height;
640
  DBusMessage *reply;
641

            
642
1
  g_return_val_if_fail (ATK_IS_TEXT (user_data),
643
                        droute_not_yet_handled_error (message));
644
1
  if (!dbus_message_get_args (message, NULL, DBUS_TYPE_INT32, &startOffset, DBUS_TYPE_INT32,
645
                              &endOffset, DBUS_TYPE_UINT32, &coordType, DBUS_TYPE_INVALID))
646
    {
647
      return droute_invalid_arguments_error (message);
648
    }
649
1
  memset (&rect, 0, sizeof (rect));
650
1
  atk_text_get_range_extents (text, startOffset, endOffset,
651
                              (AtkCoordType) coordType, &rect);
652
1
  x = rect.x;
653
1
  y = rect.y;
654
1
  width = rect.width;
655
1
  height = rect.height;
656
1
  reply = dbus_message_new_method_return (message);
657
1
  if (reply)
658
    {
659
1
      dbus_message_append_args (reply, DBUS_TYPE_INT32, &x, DBUS_TYPE_INT32,
660
                                &y, DBUS_TYPE_INT32, &width, DBUS_TYPE_INT32,
661
                                &height, DBUS_TYPE_INVALID);
662
    }
663
1
  return reply;
664
}
665

            
666
#define MAXRANGELEN 512
667

            
668
static DBusMessage *
669
1
impl_GetBoundedRanges (DBusConnection *bus, DBusMessage *message, void *user_data)
670
{
671
1
  AtkText *text = (AtkText *) user_data;
672
  dbus_int32_t x, y, width, height;
673
  dbus_uint32_t coordType, xClipType, yClipType;
674
1
  AtkTextRange **range_list = NULL;
675
  AtkTextRectangle rect;
676
  DBusMessage *reply;
677
  DBusMessageIter iter, array, struc, variant;
678

            
679
1
  g_return_val_if_fail (ATK_IS_TEXT (user_data),
680
                        droute_not_yet_handled_error (message));
681
1
  if (!dbus_message_get_args (message, NULL, DBUS_TYPE_INT32, &x, DBUS_TYPE_INT32, &y,
682
                              DBUS_TYPE_INT32, &height, DBUS_TYPE_INT32, &width, DBUS_TYPE_UINT32,
683
                              &coordType, DBUS_TYPE_UINT32, &xClipType, DBUS_TYPE_UINT32, &yClipType,
684
                              DBUS_TYPE_INVALID))
685
    {
686
      return droute_invalid_arguments_error (message);
687
    }
688
1
  rect.x = x;
689
1
  rect.y = y;
690
1
  rect.width = width;
691
1
  rect.height = height;
692

            
693
  range_list =
694
1
      atk_text_get_bounded_ranges (text, &rect, (AtkCoordType) coordType,
695
                                   (AtkTextClipType) xClipType,
696
                                   (AtkTextClipType) yClipType);
697
1
  reply = dbus_message_new_method_return (message);
698
1
  if (!reply)
699
    return NULL;
700
  /* This isn't pleasant. */
701
1
  dbus_message_iter_init_append (reply, &iter);
702
1
  if (dbus_message_iter_open_container (&iter, DBUS_TYPE_ARRAY, "(iisv)", &array))
703
    {
704
      int len;
705
1
      int count = (range_list ? MAXRANGELEN : 0);
706
3
      for (len = 0; len < count && range_list[len]; ++len)
707
        {
708
2
          if (dbus_message_iter_open_container (&array, DBUS_TYPE_STRUCT, NULL, &struc))
709
            {
710
              dbus_int32_t val;
711
2
              val = range_list[len]->start_offset;
712
2
              dbus_message_iter_append_basic (&struc, DBUS_TYPE_INT32, &val);
713
2
              val = range_list[len]->end_offset;
714
2
              dbus_message_iter_append_basic (&struc, DBUS_TYPE_INT32, &val);
715
2
              dbus_message_iter_append_basic (&struc, DBUS_TYPE_STRING,
716
2
                                              &range_list[len]->content);
717
              /* The variant is unimplemented in atk, but I don't want to
718
               * unilaterally muck with the spec and remove it, so I'll just
719
               * throw in a dummy value */
720
2
              if (dbus_message_iter_open_container (&struc, DBUS_TYPE_VARIANT, "i", &variant))
721
                {
722
2
                  dbus_uint32_t dummy = 0;
723
2
                  dbus_message_iter_append_basic (&variant, DBUS_TYPE_INT32,
724
                                                  &dummy);
725
2
                  dbus_message_iter_close_container (&struc, &variant);
726
                }
727
2
              dbus_message_iter_close_container (&array, &struc);
728
2
              g_free (range_list[len]->content);
729
2
              g_free (range_list[len]);
730
            }
731
        }
732
1
      dbus_message_iter_close_container (&iter, &array);
733
    }
734

            
735
1
  if (range_list)
736
1
    g_free (range_list);
737

            
738
1
  return reply;
739
}
740

            
741
static DBusMessage *
742
1
impl_GetAttributeRun (DBusConnection *bus, DBusMessage *message, void *user_data)
743
{
744
1
  AtkText *text = (AtkText *) user_data;
745
  dbus_int32_t offset;
746
  dbus_bool_t includeDefaults;
747
  dbus_int32_t startOffset, endOffset;
748
1
  gint intstart_offset = 0, intend_offset = 0;
749
  DBusMessage *reply;
750
1
  AtkAttributeSet *attributes = NULL;
751
  DBusMessageIter iter;
752

            
753
1
  g_return_val_if_fail (ATK_IS_TEXT (user_data),
754
                        droute_not_yet_handled_error (message));
755
1
  if (!dbus_message_get_args (message, NULL, DBUS_TYPE_INT32, &offset, DBUS_TYPE_BOOLEAN,
756
                              &includeDefaults, DBUS_TYPE_INVALID))
757
    {
758
      return droute_invalid_arguments_error (message);
759
    }
760

            
761
1
  if (includeDefaults)
762
    {
763
      attributes = g_slist_concat (attributes,
764
                                   atk_text_get_default_attributes (text));
765
    }
766

            
767
1
  attributes = g_slist_concat (attributes,
768
1
                               atk_text_get_run_attributes (text, offset,
769
                                                            &intstart_offset,
770
                                                            &intend_offset));
771

            
772
1
  reply = dbus_message_new_method_return (message);
773
1
  if (!reply)
774
    return NULL;
775

            
776
1
  dbus_message_iter_init_append (reply, &iter);
777
1
  spi_object_append_attribute_set (&iter, attributes);
778

            
779
1
  startOffset = intstart_offset;
780
1
  endOffset = intend_offset;
781
1
  dbus_message_iter_append_basic (&iter, DBUS_TYPE_INT32, &startOffset);
782
1
  dbus_message_iter_append_basic (&iter, DBUS_TYPE_INT32, &endOffset);
783

            
784
1
  atk_attribute_set_free (attributes);
785

            
786
1
  return reply;
787
}
788

            
789
static DBusMessage *
790
impl_GetDefaultAttributeSet (DBusConnection *bus, DBusMessage *message, void *user_data)
791
{
792
  AtkText *text = (AtkText *) user_data;
793
  DBusMessage *reply;
794
  DBusMessageIter iter;
795
  AtkAttributeSet *attributes;
796

            
797
  g_return_val_if_fail (ATK_IS_TEXT (user_data),
798
                        droute_not_yet_handled_error (message));
799

            
800
  attributes = atk_text_get_default_attributes (text);
801

            
802
  reply = dbus_message_new_method_return (message);
803
  if (reply)
804
    {
805
      dbus_message_iter_init_append (reply, &iter);
806
      spi_object_append_attribute_set (&iter, attributes);
807
    }
808

            
809
  if (attributes)
810
    atk_attribute_set_free (attributes);
811

            
812
  return reply;
813
}
814

            
815
static DBusMessage *
816
impl_ScrollSubstringTo (DBusConnection *bus,
817
                        DBusMessage *message,
818
                        void *user_data)
819
{
820
  AtkText *text = (AtkText *) user_data;
821
  dbus_int32_t startOffset, endOffset;
822
  dbus_uint32_t type;
823
  dbus_bool_t ret;
824
  DBusMessage *reply = NULL;
825

            
826
  g_return_val_if_fail (ATK_IS_TEXT (user_data),
827
                        droute_not_yet_handled_error (message));
828

            
829
  if (!dbus_message_get_args (message, NULL, DBUS_TYPE_INT32, &startOffset,
830
                              DBUS_TYPE_INT32, &endOffset,
831
                              DBUS_TYPE_UINT32, &type,
832
                              DBUS_TYPE_INVALID))
833
    {
834
      return droute_invalid_arguments_error (message);
835
    }
836

            
837
  ret = atk_text_scroll_substring_to (text, startOffset, endOffset, type);
838

            
839
  reply = dbus_message_new_method_return (message);
840
  if (reply)
841
    {
842
      dbus_message_append_args (reply, DBUS_TYPE_BOOLEAN, &ret,
843
                                DBUS_TYPE_INVALID);
844
    }
845
  return reply;
846
}
847

            
848
static DBusMessage *
849
impl_ScrollSubstringToPoint (DBusConnection *bus,
850
                             DBusMessage *message,
851
                             void *user_data)
852
{
853
  AtkText *text = (AtkText *) user_data;
854
  dbus_int32_t startOffset, endOffset;
855
  dbus_uint32_t type;
856
  dbus_int32_t x, y;
857
  dbus_bool_t ret;
858
  DBusMessage *reply = NULL;
859

            
860
  g_return_val_if_fail (ATK_IS_TEXT (user_data),
861
                        droute_not_yet_handled_error (message));
862

            
863
  if (!dbus_message_get_args (message, NULL, DBUS_TYPE_INT32, &startOffset,
864
                              DBUS_TYPE_INT32, &endOffset,
865
                              DBUS_TYPE_UINT32, &type,
866
                              DBUS_TYPE_INT32, &x,
867
                              DBUS_TYPE_INT32, &y,
868
                              DBUS_TYPE_INVALID))
869
    {
870
      return droute_invalid_arguments_error (message);
871
    }
872

            
873
  ret = atk_text_scroll_substring_to_point (text, startOffset, endOffset, type, x, y);
874

            
875
  reply = dbus_message_new_method_return (message);
876
  if (reply)
877
    {
878
      dbus_message_append_args (reply, DBUS_TYPE_BOOLEAN, &ret,
879
                                DBUS_TYPE_INVALID);
880
    }
881
  return reply;
882
}
883

            
884
static DRouteMethod methods[] = {
885
  { impl_GetText, "GetText" },
886
  { impl_SetCaretOffset, "SetCaretOffset" },
887
  { impl_GetTextBeforeOffset, "GetTextBeforeOffset" },
888
  { impl_GetTextAtOffset, "GetTextAtOffset" },
889
  { impl_GetTextAfterOffset, "GetTextAfterOffset" },
890
  { impl_GetStringAtOffset, "GetStringAtOffset" },
891
  { impl_GetCharacterAtOffset, "GetCharacterAtOffset" },
892
  { impl_GetAttributeValue, "GetAttributeValue" },
893
  { impl_GetAttributes, "GetAttributes" },
894
  { impl_GetDefaultAttributes, "GetDefaultAttributes" },
895
  { impl_GetCharacterExtents, "GetCharacterExtents" },
896
  { impl_GetOffsetAtPoint, "GetOffsetAtPoint" },
897
  { impl_GetNSelections, "GetNSelections" },
898
  { impl_GetSelection, "GetSelection" },
899
  { impl_AddSelection, "AddSelection" },
900
  { impl_RemoveSelection, "RemoveSelection" },
901
  { impl_SetSelection, "SetSelection" },
902
  { impl_GetRangeExtents, "GetRangeExtents" },
903
  { impl_GetBoundedRanges, "GetBoundedRanges" },
904
  { impl_GetAttributeRun, "GetAttributeRun" },
905
  { impl_GetDefaultAttributeSet, "GetDefaultAttributeSet" },
906
  { impl_ScrollSubstringTo, "ScrollSubstringTo" },
907
  { impl_ScrollSubstringToPoint, "ScrollSubstringToPoint" },
908
  { NULL, NULL }
909
};
910

            
911
static DRouteProperty properties[] = {
912
  { impl_get_CharacterCount, NULL, "CharacterCount" },
913
  { impl_get_CaretOffset, NULL, "CaretOffset" },
914
  { impl_get_Version, NULL, "version" },
915
  { NULL, NULL, NULL }
916
};
917

            
918
void
919
161
spi_initialize_text (DRoutePath *path)
920
{
921
161
  spi_atk_add_interface (path,
922
                         ATSPI_DBUS_INTERFACE_TEXT,
923
                         spi_org_a11y_atspi_Text,
924
                         methods, properties);
925
161
};