Module: Qt::ObjectWrapper

Defined in:
lib/qt/object_wrapper.rb

Overview

Wrap native QObject-derived pointers into generated Ruby wrapper instances.

Defined Under Namespace

Modules: ConstructorCacheHook

Class Method Summary collapse

Class Method Details

.cache_wrapper(wrapper) ⇒ Object



97
98
99
100
101
102
# File 'lib/qt/object_wrapper.rb', line 97

def cache_wrapper(wrapper)
  pointer = wrapper.handle
  wrapper_cache[pointer.address] = wrapper
  ensure_destroy_hook(wrapper, pointer)
  wrapper
end

.cached_wrapper_for(pointer) ⇒ Object



80
81
82
# File 'lib/qt/object_wrapper.rb', line 80

def cached_wrapper_for(pointer)
  wrapper_cache[pointer.address]
end

.candidate_wrapper_classes(expected_qt_class) ⇒ Object



38
39
40
41
42
43
44
45
46
47
# File 'lib/qt/object_wrapper.rb', line 38

def candidate_wrapper_classes(expected_qt_class)
  normalized_qt_class = normalize_expected_qt_class(expected_qt_class)
  @candidate_wrapper_classes ||= {}
  @candidate_wrapper_classes[normalized_qt_class] ||= begin
    base = fallback_wrapper_class(normalized_qt_class)
    wrappers = qobject_wrapper_classes
    wrappers = wrappers.select { |klass| klass <= base } if base
    wrappers.sort_by { |klass| -inheritance_depth(klass) }
  end
end

.destroy_hook_addressesObject



131
132
133
# File 'lib/qt/object_wrapper.rb', line 131

def destroy_hook_addresses
  @destroy_hook_addresses ||= {}
end

.ensure_destroy_hook(wrapper, pointer) ⇒ Object



135
136
137
138
139
140
141
142
143
144
145
146
147
148
# File 'lib/qt/object_wrapper.rb', line 135

def ensure_destroy_hook(wrapper, pointer)
  address = pointer.address
  return if destroy_hook_addresses[address]

  destroy_hook_addresses[address] = true
  Qt::EventRuntime.on_internal_signal(pointer, 'destroyed()') do |_payload|
    destroy_hook_addresses.delete(address)
    Qt::EventRuntime.clear_signal_registrations_for_address(address)
    invalidate_cached_wrapper(address, wrapper)
  end
rescue StandardError
  destroy_hook_addresses.delete(address)
  raise
end

.fallback_wrapper_class(expected_qt_class) ⇒ Object



60
61
62
63
64
65
66
67
68
69
70
71
72
# File 'lib/qt/object_wrapper.rb', line 60

def fallback_wrapper_class(expected_qt_class)
  normalized_qt_class = normalize_expected_qt_class(expected_qt_class)
  return nil unless normalized_qt_class
  return nil unless Qt.const_defined?(normalized_qt_class, false)

  klass = Qt.const_get(normalized_qt_class, false)
  return nil unless klass.is_a?(Class)
  return nil unless klass.const_defined?(:QT_CLASS, false)

  klass
rescue NameError
  nil
end

.inheritance_depth(klass) ⇒ Object



150
151
152
153
154
155
156
157
158
# File 'lib/qt/object_wrapper.rb', line 150

def inheritance_depth(klass)
  depth = 0
  current = klass
  while current.is_a?(Class)
    depth += 1
    current = current.superclass
  end
  depth
end

.install_constructor_cache_hooks!Object



118
119
120
121
122
123
124
125
# File 'lib/qt/object_wrapper.rb', line 118

def install_constructor_cache_hooks!
  qobject_wrapper_classes.each do |klass|
    next if klass.instance_variable_defined?(:@__qt_object_wrapper_constructor_hook_installed)

    klass.prepend(ConstructorCacheHook)
    klass.instance_variable_set(:@__qt_object_wrapper_constructor_hook_installed, true)
  end
end

.instantiate_wrapper(klass, pointer) ⇒ Object



74
75
76
77
78
# File 'lib/qt/object_wrapper.rb', line 74

