-
Notifications
You must be signed in to change notification settings - Fork 60
/
Copy pathgobject.rb
133 lines (112 loc) · 3.84 KB
/
gobject.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
# This module provides an interface to the top level bits of GObject
# via ruby-ffi.
#
# Author:: John Cupitt (mailto:jcupitt@gmail.com)
# License:: MIT
require "ffi"
require "forwardable"
module GObject
# we have a number of things we need to inherit in different ways:
#
# - we want to be able to subclass GObject in Ruby in a simple way
# - the layouts of the nested structs need to inherit
# - we need to be able to cast between structs which share a base struct
# without creating new wrappers or messing up refcounting
# - we need automatic gobject refcounting
#
# the solution is to split the class into four areas which we treat
# differently:
#
# - we have a "wrapper" Ruby class to allow easy subclassing ... this has a
# @struct member which holds the actual pointer
# - we use "forwardable" to forward the various ffi methods on to the
# @struct member ... we arrange things so that subclasses do not need to
# do the forwarding themselves
# - we have two versions of the struct: a plain one which we can use for
# casting that will not change the refcounts
# - and a managed one with an unref which we just use for .new
# - we separate the struct layout into a separate module to avoid repeating
# ourselves
class GObject
extend Forwardable
extend SingleForwardable
def_instance_delegators :@struct, :[], :to_ptr
def_single_delegators :ffi_struct, :ptr
attr_reader :references
# the layout of the GObject struct
module GObjectLayout
def self.included base
base.class_eval do
layout :g_type_instance, :pointer,
:ref_count, :uint,
:qdata, :pointer
end
end
end
# the struct with unref ... manage object lifetime with this
class ManagedStruct < FFI::ManagedStruct
include GObjectLayout
def self.release ptr
# GLib::logger.debug("GObject::GObject::ManagedStruct.release") {
# "unreffing #{ptr}"
# }
::GObject.g_object_unref ptr
end
end
# the plain struct ... cast with this
class Struct < FFI::Struct
include GObjectLayout
end
# don't allow ptr == nil, we never want to allocate a GObject struct
# ourselves, we just want to wrap GLib-allocated GObjects
#
# here we use ManagedStruct, not Struct, since this is the ref that will
# need the unref
def initialize ptr
# GLib::logger.debug("GObject::GObject.initialize") {"ptr = #{ptr}"}
@ptr = ptr
@struct = ffi_managed_struct.new ptr
# sometimes we need to keep refs across C calls ... hide them here
@references = []
end
# access to the casting struct for this class
def ffi_struct
self.class.ffi_struct
end
# get the pointer we were built from ... #to_ptr gets the pointer after we
# have wrapped it up with an auto unref
attr_reader :ptr
class << self
def ffi_struct
const_get :Struct
end
end
# access to the managed struct for this class
def ffi_managed_struct
self.class.ffi_managed_struct
end
class << self
def ffi_managed_struct
const_get :ManagedStruct
end
end
end
class GParamSpec < FFI::Struct
# the first few public fields
layout :g_type_instance, :pointer,
:name, :string,
:flags, :uint,
:value_type, :GType,
:owner_type, :GType
end
class GParamSpecPtr < FFI::Struct
layout :value, GParamSpec.ptr
end
attach_function :g_param_spec_get_blurb, [:pointer], :string
attach_function :g_object_ref, [:pointer], :void
attach_function :g_object_unref, [:pointer], :void
# we just use one gcallback type for every signal, hopefully this is OK
callback :gcallback, [:pointer], :void
attach_function :g_signal_connect_data,
[:pointer, :string, :gcallback, :pointer, :pointer, :int], :long
end