wxruby 1.9.6-x86-mingw32

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.
Files changed (236) hide show
  1. data/LICENSE +53 -0
  2. data/README +297 -0
  3. data/lib/wx/accessors.rb +52 -0
  4. data/lib/wx/classes/acceleratortable.rb +28 -0
  5. data/lib/wx/classes/animation.rb +18 -0
  6. data/lib/wx/classes/app.rb +45 -0
  7. data/lib/wx/classes/artprovider.rb +31 -0
  8. data/lib/wx/classes/bitmap.rb +28 -0
  9. data/lib/wx/classes/busycursor.rb +12 -0
  10. data/lib/wx/classes/checklistbox.rb +45 -0
  11. data/lib/wx/classes/choice.rb +4 -0
  12. data/lib/wx/classes/clientdc.rb +13 -0
  13. data/lib/wx/classes/clipboard.rb +16 -0
  14. data/lib/wx/classes/colour.rb +47 -0
  15. data/lib/wx/classes/combobox.rb +4 -0
  16. data/lib/wx/classes/commandevent.rb +7 -0
  17. data/lib/wx/classes/controlwithitems.rb +10 -0
  18. data/lib/wx/classes/dc.rb +57 -0
  19. data/lib/wx/classes/event.rb +5 -0
  20. data/lib/wx/classes/evthandler.rb +921 -0
  21. data/lib/wx/classes/font.rb +118 -0
  22. data/lib/wx/classes/functions.rb +44 -0
  23. data/lib/wx/classes/gauge.rb +12 -0
  24. data/lib/wx/classes/grid.rb +138 -0
  25. data/lib/wx/classes/helpcontroller.rb +5 -0
  26. data/lib/wx/classes/htmlhelpcontroller.rb +5 -0
  27. data/lib/wx/classes/htmlwindow.rb +14 -0
  28. data/lib/wx/classes/icon.rb +21 -0
  29. data/lib/wx/classes/iconbundle.rb +3 -0
  30. data/lib/wx/classes/image.rb +31 -0
  31. data/lib/wx/classes/imagelist.rb +3 -0
  32. data/lib/wx/classes/listbox.rb +4 -0
  33. data/lib/wx/classes/listctrl.rb +21 -0
  34. data/lib/wx/classes/locale.rb +28 -0
  35. data/lib/wx/classes/mediactrl.rb +22 -0
  36. data/lib/wx/classes/menu.rb +62 -0
  37. data/lib/wx/classes/menuitem.rb +7 -0
  38. data/lib/wx/classes/object.rb +7 -0
  39. data/lib/wx/classes/paintdc.rb +12 -0
  40. data/lib/wx/classes/point.rb +48 -0
  41. data/lib/wx/classes/previewframe.rb +13 -0
  42. data/lib/wx/classes/rect.rb +10 -0
  43. data/lib/wx/classes/size.rb +49 -0
  44. data/lib/wx/classes/sound.rb +23 -0
  45. data/lib/wx/classes/styledtextctrl.rb +92 -0
  46. data/lib/wx/classes/textctrl.rb +14 -0
  47. data/lib/wx/classes/texturlevent.rb +6 -0
  48. data/lib/wx/classes/timer.rb +94 -0
  49. data/lib/wx/classes/toolbartool.rb +4 -0
  50. data/lib/wx/classes/treectrl.rb +44 -0
  51. data/lib/wx/classes/window.rb +82 -0
  52. data/lib/wx/classes/xmlresource.rb +37 -0
  53. data/lib/wx/keyword_ctors.rb +222 -0
  54. data/lib/wx/keyword_defs.rb +492 -0
  55. data/lib/wx/version.rb +3 -0
  56. data/lib/wx.rb +42 -0
  57. data/lib/wxruby2.so +0 -0
  58. data/samples/SAMPLES-LICENSE.TXT +18 -0
  59. data/samples/aui/aui.rb +1356 -0
  60. data/samples/bigdemo/About.rbw +39 -0
  61. data/samples/bigdemo/ColorPanel.rbw +23 -0
  62. data/samples/bigdemo/GridSimple.rbw +78 -0
  63. data/samples/bigdemo/MDIDemo.rbw +57 -0
  64. data/samples/bigdemo/PopupMenu.rbw +149 -0
  65. data/samples/bigdemo/ShapedWindow.rbw +131 -0
  66. data/samples/bigdemo/Sizers.rbw +543 -0
  67. data/samples/bigdemo/bigdemo.rb +823 -0
  68. data/samples/bigdemo/demoTemplate.rbw +33 -0
  69. data/samples/bigdemo/helpfile.htb +0 -0
  70. data/samples/bigdemo/icons/Test 015.jpg +0 -0
  71. data/samples/bigdemo/icons/Test 015.png +0 -0
  72. data/samples/bigdemo/icons/choice.bmp +0 -0
  73. data/samples/bigdemo/icons/choice.xpm +27 -0
  74. data/samples/bigdemo/icons/combo.bmp +0 -0
  75. data/samples/bigdemo/icons/combo.xpm +27 -0
  76. data/samples/bigdemo/icons/copy.xpm +25 -0
  77. data/samples/bigdemo/icons/cut.xpm +24 -0
  78. data/samples/bigdemo/icons/gauge.bmp +0 -0
  79. data/samples/bigdemo/icons/gauge.xpm +27 -0
  80. data/samples/bigdemo/icons/help.xpm +25 -0
  81. data/samples/bigdemo/icons/list.bmp +0 -0
  82. data/samples/bigdemo/icons/list.xpm +27 -0
  83. data/samples/bigdemo/icons/mondrian.ico +0 -0
  84. data/samples/bigdemo/icons/mondrian.xpm +44 -0
  85. data/samples/bigdemo/icons/new.xpm +24 -0
  86. data/samples/bigdemo/icons/ogl.ico +0 -0
  87. data/samples/bigdemo/icons/ogl.xpm +45 -0
  88. data/samples/bigdemo/icons/open.xpm +26 -0
  89. data/samples/bigdemo/icons/paste.bmp +0 -0
  90. data/samples/bigdemo/icons/paste.xpm +38 -0
  91. data/samples/bigdemo/icons/pointy.png +0 -0
  92. data/samples/bigdemo/icons/preview.xpm +26 -0
  93. data/samples/bigdemo/icons/print.xpm +26 -0
  94. data/samples/bigdemo/icons/radio.bmp +0 -0
  95. data/samples/bigdemo/icons/radio.xpm +27 -0
  96. data/samples/bigdemo/icons/robert.xpm +415 -0
  97. data/samples/bigdemo/icons/ruby.png +0 -0
  98. data/samples/bigdemo/icons/sashtest.ico +0 -0
  99. data/samples/bigdemo/icons/save.xpm +25 -0
  100. data/samples/bigdemo/icons/smiles.bmp +0 -0
  101. data/samples/bigdemo/icons/smiles.xpm +39 -0
  102. data/samples/bigdemo/icons/smiley.ico +0 -0
  103. data/samples/bigdemo/icons/smiley.xpm +42 -0
  104. data/samples/bigdemo/icons/stattext.xpm +24 -0
  105. data/samples/bigdemo/icons/test2.bmp +0 -0
  106. data/samples/bigdemo/icons/test2.png +0 -0
  107. data/samples/bigdemo/icons/test2.xpm +79 -0
  108. data/samples/bigdemo/icons/text.bmp +0 -0
  109. data/samples/bigdemo/icons/text.xpm +27 -0
  110. data/samples/bigdemo/icons/tog1.bmp +0 -0
  111. data/samples/bigdemo/icons/tog1.xpm +38 -0
  112. data/samples/bigdemo/icons/tog2.bmp +0 -0
  113. data/samples/bigdemo/icons/tog2.xpm +38 -0
  114. data/samples/bigdemo/icons/wxwin.ico +0 -0
  115. data/samples/bigdemo/icons/wxwin16x16.png +0 -0
  116. data/samples/bigdemo/icons/wxwin16x16.xpm +25 -0
  117. data/samples/bigdemo/icons/wxwin32x32.png +0 -0
  118. data/samples/bigdemo/icons/wxwin48x48.png +0 -0
  119. data/samples/bigdemo/run.rb +90 -0
  120. data/samples/bigdemo/tips.txt +7 -0
  121. data/samples/bigdemo/utils.rb +12 -0
  122. data/samples/bigdemo/wxArtProvider.rbw +281 -0
  123. data/samples/bigdemo/wxBitmapButton.rbw +65 -0
  124. data/samples/bigdemo/wxButton.rbw +64 -0
  125. data/samples/bigdemo/wxCalendarCtrl.rbw +60 -0
  126. data/samples/bigdemo/wxCheckBox.rbw +50 -0
  127. data/samples/bigdemo/wxCheckListBox.rbw +75 -0
  128. data/samples/bigdemo/wxChoice.rbw +47 -0
  129. data/samples/bigdemo/wxChoicebook.rbw +78 -0
  130. data/samples/bigdemo/wxColourDialog.rbw +31 -0
  131. data/samples/bigdemo/wxComboBox.rbw +77 -0
  132. data/samples/bigdemo/wxCursor.rbw +136 -0
  133. data/samples/bigdemo/wxDialog.rbw +74 -0
  134. data/samples/bigdemo/wxDirDialog.rbw +29 -0
  135. data/samples/bigdemo/wxDragImage.rbw +70 -0
  136. data/samples/bigdemo/wxFileDialog.rbw +37 -0
  137. data/samples/bigdemo/wxFileDialog_Save.rbw +35 -0
  138. data/samples/bigdemo/wxFindReplaceDialog.rbw +82 -0
  139. data/samples/bigdemo/wxFontDialog.rbw +173 -0
  140. data/samples/bigdemo/wxFrame.rbw +53 -0
  141. data/samples/bigdemo/wxGauge.rbw +71 -0
  142. data/samples/bigdemo/wxGenericDirCtrl.rbw +74 -0
  143. data/samples/bigdemo/wxGrid.rbw +66 -0
  144. data/samples/bigdemo/wxHtmlHelpController.rbw +52 -0
  145. data/samples/bigdemo/wxListBox.rbw +140 -0
  146. data/samples/bigdemo/wxListCtrl_virtual.rbw +107 -0
  147. data/samples/bigdemo/wxMDIWindows.rbw +50 -0
  148. data/samples/bigdemo/wxMenu.rbw +236 -0
  149. data/samples/bigdemo/wxMessageDialog.rbw +27 -0
  150. data/samples/bigdemo/wxMiniFrame.rbw +70 -0
  151. data/samples/bigdemo/wxMultipleChoiceDialog.rbw +32 -0
  152. data/samples/bigdemo/wxNotebook.rbw +136 -0
  153. data/samples/bigdemo/wxProgressDialog.rbw +43 -0
  154. data/samples/bigdemo/wxRadioBox.rbw +72 -0
  155. data/samples/bigdemo/wxRadioButton.rbw +125 -0
  156. data/samples/bigdemo/wxSashWindow.rbw +141 -0
  157. data/samples/bigdemo/wxScrolledMessageDialog.rbw +57 -0
  158. data/samples/bigdemo/wxScrolledWindow.rbw +199 -0
  159. data/samples/bigdemo/wxSingleChoiceDialog.rbw +33 -0
  160. data/samples/bigdemo/wxSlider.rbw +42 -0
  161. data/samples/bigdemo/wxSpinButton.rbw +50 -0
  162. data/samples/bigdemo/wxSpinCtrl.rbw +51 -0
  163. data/samples/bigdemo/wxSplitterWindow.rbw +63 -0
  164. data/samples/bigdemo/wxStaticBitmap.rbw +51 -0
  165. data/samples/bigdemo/wxStaticText.rbw +55 -0
  166. data/samples/bigdemo/wxStatusBar.rbw +126 -0
  167. data/samples/bigdemo/wxTextCtrl.rbw +149 -0
  168. data/samples/bigdemo/wxTextEntryDialog.rbw +31 -0
  169. data/samples/bigdemo/wxToggleButton.rbw +49 -0
  170. data/samples/bigdemo/wxToolBar.rbw +131 -0
  171. data/samples/bigdemo/wxTreeCtrl.rbw +190 -0
  172. data/samples/calendar/calendar.rb +271 -0
  173. data/samples/caret/caret.rb +282 -0
  174. data/samples/caret/mondrian.xpm +44 -0
  175. data/samples/controls/controls.rb +1136 -0
  176. data/samples/controls/get_item_sample.rb +87 -0
  177. data/samples/controls/icons/choice.xpm +27 -0
  178. data/samples/controls/icons/combo.xpm +27 -0
  179. data/samples/controls/icons/gauge.xpm +27 -0
  180. data/samples/controls/icons/list.xpm +27 -0
  181. data/samples/controls/icons/radio.xpm +27 -0
  182. data/samples/controls/icons/stattext.xpm +24 -0
  183. data/samples/controls/icons/text.xpm +27 -0
  184. data/samples/controls/mondrian.ico +0 -0
  185. data/samples/controls/mondrian.xpm +44 -0
  186. data/samples/controls/test2.bmp +0 -0
  187. data/samples/dialogs/dialogs.rb +723 -0
  188. data/samples/dialogs/tips.txt +18 -0
  189. data/samples/drawing/graphics_drawing.rb +235 -0
  190. data/samples/drawing/images.rb +37 -0
  191. data/samples/drawing/paperclip.png +0 -0
  192. data/samples/etc/activation.rb +102 -0
  193. data/samples/etc/choice.rb +67 -0
  194. data/samples/etc/miniframe.rb +79 -0
  195. data/samples/etc/sash.rb +130 -0
  196. data/samples/etc/scrollwin.rb +110 -0
  197. data/samples/etc/system_settings.rb +252 -0
  198. data/samples/etc/threaded.rb +72 -0
  199. data/samples/etc/wizard.rb +74 -0
  200. data/samples/event/event.rb +182 -0
  201. data/samples/grid/grid.rb +198 -0
  202. data/samples/grid/gridtablebase.rb +134 -0
  203. data/samples/html/html.rb +262 -0
  204. data/samples/listbook/listbook.rb +174 -0
  205. data/samples/listbook/listbook.xrc +370 -0
  206. data/samples/mdi/mdi.rb +82 -0
  207. data/samples/media/mediactrl.rb +167 -0
  208. data/samples/minimal/minimal.rb +77 -0
  209. data/samples/minimal/mondrian.ico +0 -0
  210. data/samples/minimal/mondrian.png +0 -0
  211. data/samples/minimal/nothing.rb +16 -0
  212. data/samples/opengl/cube.rb +117 -0
  213. data/samples/printing/mondrian.ico +0 -0
  214. data/samples/printing/mondrian.xpm +44 -0
  215. data/samples/printing/printing.rb +310 -0
  216. data/samples/sockets/SocketPackets.rb +27 -0
  217. data/samples/sockets/res/message-new.png +0 -0
  218. data/samples/sockets/res/user.png +0 -0
  219. data/samples/sockets/wxClient.rb +395 -0
  220. data/samples/sockets/wxServer.rb +422 -0
  221. data/samples/sockets/wxSocketGUI.rb +97 -0
  222. data/samples/text/mondrian.ico +0 -0
  223. data/samples/text/mondrian.xpm +44 -0
  224. data/samples/text/scintilla.rb +169 -0
  225. data/samples/text/textctrl.rb +113 -0
  226. data/samples/text/unicode.rb +242 -0
  227. data/samples/text/utf8.txt +15 -0
  228. data/samples/treectrl/icon1.xpm +79 -0
  229. data/samples/treectrl/icon2.xpm +53 -0
  230. data/samples/treectrl/icon3.xpm +79 -0
  231. data/samples/treectrl/icon4.xpm +43 -0
  232. data/samples/treectrl/icon5.xpm +79 -0
  233. data/samples/treectrl/treectrl.rb +1174 -0
  234. data/samples/xrc/samples.xrc +46 -0
  235. data/samples/xrc/xrc_sample.rb +96 -0
  236. metadata +313 -0
