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
 *
7
 * This library is free software; you can redistribute it and/or
8
 * modify it under the terms of the GNU Lesser General Public
9
 * License as published by the Free Software Foundation; either
10
 * version 2.1 of the License, or (at your option) any later version.
11
 *
12
 * This library is distributed in the hope that it will be useful,
13
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15
 * Lesser General Public License for more details.
16
 *
17
 * You should have received a copy of the GNU Lesser General Public
18
 * License along with this library; if not, write to the
19
 * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
20
 * Boston, MA 02110-1301, USA.
21
 */
22

            
23
#include <dbus/dbus.h>
24
#include <glib-object.h>
25
#include <glib.h>
26
#include <stdio.h>
27
#include <stdlib.h>
28
#include <string.h>
29

            
30
#include "accessible-register.h"
31
#include <atspi/atspi.h>
32

            
33
DBusMessage *
34
spi_dbus_general_error (DBusMessage *message)
35
{
36
  return dbus_message_new_error (message,
37
                                 "org.a11y.atspi.GeneralError",
38
                                 "General error");
39
}
40

            
41
DBusMessage *
42
4
spi_dbus_return_rect (DBusMessage *message, gint ix, gint iy, gint iwidth, gint iheight)
43
{
44
  DBusMessage *reply;
45
  dbus_uint32_t x, y, width, height;
46

            
47
4
  x = ix;
48
4
  y = iy;
49
4
  width = iwidth;
50
4
  height = iheight;
51
4
  reply = dbus_message_new_method_return (message);
52
4
  if (reply)
53
    {
54
      DBusMessageIter iter, sub;
55
4
      dbus_message_iter_init_append (reply, &iter);
56
4
      if (!dbus_message_iter_open_container (&iter, DBUS_TYPE_STRUCT, NULL, &sub))
57
        goto oom;
58
4
      dbus_message_iter_append_basic (&sub, DBUS_TYPE_INT32, &x);
59
4
      dbus_message_iter_append_basic (&sub, DBUS_TYPE_INT32, &y);
60
4
      dbus_message_iter_append_basic (&sub, DBUS_TYPE_INT32, &width);
61
4
      dbus_message_iter_append_basic (&sub, DBUS_TYPE_INT32, &height);
62
4
      if (!dbus_message_iter_close_container (&iter, &sub))
63
        goto oom;
64
    }
65
4
  return reply;
66
oom:
67
  /* todo: return an error */
68
  return reply;
69
}
70

            
71
dbus_bool_t
72
spi_dbus_message_iter_get_struct (DBusMessageIter *iter, ...)
73
{
74
  va_list args;
75
  DBusMessageIter iter_struct;
76
  int type;
77
  void *ptr;
78

            
79
  dbus_message_iter_recurse (iter, &iter_struct);
80
  va_start (args, iter);
81
  for (;;)
82
    {
83
      type = va_arg (args, int);
84
      if (type == DBUS_TYPE_INVALID)
85
        break;
86
      if (type != dbus_message_iter_get_arg_type (&iter_struct))
87
        {
88
          va_end (args);
89
          return FALSE;
90
        }
91
      ptr = va_arg (args, void *);
92
      dbus_message_iter_get_basic (&iter_struct, ptr);
93
      dbus_message_iter_next (&iter_struct);
94
    }
95
  dbus_message_iter_next (iter);
96
  va_end (args);
97
  return TRUE;
98
}
99

            
100
dbus_bool_t
101
spi_dbus_message_iter_append_struct (DBusMessageIter *iter, ...)
102
{
103
  va_list args;
104
  DBusMessageIter iter_struct;
105
  int type;
106
  void *ptr;
107

            
108
  if (!dbus_message_iter_open_container (iter, DBUS_TYPE_STRUCT, NULL, &iter_struct))
109
    return FALSE;
110
  va_start (args, iter);
111
  for (;;)
112
    {
113
      type = va_arg (args, int);
114
      if (type == DBUS_TYPE_INVALID)
115
        break;
116
      ptr = va_arg (args, void *);
117
      dbus_message_iter_append_basic (&iter_struct, type, ptr);
118
    }
119
  va_end (args);
120
  if (!dbus_message_iter_close_container (iter, &iter_struct))
121
    return FALSE;
122
  return TRUE;
123
}
124

            
125
dbus_bool_t
126
spi_dbus_marshal_deviceEvent (DBusMessage *message, const AtspiDeviceEvent *e)
127
{
128
  DBusMessageIter iter;
129

            
130
  if (!message)
131
    return FALSE;
132
  dbus_message_iter_init_append (message, &iter);
133
  return spi_dbus_message_iter_append_struct (&iter, DBUS_TYPE_UINT32, &e->type, DBUS_TYPE_INT32, &e->id, DBUS_TYPE_INT16, &e->hw_code, DBUS_TYPE_INT16, &e->modifiers, DBUS_TYPE_INT32, &e->timestamp, DBUS_TYPE_STRING, &e->event_string, DBUS_TYPE_BOOLEAN, &e->is_text, DBUS_TYPE_INVALID);
134
}
135

            
136
dbus_bool_t
137
spi_dbus_demarshal_deviceEvent (DBusMessage *message, AtspiDeviceEvent *e)
138
{
139
  DBusMessageIter iter;
140

            
141
  dbus_message_iter_init (message, &iter);
142
  return spi_dbus_message_iter_get_struct (&iter, DBUS_TYPE_UINT32, &e->type, DBUS_TYPE_INT32, &e->id, DBUS_TYPE_INT16, &e->hw_code, DBUS_TYPE_INT16, &e->modifiers, DBUS_TYPE_INT32, &e->timestamp, DBUS_TYPE_STRING, &e->event_string, DBUS_TYPE_BOOLEAN, &e->is_text, DBUS_TYPE_INVALID);
143
}
144

            
145
/*
146
 * This is a rather annoying function needed to replace
147
 * NULL values of strings with the empty string. Null string
148
 * values can be created by the atk_object_get_name or text selection
149
 */
