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 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204
|
# frozen_string_literal: true
GObject.load_class :Value
module GObject
# Overrides for GValue, GObject's generic value container structure.
class Value
setup_instance_method! :init
METHOD_MAP = {
TYPE_INVALID => [:get_none, :set_none],
# TYPE_NONE is skipped
TYPE_INTERFACE => [:get_object, :set_instance_enhanced],
TYPE_CHAR => [:get_schar, :set_schar],
TYPE_UCHAR => [:get_uchar, :set_uchar],
TYPE_BOOLEAN => [:get_boolean, :set_boolean],
TYPE_INT => [:get_int, :set_int],
TYPE_UINT => [:get_uint, :set_uint],
TYPE_LONG => [:get_long, :set_long],
TYPE_ULONG => [:get_ulong, :set_ulong],
TYPE_INT64 => [:get_int64, :set_int64],
TYPE_UINT64 => [:get_uint64, :set_uint64],
TYPE_ENUM => [:get_enum_enhanced, :set_enum_enhanced],
TYPE_FLAGS => [:get_flags_enhanced, :set_flags_enhanced],
TYPE_FLOAT => [:get_float, :set_float],
TYPE_DOUBLE => [:get_double, :set_double],
TYPE_STRING => [:get_string, :set_string],
TYPE_POINTER => [:get_pointer, :set_pointer],
TYPE_BOXED => [:get_boxed, :set_boxed],
TYPE_PARAM => [:get_param, :set_param],
TYPE_OBJECT => [:get_object, :set_instance_enhanced],
TYPE_GTYPE => [:get_gtype, :set_gtype],
TYPE_VARIANT => [:get_variant, :set_variant]
}.freeze
# TODO: Give more generic name
def self.wrap_ruby_value(val)
new.tap { |gv| gv.__send__ :set_ruby_value, val }
end
def self.from(val)
case val
when self
val
else
wrap_ruby_value val
end
end
def self.for_gtype(gtype)
new.tap do |it|
it.init gtype
end
end
# TODO: Combine with wrap_ruby_value
def self.wrap_instance(instance)
new.tap do |it|
it.init GObject.type_from_instance instance
it.set_instance instance
end
end
def self.copy_value_to_pointer(value, pointer, offset = 0)
target = wrap(pointer + offset)
target.init(value.current_gtype)
Lib.g_value_copy value, target unless value.uninitialized?
end
CLASS_TO_GTYPE_MAP = {
NilClass => TYPE_INVALID,
TrueClass => TYPE_BOOLEAN,
FalseClass => TYPE_BOOLEAN,
Integer => TYPE_INT,
String => TYPE_STRING
}.freeze
# Overrides for existing Value methods
module Overrides
def set_value(val)
send set_method, val
end
alias_method :value=, :set_value
def current_gtype
struct[:g_type]
end
def current_fundamental_type
GObject.type_fundamental current_gtype
end
def current_gtype_name
GObject.type_name current_gtype
end
def get_value
value = get_value_plain
if current_fundamental_type == TYPE_BOXED
wrap_boxed value
else
value
end
end
def get_value_plain
send get_method
end
def uninitialized?
current_gtype == TYPE_INVALID
end
def init(type)
Lib.g_value_init self, type unless [TYPE_NONE, TYPE_INVALID].include? type
self
end
private
def set_ruby_value(val)
init_for_ruby_value val if uninitialized?
set_value val
end
def init_for_ruby_value(val)
return init val.class.gtype if val.class.respond_to? :gtype
CLASS_TO_GTYPE_MAP.each do |klass, type|
return init type if val.is_a? klass
end
raise "Can't handle #{val.class}"
end
def set_none(_val); end
def get_none; end
def set_instance_enhanced(val)
check_type_compatibility val if val
set_instance val
end
def set_enum_enhanced(val)
val = current_gtype_class.to_native(val, nil)
set_enum val
end
def get_enum_enhanced
current_gtype_class.wrap(get_enum)
end
def set_flags_enhanced(val)
val = current_gtype_class.to_native(val, nil)
set_flags val
end
def get_flags_enhanced
current_gtype_class.wrap(get_flags)
end
def current_gtype_class
GirFFI::Builder.build_by_gtype(current_gtype)
end
def check_type_compatibility(val)
if GObject::Value.type_compatible(GObject.type_from_instance(val), current_gtype)
return
end
raise ArgumentError, "#{val.class} is incompatible with #{current_gtype_name}"
end
def wrap_boxed(boxed)
case current_gtype
when TYPE_STRV
GLib::Strv.wrap boxed
when TYPE_HASH_TABLE
GLib::HashTable.wrap [:gpointer, :gpointer], boxed
when TYPE_ARRAY
GLib::Array.wrap nil, boxed
else
current_gtype_class.wrap(boxed) unless boxed.null?
end
end
def get_method
method_map_entry.first
end
def set_method
method_map_entry.last
end
def method_map_entry
METHOD_MAP[current_gtype] || METHOD_MAP[current_fundamental_type] ||
raise("No method map entry for '#{current_gtype_name}'")
end
end
prepend Overrides
end
end
|