~ubuntu-branches/ubuntu/wily/lua-lgi/wily

« back to all changes in this revision

Viewing changes to lgi/override/GObject-Value.lua

  • Committer: Package Import Robot
  • Author(s): Enrico Tassi
  • Date: 2012-04-02 13:16:07 UTC
  • Revision ID: package-import@ubuntu.com-20120402131607-qcd5l8n9rx8lsq59
Tags: upstream-0.4+29+g74cbbb1
ImportĀ upstreamĀ versionĀ 0.4+29+g74cbbb1

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
------------------------------------------------------------------------------
 
2
--
 
3
--  LGI GObject.Value support.
 
4
--
 
5
--  Copyright (c) 2010, 2011 Pavel Holejsovsky
 
6
--  Licensed under the MIT license:
 
7
--  http://www.opensource.org/licenses/mit-license.php
 
8
--
 
9
------------------------------------------------------------------------------
 
10
 
 
11
local assert, pairs, select, type, tostring, error =
 
12
   assert, pairs, select, type, tostring, error
 
13
local lgi = require 'lgi'
 
14
local core = require 'lgi.core'
 
15
local repo = core.repo
 
16
local gi = core.gi
 
17
local Type = repo.GObject.Type
 
18
 
 
19
-- Value is constructible from any kind of source Lua value, and the
 
20
-- type of the value can be hinted by type name.
 
21
local Value = repo.GObject.Value
 
22
local value_info = gi.GObject.Value
 
23
 
 
24
local log = lgi.log.domain('Lgi')
 
25
 
 
26
-- Workaround for incorrect annotations - g_value_set_xxx are missing
 
27
-- (allow-none) annotations in glib < 2.30.
 
28
for _, name in pairs { 'set_object', 'set_variant', 'set_string' } do
 
29
   if not value_info.methods[name].args[1].optional then
 
30
      log.message("g_value_%s() is missing (allow-none)", name)
 
31
      local setter = Value[name]
 
32
      Value._method[name] =
 
33
      function(value, val)
 
34
         if not val then Value.reset(value) else setter(value, val) end
 
35
      end
 
36
   end
 
37
end
 
38
 
 
39
-- Do not allow direct access to fields.
 
40
local value_field_gtype = Value._field.g_type
 
41
Value._field = nil
 
42
 
 
43
-- 'type' property controls gtype of the property.
 
44
Value._attribute = { gtype = {} }
 
45
function Value._attribute.gtype.get(value)
 
46
   return core.record.field(value, value_field_gtype)
 
47
end
 
48
function Value._attribute.gtype.set(value, newtype)
 
49
   local gtype = core.record.field(value, value_field_gtype)
 
50
   if gtype then
 
51
      if newtype then
 
52
         -- Try converting old value to new one.
 
53
         local dest = core.record.new(value_info)
 
54
         Value.init(dest, newtype)
 
55
         if not Value.transform(value, dest) then
 
56
            error(("GObject.Value: cannot convert `%s' to `%s'"):format(
 
57
                     gtype, core.record.field(dest, value_field_gtype)))
 
58
         end
 
59
         Value.unset(value)
 
60
         Value.init(value, newtype)
 
61
         Value.copy(dest, value)
 
62
      else
 
63
         Value.unset(value)
 
64
      end
 
65
   elseif newtype then
 
66
      -- No value was set and some is requested, so set it.
 
67
      Value.init(value, newtype)
 
68
   end
 
69
end
 
70
 
 
71
local value_marshallers = {}
 
72
for name, gtype in pairs(Type) do
 
73
   local get = Value._method['get_' .. name:lower()]
 
74
   local set = Value._method['set_' .. name:lower()]
 
75
   if get and set then
 
76
      value_marshallers[gtype] =
 
77
      function(value, params, ...)
 
78
         return (select('#', ...) > 0 and set or get)(value, ...)
 
79
      end
 
80
   end
 
81
end
 
82
 
 
83
-- Interface marshaller is the same as object marshaller.
 
84
value_marshallers[Type.INTERFACE] = value_marshallers[Type.OBJECT]
 
85
 
 
86
-- Override 'boxed' marshaller, default one marshalls to gpointer
 
87
-- instead of target boxed type.
 
88
value_marshallers[Type.BOXED] =
 
89
function(value, params, ...)
 
90
   local gtype = core.record.field(value, value_field_gtype)
 
91
   if select('#', ...) > 0 then
 
92
      Value.set_boxed(value, core.record.query((...), 'addr', gtype))
 
93
   else
 
94
      return core.record.new(gi[core.gtype(gtype)], Value.get_boxed(value))
 
95
   end
 
96
end
 
97
 
 
98
-- Override marshallers for enums and bitmaps, marshal them as strings
 
