glib2 0.20.0

Sign up to get free protection for your applications and to get access to all the features.
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
+