|
1 /* |
|
2 * properties-mixin.c - Source for GabblePropertiesMixin |
|
3 * Copyright (C) 2006 Collabora Ltd. |
|
4 * |
|
5 * @author Ole Andre Vadla Ravnaas <ole.andre.ravnaas@collabora.co.uk> |
|
6 * @author Robert McQueen <robert.mcqueen@collabora.co.uk> |
|
7 * |
|
8 * This library is free software; you can redistribute it and/or |
|
9 * modify it under the terms of the GNU Lesser General Public |
|
10 * License as published by the Free Software Foundation; either |
|
11 * version 2.1 of the License, or (at your option) any later version. |
|
12 * |
|
13 * This library is distributed in the hope that it will be useful, |
|
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
|
16 * Lesser General Public License for more details. |
|
17 * |
|
18 * You should have received a copy of the GNU Lesser General Public |
|
19 * License along with this library; if not, write to the Free Software |
|
20 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA |
|
21 */ |
|
22 |
|
23 #include <dbus/dbus-glib.h> |
|
24 #include <stdio.h> |
|
25 #include <string.h> |
|
26 |
|
27 #define DEBUG_FLAG GABBLE_DEBUG_PROPERTIES |
|
28 |
|
29 #include "ansi.h" |
|
30 #include "debug.h" |
|
31 #include "properties-mixin.h" |
|
32 #include "properties-mixin-signals-marshal.h" |
|
33 #include "telepathy-errors.h" |
|
34 |
|
35 |
|
36 #ifdef EMULATOR |
|
37 #include "libgabble_wsd_solution.h" |
|
38 |
|
39 GET_STATIC_VAR_FROM_TLS(offset_quark1,gabble_mixin,GQuark) |
|
40 #define offset_quark1 (*GET_WSD_VAR_NAME(offset_quark1,gabble_mixin, s)()) |
|
41 |
|
42 GET_STATIC_VAR_FROM_TLS(offset_quark,gabble_mixin,GQuark) |
|
43 #define offset_quark (*GET_WSD_VAR_NAME(offset_quark,gabble_mixin, s)()) |
|
44 |
|
45 |
|
46 #endif |
|
47 |
|
48 struct _GabblePropertiesContext { |
|
49 GabblePropertiesMixinClass *mixin_cls; |
|
50 GabblePropertiesMixin *mixin; |
|
51 |
|
52 DBusGMethodInvocation *dbus_ctx; |
|
53 guint32 remaining; |
|
54 GValue **values; |
|
55 }; |
|
56 |
|
57 struct _GabblePropertiesMixinPrivate { |
|
58 GObject *object; |
|
59 GabblePropertiesContext context; |
|
60 }; |
|
61 |
|
62 /** |
|
63 * gabble_properties_mixin_class_get_offset_quark: |
|
64 * |
|
65 * Returns: the quark used for storing mixin offset on a GObjectClass |
|
66 */ |
|
67 GQuark |
|
68 gabble_properties_mixin_class_get_offset_quark () |
|
69 { |
|
70 #ifndef EMULATOR |
|
71 static GQuark offset_quark1= 0; |
|
72 #endif |
|
73 if (!offset_quark1) |
|
74 offset_quark1 = g_quark_from_static_string("PropertiesMixinClassOffsetQuark"); |
|
75 return offset_quark1; |
|
76 } |
|
77 |
|
78 /** |
|
79 * gabble_properties_mixin_get_offset_quark: |
|
80 * |
|
81 * Returns: the quark used for storing mixin offset on a GObject |
|
82 */ |
|
83 GQuark |
|
84 gabble_properties_mixin_get_offset_quark () |
|
85 { |
|
86 #ifndef EMULATOR |
|
87 static GQuark offset_quark = 0; |
|
88 #endif |
|
89 if (!offset_quark) |
|
90 offset_quark = g_quark_from_static_string("PropertiesMixinOffsetQuark"); |
|
91 return offset_quark; |
|
92 } |
|
93 |
|
94 void gabble_properties_mixin_class_init (GObjectClass *obj_cls, |
|
95 glong offset, |
|
96 const GabblePropertySignature *signatures, |
|
97 guint num_properties, |
|
98 GabblePropertiesSetFunc set_func) |
|
99 { |
|
100 GabblePropertiesMixinClass *mixin_cls; |
|
101 |
|
102 g_assert (G_IS_OBJECT_CLASS (obj_cls)); |
|
103 |
|
104 g_type_set_qdata (G_OBJECT_CLASS_TYPE (obj_cls), |
|
105 GABBLE_PROPERTIES_MIXIN_CLASS_OFFSET_QUARK, |
|
106 GINT_TO_POINTER (offset)); |
|
107 |
|
108 mixin_cls = GABBLE_PROPERTIES_MIXIN_CLASS (obj_cls); |
|
109 |
|
110 mixin_cls->signatures = signatures; |
|
111 mixin_cls->num_props = num_properties; |
|
112 |
|
113 mixin_cls->set_properties = set_func; |
|
114 |
|
115 mixin_cls->properties_changed_signal_id = |
|
116 g_signal_new ("properties-changed", |
|
117 G_OBJECT_CLASS_TYPE (obj_cls), |
|
118 G_SIGNAL_RUN_LAST | G_SIGNAL_DETAILED, |
|
119 0, |
|
120 NULL, NULL, |
|
121 g_cclosure_marshal_VOID__BOXED, |
|
122 G_TYPE_NONE, 1, (dbus_g_type_get_collection ("GPtrArray", (dbus_g_type_get_struct ("GValueArray", G_TYPE_UINT, G_TYPE_VALUE, G_TYPE_INVALID))))); |
|
123 |
|
124 mixin_cls->property_flags_changed_signal_id = |
|
125 g_signal_new ("property-flags-changed", |
|
126 G_OBJECT_CLASS_TYPE (obj_cls), |
|
127 G_SIGNAL_RUN_LAST | G_SIGNAL_DETAILED, |
|
128 0, |
|
129 NULL, NULL, |
|
130 g_cclosure_marshal_VOID__BOXED, |
|
131 G_TYPE_NONE, 1, (dbus_g_type_get_collection ("GPtrArray", (dbus_g_type_get_struct ("GValueArray", G_TYPE_UINT, G_TYPE_UINT, G_TYPE_INVALID))))); |
|
132 } |
|
133 |
|
134 void gabble_properties_mixin_init (GObject *obj, glong offset) |
|
135 { |
|
136 GabblePropertiesMixinClass *mixin_cls; |
|
137 GabblePropertiesMixin *mixin; |
|
138 GabblePropertiesContext *ctx; |
|
139 |
|
140 g_assert (G_IS_OBJECT (obj)); |
|
141 |
|
142 g_type_set_qdata (G_OBJECT_TYPE (obj), |
|
143 GABBLE_PROPERTIES_MIXIN_OFFSET_QUARK, |
|
144 GINT_TO_POINTER (offset)); |
|
145 |
|
146 mixin = GABBLE_PROPERTIES_MIXIN (obj); |
|
147 mixin_cls = GABBLE_PROPERTIES_MIXIN_CLASS (G_OBJECT_GET_CLASS (obj)); |
|
148 |
|
149 mixin->properties = g_new0 (GabbleProperty, mixin_cls->num_props); |
|
150 |
|
151 mixin->priv = g_new0 (GabblePropertiesMixinPrivate, 1); |
|
152 mixin->priv->object = obj; |
|
153 |
|
154 ctx = &mixin->priv->context; |
|
155 ctx->mixin_cls = mixin_cls; |
|
156 ctx->mixin = mixin; |
|
157 ctx->values = g_new0 (GValue *, mixin_cls->num_props); |
|
158 } |
|
159 |
|
160 void gabble_properties_mixin_finalize (GObject *obj) |
|
161 { |
|
162 GabblePropertiesMixin *mixin = GABBLE_PROPERTIES_MIXIN (obj); |
|
163 GabblePropertiesMixinClass *mixin_cls = GABBLE_PROPERTIES_MIXIN_CLASS ( |
|
164 G_OBJECT_GET_CLASS (obj)); |
|
165 GabblePropertiesContext *ctx = &mixin->priv->context; |
|
166 guint i; |
|
167 |
|
168 for (i = 0; i < mixin_cls->num_props; i++) |
|
169 { |
|
170 GabbleProperty *prop = &mixin->properties[i]; |
|
171 |
|
172 if (prop->value) |
|
173 { |
|
174 g_value_unset (prop->value); |
|
175 g_free (prop->value); |
|
176 } |
|
177 |
|
178 if (ctx->values[i]) |
|
179 { |
|
180 g_value_unset (ctx->values[i]); |
|
181 } |
|
182 } |
|
183 |
|
184 g_free (ctx->values); |
|
185 |
|
186 g_free (mixin->priv); |
|
187 |
|
188 g_free (mixin->properties); |
|
189 } |
|
190 |
|
191 gboolean |
|
192 gabble_properties_mixin_list_properties (GObject *obj, GPtrArray **ret, GError **error) |
|
193 { |
|
194 GabblePropertiesMixin *mixin = GABBLE_PROPERTIES_MIXIN (obj); |
|
195 GabblePropertiesMixinClass *mixin_cls = GABBLE_PROPERTIES_MIXIN_CLASS ( |
|
196 G_OBJECT_GET_CLASS (obj)); |
|
197 guint i; |
|
198 |
|
199 *ret = g_ptr_array_sized_new (mixin_cls->num_props); |
|
200 |
|
201 for (i = 0; i < mixin_cls->num_props; i++) |
|
202 { |
|
203 const GabblePropertySignature *sig = &mixin_cls->signatures[i]; |
|
204 GabbleProperty *prop = &mixin->properties[i]; |
|
205 const gchar *dbus_sig; |
|
206 GValue val = { 0, }; |
|
207 |
|
208 switch (sig->type) { |
|
209 case G_TYPE_BOOLEAN: |
|
210 dbus_sig = "b"; |
|
211 break; |
|
212 case G_TYPE_INT: |
|
213 dbus_sig = "i"; |
|
214 break; |
|
215 case G_TYPE_UINT: |
|
216 dbus_sig = "u"; |
|
217 break; |
|
218 case G_TYPE_STRING: |
|
219 dbus_sig = "s"; |
|
220 break; |
|
221 default: |
|
222 g_assert_not_reached (); |
|
223 continue; |
|
224 }; |
|
225 |
|
226 g_value_init (&val, TP_TYPE_PROPERTY_INFO_STRUCT); |
|
227 g_value_take_boxed (&val, |
|
228 dbus_g_type_specialized_construct (TP_TYPE_PROPERTY_INFO_STRUCT)); |
|
229 |
|
230 dbus_g_type_struct_set (&val, |
|
231 0, i, |
|
232 1, sig->name, |
|
233 2, dbus_sig, |
|
234 3, prop->flags, |
|
235 G_MAXUINT); |
|
236 |
|
237 g_ptr_array_add (*ret, g_value_get_boxed (&val)); |
|
238 } |
|
239 |
|
240 return TRUE; |
|
241 } |
|
242 |
|
243 gboolean |
|
244 gabble_properties_mixin_get_properties (GObject *obj, const GArray *properties, GPtrArray **ret, GError **error) |
|
245 { |
|
246 GabblePropertiesMixin *mixin = GABBLE_PROPERTIES_MIXIN (obj); |
|
247 GabblePropertiesMixinClass *mixin_cls = GABBLE_PROPERTIES_MIXIN_CLASS ( |
|
248 G_OBJECT_GET_CLASS (obj)); |
|
249 guint i; |
|
250 |
|
251 /* Check input property identifiers */ |
|
252 for (i = 0; i < properties->len; i++) |
|
253 { |
|
254 guint prop_id = g_array_index (properties, guint, i); |
|
255 |
|
256 /* Valid? */ |
|
257 if (prop_id >= mixin_cls->num_props) |
|
258 { |
|
259 g_set_error (error, TELEPATHY_ERRORS, InvalidArgument, |
|
260 "invalid property identifier %d", prop_id); |
|
261 |
|
262 return FALSE; |
|
263 } |
|
264 |
|
265 /* Permitted? */ |
|
266 if (!gabble_properties_mixin_is_readable (obj, prop_id)) |
|
267 { |
|
268 g_set_error (error, TELEPATHY_ERRORS, PermissionDenied, |
|
269 "permission denied for property identifier %d", prop_id); |
|
270 |
|
271 return FALSE; |
|
272 } |
|
273 } |
|
274 |
|
275 /* If we got this far, return the actual values */ |
|
276 *ret = g_ptr_array_sized_new (properties->len); |
|
277 |
|
278 for (i = 0; i < properties->len; i++) |
|
279 { |
|
280 guint prop_id = g_array_index (properties, guint, i); |
|
281 GValue val_struct = { 0, }; |
|
282 |
|
283 /* id/value struct */ |
|
284 g_value_init (&val_struct, TP_TYPE_PROPERTY_VALUE_STRUCT); |
|
285 g_value_take_boxed (&val_struct, |
|
286 dbus_g_type_specialized_construct (TP_TYPE_PROPERTY_VALUE_STRUCT)); |
|
287 |
|
288 dbus_g_type_struct_set (&val_struct, |
|
289 0, prop_id, |
|
290 1, mixin->properties[prop_id].value, |
|
291 G_MAXUINT); |
|
292 |
|
293 g_ptr_array_add (*ret, g_value_get_boxed (&val_struct)); |
|
294 } |
|
295 |
|
296 return TRUE; |
|
297 } |
|
298 |
|
299 void |
|
300 gabble_properties_mixin_set_properties (GObject *obj, |
|
301 const GPtrArray *properties, |
|
302 DBusGMethodInvocation *context) |
|
303 { |
|
304 GabblePropertiesMixin *mixin = GABBLE_PROPERTIES_MIXIN (obj); |
|
305 GabblePropertiesMixinClass *mixin_cls = GABBLE_PROPERTIES_MIXIN_CLASS ( |
|
306 G_OBJECT_GET_CLASS (obj)); |
|
307 GabblePropertiesContext *ctx = &mixin->priv->context; |
|
308 GError *error = NULL; |
|
309 guint i; |
|
310 |
|
311 /* Is another SetProperties request already in progress? */ |
|
312 if (ctx->dbus_ctx) |
|
313 { |
|
314 error = g_error_new (TELEPATHY_ERRORS, NotAvailable, |
|
315 "A SetProperties request is already in progress"); |
|
316 goto ERROR; |
|
317 } |
|
318 |
|
319 ctx->dbus_ctx = context; |
|
320 error = NULL; |
|
321 |
|
322 /* Check input property identifiers */ |
|
323 for (i = 0; i < properties->len; i++) |
|
324 { |
|
325 GValue val_struct = { 0, }; |
|
326 guint prop_id; |
|
327 GValue *prop_val; |
|
328 |
|
329 g_value_init (&val_struct, TP_TYPE_PROPERTY_VALUE_STRUCT); |
|
330 g_value_set_static_boxed (&val_struct, g_ptr_array_index (properties, i)); |
|
331 |
|
332 dbus_g_type_struct_get (&val_struct, |
|
333 0, &prop_id, |
|
334 1, &prop_val, |
|
335 G_MAXUINT); |
|
336 |
|
337 /* Valid? */ |
|
338 if (prop_id >= mixin_cls->num_props) |
|
339 { |
|
340 g_value_unset (prop_val); |
|
341 |
|
342 error = g_error_new (TELEPATHY_ERRORS, InvalidArgument, |
|
343 "invalid property identifier %d", prop_id); |
|
344 goto ERROR; |
|
345 } |
|
346 |
|
347 /* Store the value in the context */ |
|
348 ctx->remaining |= 1 << prop_id; |
|
349 ctx->values[prop_id] = prop_val; |
|
350 |
|
351 /* Permitted? */ |
|
352 if (!gabble_properties_mixin_is_writable (obj, prop_id)) |
|
353 { |
|
354 error = g_error_new (TELEPATHY_ERRORS, PermissionDenied, |
|
355 "permission denied for property identifier %d", prop_id); |
|
356 goto ERROR; |
|
357 } |
|
358 |
|
359 /* Compatible type? */ |
|
360 if (!g_value_type_compatible (G_VALUE_TYPE (prop_val), |
|
361 mixin_cls->signatures[prop_id].type)) |
|
362 { |
|
363 error = g_error_new (TELEPATHY_ERRORS, NotAvailable, |
|
364 "incompatible value type for property identifier %d", |
|
365 prop_id); |
|
366 goto ERROR; |
|
367 } |
|
368 } |
|
369 |
|
370 if (mixin_cls->set_properties) |
|
371 { |
|
372 if (mixin_cls->set_properties (obj, ctx, &error)) |
|
373 return; |
|
374 } |
|
375 else |
|
376 { |
|
377 gabble_properties_context_return (ctx, NULL); |
|
378 return; |
|
379 } |
|
380 |
|
381 ERROR: |
|
382 gabble_properties_context_return (ctx, error); |
|
383 } |
|
384 |
|
385 gboolean |
|
386 gabble_properties_mixin_has_property (GObject *obj, const gchar *name, |
|
387 guint *property) |
|
388 { |
|
389 GabblePropertiesMixinClass *mixin_cls = GABBLE_PROPERTIES_MIXIN_CLASS ( |
|
390 G_OBJECT_GET_CLASS (obj)); |
|
391 guint i; |
|
392 |
|
393 for (i = 0; i < mixin_cls->num_props; i++) |
|
394 { |
|
395 if (strcmp (mixin_cls->signatures[i].name, name) == 0) |
|
396 { |
|
397 if (property) |
|
398 *property = i; |
|
399 |
|
400 return TRUE; |
|
401 } |
|
402 } |
|
403 |
|
404 return FALSE; |
|
405 } |
|
406 |
|
407 gboolean |
|
408 gabble_properties_context_has (GabblePropertiesContext *ctx, guint property) |
|
409 { |
|
410 g_assert (property < ctx->mixin_cls->num_props); |
|
411 |
|
412 return (ctx->values[property] != NULL); |
|
413 } |
|
414 |
|
415 gboolean |
|
416 gabble_properties_context_has_other_than (GabblePropertiesContext *ctx, guint property) |
|
417 { |
|
418 g_assert (property < ctx->mixin_cls->num_props); |
|
419 |
|
420 return ((ctx->remaining & ~(1 << property)) != 0); |
|
421 } |
|
422 |
|
423 const GValue * |
|
424 gabble_properties_context_get (GabblePropertiesContext *ctx, guint property) |
|
425 { |
|
426 g_assert (property < ctx->mixin_cls->num_props); |
|
427 |
|
428 return ctx->values[property]; |
|
429 } |
|
430 |
|
431 guint |
|
432 gabble_properties_context_get_value_count (GabblePropertiesContext *ctx) |
|
433 { |
|
434 guint i, n; |
|
435 |
|
436 n = 0; |
|
437 for (i = 0; i < ctx->mixin_cls->num_props; i++) |
|
438 { |
|
439 if (ctx->values[i]) |
|
440 n++; |
|
441 } |
|
442 |
|
443 return n; |
|
444 } |
|
445 |
|
446 void |
|
447 gabble_properties_context_remove (GabblePropertiesContext *ctx, guint property) |
|
448 { |
|
449 g_assert (property < ctx->mixin_cls->num_props); |
|
450 |
|
451 ctx->remaining &= ~(1 << property); |
|
452 } |
|
453 |
|
454 void |
|
455 gabble_properties_context_return (GabblePropertiesContext *ctx, GError *error) |
|
456 { |
|
457 GObject *obj = ctx->mixin->priv->object; |
|
458 GArray *changed_props_val, *changed_props_flags; |
|
459 guint i; |
|
460 |
|
461 gabble_debug (DEBUG_FLAG, "%s", (error) ? "failure" : "success"); |
|
462 |
|
463 changed_props_val = changed_props_flags = NULL; |
|
464 |
|
465 for (i = 0; i < ctx->mixin_cls->num_props; i++) |
|
466 { |
|
467 if (ctx->values[i]) |
|
468 { |
|
469 if (!error) |
|
470 { |
|
471 gabble_properties_mixin_change_value (obj, i, ctx->values[i], |
|
472 &changed_props_val); |
|
473 |
|
474 gabble_properties_mixin_change_flags (obj, i, |
|
475 TP_PROPERTY_FLAG_READ, 0, &changed_props_flags); |
|
476 } |
|
477 |
|
478 g_value_unset (ctx->values[i]); |
|
479 ctx->values[i] = NULL; |
|
480 } |
|
481 } |
|
482 |
|
483 if (!error) |
|
484 { |
|
485 gabble_properties_mixin_emit_changed (obj, &changed_props_val); |
|
486 gabble_properties_mixin_emit_flags (obj, &changed_props_flags); |
|
487 |
|
488 dbus_g_method_return (ctx->dbus_ctx); |
|
489 } |
|
490 else |
|
491 { |
|
492 dbus_g_method_return_error (ctx->dbus_ctx, error); |
|
493 g_error_free (error); |
|
494 } |
|
495 |
|
496 ctx->dbus_ctx = NULL; |
|
497 ctx->remaining = 0; |
|
498 } |
|
499 |
|
500 gboolean |
|
501 gabble_properties_context_return_if_done (GabblePropertiesContext *ctx) |
|
502 { |
|
503 if (ctx->remaining == 0) |
|
504 { |
|
505 gabble_properties_context_return (ctx, NULL); |
|
506 return TRUE; |
|
507 } |
|
508 |
|
509 return FALSE; |
|
510 } |
|
511 |
|
512 #define RPTS_APPEND_FLAG_IF_SET(flag) \ |
|
513 if (flags & flag) \ |
|
514 { \ |
|
515 if (i++ > 0) \ |
|
516 g_string_append (str, "|"); \ |
|
517 g_string_append (str, #flag + 17); \ |
|
518 } |
|
519 |
|
520 static gchar * |
|
521 property_flags_to_string (TpPropertyFlags flags) |
|
522 { |
|
523 gint i = 0; |
|
524 GString *str; |
|
525 |
|
526 str = g_string_new ("[" ANSI_BOLD_OFF); |
|
527 |
|
528 RPTS_APPEND_FLAG_IF_SET (TP_PROPERTY_FLAG_READ); |
|
529 RPTS_APPEND_FLAG_IF_SET (TP_PROPERTY_FLAG_WRITE); |
|
530 |
|
531 g_string_append (str, ANSI_BOLD_ON "]"); |
|
532 |
|
533 return g_string_free (str, FALSE); |
|
534 } |
|
535 |
|
536 static gboolean |
|
537 values_are_equal (const GValue *v1, const GValue *v2) |
|
538 { |
|
539 GType type = G_VALUE_TYPE (v1); |
|
540 const gchar *s1, *s2; |
|
541 |
|
542 switch (type) { |
|
543 case G_TYPE_BOOLEAN: |
|
544 return (g_value_get_boolean (v1) == g_value_get_boolean (v2)); |
|
545 |
|
546 case G_TYPE_STRING: |
|
547 s1 = g_value_get_string (v1); |
|
548 s2 = g_value_get_string (v2); |
|
549 |
|
550 /* are they both NULL? */ |
|
551 if (s1 == s2) |
|
552 return TRUE; |
|
553 |
|
554 /* is one of them NULL? */ |
|
555 if (s1 == NULL || s2 == NULL) |
|
556 return FALSE; |
|
557 |
|
558 return (strcmp (s1, s2) == 0); |
|
559 |
|
560 case G_TYPE_UINT: |
|
561 return (g_value_get_uint (v1) == g_value_get_uint (v2)); |
|
562 |
|
563 case G_TYPE_INT: |
|
564 return (g_value_get_int (v1) == g_value_get_int (v2)); |
|
565 } |
|
566 |
|
567 return FALSE; |
|
568 } |
|
569 |
|
570 void |
|
571 gabble_properties_mixin_change_value (GObject *obj, guint prop_id, |
|
572 const GValue *new_value, |
|
573 GArray **props) |
|
574 { |
|
575 GabblePropertiesMixin *mixin = GABBLE_PROPERTIES_MIXIN (obj); |
|
576 GabblePropertiesMixinClass *mixin_cls = GABBLE_PROPERTIES_MIXIN_CLASS ( |
|
577 G_OBJECT_GET_CLASS (obj)); |
|
578 GabbleProperty *prop; |
|
579 |
|
580 g_assert (prop_id < mixin_cls->num_props); |
|
581 |
|
582 prop = &mixin->properties[prop_id]; |
|
583 |
|
584 if (prop->value) |
|
585 { |
|
586 if (values_are_equal (prop->value, new_value)) |
|
587 return; |
|
588 } |
|
589 else |
|
590 { |
|
591 prop->value = g_new0 (GValue, 1); |
|
592 g_value_init (prop->value, mixin_cls->signatures[prop_id].type); |
|
593 } |
|
594 |
|
595 g_value_copy (new_value, prop->value); |
|
596 |
|
597 if (props) |
|
598 { |
|
599 guint i; |
|
600 |
|
601 if (*props == NULL) |
|
602 { |
|
603 *props = g_array_sized_new (FALSE, FALSE, sizeof (guint), |
|
604 mixin_cls->num_props); |
|
605 } |
|
606 |
|
607 for (i = 0; i < (*props)->len; i++) |
|
608 { |
|
609 if (g_array_index (*props, guint, i) == prop_id) |
|
610 return; |
|
611 } |
|
612 |
|
613 g_array_append_val (*props, prop_id); |
|
614 } |
|
615 else |
|
616 { |
|
617 GArray *changed_props = g_array_sized_new (FALSE, FALSE, |
|
618 sizeof (guint), 1); |
|
619 g_array_append_val (changed_props, prop_id); |
|
620 |
|
621 gabble_properties_mixin_emit_changed (obj, &changed_props); |
|
622 } |
|
623 } |
|
624 |
|
625 void |
|
626 gabble_properties_mixin_change_flags (GObject *obj, guint prop_id, |
|
627 TpPropertyFlags add, |
|
628 TpPropertyFlags remove, |
|
629 GArray **props) |
|
630 { |
|
631 GabblePropertiesMixin *mixin = GABBLE_PROPERTIES_MIXIN (obj); |
|
632 GabblePropertiesMixinClass *mixin_cls = GABBLE_PROPERTIES_MIXIN_CLASS ( |
|
633 G_OBJECT_GET_CLASS (obj)); |
|
634 GabbleProperty *prop; |
|
635 guint prev_flags; |
|
636 |
|
637 g_assert (prop_id < mixin_cls->num_props); |
|
638 |
|
639 prop = &mixin->properties[prop_id]; |
|
640 |
|
641 prev_flags = prop->flags; |
|
642 |
|
643 prop->flags |= add; |
|
644 prop->flags &= ~remove; |
|
645 |
|
646 if (prop->flags == prev_flags) |
|
647 return; |
|
648 |
|
649 if (props) |
|
650 { |
|
651 guint i; |
|
652 |
|
653 if (*props == NULL) |
|
654 { |
|
655 *props = g_array_sized_new (FALSE, FALSE, sizeof (guint), |
|
656 mixin_cls->num_props); |
|
657 } |
|
658 |
|
659 for (i = 0; i < (*props)->len; i++) |
|
660 { |
|
661 if (g_array_index (*props, guint, i) == prop_id) |
|
662 return; |
|
663 } |
|
664 |
|
665 g_array_append_val (*props, prop_id); |
|
666 } |
|
667 else |
|
668 { |
|
669 GArray *changed_props = g_array_sized_new (FALSE, FALSE, |
|
670 sizeof (guint), 1); |
|
671 g_array_append_val (changed_props, prop_id); |
|
672 |
|
673 gabble_properties_mixin_emit_flags (obj, &changed_props); |
|
674 } |
|
675 } |
|
676 |
|
677 void |
|
678 gabble_properties_mixin_emit_changed (GObject *obj, GArray **props) |
|
679 { |
|
680 GabblePropertiesMixin *mixin = GABBLE_PROPERTIES_MIXIN (obj); |
|
681 GabblePropertiesMixinClass *mixin_cls = GABBLE_PROPERTIES_MIXIN_CLASS ( |
|
682 G_OBJECT_GET_CLASS (obj)); |
|
683 GPtrArray *prop_arr; |
|
684 GValue prop_list = { 0, }; |
|
685 guint i; |
|
686 |
|
687 if (*props == NULL) |
|
688 return; |
|
689 |
|
690 if ((*props)->len == 0) |
|
691 return; |
|
692 |
|
693 prop_arr = g_ptr_array_sized_new ((*props)->len); |
|
694 |
|
695 if (DEBUGGING) |
|
696 g_message (ANSI_BOLD_ON ANSI_FG_CYAN |
|
697 "%s: emitting properties changed for propert%s:\n", |
|
698 G_STRFUNC, ((*props)->len > 1) ? "ies" : "y"); |
|
699 |
|
700 for (i = 0; i < (*props)->len; i++) |
|
701 { |
|
702 GValue prop_val = { 0, }; |
|
703 guint prop_id = g_array_index (*props, guint, i); |
|
704 |
|
705 g_value_init (&prop_val, TP_TYPE_PROPERTY_VALUE_STRUCT); |
|
706 g_value_take_boxed (&prop_val, |
|
707 dbus_g_type_specialized_construct (TP_TYPE_PROPERTY_VALUE_STRUCT)); |
|
708 |
|
709 dbus_g_type_struct_set (&prop_val, |
|
710 0, prop_id, |
|
711 1, mixin->properties[prop_id].value, |
|
712 G_MAXUINT); |
|
713 |
|
714 g_ptr_array_add (prop_arr, g_value_get_boxed (&prop_val)); |
|
715 |
|
716 if (DEBUGGING) |
|
717 g_message (" %s\n", mixin_cls->signatures[prop_id].name); |
|
718 } |
|
719 |
|
720 if (DEBUGGING) |
|
721 { |
|
722 g_message (ANSI_RESET); |
|
723 fflush (stdout); |
|
724 } |
|
725 |
|
726 g_signal_emit (obj, mixin_cls->properties_changed_signal_id, 0, prop_arr); |
|
727 |
|
728 g_value_init (&prop_list, TP_TYPE_PROPERTY_VALUE_LIST); |
|
729 g_value_take_boxed (&prop_list, prop_arr); |
|
730 g_value_unset (&prop_list); |
|
731 |
|
732 g_array_free (*props, TRUE); |
|
733 *props = NULL; |
|
734 } |
|
735 |
|
736 void |
|
737 gabble_properties_mixin_emit_flags (GObject *obj, GArray **props) |
|
738 { |
|
739 GabblePropertiesMixin *mixin = GABBLE_PROPERTIES_MIXIN (obj); |
|
740 GabblePropertiesMixinClass *mixin_cls = GABBLE_PROPERTIES_MIXIN_CLASS ( |
|
741 G_OBJECT_GET_CLASS (obj)); |
|
742 GPtrArray *prop_arr; |
|
743 GValue prop_list = { 0, }; |
|
744 guint i; |
|
745 |
|
746 if (*props == NULL) |
|
747 return; |
|
748 |
|
749 if ((*props)->len == 0) |
|
750 return; |
|
751 |
|
752 prop_arr = g_ptr_array_sized_new ((*props)->len); |
|
753 |
|
754 if (DEBUGGING) |
|
755 g_message (ANSI_BOLD_ON ANSI_FG_WHITE |
|
756 "%s: emitting properties flags changed for propert%s:\n", |
|
757 G_STRFUNC, ((*props)->len > 1) ? "ies" : "y"); |
|
758 |
|
759 for (i = 0; i < (*props)->len; i++) |
|
760 { |
|
761 GValue prop_val = { 0, }; |
|
762 guint prop_id = g_array_index (*props, guint, i); |
|
763 guint prop_flags; |
|
764 |
|
765 prop_flags = mixin->properties[prop_id].flags; |
|
766 |
|
767 g_value_init (&prop_val, TP_TYPE_PROPERTY_FLAGS_STRUCT); |
|
768 g_value_take_boxed (&prop_val, |
|
769 dbus_g_type_specialized_construct (TP_TYPE_PROPERTY_FLAGS_STRUCT)); |
|
770 |
|
771 dbus_g_type_struct_set (&prop_val, |
|
772 0, prop_id, |
|
773 1, prop_flags, |
|
774 G_MAXUINT); |
|
775 |
|
776 g_ptr_array_add (prop_arr, g_value_get_boxed (&prop_val)); |
|
777 |
|
778 if (DEBUGGING) |
|
779 { |
|
780 gchar *str_flags = property_flags_to_string (prop_flags); |
|
781 |
|
782 g_message (" %s's flags now: %s\n", |
|
783 mixin_cls->signatures[prop_id].name, str_flags); |
|
784 |
|
785 g_free (str_flags); |
|
786 } |
|
787 } |
|
788 |
|
789 if (DEBUGGING) |
|
790 { |
|
791 g_message (ANSI_RESET); |
|
792 fflush (stdout); |
|
793 } |
|
794 |
|
795 g_signal_emit (obj, mixin_cls->property_flags_changed_signal_id, 0, prop_arr); |
|
796 |
|
797 g_value_init (&prop_list, TP_TYPE_PROPERTY_FLAGS_LIST); |
|
798 g_value_take_boxed (&prop_list, prop_arr); |
|
799 g_value_unset (&prop_list); |
|
800 |
|
801 g_array_free (*props, TRUE); |
|
802 *props = NULL; |
|
803 } |
|
804 |
|
805 gboolean |
|
806 gabble_properties_mixin_is_readable (GObject *obj, guint prop_id) |
|
807 { |
|
808 GabblePropertiesMixin *mixin = GABBLE_PROPERTIES_MIXIN (obj); |
|
809 GabblePropertiesMixinClass *mixin_cls = GABBLE_PROPERTIES_MIXIN_CLASS ( |
|
810 G_OBJECT_GET_CLASS (obj)); |
|
811 |
|
812 if (prop_id >= mixin_cls->num_props) |
|
813 return FALSE; |
|
814 |
|
815 return ((mixin->properties[prop_id].flags & TP_PROPERTY_FLAG_READ) != 0); |
|
816 } |
|
817 |
|
818 gboolean |
|
819 gabble_properties_mixin_is_writable (GObject *obj, guint prop_id) |
|
820 { |
|
821 GabblePropertiesMixin *mixin = GABBLE_PROPERTIES_MIXIN (obj); |
|
822 GabblePropertiesMixinClass *mixin_cls = GABBLE_PROPERTIES_MIXIN_CLASS ( |
|
823 G_OBJECT_GET_CLASS (obj)); |
|
824 |
|
825 if (prop_id >= mixin_cls->num_props) |
|
826 return FALSE; |
|
827 |
|
828 return ((mixin->properties[prop_id].flags & TP_PROPERTY_FLAG_WRITE) != 0); |
|
829 } |
|
830 |