150
static const void *
151
provide_defaults (const gint type,
152
                  const void *val)
153
{
154
  switch (type)
155
    {
156
    case DBUS_TYPE_STRING:
157
    case DBUS_TYPE_OBJECT_PATH:
158
      if (!val)
159
        return "";
160
      else
161
        return val;
162
    default:
163
      return val;
164
    }
165
}
166

            
167
/*
168
 * Appends all the standard parameters to an AT-SPI event.
169
 */
170
void
171
spi_dbus_signal_new (const char *path,
172
                     const char *klass,
173
                     const char *major,
174
                     const char *minor,
175
                     dbus_int32_t detail1,
176
                     dbus_int32_t detail2)
177
{
178
  DBusMessage *sig;
179
  DBusMessageIter iter;
180
  gchar *cname, *t;
181

            
182
  if (!klass)
183
    klass = "";
184
  if (!major)
185
    major = "";
186
  if (!minor)
187
    minor = "";
188

            
189
  /*
190
   * This is very annoying, but as '-' isn't a legal signal
191
   * name in D-Bus (Why not??!?) The names need converting
192
   * on this side, and again on the client side.
193
   */
194
  cname = g_strdup (major);
195
  while ((t = strchr (cname, '-')) != NULL)
196
    *t = '_';
197

            
198
  sig = dbus_message_new_signal (path, klass, cname);
199
  g_free (cname);
200

            
201
  dbus_message_iter_init_append (sig, &iter);
202

            
203
  dbus_message_iter_append_basic (&iter, DBUS_TYPE_STRING, &minor);
204
  dbus_message_iter_append_basic (&iter, DBUS_TYPE_INT32, &detail1);
205
  dbus_message_iter_append_basic (&iter, DBUS_TYPE_INT32, &detail2);
206
}
207

            
208
void
209
spi_dbus_emit_signal (DBusConnection *bus, const char *path, const char *klass, const char *major, const char *minor, dbus_int32_t detail1, dbus_int32_t detail2, const char *type, const void *val)
210
{
211
  gchar *cname, *t;
212
  DBusMessage *sig;
213
  DBusMessageIter iter, sub;
214
  if (!klass)
215
    klass = "";
216
  if (!major)
217
    major = "";
218
  if (!minor)
219
    minor = "";
220
  if (!type)
221
    type = "u";
222

            
223
  /*
224
   * This is very annoying, but as '-' isn't a legal signal
225
   * name in D-Bus (Why not??!?) The names need converting
226
   * on this side, and again on the client side.
227
   */
228
  cname = g_strdup (major);
229
  while ((t = strchr (cname, '-')) != NULL)
230
    *t = '_';
231

            
232
  sig = dbus_message_new_signal (path, klass, cname);
233
  g_free (cname);
234

            
235
  dbus_message_iter_init_append (sig, &iter);
236

            
237
  dbus_message_iter_append_basic (&iter, DBUS_TYPE_STRING, &minor);
238
  dbus_message_iter_append_basic (&iter, DBUS_TYPE_INT32, &detail1);
239
  dbus_message_iter_append_basic (&iter, DBUS_TYPE_INT32, &detail2);
240

            
241
  dbus_message_iter_open_container (&iter, DBUS_TYPE_VARIANT, type, &sub);
242
  /*
243
   * I need to convert the string signature to an integer type signature.
244
   * DBUS_TYPE_INT32 is defined as 'i' whereas the string is "i".
245
   * I should just be able to cast the first character of the string to an
246
   * integer.
247
   */
248
  val = provide_defaults ((int) *type, val);
249
  dbus_message_iter_append_basic (&sub, (int) *type, &val);
250
  dbus_message_iter_close_container (&iter, &sub);
251

            
252
  dbus_connection_send (bus, sig, NULL);
253
  dbus_message_unref (sig);
254
}
255

            
256
/* Returns an AtkObject from a DBusMessageIter and advances the iter.
257
 * Expects the iter to point to a (so) structure representing an object. */
258
GObject *
259
4
spi_dbus_get_object_from_iter (DBusMessageIter *iter)
260
{
261
  DBusMessageIter iter_struct;
262
  const char *bus_name, *path;
263

            
264
4
  dbus_message_iter_recurse (iter, &iter_struct);
265
4
  dbus_message_iter_get_basic (&iter_struct, &bus_name);
266
4
  dbus_message_iter_next (&iter_struct);
267
4
  dbus_message_iter_get_basic (&iter_struct, &path);
268
4
  dbus_message_iter_next (iter);
269
  /* TODO: verify bus name */
270
4
  return spi_global_register_path_to_object (path);
271
}