1 /////////////////////////////////////////////////////////////////////////////
2 // Name: src/osx/core/utilsexc_cf.cpp
3 // Purpose: Execution-related utilities for Darwin
4 // Author: David Elliott, Ryan Norton (wxMacExecute)
5 // Modified by: Stefan Csomor (added necessary wxT for unicode builds)
6 // Created: 2004-11-04
7 // Copyright: (c) David Elliott, Ryan Norton
8 // (c) 2013 Rob Bresalier
9 // Licence: wxWindows licence
10 // Notes: This code comes from src/osx/carbon/utilsexc.cpp,1.11
11 /////////////////////////////////////////////////////////////////////////////
12
13 #include "wx/wxprec.h"
14 #ifndef WX_PRECOMP
15 #include "wx/log.h"
16 #include "wx/utils.h"
17 #endif //ndef WX_PRECOMP
18 #include "wx/stdpaths.h"
19 #include "wx/app.h"
20 #include "wx/apptrait.h"
21 #include "wx/thread.h"
22 #include "wx/process.h"
23
24 #include "wx/evtloop.h"
25 #include "wx/evtloopsrc.h"
26 #include "wx/private/eventloopsourcesmanager.h"
27
28 #include <sys/wait.h>
29
30 #include <CoreFoundation/CFSocket.h>
31
32 #if wxUSE_EVENTLOOP_SOURCE
33
34 namespace
35 {
36
37 extern "C"
38 void
wx_socket_callback(CFSocketRef WXUNUSED (s),CFSocketCallBackType callbackType,CFDataRef WXUNUSED (address),void const * WXUNUSED (data),void * ctxData)39 wx_socket_callback(CFSocketRef WXUNUSED(s),
40 CFSocketCallBackType callbackType,
41 CFDataRef WXUNUSED(address),
42 void const *WXUNUSED(data),
43 void *ctxData)
44 {
45 wxLogTrace(wxTRACE_EVT_SOURCE,
46 "CFSocket callback, type=%d", static_cast<int>(callbackType));
47
48 wxCFEventLoopSource * const
49 source = static_cast<wxCFEventLoopSource *>(ctxData);
50
51 wxEventLoopSourceHandler * const
52 handler = source->GetHandler();
53
54 switch ( callbackType )
55 {
56 case kCFSocketReadCallBack:
57 handler->OnReadWaiting();
58 break;
59
60 case kCFSocketWriteCallBack:
61 handler->OnWriteWaiting();
62 break;
63
64 default:
65 wxFAIL_MSG( "Unexpected callback type." );
66 }
67 }
68
69 } // anonymous namespace
70
71 class wxCFEventLoopSourcesManager : public wxEventLoopSourcesManagerBase
72 {
73 public:
74 wxEventLoopSource *
AddSourceForFD(int fd,wxEventLoopSourceHandler * handler,int flags)75 AddSourceForFD(int fd, wxEventLoopSourceHandler *handler, int flags) wxOVERRIDE
76 {
77 wxCHECK_MSG( fd != -1, NULL, "can't monitor invalid fd" );
78
79 wxScopedPtr<wxCFEventLoopSource>
80 source(new wxCFEventLoopSource(handler, flags));
81
82 CFSocketContext context = { 0, source.get(), NULL, NULL, NULL };
83
84 int callbackTypes = 0;
85 if ( flags & wxEVENT_SOURCE_INPUT )
86 callbackTypes |= kCFSocketReadCallBack;
87 if ( flags & wxEVENT_SOURCE_OUTPUT )
88 callbackTypes |= kCFSocketWriteCallBack;
89
90 wxCFRef<CFSocketRef>
91 cfSocket(CFSocketCreateWithNative
92 (
93 kCFAllocatorDefault,
94 fd,
95 callbackTypes,
96 &wx_socket_callback,
97 &context
98 ));
99
100 if ( !cfSocket )
101 {
102 wxLogError(wxS("Failed to create event loop source socket."));
103 return NULL;
104 }
105
106 // Adjust the socket options to suit our needs:
107 CFOptionFlags sockopt = CFSocketGetSocketFlags(cfSocket);
108
109 // First, by default, write callback is not called repeatedly when data
110 // can be written to the socket but we need this behaviour so request
111 // it explicitly.
112 if ( flags & wxEVENT_SOURCE_OUTPUT )
113 sockopt |= kCFSocketAutomaticallyReenableWriteCallBack;
114
115 // Second, we use the socket to monitor the FD but it doesn't own it,
116 // so prevent the FD from being closed when the socket is invalidated.
117 sockopt &= ~kCFSocketCloseOnInvalidate;
118
119 CFSocketSetSocketFlags(cfSocket, sockopt);
120
121 wxCFRef<CFRunLoopSourceRef>
122 runLoopSource(CFSocketCreateRunLoopSource
123 (
124 kCFAllocatorDefault,
125 cfSocket,
126 0 // Lowest index means highest priority
127 ));
128 if ( !runLoopSource )
129 {
130 wxLogError(wxS("Failed to create low level event loop source."));
131 CFSocketInvalidate(cfSocket);
132 return NULL;
133 }
134
135 // Save the socket so that we can remove it later if asked to.
136 source->InitSourceSocket(cfSocket.release());
137
138 CFRunLoopAddSource(CFRunLoopGetCurrent(), runLoopSource, kCFRunLoopCommonModes);
139
140 return source.release();
141 }
142 };
143
GetEventLoopSourcesManager()144 wxEventLoopSourcesManagerBase* wxGUIAppTraits::GetEventLoopSourcesManager()
145 {
146 static wxCFEventLoopSourcesManager s_eventLoopSourcesManager;
147
148 return &s_eventLoopSourcesManager;
149 }
150
151 #endif // wxUSE_EVENTLOOP_SOURCE
152
153 /////////////////////////////////////////////////////////////////////////////
154
155 #if wxUSE_SOCKETS
156
157 // we need to implement this method in a file of the core library as it should
158 // only be used for the GUI applications but we can't use socket stuff from it
159 // directly as this would create unwanted dependencies of core on net library
160 //
161 // so we have this global pointer which is set from sockosx.cpp when it is
162 // linked in and we simply return it from here
163 extern WXDLLIMPEXP_BASE wxSocketManager *wxOSXSocketManagerCF;
GetSocketManager()164 wxSocketManager *wxGUIAppTraits::GetSocketManager()
165 {
166 return wxOSXSocketManagerCF ? wxOSXSocketManagerCF
167 : wxGUIAppTraitsBase::GetSocketManager();
168 }
169
170 #endif // wxUSE_SOCKETS
171