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