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, #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.



76
77
78
79
80
81
82
83
84
# File 'lib/glimmer/swt/display_proxy.rb', line 76

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, *args, &block) ⇒ Object



163
164
165
166
167
168
169
170
171
172
# File 'lib/glimmer/swt/display_proxy.rb', line 163

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

Instance Attribute Details

#swt_displayObject (readonly)

SWT Display object wrapped



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

def swt_display
  @swt_display
end

Class Method Details

.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



215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
# File 'lib/glimmer/swt/display_proxy.rb', line 215

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



92
93
94
95
96
97
98
99
100
101
# File 'lib/glimmer/swt/display_proxy.rb', line 92

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)


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

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



145
146
147
148
149
150
151
152
153
# File 'lib/glimmer/swt/display_proxy.rb', line 145

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)


180
181
182
183
184
185
186
187
188
189
190
191
# File 'lib/glimmer/swt/display_proxy.rb', line 180

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



86
87
88
# File 'lib/glimmer/swt/display_proxy.rb', line 86

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

#disposed?Boolean

Returns:

  • (Boolean)


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

def disposed?
  @swt_display.isDisposed
end

#execs_in_progressObject



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

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

#handle_observation_request(observation_request, &block) ⇒ Object



193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
# File 'lib/glimmer/swt/display_proxy.rb', line 193

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)
    Glimmer::UI::CustomWidget.current_custom_widgets.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)
        Glimmer::UI::CustomWidget.current_custom_widgets.last&.observer_registrations&.push(display_mac_event_registration)
        display_mac_event_registration
      end
    end
  end
end

#on_widget_disposed(&block) ⇒ Object



155
156
157
# File 'lib/glimmer/swt/display_proxy.rb', line 155

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

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

Returns:

  • (Boolean)


174
175
176
177
178
# File 'lib/glimmer/swt/display_proxy.rb', line 174

def respond_to?(method, *args, &block)
  super ||
    can_handle_observation_request?(method) ||
    swt_display.respond_to?(method, *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



105
106
107
108
109
110
111
112
113
114
115
116
# File 'lib/glimmer/swt/display_proxy.rb', line 105

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)


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

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)


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

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

#timer_exec(delay_in_millis, &block) ⇒ Object



118
119
120
# File 'lib/glimmer/swt/display_proxy.rb', line 118

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