blob: 13dbbe7f344ed07c329c0b8bd0379550d33b58ea [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
301 if (interrupted) return -1;
302
Jack Jansene3ae0df1997-06-03 15:28:29 +0000303 if ( msg == SP_AUTO_SPIN )
304 maxsleep = 0;
305 if ( msg==SP_SLEEP||msg==SP_SELECT )
306 maxsleep = arg;
Jack Jansenf6865f71996-09-04 15:24:59 +0000307
Jack Jansene3ae0df1997-06-03 15:28:29 +0000308 PyMac_DoYield(maxsleep, 0); /* XXXX or is it safe to call python here? */
Jack Jansenf6865f71996-09-04 15:24:59 +0000309
310 return 0;
311}
312
313void
314PyMac_SetGUSISpin() {
315 GUSISetHook(GUSI_SpinHook, (GUSIHook)PyMac_GUSISpin);
316}
Jack Jansen2d1306b2000-04-07 09:10:49 +0000317#endif
Jack Jansenf6865f71996-09-04 15:24:59 +0000318
Jack Jansena39f1b01997-05-23 15:35:14 +0000319/* Called at exit() time thru atexit(), to stop event processing */
320void
321PyMac_StopGUSISpin() {
322 PyMac_ConsoleIsDead = 1;
323}
324
Jack Jansen6e68a7e2001-05-12 21:31:34 +0000325#if TARGET_API_MAC_OS8
Jack Jansena39f1b01997-05-23 15:35:14 +0000326/*
327** Replacement routines for the PLstr... functions so we don't need
Jack Jansen6ba34aa2001-01-11 23:03:56 +0000328** StdCLib.
Jack Jansena39f1b01997-05-23 15:35:14 +0000329*/
Jack Jansen8bb573e1999-12-12 21:37:14 +0000330pascal void
Jack Jansen9ae898b2000-07-11 21:16:03 +0000331PLstrcpy(unsigned char *to, unsigned char *fr)
Jack Jansena39f1b01997-05-23 15:35:14 +0000332{
333 memcpy(to, fr, fr[0]+1);
334}
335
Jack Jansen8bb573e1999-12-12 21:37:14 +0000336pascal int
Jack Jansen9ae898b2000-07-11 21:16:03 +0000337PLstrcmp(unsigned char *s1, unsigned char *s2)
Jack Jansena39f1b01997-05-23 15:35:14 +0000338{
339 int res;
340 int l = s1[0] < s2[0] ? s1[0] : s2[0];
341
342 res = memcmp(s1+1, s2+1, l);
343 if ( res != 0 )
344 return res;
345
Jack Jansen7e1fb7c1998-07-31 09:36:30 +0000346 if ( s1[0] < s2[0] )
Jack Jansena39f1b01997-05-23 15:35:14 +0000347 return -1;
Jack Jansen7e1fb7c1998-07-31 09:36:30 +0000348 else if ( s1[0] > s2[0] )
Jack Jansena39f1b01997-05-23 15:35:14 +0000349 return 1;
350 else
351 return 0;
352}
353
Jack Jansen8bb573e1999-12-12 21:37:14 +0000354pascal unsigned char *
Jack Jansen9ae898b2000-07-11 21:16:03 +0000355PLstrrchr(unsigned char *str, unsigned char chr)
Jack Jansena39f1b01997-05-23 15:35:14 +0000356{
357 unsigned char *ptr = 0;
358 unsigned char *p;
359
360 for(p=str+1; p<str+str[0]; p++)
361 if ( *p == chr )
362 ptr = p;
363 return ptr;
364}
365
Jack Jansen6e68a7e2001-05-12 21:31:34 +0000366#endif /* TARGET_API_MAC_OS8 */
Jack Jansena39f1b01997-05-23 15:35:14 +0000367#endif /* USE_GUSI */
Jack Jansen378815c1996-03-06 16:21:34 +0000368
Jack Jansen819f1771995-08-14 12:35:10 +0000369
Jack Jansen5f653091995-01-18 13:53:49 +0000370/* Convert C to Pascal string. Returns pointer to static buffer. */
371unsigned char *
372Pstring(char *str)
373{
374 static Str255 buf;
375 int len;
376
377 len = strlen(str);
Guido van Rossum9aa3d131995-01-21 13:46:04 +0000378 if (len > 255)
379 len = 255;
Jack Jansen5f653091995-01-18 13:53:49 +0000380 buf[0] = (unsigned char)len;
381 strncpy((char *)buf+1, str, len);
382 return buf;
383}
384
Jack Jansen6e68a7e2001-05-12 21:31:34 +0000385#if TARGET_API_MAC_OS8
Jack Jansen5afad832000-12-12 22:12:14 +0000386void
387c2pstrcpy(unsigned char *dst, const char *src)
388{
389 int len;
390
391 len = strlen(src);
392 if ( len > 255 ) len = 255;
393 strncpy((char *)dst+1, src, len);
394 dst[0] = len;
395}
Jack Jansen6e68a7e2001-05-12 21:31:34 +0000396#endif /* TARGET_API_MAC_OS8 */
Jack Jansen5afad832000-12-12 22:12:14 +0000397
Jack Jansen1ed95291996-07-22 15:25:10 +0000398#ifdef USE_STACKCHECK
399/* Check for stack overflow */
400int
401PyOS_CheckStack()
402{
Jack Jansen14a91712000-08-25 21:57:23 +0000403 char here;
404 static char *sentinel = 0;
Jack Jansen53bafd92000-09-08 22:05:48 +0000405 static PyThreadState *thread_for_sentinel = 0;
Jack Jansen1ed95291996-07-22 15:25:10 +0000406
Jack Jansen340eb882001-02-02 22:40:28 +0000407 if ( sentinel == 0 ) {
408 unsigned long stackspace = StackSpace();
409
410#ifdef MAXIMUM_STACK_SIZE
411 /* See the comment at the definition */
412 if ( stackspace > MAXIMUM_STACK_SIZE )
413 stackspace = MAXIMUM_STACK_SIZE;
414#endif
415 sentinel = &here - stackspace + MINIMUM_STACK_SIZE;
Jack Jansen14a91712000-08-25 21:57:23 +0000416 }
Jack Jansen53bafd92000-09-08 22:05:48 +0000417 if ( thread_for_sentinel == 0 ) {
418 thread_for_sentinel = PyThreadState_Get();
419 }
420 if ( &here < sentinel ) {
421 if (thread_for_sentinel == PyThreadState_Get()) {
422 return -1;
423#if 0
424 } else {
425 /* Else we are unsure... */
426 fprintf(stderr, "Stackcheck in other thread (was %x now %x)\n", thread_for_sentinel,PyThreadState_Get());
427#endif
428 }
429 }
Jack Jansen1ed95291996-07-22 15:25:10 +0000430 return 0;
431}
432#endif /* USE_STACKCHECK */
433
Jack Jansen0194ad52001-05-12 22:46:35 +0000434#if !TARGET_API_MAC_OSX
Jack Jansenee23d6e1995-01-27 14:43:25 +0000435/* The catcher routine (which may not be used for all compilers) */
436static RETSIGTYPE
437intcatcher(sig)
438 int sig;
439{
440 interrupted = 1;
441 signal(SIGINT, intcatcher);
442}
443
444void
445PyOS_InitInterrupts()
446{
447 if (signal(SIGINT, SIG_IGN) != SIG_IGN)
448 signal(SIGINT, intcatcher);
449}
450
Jack Jansena8441de1997-08-08 14:57:37 +0000451void
452PyOS_FiniInterrupts()
453{
454}
455
Jack Jansenee23d6e1995-01-27 14:43:25 +0000456/*
457** This routine scans the event queue looking for cmd-.
458** This is the only way to get an interrupt under THINK (since it
459** doesn't do SIGINT handling), but is also used under MW, when
460** the full-fledged event loop is disabled. This way, we can at least
461** interrupt a runaway python program.
462*/
463static void
464scan_event_queue(flush)
465 int flush;
466{
Jack Jansen6e68a7e2001-05-12 21:31:34 +0000467#if !TARGET_API_MAC_OS8
Jack Jansend7b68022001-01-12 23:42:28 +0000468 if ( CheckEventQueueForUserCancel() )
469 interrupted = 1;
Jack Jansenbb6d83a2000-06-02 21:27:11 +0000470#else
Jack Jansenee23d6e1995-01-27 14:43:25 +0000471 register EvQElPtr q;
472
Jack Jansenefaada71998-02-20 16:03:15 +0000473 q = (EvQElPtr) LMGetEventQueue()->qHead;
Jack Jansenee23d6e1995-01-27 14:43:25 +0000474
475 for (; q; q = (EvQElPtr)q->qLink) {
476 if (q->evtQWhat == keyDown &&
477 (char)q->evtQMessage == '.' &&
478 (q->evtQModifiers & cmdKey) != 0) {
479 if ( flush )
480 FlushEvents(keyDownMask, 0);
481 interrupted = 1;
482 break;
483 }
484 }
Jack Jansenbb6d83a2000-06-02 21:27:11 +0000485#endif
Jack Jansenee23d6e1995-01-27 14:43:25 +0000486}
487
488int
Jack Jansen36ed5061997-06-20 16:18:15 +0000489PyErr_CheckSignals()
Jack Jansenee23d6e1995-01-27 14:43:25 +0000490{
Jack Jansene3ae0df1997-06-03 15:28:29 +0000491 if (schedparams.enabled) {
492 if ( (unsigned long)LMGetTicks() > schedparams.next_check ) {
Jack Jansen36ed5061997-06-20 16:18:15 +0000493 if ( PyMac_Yield() < 0)
494 return -1;
Jack Jansene3ae0df1997-06-03 15:28:29 +0000495 schedparams.next_check = (unsigned long)LMGetTicks()
496 + schedparams.check_interval;
497 if (interrupted) {
Jack Jansencaa7c461997-06-12 10:49:13 +0000498 scan_event_queue(1); /* Eat events up to cmd-. */
Jack Jansene3ae0df1997-06-03 15:28:29 +0000499 interrupted = 0;
Jack Jansen36ed5061997-06-20 16:18:15 +0000500 PyErr_SetNone(PyExc_KeyboardInterrupt);
501 return -1;
Jack Jansene3ae0df1997-06-03 15:28:29 +0000502 }
503 }
Jack Jansenee23d6e1995-01-27 14:43:25 +0000504 }
505 return 0;
506}
507
Jack Jansen36ed5061997-06-20 16:18:15 +0000508int
509PyOS_InterruptOccurred()
510{
511 scan_event_queue(1);
512 return interrupted;
513}
Jack Jansen0194ad52001-05-12 22:46:35 +0000514
Jack Jansenee23d6e1995-01-27 14:43:25 +0000515/* Check whether we are in the foreground */
Jack Jansen9ae898b2000-07-11 21:16:03 +0000516static int
517PyMac_InForeground(void)
Jack Jansenee23d6e1995-01-27 14:43:25 +0000518{
519 static ProcessSerialNumber ours;
520 static inited;
521 ProcessSerialNumber curfg;
522 Boolean eq;
523
Jack Jansene3ae0df1997-06-03 15:28:29 +0000524 if ( inited == 0 ) {
Jack Jansenee23d6e1995-01-27 14:43:25 +0000525 (void)GetCurrentProcess(&ours);
Jack Jansene3ae0df1997-06-03 15:28:29 +0000526 inited = 1;
527 }
Jack Jansenee23d6e1995-01-27 14:43:25 +0000528 if ( GetFrontProcess(&curfg) < 0 )
529 eq = 1;
530 else if ( SameProcess(&ours, &curfg, &eq) < 0 )
531 eq = 1;
532 return (int)eq;
Jack Jansenee23d6e1995-01-27 14:43:25 +0000533}
Jack Jansen0194ad52001-05-12 22:46:35 +0000534#endif
Jack Jansenee23d6e1995-01-27 14:43:25 +0000535
Jack Jansen36ed5061997-06-20 16:18:15 +0000536int
537PyMac_SetEventHandler(PyObject *evh)
538{
539 if ( evh && python_event_handler ) {
540 PyErr_SetString(PyExc_RuntimeError, "Python event handler already set");
541 return 0;
542 }
543 if ( python_event_handler )
544 Py_DECREF(python_event_handler);
545 if ( evh )
546 Py_INCREF(evh);
547 python_event_handler = evh;
548 return 1;
549}
550
Jack Jansenf93c72a1994-12-14 14:07:50 +0000551/*
Jack Jansena76382a1995-02-02 14:25:56 +0000552** Handle an event, either one found in the mainloop eventhandler or
553** one passed back from the python program.
554*/
555void
Jack Jansen36ed5061997-06-20 16:18:15 +0000556PyMac_HandleEventIntern(evp)
Jack Jansena76382a1995-02-02 14:25:56 +0000557 EventRecord *evp;
558{
Jack Jansen6e68a7e2001-05-12 21:31:34 +0000559#if TARGET_API_MAC_OS8
Jack Jansen0c968871997-08-26 13:20:34 +0000560 if ( evp->what == mouseDown ) {
561 WindowPtr wp;
562
563 if ( FindWindow(evp->where, &wp) == inSysWindow ) {
564 SystemClick(evp, wp);
565 return;
566 }
567 }
Jack Jansenbb6d83a2000-06-02 21:27:11 +0000568#endif
Jack Jansena76382a1995-02-02 14:25:56 +0000569#ifdef __MWERKS__
Jack Jansen38e97661995-11-10 14:53:00 +0000570 {
571 int siouxdidit;
572
573 /* If SIOUX wants it we're done */
574 siouxdidit = SIOUXHandleOneEvent(evp);
575 if ( siouxdidit )
576 return;
577 }
Jack Jansena76382a1995-02-02 14:25:56 +0000578#else
Jack Jansen0c968871997-08-26 13:20:34 +0000579 /* Other compilers are just unlucky... */
Jack Jansena76382a1995-02-02 14:25:56 +0000580#endif /* !__MWERKS__ */
Jack Jansen36ed5061997-06-20 16:18:15 +0000581}
582
583/*
584** Handle an event, either through HandleEvent or by passing it to the Python
585** event handler.
586*/
587int
588PyMac_HandleEvent(evp)
589 EventRecord *evp;
590{
591 PyObject *rv;
592
593 if ( python_event_handler ) {
594 rv = PyObject_CallFunction(python_event_handler, "(O&)",
595 PyMac_BuildEventRecord, evp);
596 if ( rv )
597 Py_DECREF(rv);
598 else
599 return -1; /* Propagate exception */
600 } else {
601 PyMac_HandleEventIntern(evp);
602 }
603 return 0;
Jack Jansena76382a1995-02-02 14:25:56 +0000604}
605
Jack Jansen0194ad52001-05-12 22:46:35 +0000606#if !TARGET_API_MAC_OSX
Jack Jansena76382a1995-02-02 14:25:56 +0000607/*
Jack Jansene3ae0df1997-06-03 15:28:29 +0000608** Yield the CPU to other tasks without processing events.
Jack Jansene8e8ae01995-01-26 16:36:45 +0000609*/
Jack Jansen2d1306b2000-04-07 09:10:49 +0000610int
Jack Jansene3ae0df1997-06-03 15:28:29 +0000611PyMac_DoYield(int maxsleep, int maycallpython)
Jack Jansenf93c72a1994-12-14 14:07:50 +0000612{
613 EventRecord ev;
Jack Jansene8e8ae01995-01-26 16:36:45 +0000614 int gotone;
Jack Jansene3ae0df1997-06-03 15:28:29 +0000615 long latest_time_ready;
Jack Jansen36ed5061997-06-20 16:18:15 +0000616 static int in_here = 0;
Jack Jansene8e8ae01995-01-26 16:36:45 +0000617
Jack Jansen36ed5061997-06-20 16:18:15 +0000618 in_here++;
Jack Jansene3ae0df1997-06-03 15:28:29 +0000619 /*
620 ** First check for interrupts, if wanted.
621 ** This sets a flag that will be picked up at an appropriate
622 ** moment in the mainloop.
623 */
624 if (schedparams.check_interrupt)
Jack Jansenee23d6e1995-01-27 14:43:25 +0000625 scan_event_queue(0);
Jack Jansene3ae0df1997-06-03 15:28:29 +0000626
627 /* XXXX Implementing an idle routine goes here */
Jack Jansene8e8ae01995-01-26 16:36:45 +0000628
Jack Jansene3ae0df1997-06-03 15:28:29 +0000629 /*
630 ** Check which of the eventloop cases we have:
631 ** - process events
632 ** - don't process events but do yield
633 ** - do neither
634 */
Jack Jansen36ed5061997-06-20 16:18:15 +0000635 if( in_here > 1 || !schedparams.process_events ||
636 (python_event_handler && !maycallpython) ) {
Jack Jansene3ae0df1997-06-03 15:28:29 +0000637 if ( maxsleep >= 0 ) {
Jack Jansen6e68a7e2001-05-12 21:31:34 +0000638#if TARGET_API_MAC_OS8
Jack Jansene8e8ae01995-01-26 16:36:45 +0000639 SystemTask();
Jack Jansen15f1c082001-04-25 22:07:27 +0000640#else
641 int xxx = 0;
Jack Jansenbb6d83a2000-06-02 21:27:11 +0000642#endif
Jack Jansen15f1c082001-04-25 22:07:27 +0000643 }
Jack Jansene3ae0df1997-06-03 15:28:29 +0000644 } else {
645 latest_time_ready = LMGetTicks() + maxsleep;
Jack Jansen2d1306b2000-04-07 09:10:49 +0000646 do {
Jack Jansen0c968871997-08-26 13:20:34 +0000647 /* XXXX Hack by Jack.
648 ** In time.sleep() you can click to another application
649 ** once only. If you come back to Python you cannot get away
650 ** again.
651 **/
Jack Jansen36ed5061997-06-20 16:18:15 +0000652 gotone = WaitNextEvent(schedparams.process_events, &ev, maxsleep, NULL);
Jack Jansene3ae0df1997-06-03 15:28:29 +0000653 /* Get out quickly if nothing interesting is happening */
654 if ( !gotone || ev.what == nullEvent )
655 break;
Jack Jansen36ed5061997-06-20 16:18:15 +0000656 if ( PyMac_HandleEvent(&ev) < 0 ) {
657 in_here--;
658 return -1;
659 }
Jack Jansene3ae0df1997-06-03 15:28:29 +0000660 maxsleep = latest_time_ready - LMGetTicks();
Jack Jansen2d1306b2000-04-07 09:10:49 +0000661 } while ( maxsleep > 0 );
Jack Jansenf93c72a1994-12-14 14:07:50 +0000662 }
Jack Jansen36ed5061997-06-20 16:18:15 +0000663 in_here--;
664 return 0;
Jack Jansene8e8ae01995-01-26 16:36:45 +0000665}
666
667/*
Jack Jansene3ae0df1997-06-03 15:28:29 +0000668** Process events and/or yield the CPU to other tasks if opportune
Jack Jansene8e8ae01995-01-26 16:36:45 +0000669*/
Jack Jansen36ed5061997-06-20 16:18:15 +0000670int
Jack Jansene8e8ae01995-01-26 16:36:45 +0000671PyMac_Yield() {
Jack Jansene3ae0df1997-06-03 15:28:29 +0000672 unsigned long maxsleep;
Jack Jansene8e8ae01995-01-26 16:36:45 +0000673
Jack Jansene3ae0df1997-06-03 15:28:29 +0000674 if( PyMac_InForeground() )
675 maxsleep = 0;
Jack Jansenee23d6e1995-01-27 14:43:25 +0000676 else
Jack Jansene3ae0df1997-06-03 15:28:29 +0000677 maxsleep = schedparams.bg_yield;
678
Jack Jansen36ed5061997-06-20 16:18:15 +0000679 return PyMac_DoYield(maxsleep, 1);
Jack Jansene8e8ae01995-01-26 16:36:45 +0000680}
681
682/*
Jack Jansene3ae0df1997-06-03 15:28:29 +0000683** Return current scheduler parameters
Jack Jansene8e8ae01995-01-26 16:36:45 +0000684*/
Jack Jansene3ae0df1997-06-03 15:28:29 +0000685void
686PyMac_GetSchedParams(PyMacSchedParams *sp)
Jack Jansene8e8ae01995-01-26 16:36:45 +0000687{
Jack Jansene3ae0df1997-06-03 15:28:29 +0000688 sp->check_interrupt = schedparams.check_interrupt;
689 sp->process_events = schedparams.process_events;
690 sp->besocial = schedparams.besocial;
691 sp->check_interval = schedparams.check_interval / 60.0;
692 sp->bg_yield = schedparams.bg_yield / 60.0;
Jack Jansenf93c72a1994-12-14 14:07:50 +0000693}
Jack Jansenf6865f71996-09-04 15:24:59 +0000694
Jack Jansen74162f31995-02-15 22:58:33 +0000695/*
Jack Jansene3ae0df1997-06-03 15:28:29 +0000696** Set current scheduler parameters
697*/
698void
699PyMac_SetSchedParams(PyMacSchedParams *sp)
700{
701 schedparams.check_interrupt = sp->check_interrupt;
702 schedparams.process_events = sp->process_events;
703 schedparams.besocial = sp->besocial;
704 schedparams.check_interval = (unsigned long)(sp->check_interval*60);
705 schedparams.bg_yield = (unsigned long)(sp->bg_yield*60);
706 if ( schedparams.check_interrupt || schedparams.process_events ||
707 schedparams.besocial )
708 schedparams.enabled = 1;
709 else
710 schedparams.enabled = 0;
711 schedparams.next_check = 0; /* Check immedeately */
712}
Jack Jansencaa7c461997-06-12 10:49:13 +0000713
Jack Jansene3ae0df1997-06-03 15:28:29 +0000714/*
Jack Jansen3469e991996-09-06 00:30:45 +0000715** Install our menu bar.
716*/
717void
718PyMac_InitMenuBar()
719{
Jack Jansen3469e991996-09-06 00:30:45 +0000720 MenuHandle applemenu;
721
Jack Jansen15f1c082001-04-25 22:07:27 +0000722 if ( sioux_mbar ) return;
Jack Jansen95837f12001-11-01 23:17:35 +0000723#if 0
724 /* This code does not seem to work anymore: apparently
725 ** we now always have a menubar (since MacOS9?).
726 ** So we simply always setup the Sioux menus here.
727 */
Jack Jansencaa7c461997-06-12 10:49:13 +0000728 if ( (sioux_mbar=GetMenuBar()) == NULL ) {
Jack Jansen95837f12001-11-01 23:17:35 +0000729#else
730 {
731#endif
Jack Jansencaa7c461997-06-12 10:49:13 +0000732 /* Sioux menu not installed yet. Do so */
733 SIOUXSetupMenus();
734 if ( (sioux_mbar=GetMenuBar()) == NULL )
735 return;
736 }
Jack Jansen08c3be31997-04-08 15:27:00 +0000737 if ( (applemenu=GetMenuHandle(SIOUX_APPLEID)) == NULL ) return;
Jack Jansen3469e991996-09-06 00:30:45 +0000738 SetMenuItemText(applemenu, 1, "\pAbout Python...");
739}
740
741/*
Jack Jansencaa7c461997-06-12 10:49:13 +0000742** Restore sioux menu bar
743*/
744void
745PyMac_RestoreMenuBar()
746{
Jack Jansen15f1c082001-04-25 22:07:27 +0000747#if 1
Jack Jansen657ba272001-02-17 22:02:07 +0000748 /* This doesn't seem to work anymore? Or only for Carbon? */
749 MenuBarHandle curmenubar;
750
751 curmenubar = GetMenuBar();
Jack Janseneda78631997-06-12 15:29:46 +0000752 if ( sioux_mbar ) {
Jack Jansencaa7c461997-06-12 10:49:13 +0000753 SetMenuBar(sioux_mbar);
Jack Janseneda78631997-06-12 15:29:46 +0000754 DrawMenuBar();
Jack Jansen657ba272001-02-17 22:02:07 +0000755 } else {
Jack Jansenefaada71998-02-20 16:03:15 +0000756 PyMac_InitMenuBar();
Jack Jansen657ba272001-02-17 22:02:07 +0000757 DrawMenuBar();
758 }
759#endif
Jack Jansencaa7c461997-06-12 10:49:13 +0000760}
761
Jack Jansen15f1c082001-04-25 22:07:27 +0000762void
763PyMac_RaiseConsoleWindow()
764{
765 /* Note: this is a hack. SIOUXTextWindow is SIOUX's internal structure
766 ** and we happen to know that the first entry is the window pointer.
767 */
768 extern WindowRef *SIOUXTextWindow;
769
770 if ( SIOUXTextWindow == NULL || *SIOUXTextWindow == NULL )
771 return;
772 if ( FrontWindow() != *SIOUXTextWindow )
773 BringToFront(*SIOUXTextWindow);
774}
Jack Jansencaa7c461997-06-12 10:49:13 +0000775
776/*
Jack Jansen3469e991996-09-06 00:30:45 +0000777** Our replacement about box
778*/
Jack Jansen7e1fb7c1998-07-31 09:36:30 +0000779
780#include "patchlevel.h"
781
Jack Jansen3469e991996-09-06 00:30:45 +0000782void
783SIOUXDoAboutBox(void)
784{
785 DialogPtr theDialog;
Jack Jansen7e1fb7c1998-07-31 09:36:30 +0000786 WindowPtr theWindow;
Jack Jansen3469e991996-09-06 00:30:45 +0000787 short item;
Jack Jansen7e1fb7c1998-07-31 09:36:30 +0000788 short fontID;
Jack Jansen3469e991996-09-06 00:30:45 +0000789
790 if( (theDialog = GetNewDialog(ABOUT_ID, NULL, (WindowPtr)-1)) == NULL )
791 return;
Jack Jansend617c571996-09-22 22:14:30 +0000792 theWindow = GetDialogWindow(theDialog);
Jack Jansen7e1fb7c1998-07-31 09:36:30 +0000793 SetPortWindowPort(theWindow);
794 GetFNum("\pPython-Sans", &fontID);
795 if (fontID == 0)
796 fontID = kFontIDGeneva;
797 TextFont(fontID);
798 TextSize(9);
Jack Jansenf60edf82001-08-19 22:32:27 +0000799 ParamText(Pstring(PY_VERSION), "\p", "\p", "\p");
Jack Jansend617c571996-09-22 22:14:30 +0000800 ShowWindow(theWindow);
Jack Jansen3469e991996-09-06 00:30:45 +0000801 ModalDialog(NULL, &item);
802 DisposeDialog(theDialog);
803}
804
Jack Jansen0194ad52001-05-12 22:46:35 +0000805#endif /* !TARGET_API_MAC_OSX */
Jack Janseneda78631997-06-12 15:29:46 +0000806
Jack Jansen0194ad52001-05-12 22:46:35 +0000807#if TARGET_API_MAC_OS8
Jack Janseneda78631997-06-12 15:29:46 +0000808/*
Jack Jansen3ec804a1995-02-20 15:56:10 +0000809** Helper routine for GetDirectory
810*/
Guido van Rossum24a45e31995-02-20 23:45:53 +0000811static pascal short
Jack Jansen819f1771995-08-14 12:35:10 +0000812myhook_proc(short item, DialogPtr theDialog, struct hook_args *dataptr)
Jack Jansen3ec804a1995-02-20 15:56:10 +0000813{
Jack Jansen819f1771995-08-14 12:35:10 +0000814 if ( item == sfHookFirstCall && dataptr->prompt) {
815 Handle prompth;
816 short type;
817 Rect rect;
818
819 GetDialogItem(theDialog, PROMPT_ITEM, &type, &prompth, &rect);
820 if ( prompth )
821 SetDialogItemText(prompth, (unsigned char *)dataptr->prompt);
822 } else
Jack Jansen3ec804a1995-02-20 15:56:10 +0000823 if ( item == SELECTCUR_ITEM ) {
824 item = sfItemCancelButton;
Jack Jansen819f1771995-08-14 12:35:10 +0000825 dataptr->selectcur_hit = 1;
Jack Jansen3ec804a1995-02-20 15:56:10 +0000826 }
827 return item;
828}
Jack Jansen0194ad52001-05-12 22:46:35 +0000829
Jack Jansen3ec804a1995-02-20 15:56:10 +0000830/*
831** Ask the user for a directory. I still can't understand
832** why Apple doesn't provide a standard solution for this...
833*/
834int
Jack Jansen819f1771995-08-14 12:35:10 +0000835PyMac_GetDirectory(dirfss, prompt)
Jack Jansen3ec804a1995-02-20 15:56:10 +0000836 FSSpec *dirfss;
Jack Jansen819f1771995-08-14 12:35:10 +0000837 char *prompt;
Jack Jansen3ec804a1995-02-20 15:56:10 +0000838{
839 static SFTypeList list = {'fldr', 0, 0, 0};
840 static Point where = {-1, -1};
Jack Jansen3ec804a1995-02-20 15:56:10 +0000841 StandardFileReply reply;
Jack Jansen819f1771995-08-14 12:35:10 +0000842 struct hook_args hook_args;
Jack Jansen3ec804a1995-02-20 15:56:10 +0000843
844 if ( !upp_inited ) {
845 myhook_upp = NewDlgHookYDProc(myhook_proc);
846 upp_inited = 1;
847 }
Jack Jansen819f1771995-08-14 12:35:10 +0000848 if ( prompt && *prompt )
849 hook_args.prompt = (char *)Pstring(prompt);
850 else
851 hook_args.prompt = NULL;
852 hook_args.selectcur_hit = 0;
Guido van Rossum24a45e31995-02-20 23:45:53 +0000853 CustomGetFile((FileFilterYDUPP)0, 1, list, &reply, GETDIR_ID, where, myhook_upp,
Jack Jansen819f1771995-08-14 12:35:10 +0000854 NULL, NULL, NULL, (void *)&hook_args);
Jack Jansen3ec804a1995-02-20 15:56:10 +0000855
856 reply.sfFile.name[0] = 0;
857 if( FSMakeFSSpec(reply.sfFile.vRefNum, reply.sfFile.parID, reply.sfFile.name, dirfss) )
858 return 0;
Jack Jansen819f1771995-08-14 12:35:10 +0000859 return hook_args.selectcur_hit;
860}
861
862/*
863** Slightly extended StandardGetFile: accepts a prompt */
864void PyMac_PromptGetFile(short numTypes, ConstSFTypeListPtr typeList,
865 StandardFileReply *reply, char *prompt)
866{
867 static Point where = {-1, -1};
868 struct hook_args hook_args;
869
870 if ( !upp_inited ) {
871 myhook_upp = NewDlgHookYDProc(myhook_proc);
872 upp_inited = 1;
873 }
874 if ( prompt && *prompt )
875 hook_args.prompt = (char *)Pstring(prompt);
876 else
877 hook_args.prompt = NULL;
878 hook_args.selectcur_hit = 0;
879 CustomGetFile((FileFilterYDUPP)0, numTypes, typeList, reply, GETFILEPROMPT_ID, where,
880 myhook_upp, NULL, NULL, NULL, (void *)&hook_args);
Jack Jansen3ec804a1995-02-20 15:56:10 +0000881}
Jack Jansen6e68a7e2001-05-12 21:31:34 +0000882#endif /* TARGET_API_MAC_OS8 */
Jack Jansen5f653091995-01-18 13:53:49 +0000883
Jack Jansen5f653091995-01-18 13:53:49 +0000884