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.
- data/ChangeLog +3023 -0
- data/README +28 -0
- data/Rakefile +87 -0
- data/extconf.rb +61 -0
- data/sample/bookmarkfile.rb +66 -0
- data/sample/completion.rb +45 -0
- data/sample/idle.rb +41 -0
- data/sample/iochannel.rb +44 -0
- data/sample/keyfile.rb +62 -0
- data/sample/shell.rb +36 -0
- data/sample/spawn.rb +25 -0
- data/sample/timeout.rb +28 -0
- data/sample/timeout2.rb +35 -0
- data/sample/timer.rb +40 -0
- data/sample/type-register.rb +103 -0
- data/sample/type-register2.rb +104 -0
- data/sample/utils.rb +54 -0
- data/src/glib-enum-types.c +1032 -0
- data/src/glib-enum-types.h +140 -0
- data/src/lib/glib-mkenums.rb +199 -0
- data/src/lib/glib2.rb +220 -0
- data/src/lib/mkmf-gnome2.rb +390 -0
- data/src/lib/pkg-config.rb +137 -0
- data/src/rbgcompat.h +30 -0
- data/src/rbglib.c +320 -0
- data/src/rbglib.h +96 -0
- data/src/rbglib_bookmarkfile.c +595 -0
- data/src/rbglib_completion.c +192 -0
- data/src/rbglib_convert.c +195 -0
- data/src/rbglib_error.c +95 -0
- data/src/rbglib_fileutils.c +83 -0
- data/src/rbglib_i18n.c +44 -0
- data/src/rbglib_int64.c +157 -0
- data/src/rbglib_iochannel.c +883 -0
- data/src/rbglib_keyfile.c +846 -0
- data/src/rbglib_maincontext.c +917 -0
- data/src/rbglib_mainloop.c +87 -0
- data/src/rbglib_messages.c +150 -0
- data/src/rbglib_pollfd.c +111 -0
- data/src/rbglib_shell.c +68 -0
- data/src/rbglib_source.c +190 -0
- data/src/rbglib_spawn.c +345 -0
- data/src/rbglib_threads.c +51 -0
- data/src/rbglib_timer.c +127 -0
- data/src/rbglib_unicode.c +611 -0
- data/src/rbglib_utils.c +386 -0
- data/src/rbglib_win32.c +136 -0
- data/src/rbgobj_boxed.c +251 -0
- data/src/rbgobj_closure.c +337 -0
- data/src/rbgobj_convert.c +167 -0
- data/src/rbgobj_enums.c +961 -0
- data/src/rbgobj_fundamental.c +30 -0
- data/src/rbgobj_object.c +892 -0
- data/src/rbgobj_param.c +390 -0
- data/src/rbgobj_paramspecs.c +305 -0
- data/src/rbgobj_signal.c +963 -0
- data/src/rbgobj_strv.c +61 -0
- data/src/rbgobj_type.c +851 -0
- data/src/rbgobj_typeinstance.c +121 -0
- data/src/rbgobj_typeinterface.c +148 -0
- data/src/rbgobj_typemodule.c +66 -0
- data/src/rbgobj_typeplugin.c +49 -0
- data/src/rbgobj_value.c +313 -0
- data/src/rbgobj_valuearray.c +59 -0
- data/src/rbgobj_valuetypes.c +298 -0
- data/src/rbgobject.c +406 -0
- data/src/rbgobject.h +265 -0
- data/src/rbgprivate.h +88 -0
- data/src/rbgutil.c +222 -0
- data/src/rbgutil.h +82 -0
- data/src/rbgutil_callback.c +231 -0
- data/test/glib-test-init.rb +6 -0
- data/test/glib-test-utils.rb +12 -0
- data/test/run-test.rb +25 -0
- data/test/test_enum.rb +99 -0
- data/test/test_file_utils.rb +15 -0
- data/test/test_glib2.rb +120 -0
- data/test/test_iochannel.rb +275 -0
- data/test/test_key_file.rb +38 -0
- data/test/test_mkenums.rb +25 -0
- data/test/test_signal.rb +20 -0
- data/test/test_timeout.rb +28 -0
- data/test/test_unicode.rb +369 -0
- data/test/test_utils.rb +37 -0
- data/test/test_win32.rb +13 -0
- 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
|
+
}
|
data/src/rbgobj_object.c
ADDED
@@ -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", ¶ms_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", ¶ms_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
|
+
|