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.
- data/LICENSE +53 -0
- data/README +297 -0
- data/lib/wx/accessors.rb +52 -0
- data/lib/wx/classes/acceleratortable.rb +28 -0
- data/lib/wx/classes/animation.rb +18 -0
- data/lib/wx/classes/app.rb +45 -0
- data/lib/wx/classes/artprovider.rb +31 -0
- data/lib/wx/classes/bitmap.rb +28 -0
- data/lib/wx/classes/busycursor.rb +12 -0
- data/lib/wx/classes/checklistbox.rb +45 -0
- data/lib/wx/classes/choice.rb +4 -0
- data/lib/wx/classes/clientdc.rb +13 -0
- data/lib/wx/classes/clipboard.rb +16 -0
- data/lib/wx/classes/colour.rb +47 -0
- data/lib/wx/classes/combobox.rb +4 -0
- data/lib/wx/classes/commandevent.rb +7 -0
- data/lib/wx/classes/controlwithitems.rb +10 -0
- data/lib/wx/classes/dc.rb +57 -0
- data/lib/wx/classes/event.rb +5 -0
- data/lib/wx/classes/evthandler.rb +921 -0
- data/lib/wx/classes/font.rb +118 -0
- data/lib/wx/classes/functions.rb +44 -0
- data/lib/wx/classes/gauge.rb +12 -0
- data/lib/wx/classes/grid.rb +138 -0
- data/lib/wx/classes/helpcontroller.rb +5 -0
- data/lib/wx/classes/htmlhelpcontroller.rb +5 -0
- data/lib/wx/classes/htmlwindow.rb +14 -0
- data/lib/wx/classes/icon.rb +21 -0
- data/lib/wx/classes/iconbundle.rb +3 -0
- data/lib/wx/classes/image.rb +31 -0
- data/lib/wx/classes/imagelist.rb +3 -0
- data/lib/wx/classes/listbox.rb +4 -0
- data/lib/wx/classes/listctrl.rb +21 -0
- data/lib/wx/classes/locale.rb +28 -0
- data/lib/wx/classes/mediactrl.rb +22 -0
- data/lib/wx/classes/menu.rb +62 -0
- data/lib/wx/classes/menuitem.rb +7 -0
- data/lib/wx/classes/object.rb +7 -0
- data/lib/wx/classes/paintdc.rb +12 -0
- data/lib/wx/classes/point.rb +48 -0
- data/lib/wx/classes/previewframe.rb +13 -0
- data/lib/wx/classes/rect.rb +10 -0
- data/lib/wx/classes/size.rb +49 -0
- data/lib/wx/classes/sound.rb +23 -0
- data/lib/wx/classes/styledtextctrl.rb +92 -0
- data/lib/wx/classes/textctrl.rb +14 -0
- data/lib/wx/classes/texturlevent.rb +6 -0
- data/lib/wx/classes/timer.rb +94 -0
- data/lib/wx/classes/toolbartool.rb +4 -0
- data/lib/wx/classes/treectrl.rb +44 -0
- data/lib/wx/classes/window.rb +82 -0
- data/lib/wx/classes/xmlresource.rb +37 -0
- data/lib/wx/keyword_ctors.rb +222 -0
- data/lib/wx/keyword_defs.rb +492 -0
- data/lib/wx/version.rb +3 -0
- data/lib/wx.rb +42 -0
- data/lib/wxruby2.so +0 -0
- data/samples/SAMPLES-LICENSE.TXT +18 -0
- data/samples/aui/aui.rb +1356 -0
- data/samples/bigdemo/About.rbw +39 -0
- data/samples/bigdemo/ColorPanel.rbw +23 -0
- data/samples/bigdemo/GridSimple.rbw +78 -0
- data/samples/bigdemo/MDIDemo.rbw +57 -0
- data/samples/bigdemo/PopupMenu.rbw +149 -0
- data/samples/bigdemo/ShapedWindow.rbw +131 -0
- data/samples/bigdemo/Sizers.rbw +543 -0
- data/samples/bigdemo/bigdemo.rb +823 -0
- data/samples/bigdemo/demoTemplate.rbw +33 -0
- data/samples/bigdemo/helpfile.htb +0 -0
- data/samples/bigdemo/icons/Test 015.jpg +0 -0
- data/samples/bigdemo/icons/Test 015.png +0 -0
- data/samples/bigdemo/icons/choice.bmp +0 -0
- data/samples/bigdemo/icons/choice.xpm +27 -0
- data/samples/bigdemo/icons/combo.bmp +0 -0
- data/samples/bigdemo/icons/combo.xpm +27 -0
- data/samples/bigdemo/icons/copy.xpm +25 -0
- data/samples/bigdemo/icons/cut.xpm +24 -0
- data/samples/bigdemo/icons/gauge.bmp +0 -0
- data/samples/bigdemo/icons/gauge.xpm +27 -0
- data/samples/bigdemo/icons/help.xpm +25 -0
- data/samples/bigdemo/icons/list.bmp +0 -0
- data/samples/bigdemo/icons/list.xpm +27 -0
- data/samples/bigdemo/icons/mondrian.ico +0 -0
- data/samples/bigdemo/icons/mondrian.xpm +44 -0
- data/samples/bigdemo/icons/new.xpm +24 -0
- data/samples/bigdemo/icons/ogl.ico +0 -0
- data/samples/bigdemo/icons/ogl.xpm +45 -0
- data/samples/bigdemo/icons/open.xpm +26 -0
- data/samples/bigdemo/icons/paste.bmp +0 -0
- data/samples/bigdemo/icons/paste.xpm +38 -0
- data/samples/bigdemo/icons/pointy.png +0 -0
- data/samples/bigdemo/icons/preview.xpm +26 -0
- data/samples/bigdemo/icons/print.xpm +26 -0
- data/samples/bigdemo/icons/radio.bmp +0 -0
- data/samples/bigdemo/icons/radio.xpm +27 -0
- data/samples/bigdemo/icons/robert.xpm +415 -0
- data/samples/bigdemo/icons/ruby.png +0 -0
- data/samples/bigdemo/icons/sashtest.ico +0 -0
- data/samples/bigdemo/icons/save.xpm +25 -0
- data/samples/bigdemo/icons/smiles.bmp +0 -0
- data/samples/bigdemo/icons/smiles.xpm +39 -0
- data/samples/bigdemo/icons/smiley.ico +0 -0
- data/samples/bigdemo/icons/smiley.xpm +42 -0
- data/samples/bigdemo/icons/stattext.xpm +24 -0
- data/samples/bigdemo/icons/test2.bmp +0 -0
- data/samples/bigdemo/icons/test2.png +0 -0
- data/samples/bigdemo/icons/test2.xpm +79 -0
- data/samples/bigdemo/icons/text.bmp +0 -0
- data/samples/bigdemo/icons/text.xpm +27 -0
- data/samples/bigdemo/icons/tog1.bmp +0 -0
- data/samples/bigdemo/icons/tog1.xpm +38 -0
- data/samples/bigdemo/icons/tog2.bmp +0 -0
- data/samples/bigdemo/icons/tog2.xpm +38 -0
- data/samples/bigdemo/icons/wxwin.ico +0 -0
- data/samples/bigdemo/icons/wxwin16x16.png +0 -0
- data/samples/bigdemo/icons/wxwin16x16.xpm +25 -0
- data/samples/bigdemo/icons/wxwin32x32.png +0 -0
- data/samples/bigdemo/icons/wxwin48x48.png +0 -0
- data/samples/bigdemo/run.rb +90 -0
- data/samples/bigdemo/tips.txt +7 -0
- data/samples/bigdemo/utils.rb +12 -0
- data/samples/bigdemo/wxArtProvider.rbw +281 -0
- data/samples/bigdemo/wxBitmapButton.rbw +65 -0
- data/samples/bigdemo/wxButton.rbw +64 -0
- data/samples/bigdemo/wxCalendarCtrl.rbw +60 -0
- data/samples/bigdemo/wxCheckBox.rbw +50 -0
- data/samples/bigdemo/wxCheckListBox.rbw +75 -0
- data/samples/bigdemo/wxChoice.rbw +47 -0
- data/samples/bigdemo/wxChoicebook.rbw +78 -0
- data/samples/bigdemo/wxColourDialog.rbw +31 -0
- data/samples/bigdemo/wxComboBox.rbw +77 -0
- data/samples/bigdemo/wxCursor.rbw +136 -0
- data/samples/bigdemo/wxDialog.rbw +74 -0
- data/samples/bigdemo/wxDirDialog.rbw +29 -0
- data/samples/bigdemo/wxDragImage.rbw +70 -0
- data/samples/bigdemo/wxFileDialog.rbw +37 -0
- data/samples/bigdemo/wxFileDialog_Save.rbw +35 -0
- data/samples/bigdemo/wxFindReplaceDialog.rbw +82 -0
- data/samples/bigdemo/wxFontDialog.rbw +173 -0
- data/samples/bigdemo/wxFrame.rbw +53 -0
- data/samples/bigdemo/wxGauge.rbw +71 -0
- data/samples/bigdemo/wxGenericDirCtrl.rbw +74 -0
- data/samples/bigdemo/wxGrid.rbw +66 -0
- data/samples/bigdemo/wxHtmlHelpController.rbw +52 -0
- data/samples/bigdemo/wxListBox.rbw +140 -0
- data/samples/bigdemo/wxListCtrl_virtual.rbw +107 -0
- data/samples/bigdemo/wxMDIWindows.rbw +50 -0
- data/samples/bigdemo/wxMenu.rbw +236 -0
- data/samples/bigdemo/wxMessageDialog.rbw +27 -0
- data/samples/bigdemo/wxMiniFrame.rbw +70 -0
- data/samples/bigdemo/wxMultipleChoiceDialog.rbw +32 -0
- data/samples/bigdemo/wxNotebook.rbw +136 -0
- data/samples/bigdemo/wxProgressDialog.rbw +43 -0
- data/samples/bigdemo/wxRadioBox.rbw +72 -0
- data/samples/bigdemo/wxRadioButton.rbw +125 -0
- data/samples/bigdemo/wxSashWindow.rbw +141 -0
- data/samples/bigdemo/wxScrolledMessageDialog.rbw +57 -0
- data/samples/bigdemo/wxScrolledWindow.rbw +199 -0
- data/samples/bigdemo/wxSingleChoiceDialog.rbw +33 -0
- data/samples/bigdemo/wxSlider.rbw +42 -0
- data/samples/bigdemo/wxSpinButton.rbw +50 -0
- data/samples/bigdemo/wxSpinCtrl.rbw +51 -0
- data/samples/bigdemo/wxSplitterWindow.rbw +63 -0
- data/samples/bigdemo/wxStaticBitmap.rbw +51 -0
- data/samples/bigdemo/wxStaticText.rbw +55 -0
- data/samples/bigdemo/wxStatusBar.rbw +126 -0
- data/samples/bigdemo/wxTextCtrl.rbw +149 -0
- data/samples/bigdemo/wxTextEntryDialog.rbw +31 -0
- data/samples/bigdemo/wxToggleButton.rbw +49 -0
- data/samples/bigdemo/wxToolBar.rbw +131 -0
- data/samples/bigdemo/wxTreeCtrl.rbw +190 -0
- data/samples/calendar/calendar.rb +271 -0
- data/samples/caret/caret.rb +282 -0
- data/samples/caret/mondrian.xpm +44 -0
- data/samples/controls/controls.rb +1136 -0
- data/samples/controls/get_item_sample.rb +87 -0
- data/samples/controls/icons/choice.xpm +27 -0
- data/samples/controls/icons/combo.xpm +27 -0
- data/samples/controls/icons/gauge.xpm +27 -0
- data/samples/controls/icons/list.xpm +27 -0
- data/samples/controls/icons/radio.xpm +27 -0
- data/samples/controls/icons/stattext.xpm +24 -0
- data/samples/controls/icons/text.xpm +27 -0
- data/samples/controls/mondrian.ico +0 -0
- data/samples/controls/mondrian.xpm +44 -0
- data/samples/controls/test2.bmp +0 -0
- data/samples/dialogs/dialogs.rb +723 -0
- data/samples/dialogs/tips.txt +18 -0
- data/samples/drawing/graphics_drawing.rb +235 -0
- data/samples/drawing/images.rb +37 -0
- data/samples/drawing/paperclip.png +0 -0
- data/samples/etc/activation.rb +102 -0
- data/samples/etc/choice.rb +67 -0
- data/samples/etc/miniframe.rb +79 -0
- data/samples/etc/sash.rb +130 -0
- data/samples/etc/scrollwin.rb +110 -0
- data/samples/etc/system_settings.rb +252 -0
- data/samples/etc/threaded.rb +72 -0
- data/samples/etc/wizard.rb +74 -0
- data/samples/event/event.rb +182 -0
- data/samples/grid/grid.rb +198 -0
- data/samples/grid/gridtablebase.rb +134 -0
- data/samples/html/html.rb +262 -0
- data/samples/listbook/listbook.rb +174 -0
- data/samples/listbook/listbook.xrc +370 -0
- data/samples/mdi/mdi.rb +82 -0
- data/samples/media/mediactrl.rb +167 -0
- data/samples/minimal/minimal.rb +77 -0
- data/samples/minimal/mondrian.ico +0 -0
- data/samples/minimal/mondrian.png +0 -0
- data/samples/minimal/nothing.rb +16 -0
- data/samples/opengl/cube.rb +117 -0
- data/samples/printing/mondrian.ico +0 -0
- data/samples/printing/mondrian.xpm +44 -0
- data/samples/printing/printing.rb +310 -0
- data/samples/sockets/SocketPackets.rb +27 -0
- data/samples/sockets/res/message-new.png +0 -0
- data/samples/sockets/res/user.png +0 -0
- data/samples/sockets/wxClient.rb +395 -0
- data/samples/sockets/wxServer.rb +422 -0
- data/samples/sockets/wxSocketGUI.rb +97 -0
- data/samples/text/mondrian.ico +0 -0
- data/samples/text/mondrian.xpm +44 -0
- data/samples/text/scintilla.rb +169 -0
- data/samples/text/textctrl.rb +113 -0
- data/samples/text/unicode.rb +242 -0
- data/samples/text/utf8.txt +15 -0
- data/samples/treectrl/icon1.xpm +79 -0
- data/samples/treectrl/icon2.xpm +53 -0
- data/samples/treectrl/icon3.xpm +79 -0
- data/samples/treectrl/icon4.xpm +43 -0
- data/samples/treectrl/icon5.xpm +79 -0
- data/samples/treectrl/treectrl.rb +1174 -0
- data/samples/xrc/samples.xrc +46 -0
- data/samples/xrc/xrc_sample.rb +96 -0
- 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
|
+
};
|