def instantiate_wrapper(klass, pointer)
  wrapped = klass.allocate
  wrapped.instance_variable_set(:@handle, pointer)
  wrapped
end

.invalidate_cached_wrapper(pointer_or_address, expected_wrapper = nil) ⇒ Object



104
105
106
107
108
109
110
111
# File 'lib/qt/object_wrapper.rb', line 104

def invalidate_cached_wrapper(pointer_or_address, expected_wrapper = nil)
  address = pointer_or_address.is_a?(Integer) ? pointer_or_address : pointer_or_address.address
  cached = wrapper_cache[address]
  return unless cached
  return if expected_wrapper && !cached.equal?(expected_wrapper)

  wrapper_cache.delete(address)
end

.normalize_expected_qt_class(expected_qt_class) ⇒ Object



164
165
166
167
168
169
170
171
172
173
174
# File 'lib/qt/object_wrapper.rb', line 164

def normalize_expected_qt_class(expected_qt_class)
  return nil if expected_qt_class.nil?

  value = expected_qt_class.to_s.strip
  return nil if value.empty?

  value = value.delete_prefix('Qt::')
  return nil unless value.match?(/\A[A-Z]\w*\z/)

  value
end

.null_pointer?(pointer) ⇒ Boolean

Returns:

  • (Boolean)


28
29
30
# File 'lib/qt/object_wrapper.rb', line 28

def null_pointer?(pointer)
  pointer.nil? || (pointer.respond_to?(:null?) && pointer.null?)
end

.qobject_wrapper?(klass) ⇒ Boolean

Returns:

  • (Boolean)


160
161
162
# File 'lib/qt/object_wrapper.rb', line 160

def qobject_wrapper?(klass)
  klass.is_a?(Class) && klass <= Qt::QObject
end

.qobject_wrapper_classesObject



49
50
51
52
53
54
55
56
57
58
# File 'lib/qt/object_wrapper.rb', line 49

def qobject_wrapper_classes
  Qt.constants(false).filter_map do |const_name|
    klass = Qt.const_get(const_name, false)
    next unless klass.is_a?(Class)
    next unless klass.const_defined?(:QT_CLASS, false)
    next unless klass <= Qt::QObject

    klass
  end
end

.register_wrapper(wrapper) ⇒ Object



84
85
86
87
88
89
90
91
92
93
94
95
# File 'lib/qt/object_wrapper.rb', line 84

def register_wrapper(wrapper)
  return wrapper unless wrapper.respond_to?(:handle)

  pointer = wrapper.handle
  return wrapper if null_pointer?(pointer)
  return wrapper unless qobject_wrapper?(wrapper.class)

  cached = cached_wrapper_for(pointer)
  return cached if cached

  cache_wrapper(wrapper)
end

.reset_cache!Object



113
114
115
116
# File 'lib/qt/object_wrapper.rb', line 113

def reset_cache!
  @wrapper_cache = {}
  @destroy_hook_addresses = {}
end

.resolve_wrapper_class(pointer, expected_qt_class) ⇒ Object



32
33
34
35
36
# File 'lib/qt/object_wrapper.rb', line 32

def resolve_wrapper_class(pointer, expected_qt_class)
  candidate_wrapper_classes(expected_qt_class).find do |klass|
    Native.qobject_inherits(pointer, klass::QT_CLASS)
  end
end

.wrap(pointer, expected_qt_class = nil) ⇒ Object



15
16
17
18
19
20
21
22
23
24
25
26
# File 'lib/qt/object_wrapper.rb', line 15

def wrap(pointer, expected_qt_class = nil)
  return nil if null_pointer?(pointer)
  return pointer if pointer.respond_to?(:handle)

  cached = cached_wrapper_for(pointer)
  return cached if cached

  klass = resolve_wrapper_class(pointer, expected_qt_class) || fallback_wrapper_class(expected_qt_class)
  return pointer unless klass

  register_wrapper(instantiate_wrapper(klass, pointer))
end

.wrapper_cacheObject



127
128
129
# File 'lib/qt/object_wrapper.rb', line 127

def wrapper_cache
  @wrapper_cache ||= {}
end