]> git.saurik.com Git - wxWidgets.git/blame - src/mac/corefoundation/gsockosx.cpp
Fix a number of problems with tracking rectangles by avoiding rebuilding them when...
[wxWidgets.git] / src / mac / corefoundation / gsockosx.cpp
CommitLineData
02dad85e
DE
1/* -------------------------------------------------------------------------
2 * Project: GSocket (Generic Socket) for WX
0ba6a836 3 * Name: src/mac/corefoundation/gsockosx.c
02dad85e
DE
4 * Purpose: GSocket: Mac OS X mach-o part
5 * CVSID: $Id$
6 * Mac code by Brian Victor, February 2002. Email comments to bhv1@psu.edu
7 * ------------------------------------------------------------------------- */
8
0ba6a836 9#include "wx/wxprec.h"
02dad85e
DE
10
11#if wxUSE_SOCKETS
12
13#include <stdlib.h>
14#include "wx/gsocket.h"
15#include "wx/unix/gsockunx.h"
16
17#include <CoreFoundation/CoreFoundation.h>
18
19#define ALL_CALLBACK_TYPES (kCFSocketReadCallBack | kCFSocketWriteCallBack | kCFSocketConnectCallBack)
20
21struct MacGSocketData
22{
23 CFSocketRef socket;
24 CFRunLoopSourceRef source;
25};
26
7725dc7c
KH
27// Sockets must use the event loop on the main thread
28// We will store the main loop's reference when Initialize is called
29static CFRunLoopRef s_mainRunLoop = NULL;
30
02dad85e
DE
31void Mac_Socket_Callback(CFSocketRef s, CFSocketCallBackType callbackType,
32 CFDataRef address, const void* data, void* info)
33{
34 GSocket* socket = (GSocket*)info;
35 struct MacGSocketData* macdata;
36 macdata = (struct MacGSocketData*)socket->m_gui_dependent;
37 if (!macdata) return;
38 switch (callbackType)
39 {
40 case kCFSocketConnectCallBack:
41 assert(!socket->m_server);
5cf85da1
KH
42 // KH: If data is non-NULL, the connect failed, do not call Detected_Write,
43 // which will only end up creating a spurious connect event because the
44 // call to getsocketopt SO_ERROR inexplicably returns no error.
45 // The change in behavior cannot be traced to any particular commit or
46 // timeframe so I'm not sure what to think, but after so many hours,
47 // this seems to address the issue and it's time to move on.
48 if (data == NULL)
49 socket->Detected_Write();
02dad85e
DE
50 break;
51 case kCFSocketReadCallBack:
0a647691 52 socket->Detected_Read();
02dad85e
DE
53 break;
54 case kCFSocketWriteCallBack:
0a647691 55 socket->Detected_Write();
02dad85e
DE
56 break;
57 default:
58 break; /* We shouldn't get here. */
59 }
60}
61
62struct MacGSocketData* _GSocket_Get_Mac_Socket(GSocket *socket)
63{
64 /* If socket is already created, returns a pointer to the data */
65 /* Otherwise, creates socket and returns the pointer */
66 CFSocketContext cont;
67 struct MacGSocketData* data = (struct MacGSocketData*)socket->m_gui_dependent;
68
69 if (data && data->source) return data;
70
71 /* CFSocket has not been created, create it: */
72 if (socket->m_fd < 0 || !data) return NULL;
73 cont.version = 0; cont.retain = NULL;
74 cont.release = NULL; cont.copyDescription = NULL;
75 cont.info = socket;
76
77 CFSocketRef cf = CFSocketCreateWithNative(NULL, socket->m_fd,
0ba6a836 78 ALL_CALLBACK_TYPES, Mac_Socket_Callback, &cont);
02dad85e
DE
79 CFRunLoopSourceRef source = CFSocketCreateRunLoopSource(NULL, cf, 0);
80 assert(source);
81 socket->m_gui_dependent = (char*)data;
82
83 /* Keep the source and the socket around. */
84 data->source = source;
85 data->socket = cf;
86
87 return data;
88}
89
0a647691
DE
90bool GSocketGUIFunctionsTableConcrete::CanUseEventLoop()
91{ return true; }
92
93bool GSocketGUIFunctionsTableConcrete::OnInit(void)
02dad85e 94{
7725dc7c
KH
95 // No need to store the main loop again
96 if (s_mainRunLoop != NULL)
97 return true;
98
99 // Get the loop for the main thread so our events will actually fire.
100 // The common socket.cpp code will assert if initialize is called from a
101 // secondary thread, otherwise Mac would have the same problems as MSW
102 s_mainRunLoop = CFRunLoopGetCurrent();
103 CFRetain(s_mainRunLoop);
104
0a647691 105 return true;
02dad85e
DE
106}
107
0a647691 108void GSocketGUIFunctionsTableConcrete::OnExit(void)
02dad85e 109{
7725dc7c
KH
110 // Release the reference count, and set the reference back to NULL
111 CFRelease(s_mainRunLoop);
112 s_mainRunLoop = NULL;
02dad85e
DE
113}
114
0a647691 115bool GSocketGUIFunctionsTableConcrete::Init_Socket(GSocket *socket)
02dad85e 116{
facd6764 117 struct MacGSocketData *data = (struct MacGSocketData *)malloc(sizeof(struct MacGSocketData));
02dad85e
DE
118 if (data)
119 {
120 socket->m_gui_dependent = (char*)data;
121 data->socket = NULL;
122 data->source = NULL;
123 return 1;
124 }
125 return 0;
126}
127
0a647691 128void GSocketGUIFunctionsTableConcrete::Destroy_Socket(GSocket *socket)
02dad85e
DE
129{
130 struct MacGSocketData *data = (struct MacGSocketData*)(socket->m_gui_dependent);
131 if (data)
132 {
577b58df
SC
133 if ( data->source )
134 CFRelease(data->source);
ee9a28ab
SC
135 if ( data->socket )
136 CFRelease(data->socket);
02dad85e
DE
137 free(data);
138 }
139}
140
0a647691 141void GSocketGUIFunctionsTableConcrete::Install_Callback(GSocket *socket, GSocketEvent event)
02dad85e
DE
142{
143 int c;
144 struct MacGSocketData* data = _GSocket_Get_Mac_Socket(socket);
145 if (!data) return;
146 switch (event)
147 {
148 case GSOCK_CONNECTION:
149 if(socket->m_server)
150 c = kCFSocketReadCallBack;
151 else
152 c = kCFSocketConnectCallBack;
153 break;
154 case GSOCK_LOST:
155 case GSOCK_INPUT:
156 c = kCFSocketReadCallBack;
157 break;
158 case GSOCK_OUTPUT:
159 c = kCFSocketWriteCallBack;
160 break;
161 default:
162 c = 0;
163 }
164 CFSocketEnableCallBacks(data->socket, c);
165}
166
0a647691 167void GSocketGUIFunctionsTableConcrete::Uninstall_Callback(GSocket *socket, GSocketEvent event)
02dad85e
DE
168{
169 int c;
170 struct MacGSocketData* data = _GSocket_Get_Mac_Socket(socket);
171 if (!data) return;
172 switch (event)
173 {
174 case GSOCK_CONNECTION:
175 if(socket->m_server)
176 c = kCFSocketReadCallBack;
177 else
178 c = kCFSocketConnectCallBack;
179 break;
180 case GSOCK_LOST:
181 case GSOCK_INPUT:
182 c = kCFSocketReadCallBack;
183 break;
184 case GSOCK_OUTPUT:
185 c = kCFSocketWriteCallBack;
186 break;
187 default:
188 c = 0;
189 }
190 CFSocketDisableCallBacks(data->socket, c);
191}
192
0a647691 193void GSocketGUIFunctionsTableConcrete::Enable_Events(GSocket *socket)
02dad85e
DE
194{
195 struct MacGSocketData* data = _GSocket_Get_Mac_Socket(socket);
196 if (!data) return;
197
7725dc7c 198 CFRunLoopAddSource(s_mainRunLoop, data->source, kCFRunLoopCommonModes);
02dad85e
DE
199}
200
0a647691 201void GSocketGUIFunctionsTableConcrete::Disable_Events(GSocket *socket)
02dad85e
DE
202{
203 struct MacGSocketData* data = _GSocket_Get_Mac_Socket(socket);
204 if (!data) return;
205
206 /* CFSocketInvalidate does CFRunLoopRemoveSource anyway */
7725dc7c 207 CFRunLoopRemoveSource(s_mainRunLoop, data->source, kCFRunLoopCommonModes);
02dad85e
DE
208 CFSocketInvalidate(data->socket);
209}
210
211#endif // wxUSE_SOCKETS