glib2 0.20.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (86) hide show
  1. data/ChangeLog +3023 -0
  2. data/README +28 -0
  3. data/Rakefile +87 -0
  4. data/extconf.rb +61 -0
  5. data/sample/bookmarkfile.rb +66 -0
  6. data/sample/completion.rb +45 -0
  7. data/sample/idle.rb +41 -0
  8. data/sample/iochannel.rb +44 -0
  9. data/sample/keyfile.rb +62 -0
  10. data/sample/shell.rb +36 -0
  11. data/sample/spawn.rb +25 -0
  12. data/sample/timeout.rb +28 -0
  13. data/sample/timeout2.rb +35 -0
  14. data/sample/timer.rb +40 -0
  15. data/sample/type-register.rb +103 -0
  16. data/sample/type-register2.rb +104 -0
  17. data/sample/utils.rb +54 -0
  18. data/src/glib-enum-types.c +1032 -0
  19. data/src/glib-enum-types.h +140 -0
  20. data/src/lib/glib-mkenums.rb +199 -0
  21. data/src/lib/glib2.rb +220 -0
  22. data/src/lib/mkmf-gnome2.rb +390 -0
  23. data/src/lib/pkg-config.rb +137 -0
  24. data/src/rbgcompat.h +30 -0
  25. data/src/rbglib.c +320 -0
  26. data/src/rbglib.h +96 -0
  27. data/src/rbglib_bookmarkfile.c +595 -0
  28. data/src/rbglib_completion.c +192 -0
  29. data/src/rbglib_convert.c +195 -0
  30. data/src/rbglib_error.c +95 -0
  31. data/src/rbglib_fileutils.c +83 -0
  32. data/src/rbglib_i18n.c +44 -0
  33. data/src/rbglib_int64.c +157 -0
  34. data/src/rbglib_iochannel.c +883 -0
  35. data/src/rbglib_keyfile.c +846 -0
  36. data/src/rbglib_maincontext.c +917 -0
  37. data/src/rbglib_mainloop.c +87 -0
  38. data/src/rbglib_messages.c +150 -0
  39. data/src/rbglib_pollfd.c +111 -0
  40. data/src/rbglib_shell.c +68 -0
  41. data/src/rbglib_source.c +190 -0
  42. data/src/rbglib_spawn.c +345 -0
  43. data/src/rbglib_threads.c +51 -0
  44. data/src/rbglib_timer.c +127 -0
  45. data/src/rbglib_unicode.c +611 -0
  46. data/src/rbglib_utils.c +386 -0
  47. data/src/rbglib_win32.c +136 -0
  48. data/src/rbgobj_boxed.c +251 -0
  49. data/src/rbgobj_closure.c +337 -0
  50. data/src/rbgobj_convert.c +167 -0
  51. data/src/rbgobj_enums.c +961 -0
  52. data/src/rbgobj_fundamental.c +30 -0
  53. data/src/rbgobj_object.c +892 -0
  54. data/src/rbgobj_param.c +390 -0
  55. data/src/rbgobj_paramspecs.c +305 -0
  56. data/src/rbgobj_signal.c +963 -0
  57. data/src/rbgobj_strv.c +61 -0
  58. data/src/rbgobj_type.c +851 -0
  59. data/src/rbgobj_typeinstance.c +121 -0
  60. data/src/rbgobj_typeinterface.c +148 -0
  61. data/src/rbgobj_typemodule.c +66 -0
  62. data/src/rbgobj_typeplugin.c +49 -0
  63. data/src/rbgobj_value.c +313 -0
  64. data/src/rbgobj_valuearray.c +59 -0
  65. data/src/rbgobj_valuetypes.c +298 -0
  66. data/src/rbgobject.c +406 -0
  67. data/src/rbgobject.h +265 -0
  68. data/src/rbgprivate.h +88 -0
  69. data/src/rbgutil.c +222 -0
  70. data/src/rbgutil.h +82 -0
  71. data/src/rbgutil_callback.c +231 -0
  72. data/test/glib-test-init.rb +6 -0
  73. data/test/glib-test-utils.rb +12 -0
  74. data/test/run-test.rb +25 -0
  75. data/test/test_enum.rb +99 -0
  76. data/test/test_file_utils.rb +15 -0
  77. data/test/test_glib2.rb +120 -0
  78. data/test/test_iochannel.rb +275 -0
  79. data/test/test_key_file.rb +38 -0
  80. data/test/test_mkenums.rb +25 -0
  81. data/test/test_signal.rb +20 -0
  82. data/test/test_timeout.rb +28 -0
  83. data/test/test_unicode.rb +369 -0
  84. data/test/test_utils.rb +37 -0
  85. data/test/test_win32.rb +13 -0
  86. metadata +165 -0
