]> git.saurik.com Git - wxWidgets.git/blame - src/mac/carbon/utilsexc.cpp
allowing shaped windows again
[wxWidgets.git] / src / mac / carbon / utilsexc.cpp
CommitLineData
e9576ca5
SC
1/////////////////////////////////////////////////////////////////////////////
2// Name: utilsexec.cpp
3// Purpose: Execution-related utilities
a31a5f85 4// Author: Stefan Csomor
c8023fed 5// Modified by: David Elliott
a31a5f85 6// Created: 1998-01-01
e9576ca5 7// RCS-ID: $Id$
a31a5f85 8// Copyright: (c) Stefan Csomor
e40298d5 9// Licence: wxWindows licence
e9576ca5
SC
10/////////////////////////////////////////////////////////////////////////////
11
12#ifdef __GNUG__
90771fe5 13//#pragma implementation
e9576ca5
SC
14#endif
15
c8023fed 16#include "wx/log.h"
e9576ca5 17#include "wx/utils.h"
f5c6eb5c 18#ifdef __DARWIN__
5fde6fcc 19#include "wx/unix/execute.h"
c8023fed
DE
20#include <unistd.h>
21#include <sys/wait.h>
90771fe5 22extern "C" {
c8023fed 23#include <mach/mach.h>
90771fe5 24}
c8023fed 25#include <CoreFoundation/CFMachPort.h>
5fde6fcc 26#endif
e9576ca5
SC
27
28#include <stdio.h>
29#include <stdlib.h>
30#include <string.h>
31
f5c6eb5c 32#ifndef __DARWIN__
e9576ca5
SC
33#define wxEXECUTE_WIN_MESSAGE 10000
34
fadb227e
DS
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))
e9576ca5 122{
fadb227e
DS
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;
e9576ca5 133}
fadb227e 134
5fde6fcc
GD
135#endif
136
f5c6eb5c 137#ifdef __DARWIN__
c8023fed 138void wxMAC_MachPortEndProcessDetect(CFMachPortRef port, void *data)
5fde6fcc 139{
c8023fed 140 wxEndProcessData *proc_data = (wxEndProcessData*)data;
5f3f0f17 141 wxLogDebug(wxT("Wow.. this actually worked!"));
c8023fed
DE
142 int status = 0;
143 int rc = waitpid(abs(proc_data->pid), &status, WNOHANG);
144 if(!rc)
145 {
5f3f0f17 146 wxLogDebug(wxT("Mach port was invalidated, but process hasn't terminated!"));
c8023fed
DE
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 {
5f3f0f17 166 wxLogDebug(wxT("No mach_task_self()"));
c8023fed
DE
167 return -1;
168 }
5f3f0f17 169 wxLogDebug(wxT("pid=%d"),pid);
c8023fed
DE
170 kernResult = task_for_pid(taskOfOurProcess,pid, &machPortForProcess);
171 if(kernResult != KERN_SUCCESS)
172 {
c32a538a 173 wxLogDebug(wxT("no task_for_pid()"));
c8023fed
DE
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 {
5f3f0f17 194 wxLogDebug(wxT("No CFMachPortForProcess"));
c8023fed
DE
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 {
5f3f0f17 203 wxLogDebug(wxT("Couldn't deallocate mach port"));
c8023fed
DE
204 return -1;
205 }
206 }
207 CFMachPortSetInvalidationCallBack(CFMachPortForProcess, &wxMAC_MachPortEndProcessDetect);
208 CFRunLoopSourceRef runloopsource;
209 runloopsource = CFMachPortCreateRunLoopSource(NULL,CFMachPortForProcess, (CFIndex)0);
210 if(!runloopsource)
211 {
5f3f0f17 212 wxLogDebug(wxT("Couldn't create runloopsource"));
c8023fed
DE
213 return -1;
214 }
215
216 CFRelease(CFMachPortForProcess);
217
218 CFRunLoopAddSource(CFRunLoopGetCurrent(),runloopsource,kCFRunLoopDefaultMode);
219 CFRelease(runloopsource);
5f3f0f17 220 wxLogDebug(wxT("Successfully added notification to the runloop"));
c8023fed 221 return 0;
5fde6fcc 222}
f5c6eb5c 223#endif