Class: Glimmer::SWT::DisplayProxy

Inherits:
Object
  • Object
show all
Includes:
Custom::Drawable
Defined in:
lib/glimmer/swt/display_proxy.rb

Overview

Proxy for org.eclipse.swt.widgets.Display

Maintains a singleton instance since SWT only supports a single active display at a time.

Supports SWT Display’s very useful asyncExec and syncExec methods to support proper multi-threaded manipulation of SWT UI objects

Invoking ‘#swt_display` returns the SWT Display object wrapped by this proxy

Follows the Proxy Design Pattern

Defined Under Namespace

Classes: ConcreteListener

Constant Summary collapse

OBSERVED_MENU_ITEMS =
['about', 'preferences', 'quit']

Instance Attribute Summary collapse

Attributes included from Custom::Drawable

#image_double_buffered, #requires_shape_disposal

Class Method Summary collapse

Instance Method Summary collapse

Methods included from Custom::Drawable

#add_shape, #clear_shapes, #deregister_shape_painting, #drop_shapes, #expanded_shapes, #image_buffered_shapes, #paint_pixel_by_pixel, #setup_shape_painting, #shape_at_location, #shapes, #swt_drawable

Constructor Details

#initialize(*args) ⇒ DisplayProxy

Returns a new instance of DisplayProxy.



81
82
83
84
85
86
87
88
89
# File 'lib/glimmer/swt/display_proxy.rb', line 81

def initialize(*args)
  Display.app_name ||= 'Glimmer'
  @swt_display = Display.new(*args)
  @swt_display.set_data('proxy', self)
  @execs_in_progress = {}
  on_swt_Dispose {
    clear_shapes
  }
end

Dynamic Method Handling

This class handles dynamic methods through the method_missing method

#method_missing(method_name, *args, &block) ⇒ Object



168
169
170
171
172
173
174
175
176
177
# File 'lib/glimmer/swt/display_proxy.rb', line 168

def method_missing(method_name, *args, &block)
  if block && can_handle_observation_request?(method_name)
    handle_observation_request(method_name, &block)
  else
    swt_display.send(method_name, *args, &block)
  end
rescue => e
  Glimmer::Config.logger.debug {"Neither DisplayProxy nor #{swt_display.class.name} can handle the method ##{method_name}"}
  super
end

Instance Attribute Details

#swt_displayObject (readonly)

SWT Display object wrapped



79
80
81
# File 'lib/glimmer/swt/display_proxy.rb', line 79

def swt_display
  @swt_display
end

Class Method Details

.current_custom_widgets_and_shapesObject

Current custom widgets, shells, and shapes being rendered. Useful to yoke all observers evaluated during rendering of their custom widgets/shells/shapes for automatical disposal on_widget_disposed/on_shape_disposed



73
74
75
# File 'lib/glimmer/swt/display_proxy.rb', line 73

def current_custom_widgets_and_shapes
  @current_custom_widgets_and_shapes ||= []
end

.instance(*args) ⇒ Object

Returns singleton instance



59
60
61
62
63
64
65
# File 'lib/glimmer/swt/display_proxy.rb', line 59

def instance(*args)
  if @instance.nil? || @instance.swt_display.nil? || @instance.swt_display.isDisposed
    @thread = Thread.current
    @instance = new(*args)
  end
  @instance
end

.threadObject



67
68
69
70
# File 'lib/glimmer/swt/display_proxy.rb', line 67

def thread
  instance # ensure instance
  @thread
end

Instance Method Details

#add_swt_event_filter(swt_constant, &block) ⇒ Object



220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
# File 'lib/glimmer/swt/display_proxy.rb', line 220

def add_swt_event_filter(swt_constant, &block)
  event_type = SWTProxy[swt_constant]
  swt_listener = ConcreteListener.new(&block)
  @swt_display.addFilter(event_type, swt_listener)
  #WidgetListenerProxy.new(@swt_display.getListeners(event_type).last)
  WidgetListenerProxy.new(
    swt_display: @swt_display,
    event_type: event_type,
    filter: true,
    swt_listener: swt_listener,
    widget_add_listener_method: 'addFilter',
    swt_listener_class:  ConcreteListener,
    swt_listener_method: 'handleEvent'
  )
end

#async_exec(&block) ⇒ Object

asynchronously executes the block (required from threads other than first GUI thread) does not return the value produced by the block since it is async, running after the return



97
98
99
100
101
102
103
104
105
106
# File 'lib/glimmer/swt/display_proxy.rb', line 97

def async_exec(&block)
  @swt_display.asyncExec do
    execs_in_progress << :async_exec
    begin
      result = block.call
    ensure
      execs_in_progress.pop
    end
  end
end

#async_exec_in_progress?Boolean

Returns:

  • (Boolean)


133
134
135
# File 'lib/glimmer/swt/display_proxy.rb', line 133

def async_exec_in_progress?
  execs_in_progress.last == :async_exec
end

#auto_exec(override_sync_exec: nil, override_async_exec: nil, &block) ⇒ Object