@@ -0,0 +1,422 @@
1
+ #!/usr/bin/env ruby
2
+ # wxRuby2 Sample Code. Copyright (c) 2007-???? Mario J. Steele
3
+ # Freely reusable code: see SAMPLES-LICENSE.TXT for details
4
+
5
+ # This sample is a demonstration of how to implement a Multi-Threaded
6
+ # Server, using Ruby's green threads, Ruby's Asynchronous Sockets and
7
+ # wxRuby, as to not block the GUI while receiving connections and data
8
+ # from clients.
9
+
10
+ begin
11
+ require 'wx'
12
+ rescue LoadError => no_wx_err
13
+ begin
14
+ require 'rubygems'
15
+ require 'wx'
16
+ rescue LoadError
17
+ raise no_wx_err
18
+ end
19
+ end
20
+
21
+ require 'thread' # For Thread and Mutex
22
+ require 'socket' # For TCP/IP Communications
23
+
24
+ $LOAD_PATH << File.dirname(__FILE__)
25
+ require 'wxSocketGUI' # Our GUI Interface
26
+ require 'SocketPackets' # For simplfying Socket communciation
27
+
28
+ class MyServerFrame < SocketGUI
29
+ include Socket::Constants
30
+ @@constants = %w[
31
+ ID_START
32
+ ID_STOP
33
+ ID_NAME
34
+ ID_EXIT
35
+ ID_TIMER_POLL
36
+ ]
37
+ # ClientInfo holds information about each client connection to the server
38
+ # making it easier to track information, and use that throughout the
39
+ # server process.
40
+ ClientInfo = Struct.new(
41
+ :name, # User's Nickname
42
+ :host, # User's Host Address
43
+ :port, # User's Port
44
+ :sock, # User's Sock
45
+ :buffer) # Buffer for the socket
46
+
47
+ # Creates the Menus used by the server.
48
+ def create_menus()
49
+ mb = Wx::MenuBar.new
50
+
51
+ fileMenu = Wx::Menu.new
52
+ fileMenu.append(ID_START,"&Start Server\tCtrl+S","Start listening for incomming connections")
53
+ fileMenu.append(ID_STOP,"S&top Server\tCtrl+G","Stop listening for incomming connections, and disconnect all current connections")
54
+ fileMenu.append_separator()
55
+ fileMenu.append(ID_NAME,"&Nickname\tCtrl+N","Set your Nickname")
56
+ fileMenu.append_separator()
57
+ fileMenu.append(ID_EXIT,"E&xit\tCtrl+X","Exit the demo")
58
+
59
+ mb.append(fileMenu,"&File")
60
+ set_menu_bar(mb)
61
+ end
62
+
63
+ # Our initialize sequence, called by SocketGUI.
64
+ def on_init()
65
+ @nick = "Server" # Server user's Nickname
66
+ @port = 1234 # Port we're listening on
67
+ @mutex = Mutex.new # For synchronization, so there's no corruption of memory
68
+ @clients = [] # For the sockets that are connected
69
+ @timer = Wx::Timer.new(self,ID_TIMER_POLL)
70
+ # Used to poll for data
71
+
72
+ evt_menu(ID_START) { on_start }
73
+ evt_menu(ID_STOP) { on_stop }
74
+ evt_menu(ID_NAME) { on_name }
75
+ evt_menu(ID_EXIT) { on_exit }
76
+
77
+ evt_close { |evt| on_close(evt) }
78
+ evt_text_enter(@input.get_id) { on_text }
79
+ evt_timer(ID_TIMER_POLL) { Thread.pass }
80
+
81
+ get_menu_bar.enable(ID_START,true)
82
+ get_menu_bar.enable(ID_STOP,false)
83
+ end
84
+
85
+ # MyServerFrame#on_start()
86
+ # This function sets up the socket for listening to incoming connections, as
87
+ # well as starting the Thread that will do the underline work for polling for
88
+ # incoming connections as well as incoming data.
89
+ def on_start
90
+ if !@socket.nil?
91
+ Wx::message_box("The server is already started!","Server startup error",Wx::ID_OK|Wx::ICON_ERROR)
92
+ return
93
+ end
94
+
95
+ mbox = Wx::TextEntryDialog.new(self,"Enter the port you want to listen on (Default: 1234)",
96
+ "Start Server","1234")
97
+ if mbox.show_modal == Wx::ID_CANCEL
98
+ return
99
+ end
100
+ @port = mbox.get_value.to_i
101
+ @socket = Socket.new(AF_INET,SOCK_STREAM,0)
102
+ @socket.bind(Socket.sockaddr_in(@port,$LOCALHOST_NAME))
103
+ @socket.listen(5)
104
+ append_prog_msg("[#{Time.now}] - Server started on port #{@port}.")
105
+ update_users()
106
+ get_menu_bar.enable(ID_START,false)
107
+ get_menu_bar.enable(ID_STOP,true)
108
+ start_server_thread()
109
+ end
110
+
111
+ # MyServerFrame#on_stop()
112
+ # This is executed from the File > Stop menu item, which will first check to see
113
+ # if we still have Active clients. If so, confirm that the user wants to shutdown
114
+ # the server. If the user does, it'll start the MyServerFraem#shutdown() sequence.
115
+ def on_stop()
116
+ if @socket.nil?
117
+ Wx::message_box("The server is currently not active!","Server shutdown",Wx::OK|Wx::ICON_ERROR)
118
+ return
119
+ end
120
+ if @clients.size > 0
121
+ ret = Wx::message_box("There are still clients connected, do you wish to shutdown still?","Server shutdown",Wx::YES|Wx::NO|Wx::ICON_QUESTION)
122
+ if ret == Wx::NO
123
+ return
124
+ end
125
+ end
126
+ shutdown()
127
+ end
128
+
129
+ # MyServerFrame#on_name()
130
+ # This is executed from the File > Nickname menu item, which will change the nickname
131
+ # of the Server itself. If there's active connections to the server, it will notify
132
+ # all of the clients of the server's new nickname.
133
+ def on_name
134
+ mbox = Wx::TextEntryDialog.new(self,"Enter the new nickname you want to be (Default: Server)",
135
+ "Change Nickname",@nick)
136
+ ret = mbox.show_modal
137
+ if ret == Wx::ID_CANCEL
138
+ return
139
+ end
140
+ nick = mbox.get_value
141
+ nick = nick.split(" ").join("_") if nick.index(" ")
142
+ append_prog_msg("[#{Time.now}] - You changed your nickname to #{nick}.")
143
+ @clients.each do |ci|
144
+ ci.sock.send_packet("NICK #{@nick} #{nick}")
145
+ end
146
+ @nick = nick
147
+ update_users()
148
+ end
149
+
150
+ # MyServerFrame#on_exit()
151
+ # This is executed from the File > Exit menu item, it will simply delegate the actual
152
+ # processing to MyServerFrame#on_close() event, by closing the window.
153
+ def on_exit
154
+ self.close
155
+ end
156
+
157
+ # MyServerFrame#on_close(evt)
158
+ # This is executed from the OnCloseEvent that comes from when the user closes the
159
+ # window, or executes the File > Exit menu item. It will first check to see if the
160
+ # if there's an Active Socket. If there is, then it'll check and see if there are
161
+ # any clients connected. If there are clients connected, it will confirm with the
162
+ # user that they want to shutdown the server. If they don't, it will veto the
163
+ # close event, and the server will continue to run.
164
+ def on_close(evt)
165
+ ret = Wx::YES
166
+ if !@socket.nil?
167
+ if @clients.size > 0
168
+ ret = Wx::message_box("There are still clients connected to the server, do you wish to continue?","Shutdown",Wx::YES|Wx::NO|Wx::ICON_INFORMATION)
169
+ end
170
+ end
171
+ if ret == Wx::NO
172
+ evt.veto
173
+ else
174
+ shutdown()
175
+ Wx::get_app.exit_main_loop
176
+ end
177
+ end
178
+
179
+ # MyServerFrame#on_text()
180
+ # This is executed when the user presses the Enter button from the input box.
181
+ # It does small parsing to check what /commands are used, if any, then if it
182
+ # doesn't find any, it'll pass through to actually sending the data.
183
+ def on_text()
184
+ msg = @input.get_value
185
+ @input.set_value("")
186
+ case msg
187
+ when /\/start/
188
+ on_start
189
+ when /\/shutdown/
190
+ on_stop
191
+ when /\/nick/
192
+ on_name
193
+ when /\/exit/
194
+ self.close
195
+ when /\/me/
196
+ append_msg("--> #{@nick} " + msg[4..-1])
197
+ msg = "EMOTE #{@nick} " + msg[4..-1]
198
+ @mutex.lock
199
+ @clients.each do |ci|
200
+ ci.sock.send_packet(msg)
201
+ end
202
+ @mutex.unlock
203
+ else
204
+ append_msg("--> #{@nick} says: " + msg)
205
+ msg = "MSG #{@nick} " + msg
206
+ @mutex.lock
207
+ @clients.each do |ci|
208
+ ci.sock.send_packet(msg)
209
+ end
210
+ @mutex.unlock
211
+ end
212
+ end
213
+
214
+ # MyServerFrame#shutdown()
215
+ # This is the actual clean up function that will shutdown the Server, and
216
+ # disconnect any connected clients. When this is executed, there should
217
+ # already have a Mutex lock done, so that we can safely clean everything up.
218
+ def shutdown()
219
+ Thread.kill(@thread) unless @thread.nil?
220
+ @timer.stop
221
+
222
+ @clients.each do |ci|
223
+ ci.sock.send_packet("SHUTDOWN Server is going down now!")
224
+ ci.sock.close
225
+ end
226
+ @clients = []
227
+ @socket.close unless @socket.nil?
228
+ @socket = nil
229
+ append_prog_msg("[#{Time.now}] - Server has been shutdown.")
230
+ get_menu_bar.enable(ID_START,true)
231
+ get_menu_bar.enable(ID_STOP,false)
232
+ end
233
+
234
+ # MyServerFrame#poll()
235
+ # This function collects the sockets for clients, as well as the server
236
+ # socket to poll for incoming connections or data from these sockets.
237
+ # This returns three arrays of sockets from [read,write,error/oob]
238
+ def poll
239
+ pollers = [@socket]
240
+ @clients.each do |ci|
241
+ pollers << ci.sock
242
+ end
243
+ IO::select(pollers,nil,nil,0.3)
244
+ end
245
+
246
+ # MyServerFrame#check_server(socks)
247
+ # This is the core of the processing for the server side. It will check to
248
+ # see if our server socket is in the return for MyServerFrame#poll(), if it's
249
+ # there, then there's an incoming connection, and will run the accepting of
250
+ # the new client connection, and tell the other clients that there is a new
251
+ # incoming connection. It will then remove the server socket from the array
252
+ # so that it's not processed, as well as converting all the remaining sockets
253
+ # if any, back into ClientInfo structures, there by returning them to be
254
+ # processed by the MyServerFrame#check_clients()
255
+ def check_server(socks)
256
+ if socks.index(@socket)
257
+ socks.delete(@socket) # Don't need it in socks
258
+ sock, sockaddr = @socket.accept
259
+ sockaddr = Socket.unpack_sockaddr_in(sockaddr)
260
+ ci = ClientInfo.new("",sockaddr[1],sockaddr[0],sock,"")
261
+ @clients.each do |sci|
262
+ sci.sock.send_packet("CONN #{ci.host} #{ci.port}")
263
+ end
264
+ @clients << ci
265
+ append_msg("[#{Time.now}] - New connection from #{ci.host}:#{ci.port}")
266
+ update_users()
267
+ end
268
+ new_ci = []
269
+ socks.each do |sock|
270
+ @clients.each do |ci|
271
+ if ci.sock == sock
272
+ new_ci << ci
273
+ end
274
+ end
275
+ end
276
+ new_ci
277
+ end
278
+
279
+ # MyServerFrame#update_users()
280
+ # This function actually updates the User listing of thoes currently connected
281
+ # to the server.
282
+ def update_users()
283
+ clear_users()
284
+ add_user(@nick)
285
+ @clients.each do |ci|
286
+ add_user(ci.name)
287
+ end
288
+ end
289
+
290
+ # MyServerFrame#parse_message(ClientInfo,Message)
291
+ # This function parses the incoming data from a Client, to see what is being
292
+ # requested. There are currently 6 commands that the server implemented.
293
+ # CONNECT identifies the Client with their nickname.
294
+ # NICK identifies the client's new nickname if they change it.
295
+ # EMOTE identifies the message as being an Emote, or Action.
296
+ # MSG identifies the message as being a normal message to the server.
297
+ # WHO is an internal request to update who is connected to the server.
298
+ # QUIT identifies that the client is closing the connection to the server.
299
+ #
300
+ # This function parses the message, and responds appropriately, weither it
301
+ # be an internal message to be handled, or it's a repeater, that needs to be
302
+ # sent to all the connected clients, as well as being displayed to the server.
303
+ def parse_message(ci,msg)
304
+ new_msg = nil
305
+ case msg
306
+ when /CONNECT/
307
+ ci.name = msg[8..-1]
308
+ append_msg("<-> #{ci.name} has joined the server!")
309
+ new_msg = msg
310
+ update_users()
311
+ when /NICK/
312
+ new_msg = "NICK #{ci.name} #{msg[5..-1]}"
313
+ append_msg("<-> #{ci.name} has changed nickname to #{msg[5..-1]}")
314
+ ci.name = msg[5..-1]
315
+ update_users()
316
+ when /EMOTE/
317
+ new_msg = "EMOTE #{ci.name} #{msg[6..-1]}"
318
+ append_msg("<-> #{ci.name} #{msg[6..-1]}")
319
+ when /MSG/
320
+ new_msg = "MSG #{ci.name} #{msg[4..-1]}"
321
+ append_msg("<-> #{ci.name} says: #{msg[4..-1]}")
322
+ when /WHO/
323
+ who = "WHO #{@nick} "
324
+ @clients.each do |cci|
325
+ who += cci.name + " "
326
+ end
327
+ ci.sock.send_packet(who[0..-2])
328
+ when /QUIT/
329
+ new_msg = "QUIT #{ci.name}"
330
+ append_msg("<-> #{ci.name} is dis-connecting.")
331
+ else
332
+ append_error("<-- Unknown message from #{ci.name}")
333
+ append_error("<-- Message: #{msg}")
334
+ end
335
+ @clients.each do |cci|
336
+ if cci != ci
337
+ cci.sock.send_packet(new_msg)
338
+ end
339
+ end unless new_msg.nil?
340
+ end
341
+
342
+ # MyServerFrame#check_clients()
343
+ # This method, will run through the collected client connections that show that
344
+ # they have data available in their buffer. It will first check to see if the
345
+ # socket has been closed by utilizing the IO#eof? method. If there is an end
346
+ # of file detected, it means the client connection has been closed. It will then
347
+ # remove the client connection from our pool, and send the rest of the clients
348
+ # that the user has indeed disconnected from the server.
349
+ # After confirming that the connection hasn't been closed, it will check to
350
+ # see what data is available, append it to the client's buffer, where it will
351
+ # then process the data, for the LF (0x0A) termination, saying that this is the
352
+ # end of the message, and then process that data through MyServerFrame#parse_message()
353
+ def check_clients(aci)
354
+ aci.each do |ci|
355
+ if ci.sock.eof?
356
+ ci.sock.close
357
+ @clients.delete(ci)
358
+ @clients.each do |cci|
359
+ cci.sock.send_packet("DISCONN #{ci.name}")
360
+ end
361
+ append_prog_msg("[#{Time.now}] - Socket closed for #{ci.name}")
362
+ update_users()
363
+ else
364
+ msg = ci.sock.recv_packet()
365
+ ci.buffer += msg
366
+ loop do
367
+ at = ci.buffer.index("\n")
368
+ if at.nil?
369
+ break
370
+ end
371
+ data = ci.buffer[0..at-1]
372
+ ci.buffer = ci.buffer[at+1..-1]
373
+ parse_message(ci,data)
374
+ end
375
+ end
376
+ end
377
+ end
378
+
379
+ # MyServerFrame#start_server_thread()
380
+ # This is the meat and bones of the server, where it will continiously poll for
381
+ # data in a seperate Thread, that will utilize the above methods for processing
382
+ # the incoming connections, and data being inputed from clients. This thread
383
+ # does no yielding, or anything of the sort to wxRuby, as it's in a seperate
384
+ # thread being controlled by Ruby. This thread is given time to run, by the
385
+ # Thread#yield() method, that is put into a context of a Timer that executes
386
+ # every 300 Milliseconds, and so forth. We start the timer here, so that way
387
+ # we ensure that it get's started, and stopped at the correct times.
388
+ def start_server_thread()
389
+ @thread = Thread.new do
390
+ @timer.start(25)
391
+ loop do # We just run a continious loop. on_stop() will kill this thread, and stop the timer.
392
+ begin # We run here, just incase there's some kind of error
393
+ @mutex.lock # We lock the data, so there's no corruption between threads
394
+ socks = poll() # We run a poll for any incoming data, or any new incoming connections
395
+ unless socks.nil?
396
+ ci = check_server(socks[0]) # Check to see if we have any incoming connections
397
+ check_clients(ci) # Check for client activity
398
+ end
399
+ @mutex.unlock # We can now release it, as we've done everything needed here
400
+ rescue => e # We have an error, so we need to process it.
401
+ msg = ["An error has occured!"]
402
+ msg << "#{e.backtrace.delete_at(0)}: #{e} (#{e.class})"
403
+ e.backtrace.each do |line|
404
+ msg << line
405
+ end
406
+ msg.each do |line|
407
+ append_error(line)
408
+ end
409
+ end
410
+ end
411
+ end
412
+ end
413
+ end
414
+
415
+ class MySocketApp < Wx::App
416
+ def on_init
417
+ frame = MyServerFrame.new(nil,-1,"Sockets Demo >> Server")
418
+ frame.show
419
+ end
420
+ end
421
+
422
+ MySocketApp.new.main_loop
@@ -0,0 +1,97 @@
1
+ # wxRuby2 Sample Code. Copyright (c) 2007-???? Mario J. Steele
2
+ # Freely reusable code: see SAMPLES-LICENSE.TXT for details
3
+
4
+ if /darwin/ =~ RUBY_PLATFORM
5
+ $LOCALHOST_NAME = "127.0.0.1"
6
+ else
7
+ $LOCALHOST_NAME = "localhost"
8
+ end
9
+
10
+ class SocketGUI < Wx::Frame
11
+ @@constants = []
12
+
13
+ def initialize(*args)
14
+ super
15
+ icon_file = File.join( File.dirname(__FILE__), 'res', 'message-new.png')
16
+ self.icon = Wx::Icon.new(icon_file,Wx::BITMAP_TYPE_PNG)
17
+
18
+ @il = Wx::ImageList.new(16,16)
19
+ # User icon courtesy of http://www.famfamfam.com/lab/icons/silk/
20
+ icon_file = File.join( File.dirname(__FILE__), 'res', 'user.png')
21
+ @il.add( Wx::Bitmap.new(icon_file, Wx::BITMAP_TYPE_PNG) )
22
+ hbox = Wx::BoxSizer.new(Wx::HORIZONTAL)
23
+ vbox = Wx::BoxSizer.new(Wx::VERTICAL)
24
+
25
+ # For display of Text Events
26
+ @output = Wx::TextCtrl.new( self, :style => Wx::TE_RICH2|
27
+ Wx::TE_READONLY|Wx::SUNKEN_BORDER|
28
+ Wx::TE_MULTILINE|Wx::TE_AUTO_URL)
29
+ # List of Users
30
+ @users = Wx::ListCtrl.new( self, :style => Wx::LC_REPORT|
31
+ Wx::LC_NO_HEADER|Wx::LC_SINGLE_SEL)
32
+ @users.set_image_list(@il,Wx::IMAGE_LIST_SMALL)
33
+ @users.insert_column(0,"Users")
34
+ # For Input from the User
35
+ @input = Wx::TextCtrl.new(self, :style => Wx::TE_PROCESS_ENTER)
36
+ vbox.add(@output,2,Wx::EXPAND)
37
+ vbox.add(@input,0,Wx::GROW)
38
+ hbox.add(vbox,2,Wx::EXPAND)
39
+ hbox.add(@users,0,Wx::GROW)
40
+ self.sizer = hbox
41
+ @@constants.each_with_index do |const,i|
42
+ self.class.const_set(const,1001+i)
43
+ end
44
+ create_menus()
45
+ create_status_bar()
46
+ on_init()
47
+ @font = Wx::Font.new(10,Wx::FONTFAMILY_TELETYPE,Wx::NORMAL,Wx::NORMAL)
48
+ @progStyle = Wx::TextAttr.new(Wx::BLUE, Wx::YELLOW, @font)
49
+ @defStyle = Wx::TextAttr.new(Wx::BLACK, Wx::WHITE, @font)
50
+ @errStyle = Wx::TextAttr.new(Wx::RED, Wx::GREEN, @font)
51
+ self.set_size([640,480])
52
+ end
53
+
54
+ def add_user(user)
55
+ #@users.append_item(@root,user,0)
56
+ @users.insert_item(0,user,0)
57
+ end
58
+
59
+ def clear_users()
60
+ @users.delete_all_items
61
+ end
62
+
63
+ def create_menus()
64
+ # Holder Function
65
+ end
66
+
67
+ def on_init()
68
+ # Holder Function
69
+ end
70
+
71
+ def append_text(msg)
72
+ @output.freeze
73
+ c, sl = @output.position_to_xy(@output.get_last_position)
74
+ @output.append_text(msg)
75
+ @output.thaw
76
+ c, el = @output.position_to_xy(@output.get_last_position)
77
+ @output.scroll_lines((el-sl)+2) unless sl == nil || el == nil
78
+ end
79
+
80
+ def append_prog_msg(msg)
81
+ @output.set_default_style(@progStyle)
82
+ msg += "\n" if msg[-1].chr != "\n"
83
+ append_text(msg)
84
+ end
85
+
86
+ def append_msg(msg)
87
+ @output.set_default_style(@defStyle)
88
+ msg += "\n" if msg[-1].chr != "\n"
89
+ append_text(msg)
90
+ end
91
+
92
+ def append_error(msg)
93
+ @output.set_default_style(@errStyle)
94
+ msg += "\n" if msg[-1].chr != "\n"
95
+ append_text(msg)
96
+ end
97
+ end
Binary file
@@ -0,0 +1,44 @@
1
+ /* XPM */
2
+ static char *mondrian_xpm[] = {
3
+ /* columns rows colors chars-per-pixel */
4
+ "32 32 6 1",
5
+ " c Black",
6
+ ". c Blue",
7
+ "X c #00bf00",
8
+ "o c Red",
9
+ "O c Yellow",
10
+ "+ c Gray100",
11
+ /* pixels */
12
+ " ",
13
+ " oooooo +++++++++++++++++++++++ ",
14
+ " oooooo +++++++++++++++++++++++ ",
15
+ " oooooo +++++++++++++++++++++++ ",
16
+ " oooooo +++++++++++++++++++++++ ",
17
+ " oooooo +++++++++++++++++++++++ ",
18
+ " oooooo +++++++++++++++++++++++ ",
19
+ " oooooo +++++++++++++++++++++++ ",
20
+ " ",
21
+ " ++++++ ++++++++++++++++++ .... ",
22
+ " ++++++ ++++++++++++++++++ .... ",
23
+ " ++++++ ++++++++++++++++++ .... ",
24
+ " ++++++ ++++++++++++++++++ .... ",
25
+ " ++++++ ++++++++++++++++++ .... ",
26
+ " ++++++ ++++++++++++++++++ ",
27
+ " ++++++ ++++++++++++++++++ ++++ ",
28
+ " ++++++ ++++++++++++++++++ ++++ ",
29
+ " ++++++ ++++++++++++++++++ ++++ ",
30
+ " ++++++ ++++++++++++++++++ ++++ ",
31
+ " ++++++ ++++++++++++++++++ ++++ ",
32
+ " ++++++ ++++++++++++++++++ ++++ ",
33
+ " ++++++ ++++++++++++++++++ ++++ ",
34
+ " ++++++ ++++++++++++++++++ ++++ ",
35
+ " ++++++ ++++++++++++++++++ ++++ ",
36
+ " ++++++ ++++ ",
37
+ " ++++++ OOOOOOOOOOOO XXXXX ++++ ",
38
+ " ++++++ OOOOOOOOOOOO XXXXX ++++ ",
39
+ " ++++++ OOOOOOOOOOOO XXXXX ++++ ",
40
+ " ++++++ OOOOOOOOOOOO XXXXX ++++ ",
41
+ " ++++++ OOOOOOOOOOOO XXXXX ++++ ",
42
+ " ++++++ OOOOOOOOOOOO XXXXX ++++ ",
43
+ " "
44
+ };