Use the associated document manager, not the global one
[wxWidgets.git] / src / common / socketevtdispatch.cpp
1 ///////////////////////////////////////////////////////////////////////////////
2 // Name: src/common/socketevtdispatch.cpp
3 // Purpose: implements wxSocketEventDispatcher for platforms with no
4 // socket events notification
5 // Author: Angel Vidal
6 // Modified by:
7 // Created: 08.24.06
8 // RCS-ID: $Id$
9 // Copyright: (c) 2006 Angel vidal
10 // License: wxWindows licence
11 ///////////////////////////////////////////////////////////////////////////////
12
13 // ============================================================================
14 // declarations
15 // ============================================================================
16
17 // ----------------------------------------------------------------------------
18 // headers
19 // ----------------------------------------------------------------------------
20
21 // for compilers that support precompilation, includes "wx.h".
22 #include "wx/wxprec.h"
23
24 #if wxUSE_SOCKETS
25
26 #include "wx/private/socketevtdispatch.h"
27 #include "wx/module.h"
28 #include "wx/unix/private.h"
29 #include "wx/gsocket.h"
30 #include "wx/unix/gsockunx.h"
31
32 #ifndef WX_PRECOMP
33 #include "wx/hash.h"
34 #endif
35
36 #include <sys/time.h>
37 #include <unistd.h>
38
39 #ifdef HAVE_SYS_SELECT_H
40 # include <sys/select.h>
41 #endif
42
43 // ============================================================================
44 // implementation
45 // ============================================================================
46
47 // ----------------------------------------------------------------------------
48 // wxSocketEventDispatcherEntry
49 // ----------------------------------------------------------------------------
50
51 class wxSocketEventDispatcherEntry: public wxObject
52 {
53 public:
54 wxSocketEventDispatcherEntry()
55 {
56 m_fdInput = -1; m_fdOutput = -1;
57 m_socket = NULL;
58 }
59
60 int m_fdInput;
61 int m_fdOutput;
62 GSocket* m_socket;
63 };
64
65 // ----------------------------------------------------------------------------
66 // wxSocketEventDispatcher
67 // ----------------------------------------------------------------------------
68
69 wxSocketEventDispatcher* wxSocketEventDispatcher::ms_instance = NULL;
70
71 /* static */
72 wxSocketEventDispatcher& wxSocketEventDispatcher::Get()
73 {
74 if ( !ms_instance )
75 ms_instance = new wxSocketEventDispatcher;
76 return *ms_instance;
77 }
78
79 wxSocketEventDispatcherEntry* wxSocketEventDispatcher::FindEntry(int fd)
80 {
81 wxSocketEventDispatcherEntry* entry =
82 (wxSocketEventDispatcherEntry*) wxHashTable::Get(fd);
83 return entry;
84 }
85
86 void
87 wxSocketEventDispatcher::RegisterCallback(int fd,
88 wxSocketEventDispatcherType socketType,
89 GSocket* socket)
90 {
91 wxSocketEventDispatcherEntry* entry = FindEntry(fd);
92 if (!entry)
93 {
94 entry = new wxSocketEventDispatcherEntry();
95 Put(fd, entry);
96 }
97
98 if (socketType == wxSocketEventDispatcherInput)
99 entry->m_fdInput = fd;
100 else
101 entry->m_fdOutput = fd;
102
103 entry->m_socket = socket;
104 }
105
106 void
107 wxSocketEventDispatcher::UnregisterCallback(int fd,
108 wxSocketEventDispatcherType socketType)
109 {
110 wxSocketEventDispatcherEntry* entry = FindEntry(fd);
111 if (entry)
112 {
113 if (socketType == wxSocketEventDispatcherInput)
114 entry->m_fdInput = -1;
115 else
116 entry->m_fdOutput = -1;
117
118 if (entry->m_fdInput == -1 && entry->m_fdOutput == -1)
119 {
120 entry->m_socket = NULL;
121 Delete(fd);
122 delete entry;
123 }
124 }
125 }
126
127 int wxSocketEventDispatcher::FillSets(fd_set* readset, fd_set* writeset)
128 {
129 int max_fd = 0;
130
131 wxFD_ZERO(readset);
132 wxFD_ZERO(writeset);
133
134 BeginFind();
135 wxHashTable::compatibility_iterator node = Next();
136 while (node)
137 {
138 wxSocketEventDispatcherEntry* entry =
139 (wxSocketEventDispatcherEntry*) node->GetData();
140
141 if (entry->m_fdInput != -1)
142 {
143 wxFD_SET(entry->m_fdInput, readset);
144 if (entry->m_fdInput > max_fd)
145 max_fd = entry->m_fdInput;
146 }
147
148 if (entry->m_fdOutput != -1)
149 {
150 wxFD_SET(entry->m_fdOutput, writeset);
151 if (entry->m_fdOutput > max_fd)
152 max_fd = entry->m_fdOutput;
153 }
154
155 node = Next();
156 }
157
158 return max_fd;
159 }
160
161 void wxSocketEventDispatcher::AddEvents(fd_set* readset, fd_set* writeset)
162 {
163 BeginFind();
164 wxHashTable::compatibility_iterator node = Next();
165 while (node)
166 {
167 // We have to store the next node here, because the event processing can
168 // destroy the object before we call Next()
169
170 wxHashTable::compatibility_iterator next_node = Next();
171
172 wxSocketEventDispatcherEntry* entry =
173 (wxSocketEventDispatcherEntry*) node->GetData();
174
175 wxCHECK_RET(entry->m_socket, wxT("Critical: Processing a NULL socket in wxSocketEventDispatcher"));
176
177 if (entry->m_fdInput != -1 && wxFD_ISSET(entry->m_fdInput, readset))
178 entry->m_socket->Detected_Read();
179
180 if (entry->m_fdOutput != -1 && wxFD_ISSET(entry->m_fdOutput, writeset))
181 entry->m_socket->Detected_Write();;
182
183 node = next_node;
184 }
185 }
186
187 void wxSocketEventDispatcher::RunLoop(int timeout)
188 {
189 struct timeval tv;
190 tv.tv_sec = 0;
191 tv.tv_usec = timeout;
192 fd_set readset;
193 fd_set writeset;
194
195 int max_fd = FillSets( &readset, &writeset);
196 if (select( max_fd+1, &readset, &writeset, NULL, &tv ) == 0)
197 {
198 // No socket input/output. Don't add events.
199 return;
200 }
201 else
202 {
203 AddEvents(&readset, &writeset);
204 }
205 }
206
207 // ----------------------------------------------------------------------------
208 // wxSocketEventDispatcherModule
209 // ----------------------------------------------------------------------------
210
211 class wxSocketEventDispatcherModule: public wxModule
212 {
213 public:
214 bool OnInit() { return true; }
215 void OnExit() { wxDELETE(wxSocketEventDispatcher::ms_instance); }
216
217 private:
218 DECLARE_DYNAMIC_CLASS(wxSocketEventDispatcherModule)
219 };
220
221 IMPLEMENT_DYNAMIC_CLASS(wxSocketEventDispatcherModule, wxModule)
222
223
224 // ----------------------------------------------------------------------------
225 // GSocket interface
226 // ----------------------------------------------------------------------------
227
228 bool GSocketGUIFunctionsTableConcrete::CanUseEventLoop()
229 {
230 return true;
231 }
232
233 bool GSocketGUIFunctionsTableConcrete::OnInit(void)
234 {
235 return 1;
236 }
237
238 void GSocketGUIFunctionsTableConcrete::OnExit(void)
239 {
240 }
241
242 bool GSocketGUIFunctionsTableConcrete::Init_Socket(GSocket *socket)
243 {
244 int *m_id;
245
246 socket->m_gui_dependent = (char *)malloc(sizeof(int)*2);
247 m_id = (int *)(socket->m_gui_dependent);
248
249 m_id[0] = -1;
250 m_id[1] = -1;
251
252 return true;
253 }
254
255 void GSocketGUIFunctionsTableConcrete::Destroy_Socket(GSocket *socket)
256 {
257 free(socket->m_gui_dependent);
258 }
259
260 void GSocketGUIFunctionsTableConcrete::Install_Callback(GSocket *socket,
261 GSocketEvent event)
262 {
263 int *m_id = (int *)(socket->m_gui_dependent);
264 int c;
265
266 if (socket->m_fd == -1)
267 return;
268
269 switch (event)
270 {
271 case GSOCK_LOST: /* fall-through */
272 case GSOCK_INPUT: c = 0; break;
273 case GSOCK_OUTPUT: c = 1; break;
274 case GSOCK_CONNECTION: c = ((socket->m_server) ? 0 : 1); break;
275 default: return;
276 }
277
278 #if 0
279 if (m_id[c] != -1)
280 XtRemoveInput(m_id[c]);
281 #endif /* 0 */
282
283 if (c == 0)
284 {
285 m_id[0] = socket->m_fd;
286
287 wxSocketEventDispatcher::Get().RegisterCallback(
288 socket->m_fd, wxSocketEventDispatcherInput, socket);
289 }
290 else
291 {
292 m_id[1] = socket->m_fd;
293
294 wxSocketEventDispatcher::Get().RegisterCallback(
295 socket->m_fd, wxSocketEventDispatcherOutput, socket);
296 }
297 }
298
299 void GSocketGUIFunctionsTableConcrete::Uninstall_Callback(GSocket *socket,
300 GSocketEvent event)
301 {
302 int *m_id = (int *)(socket->m_gui_dependent);
303 int c;
304
305 switch (event)
306 {
307 case GSOCK_LOST: /* fall-through */
308 case GSOCK_INPUT: c = 0; break;
309 case GSOCK_OUTPUT: c = 1; break;
310 case GSOCK_CONNECTION: c = ((socket->m_server) ? 0 : 1); break;
311 default: return;
312 }
313
314 if (m_id[c] != -1)
315 {
316 if (c == 0)
317 wxSocketEventDispatcher::Get().UnregisterCallback(
318 m_id[c], wxSocketEventDispatcherInput);
319 else
320 wxSocketEventDispatcher::Get().UnregisterCallback(
321 m_id[c], wxSocketEventDispatcherOutput);
322 }
323
324 m_id[c] = -1;
325 }
326
327 void GSocketGUIFunctionsTableConcrete::Enable_Events(GSocket *socket)
328 {
329 Install_Callback(socket, GSOCK_INPUT);
330 Install_Callback(socket, GSOCK_OUTPUT);
331 }
332
333 void GSocketGUIFunctionsTableConcrete::Disable_Events(GSocket *socket)
334 {
335 Uninstall_Callback(socket, GSOCK_INPUT);
336 Uninstall_Callback(socket, GSOCK_OUTPUT);
337 }
338
339 #endif // wxUSE_SOCKETS