99
-- or sets of string flags.
 
100
for name, gtype in pairs { ENUM = Type.ENUM, FLAGS = Type.FLAGS } do
 
101
   local get = Value._method['get_' .. name:lower()]
 
102
   local set = Value._method['set_' .. name:lower()]
 
103
   value_marshallers[gtype] = function(value, params, ...)
 
104
      local rtype
 
105
      if select('#', ...) > 0 then
 
106
         local param = ...
 
107
         if type(param) ~= 'number' then
 
108
            rtype = core.repotype(core.record.field(value, value_field_gtype))
 
109
            param = rtype(param)
 
110
         end
 
111
         set(value, param)
 
112
      else
 
113
         rtype = core.repotype(core.record.field(value, value_field_gtype))
 
114
         return rtype[get(value)]
 
115
      end
 
116
   end
 
117
end
 
118
 
 
119
-- Create GStrv marshaller, implement it using typeinfo marshaller
 
120
-- with proper null-terminated-array-of-utf8 typeinfo 'stolen' from
 
121
-- g_shell_parse_argv().
 
122
value_marshallers[Type.STRV] = core.marshal.container(
 
123
   gi.GLib.shell_parse_argv.args[3].typeinfo)
 
124
 
 
125
-- Finds marshaller closure which can marshal type described either by
 
126
-- gtype or typeinfo/transfer combo.
 
127
function Value._method.find_marshaller(gtype, typeinfo, transfer)
 
128
   -- Check whether we can have marshaller for typeinfo, if the
 
129
   -- typeinfo is container.
 
130
   local marshaller
 
131
   if typeinfo then
 
132
      marshaller = core.marshal.container(typeinfo, transfer)
 
133
      if marshaller then return marshaller end
 
134
   end
 
135
 
 
136
   -- Special case for non-gtype records.
 
137
   if not gtype and typeinfo and typeinfo.tag == 'interface' then
 
138
      -- Workaround for GoI < 1.30; it does not know that GLib structs are
 
139
      -- boxed, so it does not assign them GType; moreover it incorrectly
 
140
      -- considers GParamSpec as GType-less struct instead of the class.
 
141
      local function marshal_record_no_gtype(value, params, ...)
 
142
         -- Check actual gtype of the real value.
 
143
         local gtype = core.record.field(value, value_field_gtype)
 
144
 
 
145
         if Type.is_a(gtype, Type.PARAM) then
 
146
            return value_marshallers[Type.PARAM](value, ...)
 
147
         end
 
148
 
 
149
         -- Find out proper getter/setter method for the value.
 
150
         local get, set
 
151
         if Type.is_a(gtype, Type.BOXED) then
 
152
            get, set = Value.get_boxed, Value.set_boxed
 
153
         else
 
154
            get, set = Value.get_pointer, Value.set_pointer
 
155
         end
 
156
 
 
157
         -- Do GValue<->record transfer.
 
158
         local record_info = typeinfo.interface
 
159
         if select('#', ...) > 0 then
 
160
            set(value, core.record.query((...), 'addr', record_info))
 
161
         else
 
162
            return core.record.new(record_info, get(value))
 
163
         end
 
164
      end
 
165
      return marshal_record_no_gtype
 
166
   end
 
167
 
 
168
   local gt = gtype
 
169
   if type(gt) == 'number' then gt = Type.name(gt) end
 
170
 
 
171
   -- Special marshaller, allowing only 'nil'.
 
172
   if not gt then return function() end end
 
173
 
 
174
   -- Find marshaller according to gtype of the value.
 
175
   while gt do
 
176
      -- Check simple and/or fundamental marshallers.
 
177
      marshaller = value_marshallers[gt] or core.marshal.fundamental(gt)
 
178
      if marshaller then return marshaller end
 
179
      gt = Type.parent(gt)
 
180
   end
 
181
   error(("GValue marshaller for `%s' not found"):format(tostring(gtype)))
 
182
end
 
183
 
 
184
-- Value 'value' property provides access to GValue's embedded data.
 
185
function Value._attribute:value(...)
 
186
   local marshaller = Value._method.find_marshaller(
 
187
      core.record.field(self, value_field_gtype))
 
188
   return marshaller(self, nil, ...)
 
189
end
 
190
 
 
191
-- Implement custom 'constructor', taking optionally two values (type
 
192
-- and value).  The reason why it is overriden is that the order of
 
193
-- initialization is important, and standard record intializer cannot
 
194
-- enforce the order.
 
195
function Value:_new(gtype, value)
 
196
   local v = core.record.new(value_info)
 
197
   if gtype then v.gtype = gtype end
 
198
   if value then v.value = value end
 
199
   return v
 
200
end