Invoke block with ‘sync_exec` only when necessary (running from a separate thread) Override sync_exec as `true` to force using or `false` to force avoiding Override async_exec as `true` to force using or `:unless_in_progress` to force using only if no `async_exec` is in progress Disable auto execution of `sync_exec` via `Glimmer::Config.auto_sync_exec = false` Otherwise, runs normally, thus allowing SWT to decide how to batch/optimize GUI updates



150
151
152
153
154
155
156
157
158
# File 'lib/glimmer/swt/display_proxy.rb', line 150

def auto_exec(override_sync_exec: nil, override_async_exec: nil, &block)
  if override_sync_exec || override_sync_exec.nil? && !override_async_exec && sync_exec_required? && Config.auto_sync_exec? && !sync_exec_in_progress? && !async_exec_in_progress?
    sync_exec(&block)
  elsif override_async_exec || override_async_exec.to_s == 'unless_in_progress' && !async_exec_in_progress?
    async_exec(&block)
  else
    block.call
  end
end

#can_handle_observation_request?(observation_request) ⇒ Boolean

Returns:

  • (Boolean)


185
186
187
188
189
190
191
192
193
194
195
196
# File 'lib/glimmer/swt/display_proxy.rb', line 185

def can_handle_observation_request?(observation_request)
  observation_request = observation_request.to_s
  if observation_request.start_with?('on_swt_')
    constant_name = observation_request.sub(/^on_swt_/, '')
    SWTProxy.has_constant?(constant_name)
  elsif observation_request.start_with?('on_')
    event_name = observation_request.sub(/^on_/, '')
    OBSERVED_MENU_ITEMS.include?(event_name)
  else
    false
  end
end

#content(&block) ⇒ Object



91
92
93
# File 'lib/glimmer/swt/display_proxy.rb', line 91

def content(&block)
  Glimmer::DSL::Engine.add_content(self, Glimmer::DSL::SWT::DisplayExpression.new, 'display', &block)
end

#disposed?Boolean

Returns:

  • (Boolean)


164
165
166
# File 'lib/glimmer/swt/display_proxy.rb', line 164

def disposed?
  @swt_display.isDisposed
end

#execs_in_progressObject



141
142
143
# File 'lib/glimmer/swt/display_proxy.rb', line 141

def execs_in_progress
  @execs_in_progress[Thread.current] ||= []
end

#handle_observation_request(observation_request, &block) ⇒ Object



198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
# File 'lib/glimmer/swt/display_proxy.rb', line 198

def handle_observation_request(observation_request, &block)
  observation_request = observation_request.to_s
  if observation_request.start_with?('on_swt_')
    constant_name = observation_request.sub(/^on_swt_/, '')
    swt_event_reg = add_swt_event_filter(constant_name, &block)
    DisplayProxy.current_custom_widgets_and_shapes.last&.observer_registrations&.push(swt_event_reg)
    swt_event_reg
  elsif observation_request.start_with?('on_')
    event_name = observation_request.sub(/^on_/, '')
    if OBSERVED_MENU_ITEMS.include?(event_name) && OS.mac?
      auto_exec do
        system_menu = swt_display.getSystemMenu
        menu_item = system_menu.getItems.find {|menu_item| menu_item.getID == SWTProxy["ID_#{event_name.upcase}"]}
        listener = ConcreteListener.new(&block)
        display_mac_event_registration = menu_item.addListener(SWTProxy[:Selection], listener)
        DisplayProxy.current_custom_widgets_and_shapes.last&.observer_registrations&.push(display_mac_event_registration)
        display_mac_event_registration
      end
    end
  end
end

#on_widget_disposed(&block) ⇒ Object



160
161
162
# File 'lib/glimmer/swt/display_proxy.rb', line 160

def on_widget_disposed(&block)
  on_swt_Dispose(&block)
end

#respond_to?(method_name, *args, &block) ⇒ Boolean

Returns:

  • (Boolean)


179
180
181
182
183
# File 'lib/glimmer/swt/display_proxy.rb', line 179

def respond_to?(method_name, *args, &block)
  super ||
    can_handle_observation_request?(method_name) ||
    swt_display.respond_to?(method_name, *args, &block)
end

#sync_exec(&block) ⇒ Object

synchronously executes the block (required from threads other than first GUI thread) returns the value produced by the block



110
111
112
113
114
115
116
117
118
119
120
121
# File 'lib/glimmer/swt/display_proxy.rb', line 110

def sync_exec(&block)
  result = nil
  @swt_display.syncExec do
    execs_in_progress << :sync_exec
    begin
      result = block.call
    ensure
      execs_in_progress.pop
    end
  end
  result
end

#sync_exec_in_progress?Boolean

Returns:

  • (Boolean)


137
138
139
# File 'lib/glimmer/swt/display_proxy.rb', line 137

def sync_exec_in_progress?
  execs_in_progress.include?(:sync_exec)
end

#sync_exec_required?Boolean

Indicates whether ‘sync_exec` is required because of running in a different thread from the GUI thread `async_exec` could be used as an alternative to `sync_exec` when required.

Returns:

  • (Boolean)


129
130
131
# File 'lib/glimmer/swt/display_proxy.rb', line 129

def sync_exec_required?
  Thread.current != DisplayProxy.thread
end

#timer_exec(delay_in_millis, &block) ⇒ Object



123
124
125
# File 'lib/glimmer/swt/display_proxy.rb', line 123

def timer_exec(delay_in_millis, &block)
  @swt_display.timerExec(delay_in_millis, &block)
end