wxruby3 1.7.0 → 1.8.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/INSTALL.md +27 -2
- data/README.md +15 -15
- data/ext/wxruby3/include/wxRubyApp.h +145 -46
- data/ext/wxruby3/include/wxruby-ComboPopup.h +25 -8
- data/ext/wxruby3/include/wxruby-GCTracking.h +262 -0
- data/ext/wxruby3/include/wxruby-MBConv.h +190 -0
- data/ext/wxruby3/include/wxruby-SharedEventHandler.h +183 -0
- data/ext/wxruby3/include/wxruby-SharedPtr.h +104 -0
- data/ext/wxruby3/include/wxruby-runtime.h +29 -0
- data/ext/wxruby3/swig/custom/rubytracking.swg +8 -22
- data/ext/wxruby3/swig/custom/wx_ruby_shared_ptr.i +434 -0
- data/ext/wxruby3/swig/custom/wx_shared_ptr.i +431 -0
- data/ext/wxruby3/swig/mark_free_impl.i +7 -132
- data/ext/wxruby3/swig/memory_management.i +8 -44
- data/ext/wxruby3/swig/wx.i +46 -73
- data/lib/wx/core/const.rb +0 -1
- data/lib/wx/core/context_help.rb +17 -0
- data/lib/wx/core/cursor.rb +1 -0
- data/lib/wx/core/helpcontrollerhelpprovider.rb +10 -2
- data/lib/wx/core/mbconv.rb +11 -0
- data/lib/wx/core/media_ctrl.rb +31 -0
- data/lib/wx/core/top_level_window.rb +7 -0
- data/lib/wx/core.rb +6 -0
- data/lib/wx/doc/art_provider.rb +17 -0
- data/lib/wx/doc/context_help.rb +42 -0
- data/lib/wx/doc/core.rb +0 -5
- data/lib/wx/doc/functions.rb +10 -0
- data/lib/wx/doc/gen/affine_matrix2d.rb +2 -0
- data/lib/wx/doc/gen/art_provider.rb +12 -0
- data/lib/wx/doc/gen/aui/aui_notebook_event.rb +15 -15
- data/lib/wx/doc/gen/aui/aui_pane_info.rb +8 -8
- data/lib/wx/doc/gen/aui/aui_tool_bar_event.rb +5 -5
- data/lib/wx/doc/gen/book_ctrl_base.rb +2 -1
- data/lib/wx/doc/gen/calendar_event.rb +5 -5
- data/lib/wx/doc/gen/choicebook.rb +2 -2
- data/lib/wx/doc/gen/collapsible_pane.rb +1 -1
- data/lib/wx/doc/gen/colour_dialog.rb +1 -1
- data/lib/wx/doc/gen/colour_picker_event.rb +3 -3
- data/lib/wx/doc/gen/context_help_button.rb +0 -53
- data/lib/wx/doc/gen/core.rb +4 -4
- data/lib/wx/doc/gen/credential_entry_dialog.rb +2 -2
- data/lib/wx/doc/gen/date_event.rb +2 -2
- data/lib/wx/doc/gen/dial_up_event.rb +2 -2
- data/lib/wx/doc/gen/dir_filter_list_ctrl.rb +2 -2
- data/lib/wx/doc/gen/event.rb +58 -58
- data/lib/wx/doc/gen/ext_help_controller.rb +62 -16
- data/lib/wx/doc/gen/file_ctrl.rb +4 -4
- data/lib/wx/doc/gen/file_dir_picker_event.rb +2 -2
- data/lib/wx/doc/gen/file_system.rb +1 -1
- data/lib/wx/doc/gen/find_dialog_event.rb +5 -5
- data/lib/wx/doc/gen/font_picker_event.rb +1 -1
- data/lib/wx/doc/gen/grid/grid_ctrl.rb +67 -32
- data/lib/wx/doc/gen/header_ctrl_event.rb +13 -13
- data/lib/wx/doc/gen/help_controller.rb +45 -2
- data/lib/wx/doc/gen/html/html_help_controller.rb +74 -32
- data/lib/wx/doc/gen/html/html_help_window.rb +3 -3
- data/lib/wx/doc/gen/html/html_window.rb +4 -4
- data/lib/wx/doc/gen/hyperlink_ctrl.rb +1 -1
- data/lib/wx/doc/gen/list_ctrl.rb +22 -22
- data/lib/wx/doc/gen/listbook.rb +2 -2
- data/lib/wx/doc/gen/mb_conv.rb +10 -0
- data/lib/wx/doc/gen/media_event.rb +6 -6
- data/lib/wx/doc/gen/notebook.rb +2 -2
- data/lib/wx/doc/gen/pg/pg_validation_info.rb +14 -14
- data/lib/wx/doc/gen/pg/property_grid_interface.rb +2 -2
- data/lib/wx/doc/gen/rbn/ribbon_art_provider.rb +19 -9
- data/lib/wx/doc/gen/rbn/ribbon_button_bar.rb +2 -2
- data/lib/wx/doc/gen/rbn/ribbon_gallery.rb +3 -3
- data/lib/wx/doc/gen/rbn/ribbon_panel.rb +2 -2
- data/lib/wx/doc/gen/rbn/ribbon_tool_bar.rb +2 -2
- data/lib/wx/doc/gen/rt/event_list.rb +17 -0
- data/lib/wx/doc/gen/rt/shared_evt_handler.rb +14 -0
- data/lib/wx/doc/gen/rt/thread_event.rb +71 -0
- data/lib/wx/doc/gen/rtc/rich_text_ctrl.rb +19 -19
- data/lib/wx/doc/gen/sash_event.rb +2 -2
- data/lib/wx/doc/gen/sash_layout_window.rb +2 -2
- data/lib/wx/doc/gen/search_ctrl.rb +2 -2
- data/lib/wx/doc/gen/spin_ctrl.rb +2 -2
- data/lib/wx/doc/gen/splitter_window.rb +6 -6
- data/lib/wx/doc/gen/stc/styled_text_event.rb +34 -34
- data/lib/wx/doc/gen/task_bar_icon_event.rb +10 -10
- data/lib/wx/doc/gen/text_ctrl.rb +4 -4
- data/lib/wx/doc/gen/toggle_button.rb +1 -1
- data/lib/wx/doc/gen/toolbook.rb +2 -2
- data/lib/wx/doc/gen/top_level_window.rb +19 -0
- data/lib/wx/doc/gen/tree_ctrl.rb +21 -21
- data/lib/wx/doc/gen/treebook.rb +4 -4
- data/lib/wx/doc/gen/utils.rb +2 -2
- data/lib/wx/doc/gen/web/event_list.rb +95 -0
- data/lib/wx/doc/gen/web/web_view.rb +1136 -0
- data/lib/wx/doc/gen/web/web_view_event.rb +210 -0
- data/lib/wx/doc/gen/web/web_view_handler.rb +318 -0
- data/lib/wx/doc/gen/window.rb +1 -1
- data/lib/wx/doc/gen/wizard_event.rb +7 -7
- data/lib/wx/doc/html/html_help_controller.rb +23 -1
- data/lib/wx/doc/mbconv.rb +108 -0
- data/lib/wx/doc/rt/shared_event_handler.rb +49 -0
- data/lib/wx/doc/rt/thread_event.rb +28 -0
- data/lib/wx/doc/webview.rb +40 -0
- data/lib/wx/helpers.rb +1 -1
- data/lib/wx/html/htmlhelpcontroller.rb +10 -0
- data/lib/wx/keyword_defs.rb +11 -0
- data/lib/wx/rt/events/evt_list.rb +8 -0
- data/lib/wx/rt/require.rb +8 -0
- data/lib/wx/rt/thread_event.rb +14 -0
- data/lib/wx/rt.rb +16 -0
- data/lib/wx/version.rb +1 -1
- data/lib/wx/web/events/evt_list.rb +74 -0
- data/lib/wx/web/require.rb +8 -0
- data/lib/wx/web/webview.rb +106 -0
- data/lib/wx/web.rb +17 -0
- data/lib/wx/wxruby/cmd/setup.rb +15 -0
- data/lib/wx.rb +2 -0
- data/rakelib/configure.rb +24 -0
- data/rakelib/gem.rb +3 -2
- data/rakelib/install.rb +54 -27
- data/rakelib/lib/config/macosx.rb +7 -5
- data/rakelib/lib/config/mingw.rb +66 -5
- data/rakelib/lib/config/pkgman/mingw.rb +1 -1
- data/rakelib/lib/config/unixish.rb +4 -2
- data/rakelib/lib/config.rb +37 -3
- data/rakelib/lib/core/include/client_data.inc +38 -17
- data/rakelib/lib/core/include/funcall.inc +1 -1
- data/rakelib/lib/core/include/swigdirector.inc +3 -3
- data/rakelib/lib/core/include/swigrubyrun.inc +14 -26
- data/rakelib/lib/core/package.rb +0 -2
- data/rakelib/lib/director/app.rb +1 -8
- data/rakelib/lib/director/art_provider.rb +7 -3
- data/rakelib/lib/director/comboctrl.rb +0 -7
- data/rakelib/lib/director/context_help_button.rb +35 -2
- data/rakelib/lib/director/event_handler.rb +32 -28
- data/rakelib/lib/director/fs_file.rb +15 -10
- data/rakelib/lib/director/functions.rb +8 -0
- data/rakelib/lib/director/grid_cell_attr.rb +1 -3
- data/rakelib/lib/director/grid_cell_editor.rb +14 -12
- data/rakelib/lib/director/grid_cell_renderer.rb +11 -8
- data/rakelib/lib/director/grid_ctrl.rb +140 -121
- data/rakelib/lib/director/help_controller.rb +70 -2
- data/rakelib/lib/director/mb_conv.rb +30 -0
- data/rakelib/lib/director/menu.rb +92 -42
- data/rakelib/lib/director/menu_bar.rb +84 -45
- data/rakelib/lib/director/menu_item.rb +2 -2
- data/rakelib/lib/director/persistence_manager.rb +3 -2
- data/rakelib/lib/director/preview_frame.rb +2 -2
- data/rakelib/lib/director/richtext_buffer.rb +5 -2
- data/rakelib/lib/director/shared_evt_handler.rb +30 -0
- data/rakelib/lib/director/sizer.rb +8 -17
- data/rakelib/lib/director/sizer_item.rb +3 -4
- data/rakelib/lib/director/task_bar_icon.rb +7 -7
- data/rakelib/lib/director/thread_event.rb +33 -0
- data/rakelib/lib/director/validator.rb +3 -1
- data/rakelib/lib/director/variant.rb +16 -12
- data/rakelib/lib/director/webview.rb +166 -0
- data/rakelib/lib/director/webview_event.rb +37 -0
- data/rakelib/lib/director/webview_handler.rb +63 -0
- data/rakelib/lib/generate/doc/thread_event.yaml +20 -0
- data/rakelib/lib/generate/doc/web_view.yaml +135 -0
- data/rakelib/lib/generate/doc/web_view_event.yaml +38 -0
- data/rakelib/lib/generate/doc/web_view_handler.yaml +58 -0
- data/rakelib/lib/specs/interfaces.rb +12 -0
- data/rakelib/lib/typemap/common.rb +34 -1
- data/rakelib/lib/typemap/mb_conv.rb +58 -0
- data/rakelib/prepost.rake +23 -31
- data/rakelib/prepost.rb +20 -0
- data/samples/event/threaded.rb +295 -42
- data/samples/event/tn_threaded.png +0 -0
- data/samples/help/doc/back.gif +0 -0
- data/samples/help/doc/contents.gif +0 -0
- data/samples/help/doc/cshelp.txt +9 -0
- data/samples/help/doc/doc.chm +0 -0
- data/samples/help/doc/doc.cnt +8 -0
- data/samples/help/doc/doc.h +7 -0
- data/samples/help/doc/doc.hhc +40 -0
- data/samples/help/doc/doc.hhk +31 -0
- data/samples/help/doc/doc.hhp +33 -0
- data/samples/help/doc/doc.hpj +21 -0
- data/samples/help/doc/doc.htm +27 -0
- data/samples/help/doc/doc1.htm +24 -0
- data/samples/help/doc/doc2.htm +12 -0
- data/samples/help/doc/doc3.htm +12 -0
- data/samples/help/doc/doc4.htm +12 -0
- data/samples/help/doc/doc5.htm +14 -0
- data/samples/help/doc/forward.gif +0 -0
- data/samples/help/doc/up.gif +0 -0
- data/samples/help/doc.chm +0 -0
- data/samples/help/doc.chw +0 -0
- data/samples/help/doc.zip +0 -0
- data/samples/help/help.rb +352 -0
- data/samples/help/tn_help.png +0 -0
- data/samples/webview/handler_advanced.html +55 -0
- data/samples/webview/tn_webview.png +0 -0
- data/samples/webview/webview.rb +1264 -0
- data/tests/assets/handler_advanced.html +55 -0
- data/tests/assets/test.css +1 -0
- data/tests/assets/test.html +9 -0
- data/tests/assets/test.zip +0 -0
- data/tests/lib/text_entry_tests.rb +2 -2
- data/tests/lib/wxapp_runner.rb +40 -0
- data/tests/lib/wxframe_runner.rb +17 -2
- data/tests/test_art.rb +8 -8
- data/tests/test_clipboard.rb +4 -4
- data/tests/test_config.rb +6 -6
- data/tests/test_exceptions.rb +8 -6
- data/tests/test_ext_controls.rb +3 -3
- data/tests/test_file_dialog.rb +5 -5
- data/tests/test_font.rb +7 -7
- data/tests/test_grid_ctrl.rb +133 -0
- data/tests/test_help.rb +88 -0
- data/tests/test_intl.rb +1 -1
- data/tests/test_media_ctrl.rb +14 -6
- data/tests/test_menu.rb +94 -86
- data/tests/test_persistence.rb +1 -1
- data/tests/test_proof_check.rb +5 -5
- data/tests/test_propgrid.rb +1 -1
- data/tests/test_shared_event_handler.rb +141 -0
- data/tests/test_std_controls.rb +5 -5
- data/tests/test_webview.rb +492 -0
- data/tests/test_window.rb +3 -3
- metadata +78 -2
data/rakelib/prepost.rake
CHANGED
|
@@ -56,27 +56,18 @@ namespace 'wxruby' do
|
|
|
56
56
|
if WXRuby3.config.windows?
|
|
57
57
|
if WXRuby3.config.get_config('with-wxwin')
|
|
58
58
|
WXRuby3::Post.create_startup <<~__CODE
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
if RubyInstaller::Runtime.respond_to?(:add_dll_directory)
|
|
62
|
-
RubyInstaller::Runtime.add_dll_directory('#{File.expand_path('ext')}')
|
|
63
|
-
else
|
|
64
|
-
RubyInstaller::Build.add_dll_directory('#{File.expand_path('ext')}')
|
|
65
|
-
end
|
|
66
|
-
rescue LoadError
|
|
67
|
-
end
|
|
59
|
+
#{WXRuby3::Post.setup_add_dll_directory(File.expand_path(File.join('ext', 'lib')))}
|
|
60
|
+
#{WXRuby3::Post.setup_adjust_wx_prefix}
|
|
68
61
|
__CODE
|
|
69
62
|
elsif !WXRuby3.config.get_cfg_string('wxwin').empty? && File.directory?(WXRuby3.config.get_cfg_string('wxwininstdir'))
|
|
70
63
|
WXRuby3::Post.create_startup <<~__CODE
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
rescue LoadError
|
|
79
|
-
end
|
|
64
|
+
#{WXRuby3::Post.setup_add_dll_directory(WXRuby3.config.get_cfg_string('wxwininstdir'))}
|
|
65
|
+
__CODE
|
|
66
|
+
end
|
|
67
|
+
else
|
|
68
|
+
if WXRuby3.config.get_config('with-wxwin')
|
|
69
|
+
WXRuby3::Post.create_startup <<~__CODE
|
|
70
|
+
#{WXRuby3::Post.setup_adjust_wx_prefix}
|
|
80
71
|
__CODE
|
|
81
72
|
end
|
|
82
73
|
end
|
|
@@ -84,19 +75,20 @@ namespace 'wxruby' do
|
|
|
84
75
|
end
|
|
85
76
|
|
|
86
77
|
task :install do
|
|
87
|
-
if WXRuby3.config.
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
78
|
+
if WXRuby3.config.get_config('with-wxwin') && !Rake::FileUtilsExt.nowrite_flag
|
|
79
|
+
if WXRuby3.config.windows?
|
|
80
|
+
File.open(File.join(WXRuby3.config.get_cfg_string('siterubyver'), 'wx/startup.rb'), 'w') do |f|
|
|
81
|
+
f.puts <<~__CODE
|
|
82
|
+
#{WXRuby3::Post.setup_add_dll_directory(WXRuby3.config.get_cfg_string('siterubyverarch'))}
|
|
83
|
+
#{WXRuby3::Post.setup_adjust_wx_prefix}
|
|
84
|
+
__CODE
|
|
85
|
+
end
|
|
86
|
+
else
|
|
87
|
+
File.open(File.join(WXRuby3.config.get_cfg_string('siterubyver'), 'wx/startup.rb'), 'w') do |f|
|
|
88
|
+
f.puts <<~__CODE
|
|
89
|
+
#{WXRuby3::Post.setup_adjust_wx_prefix}
|
|
90
|
+
__CODE
|
|
91
|
+
end
|
|
100
92
|
end
|
|
101
93
|
end
|
|
102
94
|
end
|
data/rakelib/prepost.rb
CHANGED
|
@@ -24,6 +24,26 @@ module WXRuby3
|
|
|
24
24
|
end
|
|
25
25
|
end
|
|
26
26
|
|
|
27
|
+
def self.setup_add_dll_directory(dll_directory)
|
|
28
|
+
<<~__CODE
|
|
29
|
+
begin
|
|
30
|
+
require 'ruby_installer'
|
|
31
|
+
if RubyInstaller::Runtime.respond_to?(:add_dll_directory)
|
|
32
|
+
RubyInstaller::Runtime.add_dll_directory('#{dll_directory}')
|
|
33
|
+
else
|
|
34
|
+
RubyInstaller::Build.add_dll_directory('#{dll_directory}')
|
|
35
|
+
end
|
|
36
|
+
rescue LoadError
|
|
37
|
+
end
|
|
38
|
+
__CODE
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
def self.setup_adjust_wx_prefix
|
|
42
|
+
<<~__CODE
|
|
43
|
+
ENV['WXPREFIX'] = File.realpath(File.join(__dir__, '..', '..', 'ext'))
|
|
44
|
+
__CODE
|
|
45
|
+
end
|
|
46
|
+
|
|
27
47
|
end
|
|
28
48
|
|
|
29
49
|
end
|
data/samples/event/threaded.rb
CHANGED
|
@@ -12,20 +12,18 @@
|
|
|
12
12
|
require 'wx'
|
|
13
13
|
|
|
14
14
|
# This simple sample demonstrates how to use Ruby (green) threads
|
|
15
|
-
# to execute non-GUI code
|
|
15
|
+
# or fibers to execute non-GUI code concurrently with a wxRuby
|
|
16
16
|
# GUI. This strategy is useful in a number of situations:
|
|
17
17
|
#
|
|
18
18
|
# * To keep the GUI responsive whilst computationally intensive
|
|
19
19
|
# operations are carried out in the background
|
|
20
20
|
# * To keep the GUI responsive while waiting for networking operations
|
|
21
|
-
# to complete
|
|
22
|
-
#
|
|
23
|
-
#
|
|
24
|
-
#
|
|
25
|
-
#
|
|
26
|
-
#
|
|
27
|
-
# wxRuby's Timer class to explicitly allocate time for non-GUI threads
|
|
28
|
-
# to run. The latter technique is shown here.
|
|
21
|
+
# to complete
|
|
22
|
+
#
|
|
23
|
+
# This sample showcases how to use Ruby threading (Thread or Ractor) or
|
|
24
|
+
# cooperative concurrency (Fiber) in a wxRuby GUI application, how to
|
|
25
|
+
# communicate thread safely with the main thread and, if needed, how to
|
|
26
|
+
# provide processing time for non-GUI threads of execution.
|
|
29
27
|
|
|
30
28
|
module Threaded
|
|
31
29
|
|
|
@@ -51,42 +49,244 @@ end
|
|
|
51
49
|
|
|
52
50
|
# This frame shows a set of progress bars which monitor progress of
|
|
53
51
|
# long-running tasks. In this example, this long-running task is
|
|
54
|
-
#
|
|
55
|
-
# downloading from a socket or
|
|
52
|
+
# a (partially) simulated word counter, but could equally be
|
|
53
|
+
# downloading from a socket or anything else requiring substantial
|
|
54
|
+
# computation or blocking IO operations.
|
|
56
55
|
class ProgressFrame < Wx::Frame
|
|
57
|
-
|
|
56
|
+
|
|
57
|
+
module ID
|
|
58
|
+
include Wx::IDHelper
|
|
59
|
+
RUN_GT_WITH_CUSTOM_EVENT = self.next_id
|
|
60
|
+
RUN_GT_WITH_ASYNC_CALL = self.next_id
|
|
61
|
+
RUN_GT_WITH_QUEUE = self.next_id
|
|
62
|
+
RUN_FIBER_YIELD = self.next_id
|
|
63
|
+
RUN_FIBER_UPDATE = self.next_id
|
|
64
|
+
RUN_RACTOR_THREADS = self.next_id
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
WORKERS = 8
|
|
68
|
+
STEPS = 100
|
|
69
|
+
|
|
70
|
+
# word count simulator
|
|
71
|
+
class Simulator
|
|
72
|
+
class << self
|
|
73
|
+
def run(timeslice)
|
|
74
|
+
start = Time.now
|
|
75
|
+
count = 0
|
|
76
|
+
# use max timeslice time to analyze max 100 files
|
|
77
|
+
100.times do
|
|
78
|
+
text = File.read(__FILE__)
|
|
79
|
+
text.gsub(/\w+/) { count += 1; '' }
|
|
80
|
+
break unless (Time.now - start) < timeslice
|
|
81
|
+
end
|
|
82
|
+
count
|
|
83
|
+
end
|
|
84
|
+
end
|
|
85
|
+
end
|
|
86
|
+
|
|
58
87
|
def initialize
|
|
59
|
-
super(nil, :title => 'Threading demo')
|
|
88
|
+
super(nil, :title => 'Threading demo', size: [600, 400])
|
|
60
89
|
|
|
61
90
|
self.icon = Wx.Icon(:sample, Wx::BITMAP_TYPE_XPM, art_path: File.join(__dir__, '..'))
|
|
62
91
|
|
|
92
|
+
menuFile = Wx::Menu.new
|
|
93
|
+
helpMenu = Wx::Menu.new
|
|
94
|
+
helpMenu.append(Wx::ID_ABOUT, "&About...\tF1", "Show about dialog")
|
|
95
|
+
gt_submenu = Wx::Menu.new
|
|
96
|
+
gt_submenu.append(ID::RUN_GT_WITH_CUSTOM_EVENT, "Run with custom event", 'Run Green threads simulation with custom events')
|
|
97
|
+
gt_submenu.append(ID::RUN_GT_WITH_ASYNC_CALL, "Run with async calls", 'Run Green threads simulation with asynchronous calls')
|
|
98
|
+
gt_submenu.append(ID::RUN_GT_WITH_QUEUE, "Run with thread queue", 'Run Green threads simulation with thread queue')
|
|
99
|
+
@mi_gt = menuFile.append_sub_menu(gt_submenu, "Run &Green Threads", 'Run simulation using standard Ruby Green threads')
|
|
100
|
+
fb_submenu = Wx::Menu.new
|
|
101
|
+
fb_submenu.append(ID::RUN_FIBER_YIELD, "Run Fibers with yield", 'Run Ruby fibers with update through yield')
|
|
102
|
+
fb_submenu.append(ID::RUN_FIBER_UPDATE, "Run Fibers with update", 'Run Ruby fibers with direct GUI update')
|
|
103
|
+
@mi_fb = menuFile.append_sub_menu(fb_submenu, "Run &Fibers", 'Run simulation using Ruby Fibers')
|
|
104
|
+
@mi_rt = menuFile.append(ID::RUN_RACTOR_THREADS, "Run &Ractor Threads", 'Run simulation using Ruby Ractor threads')
|
|
105
|
+
menuFile.append_separator
|
|
106
|
+
menuFile.append(Wx::ID_EXIT, "E&xit\tAlt-X", "Quit this program")
|
|
107
|
+
menuBar = Wx::MenuBar.new
|
|
108
|
+
menuBar.append(menuFile, "&File")
|
|
109
|
+
menuBar.append(helpMenu, "&Help")
|
|
110
|
+
set_menu_bar(menuBar)
|
|
111
|
+
|
|
112
|
+
create_status_bar
|
|
113
|
+
|
|
63
114
|
@gauges = []
|
|
115
|
+
@workers = []
|
|
116
|
+
@queue = nil
|
|
64
117
|
panel = Wx::Panel.new(self)
|
|
65
118
|
sizer = Wx::BoxSizer.new(Wx::VERTICAL)
|
|
66
119
|
# progress update handler
|
|
67
120
|
evt_update_progress(:on_progress_update)
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
121
|
+
# show a gauge for each worker
|
|
122
|
+
WORKERS.times do
|
|
123
|
+
gauge = Wx::Gauge.new(panel, size: [-1, 30], :range => STEPS)
|
|
124
|
+
@gauges << gauge
|
|
125
|
+
sizer.add(gauge, 0, Wx::GROW|Wx::ALL, 2)
|
|
126
|
+
end
|
|
127
|
+
panel.sizer = sizer
|
|
128
|
+
sizer.fit(panel)
|
|
129
|
+
|
|
130
|
+
evt_menu Wx::ID_EXIT, :on_quit
|
|
131
|
+
evt_menu Wx::ID_ABOUT, :on_about
|
|
132
|
+
evt_menu_range ID::RUN_GT_WITH_CUSTOM_EVENT, ID::RUN_GT_WITH_QUEUE, :on_run_green_threads
|
|
133
|
+
evt_menu_range ID::RUN_FIBER_YIELD, ID::RUN_FIBER_UPDATE, :on_run_fibers
|
|
134
|
+
evt_menu ID::RUN_RACTOR_THREADS, :on_run_ractor_threads
|
|
135
|
+
|
|
136
|
+
evt_thread Wx::ID_ANY, :on_thread_event
|
|
137
|
+
|
|
138
|
+
evt_idle :on_idle
|
|
139
|
+
end
|
|
140
|
+
|
|
141
|
+
private def start_run
|
|
142
|
+
@mi_gt.enable(false)
|
|
143
|
+
@mi_fb.enable(false)
|
|
144
|
+
@mi_rt.enable(false)
|
|
145
|
+
reset_gauges
|
|
146
|
+
@total = 0
|
|
147
|
+
@run_start = Time.now
|
|
148
|
+
end
|
|
149
|
+
|
|
150
|
+
private def end_run(total)
|
|
151
|
+
set_status_text("#{Time.now - @run_start} seconds | #{total} words counted")
|
|
152
|
+
@mi_gt.enable
|
|
153
|
+
@mi_fb.enable
|
|
154
|
+
@mi_rt.enable
|
|
155
|
+
@queue = nil
|
|
156
|
+
@workers.clear
|
|
157
|
+
self.refresh
|
|
158
|
+
end
|
|
159
|
+
|
|
160
|
+
def on_run_green_threads(evt)
|
|
161
|
+
start_run
|
|
162
|
+
@queue = Thread::Queue.new if evt.id == ID::RUN_GT_WITH_QUEUE
|
|
163
|
+
# run a Thread for each worker
|
|
164
|
+
@workers = (0...WORKERS).collect do |worker|
|
|
165
|
+
# For each worker, start a new thread in which the task runs
|
|
166
|
+
Thread.new(evt.id, evt.id == ID::RUN_GT_WITH_QUEUE ? @queue : self) do |evt_id, queue_or_frame|
|
|
74
167
|
# The long-running task
|
|
168
|
+
count = 0
|
|
75
169
|
STEPS.times do | i |
|
|
76
|
-
|
|
170
|
+
# simulate processing step
|
|
171
|
+
count += Simulator.run(0.1) # give each processing cycle a maximum timeslice of 100 msec
|
|
77
172
|
# Update the main GUI asynchronously (more ways than 1)
|
|
78
|
-
|
|
79
|
-
|
|
173
|
+
case evt_id
|
|
174
|
+
when ID::RUN_GT_WITH_QUEUE
|
|
175
|
+
queue_or_frame << [worker, i+1]
|
|
176
|
+
when ID::RUN_GT_WITH_CUSTOM_EVENT
|
|
177
|
+
queue_or_frame.event_handler.queue_event(ProgressUpdateEvent.new(i+1, worker))
|
|
178
|
+
else # ID::RUN_GT_WITH_ASYNC_CALL
|
|
179
|
+
queue_or_frame.call_after(:update_gauge, worker, i+1)
|
|
180
|
+
end
|
|
181
|
+
end
|
|
182
|
+
count
|
|
183
|
+
end
|
|
184
|
+
end
|
|
185
|
+
end
|
|
186
|
+
|
|
187
|
+
def on_run_fibers(evt)
|
|
188
|
+
start_run
|
|
189
|
+
# run a Fiber for each worker
|
|
190
|
+
evt_id = evt.id
|
|
191
|
+
@workers = (0...WORKERS).collect do |worker|
|
|
192
|
+
# For each worker, start a new fiber in which the task runs
|
|
193
|
+
# Use a smaller time slice for each worker cycle, so as not to block the
|
|
194
|
+
# event loop too long, but increase cycles so the workers still get a decent
|
|
195
|
+
# amount of 'CPU' time running the simulated process.
|
|
196
|
+
Fiber.new do
|
|
197
|
+
# The long-running task
|
|
198
|
+
count = 0
|
|
199
|
+
(4*STEPS).times do | i |
|
|
200
|
+
# simulate processing step
|
|
201
|
+
count += Simulator.run(0.01) # give each processing cycle a maximum timeslice of 10 msec
|
|
202
|
+
# Communicate update
|
|
203
|
+
if evt_id == ID::RUN_FIBER_YIELD
|
|
204
|
+
Fiber.yield [worker, (i+1)/4]
|
|
80
205
|
else
|
|
81
|
-
|
|
206
|
+
update_gauge(worker, (i+1)/4)
|
|
207
|
+
Fiber.yield
|
|
82
208
|
end
|
|
83
209
|
end
|
|
210
|
+
count
|
|
84
211
|
end
|
|
85
|
-
@gauges << gauge
|
|
86
|
-
sizer.add(gauge, 0, Wx::GROW|Wx::ALL, 2)
|
|
87
212
|
end
|
|
88
|
-
|
|
89
|
-
|
|
213
|
+
end
|
|
214
|
+
|
|
215
|
+
def on_run_ractor_threads(_)
|
|
216
|
+
start_run
|
|
217
|
+
# run a Ractor for each worker
|
|
218
|
+
@workers = (0...WORKERS).collect do |worker|
|
|
219
|
+
# for each worker start a Ractor to run the task
|
|
220
|
+
if RUBY_VERSION >= '4.0.0'
|
|
221
|
+
pin = Ractor::Port.new
|
|
222
|
+
pmon = Ractor::Port.new
|
|
223
|
+
r = Ractor.new(worker, self.make_shared, pin) do |worker_id, evt_handler, pout|
|
|
224
|
+
# The long-running task
|
|
225
|
+
count = 0
|
|
226
|
+
STEPS.times do | i |
|
|
227
|
+
count += Simulator.run(0.1) # give each processing cycle a maximum timeslice of 100 msec
|
|
228
|
+
# Update the main GUI asynchronously
|
|
229
|
+
pout.send(i+1)
|
|
230
|
+
evt = Wx::RT::ThreadEvent.new
|
|
231
|
+
evt.set_int(worker_id)
|
|
232
|
+
evt_handler.queue_event(evt)
|
|
233
|
+
end
|
|
234
|
+
pout.send(-1)
|
|
235
|
+
evt = Wx::RT::ThreadEvent.new
|
|
236
|
+
evt.set_int(worker_id)
|
|
237
|
+
evt_handler.queue_event(evt)
|
|
238
|
+
count
|
|
239
|
+
end
|
|
240
|
+
r.monitor(pmon)
|
|
241
|
+
[r, pin, pmon]
|
|
242
|
+
else
|
|
243
|
+
r = Ractor.new(worker, self.make_shared) do |worker_id, evt_handler|
|
|
244
|
+
# The long-running task
|
|
245
|
+
count = 0
|
|
246
|
+
STEPS.times do | i |
|
|
247
|
+
# simulate processing step
|
|
248
|
+
count += Simulator.run(0.1) # give each processing cycle a maximum timeslice of 100 msec
|
|
249
|
+
# Update the main GUI asynchronously
|
|
250
|
+
evt = Wx::RT::ThreadEvent.new
|
|
251
|
+
evt.set_int(worker_id)
|
|
252
|
+
evt_handler.queue_event(evt)
|
|
253
|
+
Ractor.yield(i+1)
|
|
254
|
+
end
|
|
255
|
+
evt = Wx::RT::ThreadEvent.new
|
|
256
|
+
evt.set_int(worker_id)
|
|
257
|
+
evt_handler.queue_event(evt)
|
|
258
|
+
Ractor.yield(-1)
|
|
259
|
+
count
|
|
260
|
+
end
|
|
261
|
+
[r]
|
|
262
|
+
end
|
|
263
|
+
end
|
|
264
|
+
end
|
|
265
|
+
|
|
266
|
+
def on_thread_event(evt)
|
|
267
|
+
w = evt.get_int
|
|
268
|
+
if RUBY_VERSION >= '4.0.0'
|
|
269
|
+
step = @workers[w][1].receive
|
|
270
|
+
if step >= 0
|
|
271
|
+
update_gauge(w, step)
|
|
272
|
+
else
|
|
273
|
+
rc = @workers[w][2].receive
|
|
274
|
+
Wx.message_box("Worker ##{w} aborted with error.", 'Worker Error',
|
|
275
|
+
Wx::OK|Wx::CENTRE|Wx::ICON_ERROR, self) if rc == :aborted
|
|
276
|
+
@workers[w] << :stopped
|
|
277
|
+
end
|
|
278
|
+
else
|
|
279
|
+
step = begin; @workers[w][0].take; rescue Ractor::ClosedError; nil; end
|
|
280
|
+
if step && step >= 0
|
|
281
|
+
update_gauge(w, step)
|
|
282
|
+
else
|
|
283
|
+
@workers[w] << :stopped
|
|
284
|
+
end
|
|
285
|
+
end
|
|
286
|
+
end
|
|
287
|
+
|
|
288
|
+
def reset_gauges
|
|
289
|
+
WORKERS.times { |w| update_gauge(w, 0) }
|
|
90
290
|
end
|
|
91
291
|
|
|
92
292
|
def update_gauge(gauge_ix, value)
|
|
@@ -96,17 +296,77 @@ class ProgressFrame < Wx::Frame
|
|
|
96
296
|
def on_progress_update(evt)
|
|
97
297
|
update_gauge(evt.gauge, evt.value)
|
|
98
298
|
end
|
|
299
|
+
|
|
300
|
+
def on_idle(evt)
|
|
301
|
+
unless @workers.empty?
|
|
302
|
+
case @workers.first
|
|
303
|
+
when ::Thread
|
|
304
|
+
if @workers.any? { |worker| worker.alive? }
|
|
305
|
+
if @queue
|
|
306
|
+
WORKERS.times do
|
|
307
|
+
data = @queue.shift(true) rescue nil
|
|
308
|
+
update_gauge(*data) if data
|
|
309
|
+
break unless data
|
|
310
|
+
end
|
|
311
|
+
end
|
|
312
|
+
else
|
|
313
|
+
@total = @workers.sum { |w| w.value }
|
|
314
|
+
@workers.clear
|
|
315
|
+
if @queue
|
|
316
|
+
begin
|
|
317
|
+
data = @queue.shift(true) rescue nil
|
|
318
|
+
update_gauge(*data) if data
|
|
319
|
+
end while data
|
|
320
|
+
else
|
|
321
|
+
Wx.get_app.yield
|
|
322
|
+
end
|
|
323
|
+
end_run(@total)
|
|
324
|
+
end
|
|
325
|
+
when ::Fiber
|
|
326
|
+
if @workers.any? { |worker| worker.alive? }
|
|
327
|
+
@workers.each do |fbr|
|
|
328
|
+
if fbr.alive?
|
|
329
|
+
data = fbr.resume rescue nil
|
|
330
|
+
if data
|
|
331
|
+
if ::Array === data
|
|
332
|
+
update_gauge(*data)
|
|
333
|
+
else
|
|
334
|
+
@total += data
|
|
335
|
+
end
|
|
336
|
+
end
|
|
337
|
+
end
|
|
338
|
+
end
|
|
339
|
+
evt.request_more # make sure we get another idle event to provide time slices for the fibers
|
|
340
|
+
else
|
|
341
|
+
end_run(@total)
|
|
342
|
+
end
|
|
343
|
+
else
|
|
344
|
+
if @workers.all? { |worker| worker.last == :stopped }
|
|
345
|
+
@total = @workers.sum { |w| w[0].value }
|
|
346
|
+
@workers.clear
|
|
347
|
+
end_run(@total)
|
|
348
|
+
end
|
|
349
|
+
end
|
|
350
|
+
evt.skip
|
|
351
|
+
end
|
|
352
|
+
end
|
|
353
|
+
|
|
354
|
+
def on_quit(_)
|
|
355
|
+
close(true)
|
|
356
|
+
end
|
|
357
|
+
|
|
358
|
+
def on_about(_)
|
|
359
|
+
msg = sprintf("This is the About dialog of the threaded sample.\n" \
|
|
360
|
+
"Welcome to wxRuby, version %s", Wx::WXRUBY_VERSION)
|
|
361
|
+
Wx::message_box(msg, "About Threaded", Wx::OK|Wx::ICON_INFORMATION, self)
|
|
362
|
+
end
|
|
363
|
+
|
|
99
364
|
end
|
|
100
365
|
|
|
101
366
|
# This app class creates a frame, and, importantly, a timer to allow
|
|
102
367
|
# the threads some computing time
|
|
103
368
|
class GaugeApp < Wx::App
|
|
104
369
|
def on_init
|
|
105
|
-
# Create a global application timer that passes control to other
|
|
106
|
-
# ruby threads. The timer will run every 1/40 second (25ms). Higher
|
|
107
|
-
# values will make the other threads run more often, but will
|
|
108
|
-
# eventually degrade the responsiveness of the GUI.
|
|
109
|
-
Wx::Timer.every(25) { Thread.pass }
|
|
110
370
|
prog = ProgressFrame.new
|
|
111
371
|
prog.show
|
|
112
372
|
end
|
|
@@ -122,22 +382,15 @@ module ThreadSample
|
|
|
122
382
|
{ file: __FILE__,
|
|
123
383
|
summary: 'wxRuby threading example.',
|
|
124
384
|
description: <<~__TXT
|
|
125
|
-
wxRuby example demonstrating how to use
|
|
126
|
-
This
|
|
127
|
-
to execute non-GUI code in
|
|
385
|
+
wxRuby example demonstrating how to use concurrency in wxRuby.
|
|
386
|
+
This sample demonstrates how to use Ruby (green) threads, fibers
|
|
387
|
+
and Ractor threads to execute non-GUI code in concurrently with a wxRuby
|
|
128
388
|
GUI. This strategy is useful in a number of situations:
|
|
129
389
|
|
|
130
390
|
* To keep the GUI responsive whilst computationally intensive
|
|
131
391
|
operations are carried out in the background
|
|
132
392
|
* To keep the GUI responsive while waiting for networking operations
|
|
133
393
|
to complete
|
|
134
|
-
|
|
135
|
-
The basic problem is that, as with other Ruby GUI toolkits, non-GUI
|
|
136
|
-
threads will not, by default, get allocated time to run while Ruby is
|
|
137
|
-
busy in Wx code - the main wxRuby event loop. Strategies to deal with
|
|
138
|
-
this include using non-blocking IO, and, more generically, using
|
|
139
|
-
wxRuby's Timer class to explicitly allocate time for non-GUI threads
|
|
140
|
-
to run. The latter technique is shown here.
|
|
141
394
|
__TXT
|
|
142
395
|
}
|
|
143
396
|
end
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">
|
|
2
|
+
<HTML>
|
|
3
|
+
<HEAD>
|
|
4
|
+
<meta name="GENERATOR" content="tex2rtf">
|
|
5
|
+
<!-- Sitemap 1.0 -->
|
|
6
|
+
</HEAD><BODY>
|
|
7
|
+
<OBJECT type="text/site properties">
|
|
8
|
+
<param name="ImageType" value="Folder">
|
|
9
|
+
</OBJECT>
|
|
10
|
+
<UL>
|
|
11
|
+
<LI> <OBJECT type="text/sitemap">
|
|
12
|
+
<param name="Local" value="doc.htm">
|
|
13
|
+
<param name="Name" value="Contents">
|
|
14
|
+
<param name="ID" value=0>
|
|
15
|
+
</OBJECT>
|
|
16
|
+
<LI> <OBJECT type="text/sitemap">
|
|
17
|
+
<param name="Local" value="doc1.htm#intro">
|
|
18
|
+
<param name="Name" value="Introduction">
|
|
19
|
+
</OBJECT>
|
|
20
|
+
<UL> <LI> <OBJECT type="text/sitemap">
|
|
21
|
+
<param name="Local" value="doc2.htm#classes">
|
|
22
|
+
<param name="Name" value="Classes">
|
|
23
|
+
<param name="ID" value=2>
|
|
24
|
+
</OBJECT>
|
|
25
|
+
<LI> <OBJECT type="text/sitemap">
|
|
26
|
+
<param name="Local" value="doc3.htm#functions">
|
|
27
|
+
<param name="Name" value="Functions">
|
|
28
|
+
<param name="ID" value=1>
|
|
29
|
+
</OBJECT>
|
|
30
|
+
<LI> <OBJECT type="text/sitemap">
|
|
31
|
+
<param name="Local" value="doc4.htm#about">
|
|
32
|
+
<param name="Name" value="About">
|
|
33
|
+
<param name="ID" value=3>
|
|
34
|
+
</OBJECT>
|
|
35
|
+
</UL> <LI> <OBJECT type="text/sitemap">
|
|
36
|
+
<param name="Local" value="doc5.htm#chapter2">
|
|
37
|
+
<param name="Name" value="Chapter 2">
|
|
38
|
+
<param name="ID" value=4>
|
|
39
|
+
</OBJECT>
|
|
40
|
+
</UL>
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">
|
|
2
|
+
<HTML>
|
|
3
|
+
<HEAD>
|
|
4
|
+
<meta name="GENERATOR" content="tex2rtf">
|
|
5
|
+
<!-- Sitemap 1.0 -->
|
|
6
|
+
</HEAD><BODY>
|
|
7
|
+
<OBJECT type="text/site properties">
|
|
8
|
+
<param name="ImageType" value="Folder">
|
|
9
|
+
</OBJECT>
|
|
10
|
+
<UL>
|
|
11
|
+
<LI> <OBJECT type="text/sitemap">
|
|
12
|
+
<param name="Local" value="doc4.htm#about">
|
|
13
|
+
<param name="Name" value="About">
|
|
14
|
+
</OBJECT>
|
|
15
|
+
<LI> <OBJECT type="text/sitemap">
|
|
16
|
+
<param name="Local" value="doc1.htm#intro">
|
|
17
|
+
<param name="Name" value="Introduction">
|
|
18
|
+
</OBJECT>
|
|
19
|
+
<LI> <OBJECT type="text/sitemap">
|
|
20
|
+
<param name="Local" value="doc2.htm#classes">
|
|
21
|
+
<param name="Name" value="Classes">
|
|
22
|
+
</OBJECT>
|
|
23
|
+
<LI> <OBJECT type="text/sitemap">
|
|
24
|
+
<param name="Local" value="doc5.htm#chapter2">
|
|
25
|
+
<param name="Name" value="Chapter 2">
|
|
26
|
+
</OBJECT>
|
|
27
|
+
<LI> <OBJECT type="text/sitemap">
|
|
28
|
+
<param name="Local" value="doc3.htm#functions">
|
|
29
|
+
<param name="Name" value="Functions">
|
|
30
|
+
</OBJECT>
|
|
31
|
+
</UL>
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
[OPTIONS]
|
|
2
|
+
Compatibility=1.1 or later
|
|
3
|
+
Compiled file=doc.chm
|
|
4
|
+
Contents file=doc.hhc
|
|
5
|
+
Default Window=docHelp
|
|
6
|
+
Default topic=doc.htm
|
|
7
|
+
Display compile progress=No
|
|
8
|
+
Full-text search=Yes
|
|
9
|
+
Index file=doc.hhk
|
|
10
|
+
Language=0x809 English (United Kingdom)
|
|
11
|
+
Title=Help Demo
|
|
12
|
+
|
|
13
|
+
[WINDOWS]
|
|
14
|
+
docHelp=,"doc.hhc","doc.hhk","doc.htm",,,,,,0x2420,,0x380e,,,,,0,,,0
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
[FILES]
|
|
18
|
+
doc.htm
|
|
19
|
+
doc1.htm
|
|
20
|
+
doc2.htm
|
|
21
|
+
doc3.htm
|
|
22
|
+
doc4.htm
|
|
23
|
+
doc5.htm
|
|
24
|
+
|
|
25
|
+
[MAP]
|
|
26
|
+
#include doc.h
|
|
27
|
+
|
|
28
|
+
[TEXT POPUPS]
|
|
29
|
+
doc.h
|
|
30
|
+
cshelp.txt
|
|
31
|
+
|
|
32
|
+
[INFOTYPES]
|
|
33
|
+
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
[OPTIONS]
|
|
2
|
+
BMROOT=D:\wx2\wxWind~1\samples\help
|
|
3
|
+
TITLE=Help Demo Document
|
|
4
|
+
CONTENTS=Contents
|
|
5
|
+
COMPRESS=HIGH
|
|
6
|
+
|
|
7
|
+
[FILES]
|
|
8
|
+
doc.rtf
|
|
9
|
+
|
|
10
|
+
[CONFIG]
|
|
11
|
+
CreateButton("Up", "&Up", "JumpId(`doc.hlp', `Contents')")
|
|
12
|
+
BrowseButtons()
|
|
13
|
+
|
|
14
|
+
[MAP]
|
|
15
|
+
#define intro 100
|
|
16
|
+
#define functions 1
|
|
17
|
+
#define classes 2
|
|
18
|
+
#define about 3
|
|
19
|
+
|
|
20
|
+
[BITMAPS]
|
|
21
|
+
|