blob: f78f97f5a33fbbe8a93241475eaff484f5059df2 [file] [log] [blame]
Guido van Rossumb3404661995-01-22 18:36:13 +00001/***********************************************************
Jack Jansen42218ce1997-01-31 16:15:11 +00002Copyright 1991-1997 by Stichting Mathematisch Centrum, Amsterdam,
Guido van Rossumb3404661995-01-22 18:36:13 +00003The Netherlands.
4
5 All Rights Reserved
6
7Permission to use, copy, modify, and distribute this software and its
8documentation for any purpose and without fee is hereby granted,
9provided that the above copyright notice appear in all copies and that
10both that copyright notice and this permission notice appear in
11supporting documentation, and that the names of Stichting Mathematisch
12Centrum or CWI not be used in advertising or publicity pertaining to
13distribution of the software without specific, written prior permission.
14
15STICHTING MATHEMATISCH CENTRUM DISCLAIMS ALL WARRANTIES WITH REGARD TO
16THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
17FITNESS, IN NO EVENT SHALL STICHTING MATHEMATISCH CENTRUM BE LIABLE
18FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
19WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
20ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
21OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
22
23******************************************************************/
Jack Jansenf93c72a1994-12-14 14:07:50 +000024
Jack Jansenbf05d4c1996-08-19 15:11:45 +000025
Jack Jansenf93c72a1994-12-14 14:07:50 +000026#include "Python.h"
Guido van Rossumbecdbec1995-02-14 01:27:24 +000027
Jack Jansenf93c72a1994-12-14 14:07:50 +000028#include "macglue.h"
Jack Jansen74162f31995-02-15 22:58:33 +000029#include "marshal.h"
30#include "import.h"
Jack Janseneda78631997-06-12 15:29:46 +000031#include "importdl.h"
Jack Jansen8bb1dc12001-05-19 12:31:09 +000032#include "pymactoolbox.h"
Jack Jansenf93c72a1994-12-14 14:07:50 +000033
Jack Jansen819f1771995-08-14 12:35:10 +000034#include "pythonresources.h"
35
Jack Jansen0194ad52001-05-12 22:46:35 +000036#ifdef WITHOUT_FRAMEWORKS
Jack Jansenf93c72a1994-12-14 14:07:50 +000037#include <OSUtils.h> /* for Set(Current)A5 */
Jack Jansene8e8ae01995-01-26 16:36:45 +000038#include <Files.h>
Jack Jansen8cd2b721995-02-13 11:33:28 +000039#include <StandardFile.h>
Jack Jansenf93c72a1994-12-14 14:07:50 +000040#include <Resources.h>
41#include <Memory.h>
Jack Jansenf93c72a1994-12-14 14:07:50 +000042#include <Windows.h>
Jack Jansene8e8ae01995-01-26 16:36:45 +000043#include <Traps.h>
Jack Jansenee23d6e1995-01-27 14:43:25 +000044#include <Processes.h>
Guido van Rossumc3d1c8e1995-02-18 15:01:31 +000045#include <Fonts.h>
46#include <Menus.h>
Jack Jansen08305501995-06-18 20:03:40 +000047#include <TextUtils.h>
Jack Jansen0194ad52001-05-12 22:46:35 +000048#include <LowMem.h>
Jack Jansen0194ad52001-05-12 22:46:35 +000049#include <Events.h>
Jack Jansen0194ad52001-05-12 22:46:35 +000050#else
51#include <Carbon/Carbon.h>
52#endif
53
54#if !TARGET_API_MAC_OS8
55/* Unfortunately this call is probably slower... */
56#define LMGetTicks() TickCount()
57#endif
58
Jack Jansen16df2aa1995-02-27 16:17:28 +000059#ifdef __MWERKS__
60#include <SIOUX.h>
Jack Jansen9ae898b2000-07-11 21:16:03 +000061extern void SIOUXSetupMenus(void);
62extern void SIOUXDoAboutBox(void);
Jack Jansen16df2aa1995-02-27 16:17:28 +000063#endif
Jack Jansen9ae898b2000-07-11 21:16:03 +000064#ifdef USE_GUSI
65/* Functions we redefine because they're in obscure libraries */
66extern void SpinCursor(short x);
67extern void RotateCursor(short x);
68extern pascal void PLstrcpy(unsigned char *, unsigned char *);
69extern pascal int PLstrcmp(unsigned char *, unsigned char *);
70extern pascal unsigned char *PLstrrchr(unsigned char *, unsigned char);
71
72#endif
73
Jack Jansen2d1306b2000-04-07 09:10:49 +000074#ifdef USE_GUSI1
Jack Jansen911ad6b1996-03-05 16:56:24 +000075#include <TFileSpec.h> /* For Path2FSSpec */
Jack Jansenf6865f71996-09-04 15:24:59 +000076#include <GUSI.h>
Jack Jansen911ad6b1996-03-05 16:56:24 +000077#endif
Jack Jansenee23d6e1995-01-27 14:43:25 +000078
Jack Jansen3469e991996-09-06 00:30:45 +000079/* The ID of the Sioux apple menu */
80#define SIOUX_APPLEID 32000
81
Jack Jansenee23d6e1995-01-27 14:43:25 +000082#include <signal.h>
Jack Jansen74162f31995-02-15 22:58:33 +000083#include <stdio.h>
Jack Jansene8e8ae01995-01-26 16:36:45 +000084
Jack Jansenee23d6e1995-01-27 14:43:25 +000085/*
Jack Jansend1f06311996-08-01 15:23:54 +000086** When less than this amount of stackspace is left we
87** raise a MemoryError.
88*/
89#ifndef MINIMUM_STACK_SIZE
Jack Jansend1f06311996-08-01 15:23:54 +000090#define MINIMUM_STACK_SIZE 8192
Jack Jansend1f06311996-08-01 15:23:54 +000091#endif
92
Jack Jansen340eb882001-02-02 22:40:28 +000093#if TARGET_API_MAC_CARBON
94/*
95** On MacOSX StackSpace() lies: it gives the distance from heap end to stack pointer,
96** but the stack cannot grow that far due to rlimit values. We cannot get at this value
97** from Carbon, so we set a maximum to the stack here that is based on the default
98** stack limit of 512K.
99*/
100#define MAXIMUM_STACK_SIZE (256*1024)
101#endif
102
Jack Jansend1f06311996-08-01 15:23:54 +0000103/*
Jack Jansen16df2aa1995-02-27 16:17:28 +0000104** We have to be careful, since we can't handle
Jack Jansenee23d6e1995-01-27 14:43:25 +0000105** things like updates (and they'll keep coming back if we don't
Jack Jansen16df2aa1995-02-27 16:17:28 +0000106** handle them). Note that we don't know who has windows open, so
107** even handing updates off to SIOUX under MW isn't going to work.
Jack Jansenee23d6e1995-01-27 14:43:25 +0000108*/
Jack Jansen0c968871997-08-26 13:20:34 +0000109#define MAINLOOP_EVENTMASK (mDownMask|keyDownMask|osMask|activMask)
Jack Jansene8e8ae01995-01-26 16:36:45 +0000110
111#include <signal.h>
Jack Jansenf93c72a1994-12-14 14:07:50 +0000112
Guido van Rossumb3404661995-01-22 18:36:13 +0000113/* XXX We should include Errors.h here, but it has a name conflict
Jack Jansen5f653091995-01-18 13:53:49 +0000114** with the python errors.h. */
115#define fnfErr -43
116
Jack Jansenee23d6e1995-01-27 14:43:25 +0000117/* Interrupt code variables: */
118static int interrupted; /* Set to true when cmd-. seen */
Jack Jansend88296d2000-07-11 19:51:05 +0000119static RETSIGTYPE intcatcher(int);
Jack Jansenee23d6e1995-01-27 14:43:25 +0000120
Jack Jansen0194ad52001-05-12 22:46:35 +0000121#if !TARGET_API_MAC_OSX
Jack Jansend88296d2000-07-11 19:51:05 +0000122static int PyMac_Yield(void);
Jack Jansen0194ad52001-05-12 22:46:35 +0000123#endif
Jack Jansenf6865f71996-09-04 15:24:59 +0000124
Jack Jansene8e8ae01995-01-26 16:36:45 +0000125/*
Jack Jansene3ae0df1997-06-03 15:28:29 +0000126** These are the real scheduling parameters that control what we check
127** in the event loop, and how often we check. The values are initialized
128** from pyMac_SchedParamStruct.
129*/
130
131struct real_sched_param_struct {
132 int check_interrupt; /* if true check for command-dot */
133 int process_events; /* if nonzero enable evt processing, this mask */
134 int besocial; /* if nonzero be a little social with CPU */
135 unsigned long check_interval; /* how often to check, in ticks */
136 unsigned long bg_yield; /* yield so long when in background */
137 /* these are computed from previous and clock and such */
138 int enabled; /* check_interrupt OR process_event OR yield */
139 unsigned long next_check; /* when to check/yield next, in ticks */
140};
141
142static struct real_sched_param_struct schedparams =
143 { 1, MAINLOOP_EVENTMASK, 1, 15, 15, 1, 0};
144
Jack Jansen819f1771995-08-14 12:35:10 +0000145/*
Jack Jansenf6865f71996-09-04 15:24:59 +0000146** Workaround for sioux/gusi combo: set when we are exiting
147*/
148int PyMac_ConsoleIsDead;
149
150/*
Jack Jansencaa7c461997-06-12 10:49:13 +0000151** Sioux menu bar, saved early so we can restore it
152*/
Jack Jansen657ba272001-02-17 22:02:07 +0000153static MenuBarHandle sioux_mbar;
Jack Jansencaa7c461997-06-12 10:49:13 +0000154
155/*
Jack Jansen819f1771995-08-14 12:35:10 +0000156** Some stuff for our GetDirectory and PromptGetFile routines
157*/
158struct hook_args {
159 int selectcur_hit; /* Set to true when "select current" selected */
160 char *prompt; /* The prompt */
161};
Jack Jansen6e68a7e2001-05-12 21:31:34 +0000162#if !TARGET_API_MAC_OS8
Jack Jansenbb6d83a2000-06-02 21:27:11 +0000163/* The StandardFile hooks don't exist in Carbon. This breaks GetDirectory,
164** but the macfsn code will replace it by a NavServices version anyway.
165*/
166#define myhook_upp NULL
167#else
Jack Jansen819f1771995-08-14 12:35:10 +0000168static DlgHookYDUPP myhook_upp;
169static int upp_inited = 0;
Jack Jansenbb6d83a2000-06-02 21:27:11 +0000170#endif
Jack Jansen819f1771995-08-14 12:35:10 +0000171
Jack Jansen36ed5061997-06-20 16:18:15 +0000172/*
173** The python-code event handler
174*/
175static PyObject *python_event_handler;
176
Jack Jansen8f5725a1999-12-07 23:08:10 +0000177/*
178** Set to true if we're appearance-compliant
179*/
180int PyMac_AppearanceCompliant;
181
Jack Jansen741e0372001-05-19 12:55:57 +0000182/* Given an FSSpec, return the FSSpec of the parent folder */
183
184static OSErr
185get_folder_parent (FSSpec * fss, FSSpec * parent)
186{
187 CInfoPBRec rec;
188 short err;
189
190 * parent = * fss;
191 rec.hFileInfo.ioNamePtr = parent->name;
192 rec.hFileInfo.ioVRefNum = parent->vRefNum;
193 rec.hFileInfo.ioDirID = parent->parID;
194 rec.hFileInfo.ioFDirIndex = -1;
195 rec.hFileInfo.ioFVersNum = 0;
196 if (err = PBGetCatInfoSync (& rec))
197 return err;
198 parent->parID = rec.dirInfo.ioDrParID;
199/* parent->name[0] = 0; */
200 return 0;
201}
202
203/* Given an FSSpec return a full, colon-separated pathname */
204
205OSErr
Jack Jansencf031932001-09-11 09:22:19 +0000206PyMac_GetFullPathname (FSSpec *fss, char *buf, int length)
Jack Jansen741e0372001-05-19 12:55:57 +0000207{
208 short err;
209 FSSpec fss_parent, fss_current;
210 char tmpbuf[1024];
211 int plen;
212
213 fss_current = *fss;
214 plen = fss_current.name[0];
Jack Jansencf031932001-09-11 09:22:19 +0000215 if ( plen+2 > length ) {
216 *buf = 0;
217 return errFSNameTooLong;
218 }
Jack Jansen741e0372001-05-19 12:55:57 +0000219 memcpy(buf, &fss_current.name[1], plen);
220 buf[plen] = 0;
221 /* Special case for disk names */
222 if ( fss_current.parID <= 1 ) {
223 buf[plen++] = ':';
224 buf[plen] = 0;
225 return 0;
226 }
227 while (fss_current.parID > 1) {
228 /* Get parent folder name */
Jack Jansencf031932001-09-11 09:22:19 +0000229 if (err = get_folder_parent(&fss_current, &fss_parent)) {
230 *buf = 0;
Jack Jansen741e0372001-05-19 12:55:57 +0000231 return err;
Jack Jansencf031932001-09-11 09:22:19 +0000232 }
Jack Jansen741e0372001-05-19 12:55:57 +0000233 fss_current = fss_parent;
234 /* Prepend path component just found to buf */
235 plen = fss_current.name[0];
236 if (strlen(buf) + plen + 1 > 1024) {
237 /* Oops... Not enough space (shouldn't happen) */
238 *buf = 0;
Jack Jansencf031932001-09-11 09:22:19 +0000239 return errFSNameTooLong;
Jack Jansen741e0372001-05-19 12:55:57 +0000240 }
241 memcpy(tmpbuf, &fss_current.name[1], plen);
242 tmpbuf[plen] = ':';
243 strcpy(&tmpbuf[plen+1], buf);
Jack Jansencf031932001-09-11 09:22:19 +0000244 if ( strlen(tmpbuf) > length ) {
245 *buf = 0;
246 return errFSNameTooLong;
247 }
Jack Jansen741e0372001-05-19 12:55:57 +0000248 strcpy(buf, tmpbuf);
249 }
250 return 0;
251}
Jack Jansen1f9f2f42000-07-24 19:50:16 +0000252
Jack Jansen2d1306b2000-04-07 09:10:49 +0000253#ifdef USE_GUSI1
Jack Jansen378815c1996-03-06 16:21:34 +0000254/*
255** GUSI (1.6.0 and earlier, at the least) do not set the MacOS idea of
256** the working directory. Hence, we call this routine after each call
257** to chdir() to rectify things.
258*/
259void
260PyMac_FixGUSIcd()
261{
262 WDPBRec pb;
263 FSSpec curdirfss;
264
265 if ( Path2FSSpec(":x", &curdirfss) != noErr )
266 return;
267
268 /* Set MacOS "working directory" */
269 pb.ioNamePtr= "\p";
270 pb.ioVRefNum= curdirfss.vRefNum;
271 pb.ioWDDirID= curdirfss.parID;
Jack Jansen08c3be31997-04-08 15:27:00 +0000272 if (PBHSetVolSync(&pb) != noErr)
Jack Jansen378815c1996-03-06 16:21:34 +0000273 return;
Jack Jansen378815c1996-03-06 16:21:34 +0000274}
Jack Jansen2d1306b2000-04-07 09:10:49 +0000275#endif
Jack Jansen7ac70af1996-08-19 11:01:05 +0000276
Jack Jansen2d1306b2000-04-07 09:10:49 +0000277#ifdef USE_GUSI
Jack Jansen7d5f9e81996-09-07 17:09:31 +0000278/*
279** SpinCursor (needed by GUSI) drags in heaps of stuff, so we
280** provide a dummy here.
281*/
Jack Jansencfadbd41996-08-19 11:36:25 +0000282void SpinCursor(short x) { /* Dummy */ }
Jack Jansenefaada71998-02-20 16:03:15 +0000283void RotateCursor(short x) { /* Dummy */ }
Jack Jansencfadbd41996-08-19 11:36:25 +0000284
Jack Jansenf6865f71996-09-04 15:24:59 +0000285/*
286** Replacement GUSI Spin function
287*/
Jack Jansen2d1306b2000-04-07 09:10:49 +0000288#ifdef USE_GUSI1
Jack Jansenf6865f71996-09-04 15:24:59 +0000289static int
290PyMac_GUSISpin(spin_msg msg, long arg)
291{
Jack Jansene3ae0df1997-06-03 15:28:29 +0000292 static Boolean inForeground = true;
293 int maxsleep = 6; /* 6 ticks is "normal" sleeptime */
Jack Jansenf6865f71996-09-04 15:24:59 +0000294
295 if (PyMac_ConsoleIsDead) return 0;
296#if 0
297 if (inForeground)
298 SpinCursor(msg == SP_AUTO_SPIN ? short(arg) : 1);
299#endif
300
Jack Jansenf6865f71996-09-04 15:24:59 +0000301
Jack Jansene3ae0df1997-06-03 15:28:29 +0000302 if ( msg == SP_AUTO_SPIN )
303 maxsleep = 0;
Jack Jansen439eaa92001-11-10 00:41:43 +0000304 if ( msg==SP_SLEEP||msg==SP_SELECT ) {
Jack Jansene3ae0df1997-06-03 15:28:29 +0000305 maxsleep = arg;
Jack Jansen439eaa92001-11-10 00:41:43 +0000306 /*
307 ** We force-scan for interrupts. Not pretty, but otherwise
308 ** a program may hang in select or sleep forever.
309 */
310 scan_event_queue(1);
311 }
312 if (interrupted) {
313 interrupted = 0;
314 return -1;
315 }
Jack Jansenf6865f71996-09-04 15:24:59 +0000316
Jack Jansene3ae0df1997-06-03 15:28:29 +0000317 PyMac_DoYield(maxsleep, 0); /* XXXX or is it safe to call python here? */
Jack Jansenf6865f71996-09-04 15:24:59 +0000318
319 return 0;
320}
321
322void
323PyMac_SetGUSISpin() {
324 GUSISetHook(GUSI_SpinHook, (GUSIHook)PyMac_GUSISpin);
325}
Jack Jansen2d1306b2000-04-07 09:10:49 +0000326#endif
Jack Jansenf6865f71996-09-04 15:24:59 +0000327
Jack Jansena39f1b01997-05-23 15:35:14 +0000328/* Called at exit() time thru atexit(), to stop event processing */
329void
330PyMac_StopGUSISpin() {
331 PyMac_ConsoleIsDead = 1;
332}
333
Jack Jansen6e68a7e2001-05-12 21:31:34 +0000334#if TARGET_API_MAC_OS8
Jack Jansena39f1b01997-05-23 15:35:14 +0000335/*
336** Replacement routines for the PLstr... functions so we don't need
Jack Jansen6ba34aa2001-01-11 23:03:56 +0000337** StdCLib.
Jack Jansena39f1b01997-05-23 15:35:14 +0000338*/
Jack Jansen8bb573e1999-12-12 21:37:14 +0000339pascal void
Jack Jansen9ae898b2000-07-11 21:16:03 +0000340PLstrcpy(unsigned char *to, unsigned char *fr)
Jack Jansena39f1b01997-05-23 15:35:14 +0000341{
342 memcpy(to, fr, fr[0]+1);
343}
344
Jack Jansen8bb573e1999-12-12 21:37:14 +0000345pascal int
Jack Jansen9ae898b2000-07-11 21:16:03 +0000346PLstrcmp(unsigned char *s1, unsigned char *s2)
Jack Jansena39f1b01997-05-23 15:35:14 +0000347{
348 int res;
349 int l = s1[0] < s2[0] ? s1[0] : s2[0];
350
351 res = memcmp(s1+1, s2+1, l);
352 if ( res != 0 )
353 return res;
354
Jack Jansen7e1fb7c1998-07-31 09:36:30 +0000355 if ( s1[0] < s2[0] )
Jack Jansena39f1b01997-05-23 15:35:14 +0000356 return -1;
Jack Jansen7e1fb7c1998-07-31 09:36:30 +0000357 else if ( s1[0] > s2[0] )
Jack Jansena39f1b01997-05-23 15:35:14 +0000358 return 1;
359 else
360 return 0;
361}
362
Jack Jansen8bb573e1999-12-12 21:37:14 +0000363pascal unsigned char *
Jack Jansen9ae898b2000-07-11 21:16:03 +0000364PLstrrchr(unsigned char *str, unsigned char chr)
Jack Jansena39f1b01997-05-23 15:35:14 +0000365{
366 unsigned char *ptr = 0;
367 unsigned char *p;
368
369 for(p=str+1; p<str+str[0]; p++)
370 if ( *p == chr )
371 ptr = p;
372 return ptr;
373}
374
Jack Jansen6e68a7e2001-05-12 21:31:34 +0000375#endif /* TARGET_API_MAC_OS8 */
Jack Jansena39f1b01997-05-23 15:35:14 +0000376#endif /* USE_GUSI */
Jack Jansen378815c1996-03-06 16:21:34 +0000377
Jack Jansen819f1771995-08-14 12:35:10 +0000378
Jack Jansen5f653091995-01-18 13:53:49 +0000379/* Convert C to Pascal string. Returns pointer to static buffer. */
380unsigned char *
381Pstring(char *str)
382{
383 static Str255 buf;
384 int len;
385
386 len = strlen(str);
Guido van Rossum9aa3d131995-01-21 13:46:04 +0000387 if (len > 255)
388 len = 255;
Jack Jansen5f653091995-01-18 13:53:49 +0000389 buf[0] = (unsigned char)len;
390 strncpy((char *)buf+1, str, len);
391 return buf;
392}
393
Jack Jansen6e68a7e2001-05-12 21:31:34 +0000394#if TARGET_API_MAC_OS8
Jack Jansenb9526512001-12-27 23:01:18 +0000395Point
396LMGetMouse(void)
397{
398 return LMGetMouseLocation();
399}
400
401long LMGetExpandMem(void)
402{
403 return 0;
404}
405
Jack Jansen5afad832000-12-12 22:12:14 +0000406void
407c2pstrcpy(unsigned char *dst, const char *src)
408{
409 int len;
410
411 len = strlen(src);
412 if ( len > 255 ) len = 255;
413 strncpy((char *)dst+1, src, len);
414 dst[0] = len;
415}
Jack Jansen6e68a7e2001-05-12 21:31:34 +0000416#endif /* TARGET_API_MAC_OS8 */
Jack Jansen5afad832000-12-12 22:12:14 +0000417
Jack Jansen1ed95291996-07-22 15:25:10 +0000418#ifdef USE_STACKCHECK
419/* Check for stack overflow */
420int
421PyOS_CheckStack()
422{
Jack Jansen14a91712000-08-25 21:57:23 +0000423 char here;
424 static char *sentinel = 0;
Jack Jansen53bafd92000-09-08 22:05:48 +0000425 static PyThreadState *thread_for_sentinel = 0;
Jack Jansen1ed95291996-07-22 15:25:10 +0000426
Jack Jansen340eb882001-02-02 22:40:28 +0000427 if ( sentinel == 0 ) {
428 unsigned long stackspace = StackSpace();
429
430#ifdef MAXIMUM_STACK_SIZE
431 /* See the comment at the definition */
432 if ( stackspace > MAXIMUM_STACK_SIZE )
433 stackspace = MAXIMUM_STACK_SIZE;
434#endif
435 sentinel = &here - stackspace + MINIMUM_STACK_SIZE;
Jack Jansen14a91712000-08-25 21:57:23 +0000436 }
Jack Jansen53bafd92000-09-08 22:05:48 +0000437 if ( thread_for_sentinel == 0 ) {
438 thread_for_sentinel = PyThreadState_Get();
439 }
440 if ( &here < sentinel ) {
441 if (thread_for_sentinel == PyThreadState_Get()) {
442 return -1;
443#if 0
444 } else {
445 /* Else we are unsure... */
446 fprintf(stderr, "Stackcheck in other thread (was %x now %x)\n", thread_for_sentinel,PyThreadState_Get());
447#endif
448 }
449 }
Jack Jansen1ed95291996-07-22 15:25:10 +0000450 return 0;
451}
452#endif /* USE_STACKCHECK */
453
Jack Jansen0194ad52001-05-12 22:46:35 +0000454#if !TARGET_API_MAC_OSX
Jack Jansenee23d6e1995-01-27 14:43:25 +0000455/* The catcher routine (which may not be used for all compilers) */
456static RETSIGTYPE
457intcatcher(sig)
458 int sig;
459{
460 interrupted = 1;
461 signal(SIGINT, intcatcher);
462}
463
464void
465PyOS_InitInterrupts()
466{
467 if (signal(SIGINT, SIG_IGN) != SIG_IGN)
468 signal(SIGINT, intcatcher);
469}
470
Jack Jansena8441de1997-08-08 14:57:37 +0000471void
472PyOS_FiniInterrupts()
473{
474}
475
Jack Jansenee23d6e1995-01-27 14:43:25 +0000476/* Check whether we are in the foreground */
Jack Jansen9ae898b2000-07-11 21:16:03 +0000477static int
478PyMac_InForeground(void)
Jack Jansenee23d6e1995-01-27 14:43:25 +0000479{
480 static ProcessSerialNumber ours;
481 static inited;
482 ProcessSerialNumber curfg;
483 Boolean eq;
484
Jack Jansene3ae0df1997-06-03 15:28:29 +0000485 if ( inited == 0 ) {
Jack Jansenee23d6e1995-01-27 14:43:25 +0000486 (void)GetCurrentProcess(&ours);
Jack Jansene3ae0df1997-06-03 15:28:29 +0000487 inited = 1;
488 }
Jack Jansenee23d6e1995-01-27 14:43:25 +0000489 if ( GetFrontProcess(&curfg) < 0 )
490 eq = 1;
491 else if ( SameProcess(&ours, &curfg, &eq) < 0 )
492 eq = 1;
493 return (int)eq;
Jack Jansenee23d6e1995-01-27 14:43:25 +0000494}
Jack Jansen439eaa92001-11-10 00:41:43 +0000495
496/*
497** This routine scans the event queue looking for cmd-.
498*/
499static void
500scan_event_queue(force)
501 int force;
502{
503#if !TARGET_API_MAC_OS8
504 if ( interrupted || (!schedparams.check_interrupt && !force) )
505 return;
506 if ( CheckEventQueueForUserCancel() )
507 interrupted = 1;
508#else
509 register EvQElPtr q;
510
511 if ( interrupted || (!schedparams.check_interrupt && !force) || !PyMac_InForeground() )
512 return;
513 q = (EvQElPtr) LMGetEventQueue()->qHead;
514
515 for (; q; q = (EvQElPtr)q->qLink) {
516 if (q->evtQWhat == keyDown &&
517 (char)q->evtQMessage == '.' &&
518 (q->evtQModifiers & cmdKey) != 0) {
Jack Jansenb3be2162001-11-30 14:16:36 +0000519 FlushEvents(keyDownMask, 0);
Jack Jansen439eaa92001-11-10 00:41:43 +0000520 interrupted = 1;
521 break;
522 }
523 }
524#endif
525}
526
527int
528PyErr_CheckSignals()
529{
Jack Jansen439eaa92001-11-10 00:41:43 +0000530 if (schedparams.enabled) {
531 if ( interrupted || (unsigned long)LMGetTicks() > schedparams.next_check ) {
532 scan_event_queue(0);
533 if (interrupted) {
534 interrupted = 0;
535 PyErr_SetNone(PyExc_KeyboardInterrupt);
536 return -1;
537 }
538 if ( PyMac_Yield() < 0)
539 return -1;
Jack Jansen439eaa92001-11-10 00:41:43 +0000540 schedparams.next_check = (unsigned long)LMGetTicks()
541 + schedparams.check_interval;
542 }
543 }
544 return 0;
545}
546
547int
548PyOS_InterruptOccurred()
549{
550 scan_event_queue(0);
551 if ( !interrupted )
552 return 0;
553 interrupted = 0;
554 return 1;
555}
Jack Jansen0194ad52001-05-12 22:46:35 +0000556#endif
Jack Jansenee23d6e1995-01-27 14:43:25 +0000557
Jack Jansen36ed5061997-06-20 16:18:15 +0000558int
559PyMac_SetEventHandler(PyObject *evh)
560{
561 if ( evh && python_event_handler ) {
562 PyErr_SetString(PyExc_RuntimeError, "Python event handler already set");
563 return 0;
564 }
565 if ( python_event_handler )
566 Py_DECREF(python_event_handler);
567 if ( evh )
568 Py_INCREF(evh);
569 python_event_handler = evh;
570 return 1;
571}
572
Jack Jansenf93c72a1994-12-14 14:07:50 +0000573/*
Jack Jansena76382a1995-02-02 14:25:56 +0000574** Handle an event, either one found in the mainloop eventhandler or
575** one passed back from the python program.
576*/
577void
Jack Jansen36ed5061997-06-20 16:18:15 +0000578PyMac_HandleEventIntern(evp)
Jack Jansena76382a1995-02-02 14:25:56 +0000579 EventRecord *evp;
580{
Jack Jansen6e68a7e2001-05-12 21:31:34 +0000581#if TARGET_API_MAC_OS8
Jack Jansen0c968871997-08-26 13:20:34 +0000582 if ( evp->what == mouseDown ) {
583 WindowPtr wp;
584
585 if ( FindWindow(evp->where, &wp) == inSysWindow ) {
586 SystemClick(evp, wp);
587 return;
588 }
589 }
Jack Jansenbb6d83a2000-06-02 21:27:11 +0000590#endif
Jack Jansena76382a1995-02-02 14:25:56 +0000591#ifdef __MWERKS__
Jack Jansen38e97661995-11-10 14:53:00 +0000592 {
593 int siouxdidit;
594
595 /* If SIOUX wants it we're done */
596 siouxdidit = SIOUXHandleOneEvent(evp);
597 if ( siouxdidit )
598 return;
599 }
Jack Jansena76382a1995-02-02 14:25:56 +0000600#else
Jack Jansen0c968871997-08-26 13:20:34 +0000601 /* Other compilers are just unlucky... */
Jack Jansena76382a1995-02-02 14:25:56 +0000602#endif /* !__MWERKS__ */
Jack Jansen36ed5061997-06-20 16:18:15 +0000603}
604
605/*
606** Handle an event, either through HandleEvent or by passing it to the Python
607** event handler.
608*/
609int
610PyMac_HandleEvent(evp)
611 EventRecord *evp;
612{
613 PyObject *rv;
614
615 if ( python_event_handler ) {
616 rv = PyObject_CallFunction(python_event_handler, "(O&)",
617 PyMac_BuildEventRecord, evp);
618 if ( rv )
619 Py_DECREF(rv);
620 else
621 return -1; /* Propagate exception */
622 } else {
623 PyMac_HandleEventIntern(evp);
624 }
625 return 0;
Jack Jansena76382a1995-02-02 14:25:56 +0000626}
627
Jack Jansen0194ad52001-05-12 22:46:35 +0000628#if !TARGET_API_MAC_OSX
Jack Jansena76382a1995-02-02 14:25:56 +0000629/*
Jack Jansene3ae0df1997-06-03 15:28:29 +0000630** Yield the CPU to other tasks without processing events.
Jack Jansene8e8ae01995-01-26 16:36:45 +0000631*/
Jack Jansen2d1306b2000-04-07 09:10:49 +0000632int
Jack Jansene3ae0df1997-06-03 15:28:29 +0000633PyMac_DoYield(int maxsleep, int maycallpython)
Jack Jansenf93c72a1994-12-14 14:07:50 +0000634{
635 EventRecord ev;
Jack Jansene8e8ae01995-01-26 16:36:45 +0000636 int gotone;
Jack Jansene3ae0df1997-06-03 15:28:29 +0000637 long latest_time_ready;
Jack Jansen36ed5061997-06-20 16:18:15 +0000638 static int in_here = 0;
Jack Jansene8e8ae01995-01-26 16:36:45 +0000639
Jack Jansen36ed5061997-06-20 16:18:15 +0000640 in_here++;
Jack Jansene8e8ae01995-01-26 16:36:45 +0000641
Jack Jansene3ae0df1997-06-03 15:28:29 +0000642 /*
643 ** Check which of the eventloop cases we have:
644 ** - process events
645 ** - don't process events but do yield
646 ** - do neither
647 */
Jack Jansen36ed5061997-06-20 16:18:15 +0000648 if( in_here > 1 || !schedparams.process_events ||
649 (python_event_handler && !maycallpython) ) {
Jack Jansene3ae0df1997-06-03 15:28:29 +0000650 if ( maxsleep >= 0 ) {
Jack Jansen6e68a7e2001-05-12 21:31:34 +0000651#if TARGET_API_MAC_OS8
Jack Jansene8e8ae01995-01-26 16:36:45 +0000652 SystemTask();
Jack Jansen15f1c082001-04-25 22:07:27 +0000653#else
654 int xxx = 0;
Jack Jansenbb6d83a2000-06-02 21:27:11 +0000655#endif
Jack Jansen15f1c082001-04-25 22:07:27 +0000656 }
Jack Jansene3ae0df1997-06-03 15:28:29 +0000657 } else {
658 latest_time_ready = LMGetTicks() + maxsleep;
Jack Jansen2d1306b2000-04-07 09:10:49 +0000659 do {
Jack Jansen0c968871997-08-26 13:20:34 +0000660 /* XXXX Hack by Jack.
661 ** In time.sleep() you can click to another application
662 ** once only. If you come back to Python you cannot get away
663 ** again.
664 **/
Jack Jansen36ed5061997-06-20 16:18:15 +0000665 gotone = WaitNextEvent(schedparams.process_events, &ev, maxsleep, NULL);
Jack Jansene3ae0df1997-06-03 15:28:29 +0000666 /* Get out quickly if nothing interesting is happening */
667 if ( !gotone || ev.what == nullEvent )
668 break;
Jack Jansen36ed5061997-06-20 16:18:15 +0000669 if ( PyMac_HandleEvent(&ev) < 0 ) {
670 in_here--;
671 return -1;
672 }
Jack Jansene3ae0df1997-06-03 15:28:29 +0000673 maxsleep = latest_time_ready - LMGetTicks();
Jack Jansen2d1306b2000-04-07 09:10:49 +0000674 } while ( maxsleep > 0 );
Jack Jansenf93c72a1994-12-14 14:07:50 +0000675 }
Jack Jansen36ed5061997-06-20 16:18:15 +0000676 in_here--;
677 return 0;
Jack Jansene8e8ae01995-01-26 16:36:45 +0000678}
679
680/*
Jack Jansene3ae0df1997-06-03 15:28:29 +0000681** Process events and/or yield the CPU to other tasks if opportune
Jack Jansene8e8ae01995-01-26 16:36:45 +0000682*/
Jack Jansen36ed5061997-06-20 16:18:15 +0000683int
Jack Jansene8e8ae01995-01-26 16:36:45 +0000684PyMac_Yield() {
Jack Jansene3ae0df1997-06-03 15:28:29 +0000685 unsigned long maxsleep;
Jack Jansene8e8ae01995-01-26 16:36:45 +0000686
Jack Jansene3ae0df1997-06-03 15:28:29 +0000687 if( PyMac_InForeground() )
688 maxsleep = 0;
Jack Jansenee23d6e1995-01-27 14:43:25 +0000689 else
Jack Jansene3ae0df1997-06-03 15:28:29 +0000690 maxsleep = schedparams.bg_yield;
691
Jack Jansen36ed5061997-06-20 16:18:15 +0000692 return PyMac_DoYield(maxsleep, 1);
Jack Jansene8e8ae01995-01-26 16:36:45 +0000693}
694
695/*
Jack Jansene3ae0df1997-06-03 15:28:29 +0000696** Return current scheduler parameters
Jack Jansene8e8ae01995-01-26 16:36:45 +0000697*/
Jack Jansene3ae0df1997-06-03 15:28:29 +0000698void
699PyMac_GetSchedParams(PyMacSchedParams *sp)
Jack Jansene8e8ae01995-01-26 16:36:45 +0000700{
Jack Jansene3ae0df1997-06-03 15:28:29 +0000701 sp->check_interrupt = schedparams.check_interrupt;
702 sp->process_events = schedparams.process_events;
703 sp->besocial = schedparams.besocial;
704 sp->check_interval = schedparams.check_interval / 60.0;
705 sp->bg_yield = schedparams.bg_yield / 60.0;
Jack Jansenf93c72a1994-12-14 14:07:50 +0000706}
Jack Jansenf6865f71996-09-04 15:24:59 +0000707
Jack Jansen74162f31995-02-15 22:58:33 +0000708/*
Jack Jansene3ae0df1997-06-03 15:28:29 +0000709** Set current scheduler parameters
710*/
711void
712PyMac_SetSchedParams(PyMacSchedParams *sp)
713{
714 schedparams.check_interrupt = sp->check_interrupt;
715 schedparams.process_events = sp->process_events;
716 schedparams.besocial = sp->besocial;
717 schedparams.check_interval = (unsigned long)(sp->check_interval*60);
718 schedparams.bg_yield = (unsigned long)(sp->bg_yield*60);
719 if ( schedparams.check_interrupt || schedparams.process_events ||
720 schedparams.besocial )
721 schedparams.enabled = 1;
722 else
723 schedparams.enabled = 0;
724 schedparams.next_check = 0; /* Check immedeately */
725}
Jack Jansencaa7c461997-06-12 10:49:13 +0000726
Jack Jansene3ae0df1997-06-03 15:28:29 +0000727/*
Jack Jansen3469e991996-09-06 00:30:45 +0000728** Install our menu bar.
729*/
730void
731PyMac_InitMenuBar()
732{
Jack Jansen3469e991996-09-06 00:30:45 +0000733 MenuHandle applemenu;
Jack Jansen52306a72001-12-10 16:08:14 +0000734 Str255 about_text;
735 static unsigned char about_sioux[] = "\pAbout SIOUX";
Jack Jansen3469e991996-09-06 00:30:45 +0000736
Jack Jansen15f1c082001-04-25 22:07:27 +0000737 if ( sioux_mbar ) return;
Jack Jansen95837f12001-11-01 23:17:35 +0000738#if 0
739 /* This code does not seem to work anymore: apparently
740 ** we now always have a menubar (since MacOS9?).
741 ** So we simply always setup the Sioux menus here.
742 */
Jack Jansencaa7c461997-06-12 10:49:13 +0000743 if ( (sioux_mbar=GetMenuBar()) == NULL ) {
Jack Jansen95837f12001-11-01 23:17:35 +0000744#else
Jack Jansenb3be2162001-11-30 14:16:36 +0000745 if ( (sioux_mbar=GetMenuBar()) == NULL || GetMenuHandle(SIOUX_APPLEID) == NULL) {
Jack Jansen95837f12001-11-01 23:17:35 +0000746#endif
Jack Jansencaa7c461997-06-12 10:49:13 +0000747 /* Sioux menu not installed yet. Do so */
748 SIOUXSetupMenus();
749 if ( (sioux_mbar=GetMenuBar()) == NULL )
750 return;
751 }
Jack Jansen08c3be31997-04-08 15:27:00 +0000752 if ( (applemenu=GetMenuHandle(SIOUX_APPLEID)) == NULL ) return;
Jack Jansen52306a72001-12-10 16:08:14 +0000753 GetMenuItemText(applemenu, 1, about_text);
754 if ( about_text[0] == about_sioux[0] &&
755 strncmp((char *)(about_text+1), (char *)(about_sioux+1), about_text[0]) == 0 )
756 SetMenuItemText(applemenu, 1, "\pAbout Python...");
Jack Jansen3469e991996-09-06 00:30:45 +0000757}
758
759/*
Jack Jansencaa7c461997-06-12 10:49:13 +0000760** Restore sioux menu bar
761*/
762void
763PyMac_RestoreMenuBar()
764{
Jack Jansen15f1c082001-04-25 22:07:27 +0000765#if 1
Jack Jansen657ba272001-02-17 22:02:07 +0000766 /* This doesn't seem to work anymore? Or only for Carbon? */
767 MenuBarHandle curmenubar;
768
769 curmenubar = GetMenuBar();
Jack Janseneda78631997-06-12 15:29:46 +0000770 if ( sioux_mbar ) {
Jack Jansencaa7c461997-06-12 10:49:13 +0000771 SetMenuBar(sioux_mbar);
Jack Janseneda78631997-06-12 15:29:46 +0000772 DrawMenuBar();
Jack Jansen657ba272001-02-17 22:02:07 +0000773 } else {
Jack Jansenefaada71998-02-20 16:03:15 +0000774 PyMac_InitMenuBar();
Jack Jansen657ba272001-02-17 22:02:07 +0000775 DrawMenuBar();
776 }
777#endif
Jack Jansencaa7c461997-06-12 10:49:13 +0000778}
779
Jack Jansen15f1c082001-04-25 22:07:27 +0000780void
781PyMac_RaiseConsoleWindow()
782{
783 /* Note: this is a hack. SIOUXTextWindow is SIOUX's internal structure
784 ** and we happen to know that the first entry is the window pointer.
785 */
786 extern WindowRef *SIOUXTextWindow;
787
788 if ( SIOUXTextWindow == NULL || *SIOUXTextWindow == NULL )
789 return;
790 if ( FrontWindow() != *SIOUXTextWindow )
791 BringToFront(*SIOUXTextWindow);
792}
Jack Jansencaa7c461997-06-12 10:49:13 +0000793
794/*
Jack Jansen3469e991996-09-06 00:30:45 +0000795** Our replacement about box
796*/
Jack Jansen7e1fb7c1998-07-31 09:36:30 +0000797
798#include "patchlevel.h"
799
Jack Jansen3469e991996-09-06 00:30:45 +0000800void
801SIOUXDoAboutBox(void)
802{
803 DialogPtr theDialog;
Jack Jansen7e1fb7c1998-07-31 09:36:30 +0000804 WindowPtr theWindow;
Jack Jansen3469e991996-09-06 00:30:45 +0000805 short item;
Jack Jansen7e1fb7c1998-07-31 09:36:30 +0000806 short fontID;
Jack Jansen3469e991996-09-06 00:30:45 +0000807
808 if( (theDialog = GetNewDialog(ABOUT_ID, NULL, (WindowPtr)-1)) == NULL )
809 return;
Jack Jansend617c571996-09-22 22:14:30 +0000810 theWindow = GetDialogWindow(theDialog);
Jack Jansen7e1fb7c1998-07-31 09:36:30 +0000811 SetPortWindowPort(theWindow);
812 GetFNum("\pPython-Sans", &fontID);
813 if (fontID == 0)
814 fontID = kFontIDGeneva;
815 TextFont(fontID);
816 TextSize(9);
Jack Jansenf60edf82001-08-19 22:32:27 +0000817 ParamText(Pstring(PY_VERSION), "\p", "\p", "\p");
Jack Jansend617c571996-09-22 22:14:30 +0000818 ShowWindow(theWindow);
Jack Jansen3469e991996-09-06 00:30:45 +0000819 ModalDialog(NULL, &item);
820 DisposeDialog(theDialog);
821}
822
Jack Jansen0194ad52001-05-12 22:46:35 +0000823#endif /* !TARGET_API_MAC_OSX */
Jack Janseneda78631997-06-12 15:29:46 +0000824
Jack Jansen0194ad52001-05-12 22:46:35 +0000825#if TARGET_API_MAC_OS8
Jack Janseneda78631997-06-12 15:29:46 +0000826/*
Jack Jansen3ec804a1995-02-20 15:56:10 +0000827** Helper routine for GetDirectory
828*/
Guido van Rossum24a45e31995-02-20 23:45:53 +0000829static pascal short
Jack Jansen819f1771995-08-14 12:35:10 +0000830myhook_proc(short item, DialogPtr theDialog, struct hook_args *dataptr)
Jack Jansen3ec804a1995-02-20 15:56:10 +0000831{
Jack Jansen819f1771995-08-14 12:35:10 +0000832 if ( item == sfHookFirstCall && dataptr->prompt) {
833 Handle prompth;
834 short type;
835 Rect rect;
836
837 GetDialogItem(theDialog, PROMPT_ITEM, &type, &prompth, &rect);
838 if ( prompth )
839 SetDialogItemText(prompth, (unsigned char *)dataptr->prompt);
840 } else
Jack Jansen3ec804a1995-02-20 15:56:10 +0000841 if ( item == SELECTCUR_ITEM ) {
842 item = sfItemCancelButton;
Jack Jansen819f1771995-08-14 12:35:10 +0000843 dataptr->selectcur_hit = 1;
Jack Jansen3ec804a1995-02-20 15:56:10 +0000844 }
845 return item;
846}
Jack Jansen0194ad52001-05-12 22:46:35 +0000847
Jack Jansen3ec804a1995-02-20 15:56:10 +0000848/*
849** Ask the user for a directory. I still can't understand
850** why Apple doesn't provide a standard solution for this...
851*/
852int
Jack Jansen819f1771995-08-14 12:35:10 +0000853PyMac_GetDirectory(dirfss, prompt)
Jack Jansen3ec804a1995-02-20 15:56:10 +0000854 FSSpec *dirfss;
Jack Jansen819f1771995-08-14 12:35:10 +0000855 char *prompt;
Jack Jansen3ec804a1995-02-20 15:56:10 +0000856{
857 static SFTypeList list = {'fldr', 0, 0, 0};
858 static Point where = {-1, -1};
Jack Jansen3ec804a1995-02-20 15:56:10 +0000859 StandardFileReply reply;
Jack Jansen819f1771995-08-14 12:35:10 +0000860 struct hook_args hook_args;
Jack Jansen3ec804a1995-02-20 15:56:10 +0000861
862 if ( !upp_inited ) {
863 myhook_upp = NewDlgHookYDProc(myhook_proc);
864 upp_inited = 1;
865 }
Jack Jansen819f1771995-08-14 12:35:10 +0000866 if ( prompt && *prompt )
867 hook_args.prompt = (char *)Pstring(prompt);
868 else
869 hook_args.prompt = NULL;
870 hook_args.selectcur_hit = 0;
Guido van Rossum24a45e31995-02-20 23:45:53 +0000871 CustomGetFile((FileFilterYDUPP)0, 1, list, &reply, GETDIR_ID, where, myhook_upp,
Jack Jansen819f1771995-08-14 12:35:10 +0000872 NULL, NULL, NULL, (void *)&hook_args);
Jack Jansen3ec804a1995-02-20 15:56:10 +0000873
874 reply.sfFile.name[0] = 0;
875 if( FSMakeFSSpec(reply.sfFile.vRefNum, reply.sfFile.parID, reply.sfFile.name, dirfss) )
876 return 0;
Jack Jansen819f1771995-08-14 12:35:10 +0000877 return hook_args.selectcur_hit;
878}
879
880/*
881** Slightly extended StandardGetFile: accepts a prompt */
882void PyMac_PromptGetFile(short numTypes, ConstSFTypeListPtr typeList,
883 StandardFileReply *reply, char *prompt)
884{
885 static Point where = {-1, -1};
886 struct hook_args hook_args;
887
888 if ( !upp_inited ) {
889 myhook_upp = NewDlgHookYDProc(myhook_proc);
890 upp_inited = 1;
891 }
892 if ( prompt && *prompt )
893 hook_args.prompt = (char *)Pstring(prompt);
894 else
895 hook_args.prompt = NULL;
896 hook_args.selectcur_hit = 0;
897 CustomGetFile((FileFilterYDUPP)0, numTypes, typeList, reply, GETFILEPROMPT_ID, where,
898 myhook_upp, NULL, NULL, NULL, (void *)&hook_args);
Jack Jansen3ec804a1995-02-20 15:56:10 +0000899}
Jack Jansen6e68a7e2001-05-12 21:31:34 +0000900#endif /* TARGET_API_MAC_OS8 */
Jack Jansen5f653091995-01-18 13:53:49 +0000901
Jack Jansen5f653091995-01-18 13:53:49 +0000902