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