]> git.saurik.com Git - wxWidgets.git/blob - src/mac/classic/utilsexc.cpp
Workaround for wxMac since it is unable to dismiss the edit control
[wxWidgets.git] / src / mac / classic / utilsexc.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: utilsexec.cpp
3 // Purpose: Execution-related utilities
4 // Author: Stefan Csomor
5 // Modified by: David Elliott
6 // Created: 1998-01-01
7 // RCS-ID: $Id$
8 // Copyright: (c) Stefan Csomor
9 // Licence: wxWindows licence
10 /////////////////////////////////////////////////////////////////////////////
11
12 #include "wx/log.h"
13 #include "wx/utils.h"
14 #ifdef __DARWIN__
15 #include "wx/unix/execute.h"
16 #include <unistd.h>
17 #include <sys/wait.h>
18 extern "C" {
19 #include <mach/mach.h>
20 }
21 #include <CoreFoundation/CFMachPort.h>
22 #endif
23
24 #include <stdio.h>
25 #include <stdlib.h>
26 #include <string.h>
27
28 #ifndef __DARWIN__
29 #define wxEXECUTE_WIN_MESSAGE 10000
30
31 #include "wx/mac/private.h"
32
33 /*
34 Below FinderLaunch function comes from:
35 http://developer.apple.com/technotes/tn/tn1002.html#fndrask
36 */
37 /* FinderLaunch converts a list of nTargets FSSpec records
38 pointed to by the targetList parameter and converts the
39 list to an Apple Event. It then sends that event to the
40 Finder. The array of FSSpec records pointed to by the
41 targetList parameter may contain references to files,
42 folders, or applications. The net effect of this command
43 is equivalent to the user selecting an icon in one of the
44 Finder's windows and then choosing the open command from
45 the Finder's file menu. */
46 static OSErr FinderLaunch(long nTargets, FSSpec *targetList) {
47 OSErr err;
48 AppleEvent theAEvent, theReply;
49 AEAddressDesc fndrAddress;
50 AEDescList targetListDesc;
51 OSType fndrCreator;
52 Boolean wasChanged;
53 AliasHandle targetAlias;
54 long index;
55
56 /* set up locals */
57 AECreateDesc(typeNull, NULL, 0, &theAEvent);
58 AECreateDesc(typeNull, NULL, 0, &fndrAddress);
59 AECreateDesc(typeNull, NULL, 0, &theReply);
60 AECreateDesc(typeNull, NULL, 0, &targetListDesc);
61 targetAlias = NULL;
62 fndrCreator = 'MACS';
63
64 /* verify parameters */
65 if ((nTargets == 0) || (targetList == NULL)) {
66 err = paramErr;
67 goto bail;
68 }
69
70 /* create an open documents event targeting the
71 finder */
72 err = AECreateDesc(typeApplSignature, (Ptr) &fndrCreator,
73 sizeof(fndrCreator), &fndrAddress);
74 if (err != noErr) goto bail;
75 err = AECreateAppleEvent(kCoreEventClass, kAEOpenDocuments,
76 &fndrAddress, kAutoGenerateReturnID,
77 kAnyTransactionID, &theAEvent);
78 if (err != noErr) goto bail;
79
80 /* create the list of files to open */
81 err = AECreateList(NULL, 0, false, &targetListDesc);
82 if (err != noErr) goto bail;
83 for ( index=0; index < nTargets; index++) {
84 if (targetAlias == NULL)
85 err = NewAlias(NULL, (targetList + index),
86 &targetAlias);
87 else err = UpdateAlias(NULL, (targetList + index),
88 targetAlias, &wasChanged);
89 if (err != noErr) goto bail;
90 HLock((Handle) targetAlias);
91 err = AEPutPtr(&targetListDesc, (index + 1),
92 typeAlias, *targetAlias,
93 GetHandleSize((Handle) targetAlias));
94 HUnlock((Handle) targetAlias);
95 if (err != noErr) goto bail;
96 }
97
98 /* add the file list to the Apple Event */
99 err = AEPutParamDesc(&theAEvent, keyDirectObject,
100 &targetListDesc);
101 if (err != noErr) goto bail;
102
103 /* send the event to the Finder */
104 err = AESend(&theAEvent, &theReply, kAENoReply,
105 kAENormalPriority, kAEDefaultTimeout, NULL, NULL);
106
107 /* clean up and leave */
108 bail:
109 if (targetAlias != NULL) DisposeHandle((Handle) targetAlias);
110 AEDisposeDesc(&targetListDesc);
111 AEDisposeDesc(&theAEvent);
112 AEDisposeDesc(&fndrAddress);
113 AEDisposeDesc(&theReply);
114 return err;
115 }
116
117 long wxExecute(const wxString& command, int flags, wxProcess *WXUNUSED(handler))
118 {
119 wxASSERT_MSG( flags == wxEXEC_ASYNC,
120 wxT("wxExecute: Only wxEXEC_ASYNC is supported") );
121
122 FSSpec fsSpec;
123 wxMacFilename2FSSpec(command, &fsSpec);
124
125 // 0 means execution failed. Returning non-zero is a PID, but not
126 // on Mac where PIDs are 64 bits and won't fit in a long, so we
127 // return a dummy value for now.
128 return ( FinderLaunch(1 /*one file*/, &fsSpec) == noErr ) ? -1 : 0;
129 }
130
131 #endif
132
133 #ifdef __DARWIN__
134 void wxMAC_MachPortEndProcessDetect(CFMachPortRef port, void *data)
135 {
136 wxEndProcessData *proc_data = (wxEndProcessData*)data;
137 wxLogDebug(wxT("Wow.. this actually worked!"));
138 int status = 0;
139 int rc = waitpid(abs(proc_data->pid), &status, WNOHANG);
140 if(!rc)
141 {
142 wxLogDebug(wxT("Mach port was invalidated, but process hasn't terminated!"));
143 return;
144 }
145 if((rc != -1) && WIFEXITED(status))
146 proc_data->exitcode = WEXITSTATUS(status);
147 else
148 proc_data->exitcode = -1;
149 wxHandleProcessTermination(proc_data);
150 }
151
152 int wxAddProcessCallbackForPid(wxEndProcessData *proc_data, int pid)
153 {
154 if(pid < 1)
155 return -1;
156 kern_return_t kernResult;
157 mach_port_t taskOfOurProcess;
158 mach_port_t machPortForProcess;
159 taskOfOurProcess = mach_task_self();
160 if(taskOfOurProcess == MACH_PORT_NULL)
161 {
162 wxLogDebug(wxT("No mach_task_self()"));
163 return -1;
164 }
165 wxLogDebug(wxT("pid=%d"),pid);
166 kernResult = task_for_pid(taskOfOurProcess,pid, &machPortForProcess);
167 if(kernResult != KERN_SUCCESS)
168 {
169 wxLogDebug(wxT("no task_for_pid()"));
170 // try seeing if it is already dead or something
171 // FIXME: a better method would be to call the callback function
172 // from idle time until the process terminates. Of course, how
173 // likely is it that it will take more than 0.1 seconds for the
174 // mach terminate event to make its way to the BSD subsystem?
175 usleep(100); // sleep for 0.1 seconds
176 wxMAC_MachPortEndProcessDetect(NULL, (void*)proc_data);
177 return -1;
178 }
179 CFMachPortContext termcb_contextinfo;
180 termcb_contextinfo.version = NULL;
181 termcb_contextinfo.info = (void*)proc_data;
182 termcb_contextinfo.retain = NULL;
183 termcb_contextinfo.release = NULL;
184 termcb_contextinfo.copyDescription = NULL;
185 CFMachPortRef CFMachPortForProcess;
186 Boolean ShouldFreePort;
187 CFMachPortForProcess = CFMachPortCreateWithPort(NULL, machPortForProcess, NULL, &termcb_contextinfo, &ShouldFreePort);
188 if(!CFMachPortForProcess)
189 {
190 wxLogDebug(wxT("No CFMachPortForProcess"));
191 mach_port_deallocate(taskOfOurProcess, machPortForProcess);
192 return -1;
193 }
194 if(ShouldFreePort)
195 {
196 kernResult = mach_port_deallocate(taskOfOurProcess, machPortForProcess);
197 if(kernResult!=KERN_SUCCESS)
198 {
199 wxLogDebug(wxT("Couldn't deallocate mach port"));
200 return -1;
201 }
202 }
203 CFMachPortSetInvalidationCallBack(CFMachPortForProcess, &wxMAC_MachPortEndProcessDetect);
204 CFRunLoopSourceRef runloopsource;
205 runloopsource = CFMachPortCreateRunLoopSource(NULL,CFMachPortForProcess, (CFIndex)0);
206 if(!runloopsource)
207 {
208 wxLogDebug(wxT("Couldn't create runloopsource"));
209 return -1;
210 }
211
212 CFRelease(CFMachPortForProcess);
213
214 CFRunLoopAddSource(CFRunLoopGetCurrent(),runloopsource,kCFRunLoopDefaultMode);
215 CFRelease(runloopsource);
216 wxLogDebug(wxT("Successfully added notification to the runloop"));
217 return 0;
218 }
219 #endif