@@ -0,0 +1,30 @@
1
+ /* -*- c-file-style: "ruby"; indent-tabs-mode: nil -*- */
2
+ /************************************************
3
+
4
+ rbgobj_fundamental.c -
5
+
6
+ Copyright (C) 2007 Ruby-GNOME2 Project Team
7
+ ************************************************/
8
+
9
+ #include "rbgobject.h"
10
+ #include "rbgprivate.h"
11
+
12
+ static GList *tables = NULL;
13
+
14
+ void
15
+ rbgobj_fund_define_fundamental(RGFundamental *fundamental)
16
+ {
17
+ RGConvertTable *table;
18
+
19
+ table = g_new0(RGConvertTable, 1);
20
+ table->type = fundamental->type;
21
+ table->get_superclass = fundamental->get_superclass;
22
+ table->type_init_hook = fundamental->type_init_hook;
23
+ table->rvalue2gvalue = fundamental->rvalue2gvalue;
24
+ table->gvalue2rvalue = fundamental->gvalue2rvalue;
25
+ table->initialize = fundamental->initialize;
26
+ table->robj2instance = fundamental->robj2instance;
27
+ table->instance2robj = fundamental->instance2robj;
28
+ RG_DEF_CONVERSION(table);
29
+ tables = g_list_prepend(tables, table);
30
+ }
@@ -0,0 +1,892 @@
1
+ /* -*- c-file-style: "ruby"; indent-tabs-mode: nil -*- */
2
+ /**********************************************************************
3
+
4
+ rbgobj_object.c -
5
+
6
+ $Author: sakai $
7
+ $Date: 2007/07/19 22:03:44 $
8
+
9
+ Copyright (C) 2002-2004 Ruby-GNOME2 Project Team
10
+ Copyright (C) 2002-2003 Masahiro Sakai
11
+
12
+ This file is derived from rbgtkobject.c in Ruby/Gtk distribution.
13
+ rbgtkobject.c -
14
+ Copyright (C) 1998-2000 Yukihiro Matsumoto,
15
+ Daisuke Kanda,
16
+ Hiroshi Igarashi
17
+
18
+ **********************************************************************/
19
+
20
+ #include "rbgprivate.h"
21
+
22
+ VALUE rbgobj_cObject;
23
+ static VALUE eNoPropertyError;
24
+ static GQuark RUBY_GOBJECT_OBJ_KEY;
25
+
26
+ /* deperecated */
27
+ void
28
+ rbgobj_add_abstract_but_create_instance_class(gtype)
29
+ GType gtype;
30
+ {
31
+ }
32
+
33
+ static void
34
+ weak_notify(gpointer data, GObject *where_the_object_was)
35
+ {
36
+ gobj_holder *holder = data;
37
+
38
+ rbgobj_instance_call_cinfo_free(holder->gobj);
39
+ rbgobj_invalidate_relatives(holder->self);
40
+ holder->destroyed = TRUE;
41
+
42
+ g_object_unref(holder->gobj);
43
+ holder->gobj = NULL;
44
+ }
45
+
46
+ static void
47
+ holder_mark(gobj_holder *holder)
48
+ {
49
+ if (holder->gobj && !holder->destroyed)
50
+ rbgobj_instance_call_cinfo_mark(holder->gobj);
51
+ }
52
+
53
+ static void
54
+ holder_free(gobj_holder *holder)
55
+ {
56
+ if (holder->gobj) {
57
+ if (!holder->destroyed) {
58
+ g_object_set_qdata(holder->gobj, RUBY_GOBJECT_OBJ_KEY, NULL);
59
+ g_object_weak_unref(holder->gobj, (GWeakNotify)weak_notify, holder);
60
+ weak_notify(holder, holder->gobj);
61
+ }
62
+ holder->gobj = NULL;
63
+ }
64
+ xfree(holder);
65
+ }
66
+
67
+ static VALUE
68
+ gobj_s_allocate(klass)
69
+ VALUE klass;
70
+ {
71
+ gobj_holder* holder;
72
+ VALUE result;
73
+
74
+ result = Data_Make_Struct(klass, gobj_holder, holder_mark, holder_free, holder);
75
+ holder->self = result;
76
+ holder->gobj = NULL;
77
+ holder->cinfo = NULL;
78
+ holder->destroyed = FALSE;
79
+
80
+ return result;
81
+ }
82
+
83
+ /* deprecated */
84
+ VALUE
85
+ rbgobj_create_object(klass)
86
+ VALUE klass;
87
+ {
88
+ return gobj_s_allocate(klass);
89
+ }
90
+
91
+ void
92
+ rbgobj_gobject_initialize(obj, cobj)
93
+ VALUE obj;
94
+ gpointer cobj;
95
+ {
96
+ gobj_holder* holder = g_object_get_qdata((GObject*)cobj, RUBY_GOBJECT_OBJ_KEY);
97
+ if (holder)
98
+ rb_raise(rb_eRuntimeError, "ruby wrapper for this GObject* already exists.");
99
+ Data_Get_Struct(obj, gobj_holder, holder);
100
+ holder->cinfo = RVAL2CINFO(obj);
101
+ holder->gobj = (GObject*)cobj;
102
+ holder->destroyed = FALSE;
103
+
104
+ g_object_set_qdata((GObject*)cobj, RUBY_GOBJECT_OBJ_KEY, (gpointer)holder);
105
+ g_object_weak_ref((GObject*)cobj, (GWeakNotify)weak_notify, holder);
106
+ {
107
+ GType t1 = G_TYPE_FROM_INSTANCE(cobj);
108
+ GType t2 = CLASS2GTYPE(CLASS_OF(obj));
109
+
110
+ if (t1 != t2) {
111
+ if (!g_type_is_a(t1, t2))
112
+ rb_raise(rb_eTypeError, "%s is not subtype of %s",
113
+ g_type_name(t1), g_type_name(t2));
114
+ }
115
+ }
116
+ }
117
+
118
+ VALUE
119
+ rbgobj_get_ruby_object_from_gobject(GObject* gobj, gboolean alloc)
120
+ {
121
+ gobj_holder *holder;
122
+
123
+ holder = g_object_get_qdata(gobj, RUBY_GOBJECT_OBJ_KEY);
124
+ if (holder) {
125
+ return holder->self;
126
+ } else if (alloc) {
127
+ VALUE obj;
128
+
129
+ obj = gobj_s_allocate(GTYPE2CLASS(G_OBJECT_TYPE(gobj)));
130
+ gobj = g_object_ref(gobj);
131
+ rbgobj_gobject_initialize(obj, (gpointer)gobj);
132
+ return obj;
133
+ } else {
134
+ return Qnil;
135
+ }
136
+ }
137
+
138
+ GObject*
139
+ rbgobj_get_gobject(obj)
140
+ VALUE obj;
141
+ {
142
+ gobj_holder* holder;
143
+
144
+ if (!RVAL2CBOOL(rb_obj_is_kind_of(obj, GTYPE2CLASS(G_TYPE_OBJECT))))
145
+ rb_raise(rb_eTypeError, "not a GLib::Object");
146
+
147
+ Data_Get_Struct(obj, gobj_holder, holder);
148
+
149
+ if (holder->destroyed)
150
+ rb_raise(rb_eTypeError, "destroyed GLib::Object");
151
+ if (!holder->gobj)
152
+ rb_raise(rb_eTypeError, "uninitialize GLib::Object");
153
+
154
+ return holder->gobj;
155
+ }
156
+
157
+ static VALUE
158
+ dummy_init(argc, argv, self)
159
+ int argc;
160
+ VALUE *argv;
161
+ VALUE self;
162
+ {
163
+ GType gtype = CLASS2GTYPE(CLASS_OF(self));
164
+ if (G_TYPE_IS_ABSTRACT(gtype))
165
+ rb_raise(rb_eTypeError, "initializing abstract class");
166
+ else
167
+ return rb_call_super(argc, argv);
168
+ }
169
+
170
+ void
171
+ rbgobj_init_object_class(klass)
172
+ VALUE klass;
173
+ {
174
+ rbgobj_define_property_accessors(klass);
175
+ if (G_TYPE_IS_ABSTRACT(CLASS2GTYPE(klass)))
176
+ rb_define_method(klass, "initialize", dummy_init, -1);
177
+ }
178
+
179
+ /**********************************************************************/
180
+
181
+ static gboolean
182
+ is_gtkobject(gobj)
183
+ GObject* gobj;
184
+ {
185
+ static GType gtype_gtkobject = G_TYPE_INVALID;
186
+ if (!gtype_gtkobject)
187
+ gtype_gtkobject = g_type_from_name("GtkObject");
188
+ return gtype_gtkobject && g_type_is_a(G_OBJECT_TYPE(gobj), gtype_gtkobject);
189
+ }
190
+
191
+ static void
192
+ gobj_mark(gpointer ptr)
193
+ {
194
+ GObject* gobj = ptr;
195
+ guint n_properties;
196
+ GParamSpec** properties;
197
+ GValue gval = {0,};
198
+ int i;
199
+
200
+ properties = g_object_class_list_properties(G_OBJECT_GET_CLASS(gobj), &n_properties);
201
+
202
+ for (i = 0; i < n_properties; i++) {
203
+ GParamSpec* pspec = properties[i];
204
+ GType value_type = G_PARAM_SPEC_VALUE_TYPE(pspec);
205
+ if (G_TYPE_FUNDAMENTAL(value_type) != G_TYPE_OBJECT) continue;
206
+ if (!(pspec->flags & G_PARAM_READABLE)) continue;
207
+ /* FIXME: exclude types that doesn't have identity. */
208
+
209
+ {
210
+ g_value_init(&gval, value_type);
211
+ g_object_get_property(gobj, pspec->name, &gval);
212
+ rbgobj_gc_mark_gvalue(&gval);
213
+ g_value_unset(&gval);
214
+ }
215
+ }
216
+
217
+ g_free(properties);
218
+ }
219
+
220
+ static VALUE
221
+ gobj_s_gobject_new(argc, argv, self)
222
+ int argc;
223
+ VALUE* argv;
224
+ VALUE self;
225
+ {
226
+ const RGObjClassInfo* cinfo = rbgobj_lookup_class(self);
227
+ VALUE params_hash;
228
+ GObject* gobj;
229
+ VALUE result;
230
+
231
+ rb_scan_args(argc, argv, "01", &params_hash);
232
+
233
+ if (!NIL_P(params_hash))
234
+ Check_Type(params_hash, T_HASH);
235
+
236
+ if (cinfo->klass != self)
237
+ rb_raise(rb_eTypeError, "%s isn't registered class",
238
+ rb_class2name(self));
239
+
240
+ gobj = rbgobj_gobject_new(cinfo->gtype, params_hash);
241
+ result = GOBJ2RVAL(gobj);
242
+
243
+ // XXX: Ughhhhh
244
+ if (is_gtkobject(gobj)){
245
+ // We can't call gtk_object_sink() here.
246
+ // But hopefully someone will call it in the future.
247
+ //gtk_object_sink(gobj);
248
+ } else {
249
+ g_object_unref(gobj);
250
+ }
251
+
252
+ return result;
253
+ }
254
+
255
+ struct param_setup_arg {
256
+ GObjectClass* gclass;
257
+ GParameter* params;
258
+ guint param_size;
259
+ VALUE params_hash;
260
+ guint index;
261
+ };
262
+
263
+ static VALUE
264
+ _params_setup(arg, param_setup_arg)
265
+ VALUE arg;
266
+ struct param_setup_arg* param_setup_arg;
267
+ {
268
+ guint index;
269
+ VALUE name, val;
270
+ GParamSpec* pspec;
271
+
272
+ index = param_setup_arg->index;
273
+ if (index >= param_setup_arg->param_size)
274
+ rb_raise(rb_eArgError, "too many parameters");
275
+
276
+ name = rb_ary_entry(arg, 0);
277
+ val = rb_ary_entry(arg, 1);
278
+
279
+ if (SYMBOL_P(name))
280
+ param_setup_arg->params[index].name = rb_id2name(SYM2ID(name));
281
+ else
282
+ param_setup_arg->params[index].name = StringValuePtr(name);
283
+
284
+ pspec = g_object_class_find_property(
285
+ param_setup_arg->gclass,
286
+ param_setup_arg->params[index].name);
287
+ if (!pspec)
288
+ rb_raise(rb_eArgError, "No such property: %s",
289
+ param_setup_arg->params[index].name);
290
+
291
+ g_value_init(&(param_setup_arg->params[index].value),
292
+ G_PARAM_SPEC_VALUE_TYPE(pspec));
293
+ rbgobj_rvalue_to_gvalue(val, &(param_setup_arg->params[index].value));
294
+
295
+ param_setup_arg->index++;
296
+
297
+ return Qnil;
298
+ }
299
+
300
+ static VALUE
301
+ gobj_new_body(struct param_setup_arg* arg)
302
+ {
303
+ rb_iterate(rb_each, (VALUE)arg->params_hash, _params_setup, (VALUE)arg);
304
+ return (VALUE)g_object_newv(G_TYPE_FROM_CLASS(arg->gclass),
305
+ arg->param_size, arg->params);
306
+ }
307
+
308
+ static VALUE
309
+ gobj_new_ensure(struct param_setup_arg* arg)
310
+ {
311
+ int i;
312
+ g_type_class_unref(arg->gclass);
313
+ for (i = 0; i < arg->param_size; i++) {
314
+ if (G_IS_VALUE(&arg->params[i].value))
315
+ g_value_unset(&arg->params[i].value);
316
+ }
317
+ return Qnil;
318
+ }
319
+
320
+ GObject*
321
+ rbgobj_gobject_new(gtype, params_hash)
322
+ GType gtype;
323
+ VALUE params_hash;
324
+ {
325
+ GObject* result;
326
+
327
+ if (!g_type_is_a(gtype, G_TYPE_OBJECT))
328
+ rb_raise(rb_eArgError,
329
+ "type \"%s\" is not descendant of GObject",
330
+ g_type_name(gtype));
331
+
332
+ if (NIL_P(params_hash)) {
333
+ result = g_object_newv(gtype, 0, NULL);
334
+ } else {
335
+ size_t param_size;
336
+ struct param_setup_arg arg;
337
+
338
+ param_size = NUM2INT(rb_funcall(params_hash, rb_intern("length"), 0));
339
+
340
+ arg.param_size = param_size;
341
+ arg.gclass = G_OBJECT_CLASS(g_type_class_ref(gtype));
342
+ arg.params = ALLOCA_N(GParameter, param_size);
343
+ memset(arg.params, 0, sizeof(GParameter) * param_size);
344
+ arg.params_hash = params_hash;
345
+ arg.index = 0;
346
+
347
+ result = (GObject*)rb_ensure(&gobj_new_body, (VALUE)&arg,
348
+ &gobj_new_ensure, (VALUE)&arg);
349
+ }
350
+
351
+ if (!result)
352
+ rb_raise(rb_eRuntimeError, "g_object_newv failed");
353
+
354
+ return result;
355
+ }
356
+
357
+ static VALUE
358
+ gobj_s_install_property(int argc, VALUE* argv, VALUE self)
359
+ {
360
+ const RGObjClassInfo* cinfo = rbgobj_lookup_class(self);
361
+ gpointer gclass;
362
+ GParamSpec* pspec;
363
+ VALUE pspec_obj, prop_id;
364
+
365
+ if (cinfo->klass != self)
366
+ rb_raise(rb_eTypeError, "%s isn't registered class",
367
+ rb_class2name(self));
368
+
369
+ rb_scan_args(argc, argv, "11", &pspec_obj, &prop_id);
370
+ pspec = G_PARAM_SPEC(RVAL2GOBJ(pspec_obj));
371
+
372
+ gclass = g_type_class_ref(cinfo->gtype);
373
+ g_object_class_install_property(gclass,
374
+ NIL_P(prop_id) ? 1 : NUM2UINT(prop_id),
375
+ pspec);
376
+ g_type_class_unref(gclass);
377
+
378
+ /* FIXME: define accessor methods */
379
+
380
+ return Qnil;
381
+ }
382
+
383
+ static VALUE
384
+ gobj_s_property(self, property_name)
385
+ VALUE self, property_name;
386
+ {
387
+ GObjectClass* oclass;
388
+ const char* name;
389
+ GParamSpec* prop;
390
+ VALUE result;
391
+
392
+ if (SYMBOL_P(property_name))
393
+ name = rb_id2name(SYM2ID(property_name));
394
+ else
395
+ name = StringValuePtr(property_name);
396
+
397
+ oclass = g_type_class_ref(CLASS2GTYPE(self));
398
+
399
+ prop = g_object_class_find_property(oclass, name);
400
+ if (!prop){
401
+ g_type_class_unref(oclass);
402
+ rb_raise(eNoPropertyError, "No such property: %s", name);
403
+ }
404
+
405
+ result = GOBJ2RVAL(prop);
406
+ g_type_class_unref(oclass);
407
+ return result;
408
+ }
409
+
410
+ static VALUE
411
+ gobj_s_properties(int argc, VALUE* argv, VALUE self)
412
+ {
413
+ GObjectClass* oclass = g_type_class_ref(CLASS2GTYPE(self));
414
+ guint n_properties;
415
+ GParamSpec** props;
416
+ VALUE inherited_too;
417
+ VALUE ary;
418
+ int i;
419
+
420
+ if (rb_scan_args(argc, argv, "01", &inherited_too) == 0)
421
+ inherited_too = Qtrue;
422
+
423
+ props = g_object_class_list_properties(oclass, &n_properties);
424
+
425
+ ary = rb_ary_new();
426
+ for (i = 0; i < n_properties; i++){
427
+ if (RVAL2CBOOL(inherited_too)
428
+ || GTYPE2CLASS(props[i]->owner_type) == self)
429
+ rb_ary_push(ary, rb_str_new2(props[i]->name));
430
+ }
431
+ g_free(props);
432
+ g_type_class_unref(oclass);
433
+ return ary;
434
+ }
435
+
436
+ static VALUE type_to_prop_setter_table;
437
+ static VALUE type_to_prop_getter_table;
438
+
439
+ void
440
+ rbgobj_register_property_setter(gtype, name, func)
441
+ GType gtype;
442
+ const char* name;
443
+ RValueToGValueFunc func;
444
+ {
445
+ GObjectClass* oclass;
446
+ GParamSpec* pspec;
447
+
448
+ VALUE table = rb_hash_aref(type_to_prop_setter_table, INT2FIX(gtype));
449
+ if (NIL_P(table)){
450
+ table = rb_hash_new();
451
+ rb_hash_aset(type_to_prop_setter_table, INT2FIX(gtype), table);
452
+ }
453
+
454
+ oclass = g_type_class_ref(gtype);
455
+ pspec = g_object_class_find_property(oclass, name);
456
+
457
+ rb_hash_aset(table, rb_str_new2(g_param_spec_get_name(pspec)),
458
+ Data_Wrap_Struct(rb_cData, NULL, NULL, func));
459
+
460
+ g_type_class_unref(oclass);
461
+ }
462
+
463
+ void
464
+ rbgobj_register_property_getter(gtype, name, func)
465
+ GType gtype;
466
+ const char* name;
467
+ GValueToRValueFunc func;
468
+ {
469
+ GObjectClass* oclass;
470
+ GParamSpec* pspec;
471
+
472
+ VALUE table = rb_hash_aref(type_to_prop_getter_table, INT2FIX(gtype));
473
+ if (NIL_P(table)){
474
+ table = rb_hash_new();
475
+ rb_hash_aset(type_to_prop_getter_table, INT2FIX(gtype), table);
476
+ }
477
+
478
+ oclass = g_type_class_ref(gtype);
479
+ pspec = g_object_class_find_property(oclass, name);
480
+
481
+ rb_hash_aset(table, rb_str_new2(g_param_spec_get_name(pspec)),
482
+ Data_Wrap_Struct(rb_cData, NULL, NULL, func));
483
+ }
484
+
485
+ static VALUE
486
+ gobj_set_property(self, prop_name, val)
487
+ VALUE self, prop_name, val;
488
+ {
489
+ GParamSpec* pspec;
490
+ const char* name;
491
+
492
+ if (SYMBOL_P(prop_name))
493
+ name = rb_id2name(SYM2ID(prop_name));
494
+ else
495
+ name = StringValuePtr(prop_name);
496
+
497
+ pspec = g_object_class_find_property(G_OBJECT_GET_CLASS(RVAL2GOBJ(self)),
498
+ name);
499
+
500
+ if (!pspec)
501
+ rb_raise(eNoPropertyError, "No such property: %s", name);
502
+ else {
503
+ // FIXME: use rb_ensure to call g_value_unset()
504
+ RValueToGValueFunc setter = NULL;
505
+ GValue gval = {0,};
506
+
507
+ g_value_init(&gval, G_PARAM_SPEC_VALUE_TYPE(pspec));
508
+
509
+ {
510
+ VALUE table = rb_hash_aref(type_to_prop_setter_table,
511
+ INT2FIX(pspec->owner_type));
512
+ if (!NIL_P(table)){
513
+ VALUE obj = rb_hash_aref(table, rb_intern(g_param_spec_get_name(pspec)));
514
+ if (!NIL_P(obj))
515
+ Data_Get_Struct(obj, void, setter);
516
+ }
517
+ }
518
+ if (setter) {
519
+ setter(val, &gval);
520
+ } else {
521
+ rbgobj_rvalue_to_gvalue(val, &gval);
522
+ }
523
+
524
+ g_object_set_property(RVAL2GOBJ(self), name, &gval);
525
+ g_value_unset(&gval);
526
+
527
+ G_CHILD_SET(self, rb_intern(name), val);
528
+
529
+ return self;
530
+ }
531
+ }
532
+
533
+ static VALUE
534
+ gobj_get_property(self, prop_name)
535
+ VALUE self, prop_name;
536
+ {
537
+ GParamSpec* pspec;
538
+ const char* name;
539
+
540
+ if (SYMBOL_P(prop_name))
541
+ name = rb_id2name(SYM2ID(prop_name));
542
+ else
543
+ name = StringValuePtr(prop_name);
544
+
545
+ pspec = g_object_class_find_property(G_OBJECT_GET_CLASS(RVAL2GOBJ(self)),
546
+ name);
547
+
548
+ if (!pspec)
549
+ rb_raise(eNoPropertyError, "No such property: %s", name);
550
+ else {
551
+ // FIXME: use rb_ensure to call g_value_unset()
552
+ GValueToRValueFunc getter = NULL;
553
+ GValue gval = {0,};
554
+ VALUE ret;
555
+
556
+ {
557
+ VALUE table = rb_hash_aref(type_to_prop_getter_table,
558
+ INT2FIX(pspec->owner_type));
559
+ if (!NIL_P(table)){
560
+ VALUE obj = rb_hash_aref(table, CSTR2RVAL(g_param_spec_get_name(pspec)));
561
+ if (!NIL_P(obj))
562
+ Data_Get_Struct(obj, void, getter);
563
+ }
564
+ }
565
+
566
+ g_value_init(&gval, G_PARAM_SPEC_VALUE_TYPE(pspec));
567
+ g_object_get_property(RVAL2GOBJ(self), name, &gval);
568
+
569
+ ret = getter ? getter(&gval) : GVAL2RVAL(&gval);
570
+ g_value_unset(&gval);
571
+
572
+ G_CHILD_SET(self, rb_intern(name), ret);
573
+
574
+ return ret;
575
+ }
576
+ }
577
+
578
+ static VALUE gobj_thaw_notify(VALUE self);
579
+
580
+ static VALUE
581
+ gobj_freeze_notify(self)
582
+ VALUE self;
583
+ {
584
+ g_object_freeze_notify(RVAL2GOBJ(self));
585
+ if (rb_block_given_p()) {
586
+ return rb_ensure(rb_yield, self, gobj_thaw_notify, self);
587
+ }
588
+ return self;
589
+ }
590
+
591
+ static VALUE
592
+ gobj_notify(self, property_name)
593
+ VALUE self, property_name;
594
+ {
595
+ g_object_notify(RVAL2GOBJ(self), StringValuePtr(property_name));
596
+ return self;
597
+ }
598
+
599
+ static VALUE
600
+ gobj_thaw_notify(self)
601
+ VALUE self;
602
+ {
603
+ g_object_thaw_notify(RVAL2GOBJ(self));
604
+ return self;
605
+ }
606
+
607
+ static VALUE
608
+ gobj_is_destroyed(self)
609
+ VALUE self;
610
+ {
611
+ gobj_holder* holder;
612
+
613
+ if (!RVAL2CBOOL(rb_obj_is_kind_of(self, GTYPE2CLASS(G_TYPE_OBJECT))))
614
+ rb_raise(rb_eTypeError, "not a GLib::Object");
615
+
616
+ Data_Get_Struct(self, gobj_holder, holder);
617
+
618
+ return CBOOL2RVAL(holder->destroyed);
619
+ }
620
+
621
+ static VALUE
622
+ gobj_inspect(self)
623
+ VALUE self;
624
+ {
625
+ gobj_holder* holder;
626
+ const char *class_name;
627
+ char *s;
628
+ VALUE result;
629
+
630
+ Data_Get_Struct(self, gobj_holder, holder);
631
+
632
+ class_name = rb_class2name(CLASS_OF(self));
633
+ if (!holder->destroyed)
634
+ s = g_strdup_printf("#<%s:%p ptr=%p>", class_name, (void *)self,
635
+ holder->gobj);
636
+ else
637
+ s = g_strdup_printf("#<%s:%p destroyed>", class_name, (void *)self);
638
+
639
+ result = rb_str_new2(s);
640
+ g_free(s);
641
+
642
+ return result;
643
+ }
644
+
645
+ static VALUE
646
+ gobj_initialize(argc, argv, self)
647
+ int argc;
648
+ VALUE *argv;
649
+ VALUE self;
650
+ {
651
+ VALUE params_hash;
652
+ GObject* gobj;
653
+
654
+ rb_scan_args(argc, argv, "01", &params_hash);
655
+
656
+ if (!NIL_P(params_hash))
657
+ Check_Type(params_hash, T_HASH);
658
+
659
+ gobj = rbgobj_gobject_new(RVAL2GTYPE(self), params_hash);
660
+
661
+ if (is_gtkobject(gobj)){
662
+ gobj = g_object_ref(gobj);
663
+ // We can't call gtk_object_sink() here.
664
+ // But hopefully someone will call it in the future.
665
+ //gtk_object_sink(gobj);
666
+ }
667
+
668
+ G_INITIALIZE(self, gobj);
669
+ return Qnil;
670
+ }
671
+
672
+ static VALUE
673
+ gobj_ref_count(self)
674
+ VALUE self;
675
+ {
676
+ gobj_holder* holder;
677
+ Data_Get_Struct(self, gobj_holder, holder);
678
+ return INT2NUM(holder->gobj ? holder->gobj->ref_count : 0);
679
+ }
680
+
681
+ /**********************************************************************/
682
+
683
+ static VALUE proc_mod_eval;
684
+ static GQuark q_ruby_setter;
685
+ static GQuark q_ruby_getter;
686
+
687
+ // FIXME: use rb_protect
688
+ static void
689
+ get_prop_func(GObject* object,
690
+ guint property_id,
691
+ GValue* value,
692
+ GParamSpec* pspec)
693
+ {
694
+ ID ruby_getter = (ID)g_param_spec_get_qdata(pspec, q_ruby_getter);
695
+ if (!ruby_getter) {
696
+ gchar* name = g_strdup(g_param_spec_get_name(pspec));
697
+ gchar* p;
698
+ for (p = name; *p; p++) {
699
+ if (*p == '-')
700
+ *p = '_';
701
+ }
702
+ ruby_getter = rb_intern(name);
703
+ g_param_spec_set_qdata(pspec, q_ruby_getter, (gpointer)ruby_getter);
704
+ g_free(name);
705
+ }
706
+
707
+ {
708
+ VALUE ret = rb_funcall(GOBJ2RVAL(object), ruby_getter, 0);
709
+ rbgobj_rvalue_to_gvalue(ret, value);
710
+ }
711
+ }
712
+
713
+ // FIXME: use rb_protect
714
+ static void
715
+ set_prop_func(GObject* object,
716
+ guint property_id,
717
+ const GValue* value,
718
+ GParamSpec* pspec)
719
+ {
720
+ ID ruby_setter = (ID)g_param_spec_get_qdata(pspec, q_ruby_setter);
721
+ if (!ruby_setter) {
722
+ gchar* name = g_strconcat(g_param_spec_get_name(pspec), "=", NULL);
723
+ gchar* p;
724
+ for (p = name; *p; p++) {
725
+ if (*p == '-')
726
+ *p = '_';
727
+ }
728
+ ruby_setter = rb_intern(name);
729
+ g_param_spec_set_qdata(pspec, q_ruby_setter, (gpointer)ruby_setter);
730
+ g_free(name);
731
+ }
732
+
733
+ rb_funcall(GOBJ2RVAL(object), ruby_setter, 1, GVAL2RVAL(value));
734
+ }
735
+
736
+ // FIXME: use rb_protect
737
+ static void
738
+ class_init_func(gpointer g_class_, gpointer class_data)
739
+ {
740
+ GObjectClass* g_class = G_OBJECT_CLASS(g_class_);
741
+
742
+ g_class->set_property = set_prop_func;
743
+ g_class->get_property = get_prop_func;
744
+
745
+ #if 0
746
+ VALUE class_init_proc = (VALUE)class_data;
747
+ rb_funcall(proc_mod_eval, rb_intern("call"), 2,
748
+ GTYPE2CLASS(G_TYPE_FROM_CLASS(g_class)), class_init_proc);
749
+ #endif
750
+ }
751
+
752
+ static VALUE
753
+ type_register(int argc, VALUE* argv, VALUE self)
754
+ {
755
+ VALUE type_name, flags;
756
+ volatile VALUE class_init_proc = Qnil;
757
+ GType parent_type;
758
+ GTypeInfo* info;
759
+
760
+ rb_scan_args(argc, argv, "03", &type_name, &info, &flags);
761
+
762
+ {
763
+ const RGObjClassInfo* cinfo = rbgobj_lookup_class(self);
764
+ if (cinfo->klass == self)
765
+ rb_raise(rb_eTypeError, "already registered");
766
+ }
767
+
768
+ {
769
+ VALUE superclass = rb_funcall(self, rb_intern("superclass"), 0);
770
+ const RGObjClassInfo* cinfo = rbgobj_lookup_class(superclass);
771
+ if (cinfo->klass != superclass)
772
+ rb_raise(rb_eTypeError, "super class must be registered to GLib");
773
+ parent_type = cinfo->gtype;
774
+ }
775
+
776
+ if (NIL_P(type_name)) {
777
+ VALUE s = rb_funcall(self, rb_intern("name"), 0);
778
+
779
+ if (strlen(StringValuePtr(s)) == 0)
780
+ rb_raise(rb_eTypeError, "can't determine type name");
781
+
782
+ type_name = rb_funcall(
783
+ rb_eval_string("lambda{|x| x.gsub(/::/,'') }"),
784
+ rb_intern("call"), 1, s);
785
+ }
786
+
787
+ {
788
+ GTypeQuery query;
789
+ g_type_query(parent_type, &query);
790
+
791
+ info = g_new0(GTypeInfo, 1);
792
+ info->class_size = query.class_size;
793
+ info->base_init = NULL;
794
+ info->base_finalize = NULL;
795
+ info->class_init = class_init_func;
796
+ info->class_finalize = NULL;
797
+ info->class_data = (gpointer)class_init_proc;
798
+ info->instance_size = query.instance_size;
799
+ info->n_preallocs = 0;
800
+ info->instance_init = NULL;
801
+ info->value_table = NULL;
802
+ }
803
+
804
+ {
805
+ GType type = g_type_register_static(parent_type,
806
+ StringValuePtr(type_name),
807
+ info,
808
+ NIL_P(flags) ? 0 : NUM2INT(flags));
809
+ G_RELATIVE(self, class_init_proc);
810
+
811
+ rbgobj_register_class(self, type, TRUE, TRUE);
812
+
813
+ {
814
+ RGObjClassInfo* cinfo = (RGObjClassInfo*)rbgobj_lookup_class(self);
815
+ cinfo->flags |= RBGOBJ_DEFINED_BY_RUBY;
816
+ }
817
+
818
+ {
819
+ GType parent = g_type_parent(type);
820
+ const RGObjClassInfo* cinfo = GTYPE2CINFO(parent);
821
+ VALUE m = rb_define_module_under(self, RubyGObjectHookModule);
822
+
823
+ if (! (cinfo->flags & RBGOBJ_DEFINED_BY_RUBY)) {
824
+ rb_define_method(m, "initialize", gobj_initialize, -1);
825
+ }
826
+
827
+ rb_include_module(self, m);
828
+ }
829
+
830
+ return Qnil;
831
+ }
832
+ }
833
+
834
+ static void
835
+ Init_gobject_subclass()
836
+ {
837
+ VALUE cGObject = GTYPE2CLASS(G_TYPE_OBJECT);
838
+ rb_define_singleton_method(cGObject, "type_register", type_register, -1);
839
+
840
+ rb_global_variable(&proc_mod_eval);
841
+ proc_mod_eval = rb_eval_string("lambda{|obj,proc| obj.module_eval(&proc)}");
842
+ }
843
+
844
+ /**********************************************************************/
845
+
846
+ void
847
+ Init_gobject_gobject()
848
+ {
849
+ VALUE cGObject;
850
+
851
+ rbgobj_cObject = G_DEF_CLASS_WITH_GC_FUNC(G_TYPE_OBJECT, "Object", mGLib,
852
+ gobj_mark, NULL);
853
+ cGObject = rbgobj_cObject;
854
+
855
+ #ifdef G_TYPE_INITIALLY_UNOWNED
856
+ G_DEF_CLASS(G_TYPE_INITIALLY_UNOWNED, "InitiallyUnowned", mGLib);
857
+ #endif
858
+
859
+ RUBY_GOBJECT_OBJ_KEY = g_quark_from_static_string("__ruby_gobject_object__");
860
+
861
+ rb_define_alloc_func(cGObject, (VALUE(*)_((VALUE)))gobj_s_allocate);
862
+ rb_define_singleton_method(cGObject, "new!", gobj_s_gobject_new, -1);
863
+
864
+ rb_define_singleton_method(cGObject, "property", &gobj_s_property, 1);
865
+ rb_define_singleton_method(cGObject, "properties", &gobj_s_properties, -1);
866
+ rb_define_singleton_method(cGObject, "install_property", gobj_s_install_property, -1);
867
+ q_ruby_getter = g_quark_from_static_string("__ruby_getter");
868
+ q_ruby_setter = g_quark_from_static_string("__ruby_setter");
869
+
870
+ rb_define_method(cGObject, "set_property", gobj_set_property, 2);
871
+ rb_define_method(cGObject, "get_property", gobj_get_property, 1);
872
+ rb_define_method(cGObject, "freeze_notify", gobj_freeze_notify, 0);
873
+ rb_undef_method(cGObject, "notify");
874
+ rb_define_method(cGObject, "notify", gobj_notify, 1);
875
+ rb_define_method(cGObject, "thaw_notify", gobj_thaw_notify, 0);
876
+ rb_define_method(cGObject, "destroyed?", gobj_is_destroyed, 0);
877
+
878
+ rb_define_method(cGObject, "initialize", gobj_initialize, -1);
879
+ rb_define_method(cGObject, "ref_count", gobj_ref_count, 0); /* for debugging */
880
+ rb_define_method(cGObject, "inspect", gobj_inspect, 0);
881
+
882
+ eNoPropertyError = rb_define_class_under(mGLib, "NoPropertyError",
883
+ rb_eNameError);
884
+
885
+ rb_global_variable(&type_to_prop_setter_table);
886
+ rb_global_variable(&type_to_prop_getter_table);
887
+ type_to_prop_setter_table = rb_hash_new();
888
+ type_to_prop_getter_table = rb_hash_new();
889
+
890
+ Init_gobject_subclass();
891
+ }
892
+