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
1
impl_get_CharacterCount (DBusMessageIter *iter, void *user_data)
39
{
40
1
  AtkText *text = (AtkText *) user_data;
41
1
  g_return_val_if_fail (ATK_IS_TEXT (user_data), FALSE);
42
1
  return droute_return_v_int32 (iter, atk_text_get_character_count (text));
43
}
44

            
45
static dbus_bool_t
46
2
impl_get_CaretOffset (DBusMessageIter *iter, void *user_data)
47
{
48
2
  AtkText *text = (AtkText *) user_data;
49
2
  g_return_val_if_fail (ATK_IS_TEXT (user_data), FALSE);
50
2
  return droute_return_v_int32 (iter, atk_text_get_caret_offset (text));
51
}
52

            
53
static gchar *
54
7
validate_allocated_string (gchar *str)
55
{
56
7
  if (!str)
57
    return g_strdup ("");
58
7
  if (!g_utf8_validate (str, -1, NULL))
59
    {
60
      g_warning ("atk-bridge: received bad UTF-8 string from a get_text function");
61
      g_free (str);
62
      return g_strdup ("");
63
    }
64
7
  return str;
65
}
66

            
67
static DBusMessage *
68
2
impl_GetText (DBusConnection *bus, DBusMessage *message, void *user_data)
69
{
70
2
  AtkText *text = (AtkText *) user_data;
71
  dbus_int32_t startOffset, endOffset;
72
  gchar *txt;
73
  DBusMessage *reply;
74

            
75
2
  g_return_val_if_fail (ATK_IS_TEXT (user_data),
76
                        droute_not_yet_handled_error (message));
77
2
  if (!dbus_message_get_args (message, NULL, DBUS_TYPE_INT32, &startOffset, DBUS_TYPE_INT32,
78
                              &endOffset, DBUS_TYPE_INVALID))
79
    {
80
      return droute_invalid_arguments_error (message);
81
    }
82
2
  txt = atk_text_get_text (text, startOffset, endOffset);
83
2
  txt = validate_allocated_string (txt);
84
2
  reply = dbus_message_new_method_return (message);
85
2
  if (reply)
86
    {
87
2
      dbus_message_append_args (reply, DBUS_TYPE_STRING, &txt,
88
                                DBUS_TYPE_INVALID);
89
    }
90
2
  g_free (txt);
91
2
  return reply;
92
}
93

            
94
static DBusMessage *
95
2
impl_SetCaretOffset (DBusConnection *bus, DBusMessage *message, void *user_data)
96
{
97
2
  AtkText *text = (AtkText *) user_data;
98
  dbus_int32_t offset;
99
  dbus_bool_t rv;
100
  DBusMessage *reply;
101

            
102
2
  g_return_val_if_fail (ATK_IS_TEXT (user_data),
103
                        droute_not_yet_handled_error (message));
104
2
  if (!dbus_message_get_args (message, NULL, DBUS_TYPE_INT32, &offset, DBUS_TYPE_INVALID))
105
    {
106
      return droute_invalid_arguments_error (message);
107
    }
108
2
  rv = atk_text_set_caret_offset (text, offset);
109
2
  reply = dbus_message_new_method_return (message);
110
2
  if (reply)
111
    {
112
2
      dbus_message_append_args (reply, DBUS_TYPE_BOOLEAN, &rv,
113
                                DBUS_TYPE_INVALID);
114
    }
115
2
  return reply;
116
}
117

            
118
static DBusMessage *
119
impl_GetTextBeforeOffset (DBusConnection *bus, DBusMessage *message, void *user_data)
120
{
121
  AtkText *text = (AtkText *) user_data;
122
  dbus_int32_t offset;
123
  dbus_uint32_t type;
124
  gchar *txt;
125
  dbus_int32_t startOffset, endOffset;
126
  gint intstart_offset = 0, intend_offset = 0;
127
  DBusMessage *reply;
128

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

            
154
static DBusMessage *
155
impl_GetTextAtOffset (DBusConnection *bus, DBusMessage *message, void *user_data)
156
{
157
  AtkText *text = (AtkText *) user_data;
158
  dbus_int32_t offset, type;
159
  gchar *txt;
160
  dbus_int32_t startOffset, endOffset;
161
  gint intstart_offset = 0, intend_offset = 0;
162
  DBusMessage *reply;
163

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

            
189
static DBusMessage *
190
impl_GetTextAfterOffset (DBusConnection *bus, DBusMessage *message, void *user_data)
191
{
192
  AtkText *text = (AtkText *) user_data;
193
  dbus_int32_t offset;
194
  dbus_uint32_t type;
195
  gchar *txt;
196
  dbus_int32_t startOffset, endOffset;
197
  gint intstart_offset = 0, intend_offset = 0;
198
  DBusMessage *reply;
199

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

            
225
static DBusMessage *
226
1
impl_GetCharacterAtOffset (DBusConnection *bus, DBusMessage *message, void *user_data)
227
{
228
1
  AtkText *text = (AtkText *) user_data;
229
  dbus_int32_t offset;
230
  dbus_int32_t ch;
231
  DBusMessage *reply;
232

            
233
1
  g_return_val_if_fail (ATK_IS_TEXT (user_data),
234
                        droute_not_yet_handled_error (message));
235
1
  if (!dbus_message_get_args (message, NULL, DBUS_TYPE_INT32, &offset, DBUS_TYPE_INVALID))
236
    {
237
      return droute_invalid_arguments_error (message);
238
    }
239
1
  ch = atk_text_get_character_at_offset (text, offset);
240
1
  reply = dbus_message_new_method_return (message);
241
1
  if (reply)
242
    {
243
1
      dbus_message_append_args (reply, DBUS_TYPE_INT32, &ch,
244
                                DBUS_TYPE_INVALID);
245
    }
246
1
  return reply;
247
}
248

            
249
static gchar *
250
get_text_for_legacy_implementations (AtkText *text,
251
                                     gint offset,
252
                                     AtkTextGranularity granularity,
253
                                     gint *start_offset,
254
                                     gint *end_offset)
255
{
256
  gchar *txt = 0;
257
  AtkTextBoundary boundary = 0;
258
  switch (granularity)
259
    {
260
    case ATK_TEXT_GRANULARITY_CHAR:
261
      boundary = ATK_TEXT_BOUNDARY_CHAR;
262
      break;
263

            
264
    case ATK_TEXT_GRANULARITY_WORD:
265
      boundary = ATK_TEXT_BOUNDARY_WORD_START;
266
      break;
267

            
268
    case ATK_TEXT_GRANULARITY_SENTENCE:
269
      boundary = ATK_TEXT_BOUNDARY_SENTENCE_START;
270
      break;
271

            
272
    case ATK_TEXT_GRANULARITY_LINE:
273
      boundary = ATK_TEXT_BOUNDARY_LINE_START;
274
      break;
275

            
276
    case ATK_TEXT_GRANULARITY_PARAGRAPH:
277
      /* This is not implemented in previous versions of ATK */
278
      txt = g_strdup ("");
279
      break;
280

            
281
    default:
282
      g_assert_not_reached ();
283
    }
284

            
285
  if (!txt)
286
    {
287
      txt =
288
          atk_text_get_text_at_offset (text, offset, boundary,
289
                                       start_offset, end_offset);
290
    }
291

            
292
  return txt;
293
}
294

            
295
static DBusMessage *
296
5
impl_GetStringAtOffset (DBusConnection *bus, DBusMessage *message, void *user_data)
297
{
298
5
  AtkText *text = (AtkText *) user_data;
299
  dbus_int32_t offset;
300
  dbus_uint32_t granularity;
301
5
  gchar *txt = 0;
302
  dbus_int32_t startOffset, endOffset;
303
5
  gint intstart_offset = 0, intend_offset = 0;
304
  DBusMessage *reply;
305

            
306
5
  g_return_val_if_fail (ATK_IS_TEXT (user_data),
307
                        droute_not_yet_handled_error (message));
308
5
  if (!dbus_message_get_args (message, NULL, DBUS_TYPE_INT32, &offset, DBUS_TYPE_UINT32, &granularity,
309
                              DBUS_TYPE_INVALID))
310
    {
311
      return droute_invalid_arguments_error (message);
312
    }
313

            
314
5
  txt =
315
5
      atk_text_get_string_at_offset (text, offset, (AtkTextGranularity) granularity,
316
                                     &intstart_offset, &intend_offset);
317

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

            
327
5
  startOffset = intstart_offset;
328
5
  endOffset = intend_offset;
329
5
  txt = validate_allocated_string (txt);
330
5
  reply = dbus_message_new_method_return (message);
331
5
  if (reply)
332
    {
333
5
      dbus_message_append_args (reply, DBUS_TYPE_STRING, &txt,
334
                                DBUS_TYPE_INT32, &startOffset,
335
                                DBUS_TYPE_INT32, &endOffset,
336
                                DBUS_TYPE_INVALID);
337
    }
338
5
  g_free (txt);
339
5
  return reply;
340
}
341

            
342
static DBusMessage *
343
2
impl_GetAttributeValue (DBusConnection *bus, DBusMessage *message, void *user_data)
344
{
345
2
  AtkText *text = (AtkText *) user_data;
346
  dbus_int32_t offset;
347
  char *attributeName;
348
2
  gint intstart_offset = 0, intend_offset = 0;
349
2
  char *rv = NULL;
350
  DBusMessage *reply;
351
  AtkAttributeSet *set;
352
  GSList *cur_attr;
353
  AtkAttribute *at;
354

            
355
2
  g_return_val_if_fail (ATK_IS_TEXT (user_data),
356
                        droute_not_yet_handled_error (message));
357
2
  if (!dbus_message_get_args (message, NULL, DBUS_TYPE_INT32, &offset, DBUS_TYPE_STRING,
358
                              &attributeName, DBUS_TYPE_INVALID))
359
    {
360
      return droute_invalid_arguments_error (message);
361
    }
362

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

            
387
static DBusMessage *
388
1
impl_GetAttributes (DBusConnection *bus, DBusMessage *message, void *user_data)
389
{
390
1
  AtkText *text = (AtkText *) user_data;
391
  dbus_int32_t offset;
392
  dbus_int32_t startOffset, endOffset;
393
  gint intstart_offset, intend_offset;
394
  DBusMessage *reply;
395
  AtkAttributeSet *set;
396
  DBusMessageIter iter;
397

            
398
1
  g_return_val_if_fail (ATK_IS_TEXT (user_data),
399
                        droute_not_yet_handled_error (message));
400
1
  if (!dbus_message_get_args (message, NULL, DBUS_TYPE_INT32, &offset, DBUS_TYPE_INVALID))
401
    {
402
      return droute_invalid_arguments_error (message);
403
    }
404

            
405
1
  set = atk_text_get_run_attributes (text, offset,
406
                                     &intstart_offset, &intend_offset);
407

            
408
1
  startOffset = intstart_offset;
409
1
  endOffset = intend_offset;
410
1
  reply = dbus_message_new_method_return (message);
411
1
  if (reply)
412
    {
413
1
      dbus_message_iter_init_append (reply, &iter);
414
1
      spi_object_append_attribute_set (&iter, set);
415
1
      dbus_message_append_args (reply, DBUS_TYPE_INT32, &startOffset,
416
                                DBUS_TYPE_INT32, &endOffset,
417
                                DBUS_TYPE_INVALID);
418
    }
419
1
  atk_attribute_set_free (set);
420
1
  return reply;
421
}
422

            
423
static DBusMessage *
424
1
impl_GetDefaultAttributes (DBusConnection *bus, DBusMessage *message, void *user_data)
425
{
426
1
  AtkText *text = (AtkText *) user_data;
427
  DBusMessage *reply;
428
  AtkAttributeSet *set;
429
  DBusMessageIter iter;
430

            
431
1
  g_return_val_if_fail (ATK_IS_TEXT (user_data),
432
                        droute_not_yet_handled_error (message));
433

            
434
1
  set = atk_text_get_default_attributes (text);
435
1
  reply = dbus_message_new_method_return (message);
436
1
  if (reply)
437
    {
438
1
      dbus_message_iter_init_append (reply, &iter);
439
1
      spi_object_append_attribute_set (&iter, set);
440
    }
441
1
  atk_attribute_set_free (set);
442
1
  return reply;
443
}
444

            
445
static DBusMessage *
446
1
impl_GetCharacterExtents (DBusConnection *bus, DBusMessage *message, void *user_data)
447
{
448
1
  AtkText *text = (AtkText *) user_data;
449
  dbus_int32_t offset;
450
  dbus_uint32_t coordType;
451
  dbus_int32_t x, y, width, height;
452
1
  gint ix = 0, iy = 0, iw = 0, ih = 0;
453
  DBusMessage *reply;
454

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

            
478
static DBusMessage *
479
1
impl_GetOffsetAtPoint (DBusConnection *bus, DBusMessage *message, void *user_data)
480
{
481
1
  AtkText *text = (AtkText *) user_data;
482
  dbus_int32_t x, y;
483
  dbus_uint32_t coordType;
484
  dbus_int32_t rv;
485
  DBusMessage *reply;
486

            
487
1
  g_return_val_if_fail (ATK_IS_TEXT (user_data),
488
                        droute_not_yet_handled_error (message));
489
1
  if (!dbus_message_get_args (message, NULL, DBUS_TYPE_INT32, &x, DBUS_TYPE_INT32, &y,
490
                              DBUS_TYPE_UINT32, &coordType, DBUS_TYPE_INVALID))
491
    {
492
      return droute_invalid_arguments_error (message);
493
    }
494
1
  rv = atk_text_get_offset_at_point (text, x, y, coordType);
495
1
  reply = dbus_message_new_method_return (message);
496
1
  if (reply)
497
    {
498
1
      dbus_message_append_args (reply, DBUS_TYPE_INT32, &rv,
499
                                DBUS_TYPE_INVALID);
500
    }
501
1
  return reply;
502
}
503

            
504
static DBusMessage *
505
6
impl_GetNSelections (DBusConnection *bus, DBusMessage *message, void *user_data)
506
{
507
6
  AtkText *text = (AtkText *) user_data;
508
  dbus_int32_t rv;
509
  DBusMessage *reply;
510

            
511
6
  g_return_val_if_fail (ATK_IS_TEXT (user_data),
512
                        droute_not_yet_handled_error (message));
513
6
  rv = atk_text_get_n_selections (text);
514
6
  reply = dbus_message_new_method_return (message);
515
6
  if (reply)
516
    {
517
6
      dbus_message_append_args (reply, DBUS_TYPE_INT32, &rv,
518
                                DBUS_TYPE_INVALID);
519
    }
520
6
  return reply;
521
}
522

            
523
static DBusMessage *
524
4
impl_GetSelection (DBusConnection *bus, DBusMessage *message, void *user_data)
525
{
526
4
  AtkText *text = (AtkText *) user_data;
527
  dbus_int32_t selectionNum;
528
  dbus_int32_t startOffset, endOffset;
529
4
  gint intstart_offset = 0, intend_offset = 0;
530
  DBusMessage *reply;
531

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

            
552
static DBusMessage *
553
10
impl_AddSelection (DBusConnection *bus, DBusMessage *message, void *user_data)
554
{
555
10
  AtkText *text = (AtkText *) user_data;
556
  dbus_int32_t startOffset, endOffset;
557
  dbus_bool_t rv;
558
  DBusMessage *reply;
559

            
560
10
  g_return_val_if_fail (ATK_IS_TEXT (user_data),
561
                        droute_not_yet_handled_error (message));
562
10
  if (!dbus_message_get_args (message, NULL, DBUS_TYPE_INT32, &startOffset, DBUS_TYPE_INT32,
563
                              &endOffset, DBUS_TYPE_INVALID))
564
    {
565
      return droute_invalid_arguments_error (message);
566
    }
567
10
  rv = atk_text_add_selection (text, startOffset, endOffset);
568
10
  reply = dbus_message_new_method_return (message);
569
10
  if (reply)
570
    {
571
10
      dbus_message_append_args (reply, DBUS_TYPE_BOOLEAN, &rv,
572
                                DBUS_TYPE_INVALID);
573
    }
574
10
  return reply;
575
}
576

            
577
static DBusMessage *
578
2
impl_RemoveSelection (DBusConnection *bus, DBusMessage *message, void *user_data)
579
{
580
2
  AtkText *text = (AtkText *) user_data;
581
  dbus_int32_t selectionNum;
582
  dbus_bool_t rv;
583
  DBusMessage *reply;
584

            
585
2
  g_return_val_if_fail (ATK_IS_TEXT (user_data),
586
                        droute_not_yet_handled_error (message));
587
2
  if (!dbus_message_get_args (message, NULL, DBUS_TYPE_INT32, &selectionNum, DBUS_TYPE_INVALID))
588
    {
589
      return droute_invalid_arguments_error (message);
590
    }
591
2
  rv = atk_text_remove_selection (text, selectionNum);
592
2
  reply = dbus_message_new_method_return (message);
593
2
  if (reply)
594
    {
595
2
      dbus_message_append_args (reply, DBUS_TYPE_BOOLEAN, &rv,
596
                                DBUS_TYPE_INVALID);
597
    }
598
2
  return reply;
599
}
600

            
601
static DBusMessage *
602
2
impl_SetSelection (DBusConnection *bus, DBusMessage *message, void *user_data)
603
{
604
2
  AtkText *text = (AtkText *) user_data;
605
  dbus_int32_t selectionNum, startOffset, endOffset;
606
  dbus_bool_t rv;
607
  DBusMessage *reply;
608

            
609
2
  g_return_val_if_fail (ATK_IS_TEXT (user_data),
610
                        droute_not_yet_handled_error (message));
611
2
  if (!dbus_message_get_args (message, NULL, DBUS_TYPE_INT32, &selectionNum, DBUS_TYPE_INT32,
612
                              &startOffset, DBUS_TYPE_INT32, &endOffset, DBUS_TYPE_INVALID))
613
    {
614
      return droute_invalid_arguments_error (message);
615
    }
616
2
  rv = atk_text_set_selection (text, selectionNum, startOffset, endOffset);
617
2
  reply = dbus_message_new_method_return (message);
618
2
  if (reply)
619
    {
620
2
      dbus_message_append_args (reply, DBUS_TYPE_BOOLEAN, &rv,
621
                                DBUS_TYPE_INVALID);
622
    }
623
2
  return reply;
624
}
625

            
626
static DBusMessage *
627
1
impl_GetRangeExtents (DBusConnection *bus, DBusMessage *message, void *user_data)
628
{
629
1
  AtkText *text = (AtkText *) user_data;
630
  dbus_int32_t startOffset, endOffset;
631
  dbus_uint32_t coordType;
632
  AtkTextRectangle rect;
633
  dbus_int32_t x, y, width, height;
634
  DBusMessage *reply;
635

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

            
660
#define MAXRANGELEN 512
661

            
662
static DBusMessage *
663
1
impl_GetBoundedRanges (DBusConnection *bus, DBusMessage *message, void *user_data)
664
{
665
1
  AtkText *text = (AtkText *) user_data;
666
  dbus_int32_t x, y, width, height;
667
  dbus_uint32_t coordType, xClipType, yClipType;
668
1
  AtkTextRange **range_list = NULL;
669
  AtkTextRectangle rect;
670
  DBusMessage *reply;
671
  DBusMessageIter iter, array, struc, variant;
672

            
673
1
  g_return_val_if_fail (ATK_IS_TEXT (user_data),
674
                        droute_not_yet_handled_error (message));
675
1
  if (!dbus_message_get_args (message, NULL, DBUS_TYPE_INT32, &x, DBUS_TYPE_INT32, &y,
676
                              DBUS_TYPE_INT32, &height, DBUS_TYPE_INT32, &width, DBUS_TYPE_UINT32,
677
                              &coordType, DBUS_TYPE_UINT32, &xClipType, DBUS_TYPE_UINT32, &yClipType,
678
                              DBUS_TYPE_INVALID))
679
    {
680
      return droute_invalid_arguments_error (message);
681
    }
682
1
  rect.x = x;
683
1
  rect.y = y;
684
1
  rect.width = width;
685
1
  rect.height = height;
686

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

            
729
1
  if (range_list)
730
1
    g_free (range_list);
731

            
732
1
  return reply;
733
}
734

            
735
static DBusMessage *
736
1
impl_GetAttributeRun (DBusConnection *bus, DBusMessage *message, void *user_data)
737
{
738
1
  AtkText *text = (AtkText *) user_data;
739
  dbus_int32_t offset;
740
  dbus_bool_t includeDefaults;
741
  dbus_int32_t startOffset, endOffset;
742
1
  gint intstart_offset = 0, intend_offset = 0;
743
  DBusMessage *reply;
744
1
  AtkAttributeSet *attributes = NULL;
745
  DBusMessageIter iter;
746

            
747
1
  g_return_val_if_fail (ATK_IS_TEXT (user_data),
748
                        droute_not_yet_handled_error (message));
749
1
  if (!dbus_message_get_args (message, NULL, DBUS_TYPE_INT32, &offset, DBUS_TYPE_BOOLEAN,
750
                              &includeDefaults, DBUS_TYPE_INVALID))
751
    {
752
      return droute_invalid_arguments_error (message);
753
    }
754

            
755
1
  if (includeDefaults)
756
    {
757
      attributes = g_slist_concat (attributes,
758
                                   atk_text_get_default_attributes (text));
759
    }
760

            
761
1
  attributes = g_slist_concat (attributes,
762
1
                               atk_text_get_run_attributes (text, offset,
763
                                                            &intstart_offset,
764
                                                            &intend_offset));
765

            
766
1
  reply = dbus_message_new_method_return (message);
767
1
  if (!reply)
768
    return NULL;
769

            
770
1
  dbus_message_iter_init_append (reply, &iter);
771
1
  spi_object_append_attribute_set (&iter, attributes);
772

            
773
1
  startOffset = intstart_offset;
774
1
  endOffset = intend_offset;
775
1
  dbus_message_iter_append_basic (&iter, DBUS_TYPE_INT32, &startOffset);
776
1
  dbus_message_iter_append_basic (&iter, DBUS_TYPE_INT32, &endOffset);
777

            
778
1
  atk_attribute_set_free (attributes);
779

            
780
1
  return reply;
781
}
782

            
783
static DBusMessage *
784
impl_GetDefaultAttributeSet (DBusConnection *bus, DBusMessage *message, void *user_data)
785
{
786
  AtkText *text = (AtkText *) user_data;
787
  DBusMessage *reply;
788
  DBusMessageIter iter;
789
  AtkAttributeSet *attributes;
790

            
791
  g_return_val_if_fail (ATK_IS_TEXT (user_data),
792
                        droute_not_yet_handled_error (message));
793

            
794
  attributes = atk_text_get_default_attributes (text);
795

            
796
  reply = dbus_message_new_method_return (message);
797
  if (reply)
798
    {
799
      dbus_message_iter_init_append (reply, &iter);
800
      spi_object_append_attribute_set (&iter, attributes);
801
    }
802

            
803
  if (attributes)
804
    atk_attribute_set_free (attributes);
805

            
806
  return reply;
807
}
808

            
809
static DBusMessage *
810
impl_ScrollSubstringTo (DBusConnection *bus,
811
                        DBusMessage *message,
812
                        void *user_data)
813
{
814
  AtkText *text = (AtkText *) user_data;
815
  dbus_int32_t startOffset, endOffset;
816
  dbus_uint32_t type;
817
  dbus_bool_t ret;
818
  DBusMessage *reply = NULL;
819

            
820
  g_return_val_if_fail (ATK_IS_TEXT (user_data),
821
                        droute_not_yet_handled_error (message));
822

            
823
  if (!dbus_message_get_args (message, NULL, DBUS_TYPE_INT32, &startOffset,
824
                              DBUS_TYPE_INT32, &endOffset,
825
                              DBUS_TYPE_UINT32, &type,
826
                              DBUS_TYPE_INVALID))
827
    {
828
      return droute_invalid_arguments_error (message);
829
    }
830

            
831
  ret = atk_text_scroll_substring_to (text, startOffset, endOffset, type);
832

            
833
  reply = dbus_message_new_method_return (message);
834
  if (reply)
835
    {
836
      dbus_message_append_args (reply, DBUS_TYPE_BOOLEAN, &ret,
837
                                DBUS_TYPE_INVALID);
838
    }
839
  return reply;
840
}
841

            
842
static DBusMessage *
843
impl_ScrollSubstringToPoint (DBusConnection *bus,
844
                             DBusMessage *message,
845
                             void *user_data)
846
{
847
  AtkText *text = (AtkText *) user_data;
848
  dbus_int32_t startOffset, endOffset;
849
  dbus_uint32_t type;
850
  dbus_int32_t x, y;
851
  dbus_bool_t ret;
852
  DBusMessage *reply = NULL;
853

            
854
  g_return_val_if_fail (ATK_IS_TEXT (user_data),
855
                        droute_not_yet_handled_error (message));
856

            
857
  if (!dbus_message_get_args (message, NULL, DBUS_TYPE_INT32, &startOffset,
858
                              DBUS_TYPE_INT32, &endOffset,
859
                              DBUS_TYPE_UINT32, &type,
860
                              DBUS_TYPE_INT32, &x,
861
                              DBUS_TYPE_INT32, &y,
862
                              DBUS_TYPE_INVALID))
863
    {
864
      return droute_invalid_arguments_error (message);
865
    }
866

            
867
  ret = atk_text_scroll_substring_to_point (text, startOffset, endOffset, type, x, y);
868

            
869
  reply = dbus_message_new_method_return (message);
870
  if (reply)
871
    {
872
      dbus_message_append_args (reply, DBUS_TYPE_BOOLEAN, &ret,
873
                                DBUS_TYPE_INVALID);
874
    }
875
  return reply;
876
}
877

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

            
905
static DRouteProperty properties[] = {
906
  { impl_get_CharacterCount, NULL, "CharacterCount" },
907
  { impl_get_CaretOffset, NULL, "CaretOffset" },
908
  { NULL, NULL, NULL }
909
};
910

            
911
void
912
161
spi_initialize_text (DRoutePath *path)
913
{
914
161
  spi_atk_add_interface (path,
915
                         ATSPI_DBUS_INTERFACE_TEXT, spi_org_a11y_atspi_Text, methods, properties);
916
161
};