blob: 9c01fd74b807ed48c0bb102042989f9a2dd72265 [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
206PyMac_GetFullPath (FSSpec *fss, char *buf)
207{
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];
215 memcpy(buf, &fss_current.name[1], plen);
216 buf[plen] = 0;
217 /* Special case for disk names */
218 if ( fss_current.parID <= 1 ) {
219 buf[plen++] = ':';
220 buf[plen] = 0;
221 return 0;
222 }
223 while (fss_current.parID > 1) {
224 /* Get parent folder name */
225 if (err = get_folder_parent(&fss_current, &fss_parent))
226 return err;
227 fss_current = fss_parent;
228 /* Prepend path component just found to buf */
229 plen = fss_current.name[0];
230 if (strlen(buf) + plen + 1 > 1024) {
231 /* Oops... Not enough space (shouldn't happen) */
232 *buf = 0;
233 return -1;
234 }
235 memcpy(tmpbuf, &fss_current.name[1], plen);
236 tmpbuf[plen] = ':';
237 strcpy(&tmpbuf[plen+1], buf);
238 strcpy(buf, tmpbuf);
239 }
240 return 0;
241}
Jack Jansen1f9f2f42000-07-24 19:50:16 +0000242
Jack Jansen2d1306b2000-04-07 09:10:49 +0000243#ifdef USE_GUSI1
Jack Jansen378815c1996-03-06 16:21:34 +0000244/*
245** GUSI (1.6.0 and earlier, at the least) do not set the MacOS idea of
246** the working directory. Hence, we call this routine after each call
247** to chdir() to rectify things.
248*/
249void
250PyMac_FixGUSIcd()
251{
252 WDPBRec pb;
253 FSSpec curdirfss;
254
255 if ( Path2FSSpec(":x", &curdirfss) != noErr )
256 return;
257
258 /* Set MacOS "working directory" */
259 pb.ioNamePtr= "\p";
260 pb.ioVRefNum= curdirfss.vRefNum;
261 pb.ioWDDirID= curdirfss.parID;
Jack Jansen08c3be31997-04-08 15:27:00 +0000262 if (PBHSetVolSync(&pb) != noErr)
Jack Jansen378815c1996-03-06 16:21:34 +0000263 return;
Jack Jansen378815c1996-03-06 16:21:34 +0000264}
Jack Jansen2d1306b2000-04-07 09:10:49 +0000265#endif
Jack Jansen7ac70af1996-08-19 11:01:05 +0000266
Jack Jansen2d1306b2000-04-07 09:10:49 +0000267#ifdef USE_GUSI
Jack Jansen7d5f9e81996-09-07 17:09:31 +0000268/*
269** SpinCursor (needed by GUSI) drags in heaps of stuff, so we
270** provide a dummy here.
271*/
Jack Jansencfadbd41996-08-19 11:36:25 +0000272void SpinCursor(short x) { /* Dummy */ }
Jack Jansenefaada71998-02-20 16:03:15 +0000273void RotateCursor(short x) { /* Dummy */ }
Jack Jansencfadbd41996-08-19 11:36:25 +0000274
Jack Jansenf6865f71996-09-04 15:24:59 +0000275/*
276** Replacement GUSI Spin function
277*/
Jack Jansen2d1306b2000-04-07 09:10:49 +0000278#ifdef USE_GUSI1
Jack Jansenf6865f71996-09-04 15:24:59 +0000279static int
280PyMac_GUSISpin(spin_msg msg, long arg)
281{
Jack Jansene3ae0df1997-06-03 15:28:29 +0000282 static Boolean inForeground = true;
283 int maxsleep = 6; /* 6 ticks is "normal" sleeptime */
Jack Jansenf6865f71996-09-04 15:24:59 +0000284
285 if (PyMac_ConsoleIsDead) return 0;
286#if 0
287 if (inForeground)
288 SpinCursor(msg == SP_AUTO_SPIN ? short(arg) : 1);
289#endif
290
291 if (interrupted) return -1;
292
Jack Jansene3ae0df1997-06-03 15:28:29 +0000293 if ( msg == SP_AUTO_SPIN )
294 maxsleep = 0;
295 if ( msg==SP_SLEEP||msg==SP_SELECT )
296 maxsleep = arg;
Jack Jansenf6865f71996-09-04 15:24:59 +0000297
Jack Jansene3ae0df1997-06-03 15:28:29 +0000298 PyMac_DoYield(maxsleep, 0); /* XXXX or is it safe to call python here? */
Jack Jansenf6865f71996-09-04 15:24:59 +0000299
300 return 0;
301}
302
303void
304PyMac_SetGUSISpin() {
305 GUSISetHook(GUSI_SpinHook, (GUSIHook)PyMac_GUSISpin);
306}
Jack Jansen2d1306b2000-04-07 09:10:49 +0000307#endif
Jack Jansenf6865f71996-09-04 15:24:59 +0000308
Jack Jansena39f1b01997-05-23 15:35:14 +0000309/* Called at exit() time thru atexit(), to stop event processing */
310void
311PyMac_StopGUSISpin() {
312 PyMac_ConsoleIsDead = 1;
313}
314
Jack Jansen6e68a7e2001-05-12 21:31:34 +0000315#if TARGET_API_MAC_OS8
Jack Jansena39f1b01997-05-23 15:35:14 +0000316/*
317** Replacement routines for the PLstr... functions so we don't need
Jack Jansen6ba34aa2001-01-11 23:03:56 +0000318** StdCLib.
Jack Jansena39f1b01997-05-23 15:35:14 +0000319*/
Jack Jansen8bb573e1999-12-12 21:37:14 +0000320pascal void
Jack Jansen9ae898b2000-07-11 21:16:03 +0000321PLstrcpy(unsigned char *to, unsigned char *fr)
Jack Jansena39f1b01997-05-23 15:35:14 +0000322{
323 memcpy(to, fr, fr[0]+1);
324}
325
Jack Jansen8bb573e1999-12-12 21:37:14 +0000326pascal int
Jack Jansen9ae898b2000-07-11 21:16:03 +0000327PLstrcmp(unsigned char *s1, unsigned char *s2)
Jack Jansena39f1b01997-05-23 15:35:14 +0000328{
329 int res;
330 int l = s1[0] < s2[0] ? s1[0] : s2[0];
331
332 res = memcmp(s1+1, s2+1, l);
333 if ( res != 0 )
334 return res;
335
Jack Jansen7e1fb7c1998-07-31 09:36:30 +0000336 if ( s1[0] < s2[0] )
Jack Jansena39f1b01997-05-23 15:35:14 +0000337 return -1;
Jack Jansen7e1fb7c1998-07-31 09:36:30 +0000338 else if ( s1[0] > s2[0] )
Jack Jansena39f1b01997-05-23 15:35:14 +0000339 return 1;
340 else
341 return 0;
342}
343
Jack Jansen8bb573e1999-12-12 21:37:14 +0000344pascal unsigned char *
Jack Jansen9ae898b2000-07-11 21:16:03 +0000345PLstrrchr(unsigned char *str, unsigned char chr)
Jack Jansena39f1b01997-05-23 15:35:14 +0000346{
347 unsigned char *ptr = 0;
348 unsigned char *p;
349
350 for(p=str+1; p<str+str[0]; p++)
351 if ( *p == chr )
352 ptr = p;
353 return ptr;
354}
355
Jack Jansen6e68a7e2001-05-12 21:31:34 +0000356#endif /* TARGET_API_MAC_OS8 */
Jack Jansena39f1b01997-05-23 15:35:14 +0000357#endif /* USE_GUSI */
Jack Jansen378815c1996-03-06 16:21:34 +0000358
Jack Jansen819f1771995-08-14 12:35:10 +0000359
Jack Jansen5f653091995-01-18 13:53:49 +0000360/* Convert C to Pascal string. Returns pointer to static buffer. */
361unsigned char *
362Pstring(char *str)
363{
364 static Str255 buf;
365 int len;
366
367 len = strlen(str);
Guido van Rossum9aa3d131995-01-21 13:46:04 +0000368 if (len > 255)
369 len = 255;
Jack Jansen5f653091995-01-18 13:53:49 +0000370 buf[0] = (unsigned char)len;
371 strncpy((char *)buf+1, str, len);
372 return buf;
373}
374
Jack Jansen6e68a7e2001-05-12 21:31:34 +0000375#if TARGET_API_MAC_OS8
Jack Jansen5afad832000-12-12 22:12:14 +0000376void
377c2pstrcpy(unsigned char *dst, const char *src)
378{
379 int len;
380
381 len = strlen(src);
382 if ( len > 255 ) len = 255;
383 strncpy((char *)dst+1, src, len);
384 dst[0] = len;
385}
Jack Jansen6e68a7e2001-05-12 21:31:34 +0000386#endif /* TARGET_API_MAC_OS8 */
Jack Jansen5afad832000-12-12 22:12:14 +0000387
Jack Jansen1ed95291996-07-22 15:25:10 +0000388#ifdef USE_STACKCHECK
389/* Check for stack overflow */
390int
391PyOS_CheckStack()
392{
Jack Jansen14a91712000-08-25 21:57:23 +0000393 char here;
394 static char *sentinel = 0;
Jack Jansen53bafd92000-09-08 22:05:48 +0000395 static PyThreadState *thread_for_sentinel = 0;
Jack Jansen1ed95291996-07-22 15:25:10 +0000396
Jack Jansen340eb882001-02-02 22:40:28 +0000397 if ( sentinel == 0 ) {
398 unsigned long stackspace = StackSpace();
399
400#ifdef MAXIMUM_STACK_SIZE
401 /* See the comment at the definition */
402 if ( stackspace > MAXIMUM_STACK_SIZE )
403 stackspace = MAXIMUM_STACK_SIZE;
404#endif
405 sentinel = &here - stackspace + MINIMUM_STACK_SIZE;
Jack Jansen14a91712000-08-25 21:57:23 +0000406 }
Jack Jansen53bafd92000-09-08 22:05:48 +0000407 if ( thread_for_sentinel == 0 ) {
408 thread_for_sentinel = PyThreadState_Get();
409 }
410 if ( &here < sentinel ) {
411 if (thread_for_sentinel == PyThreadState_Get()) {
412 return -1;
413#if 0
414 } else {
415 /* Else we are unsure... */
416 fprintf(stderr, "Stackcheck in other thread (was %x now %x)\n", thread_for_sentinel,PyThreadState_Get());
417#endif
418 }
419 }
Jack Jansen1ed95291996-07-22 15:25:10 +0000420 return 0;
421}
422#endif /* USE_STACKCHECK */
423
Jack Jansen0194ad52001-05-12 22:46:35 +0000424#if !TARGET_API_MAC_OSX
Jack Jansenee23d6e1995-01-27 14:43:25 +0000425/* The catcher routine (which may not be used for all compilers) */
426static RETSIGTYPE
427intcatcher(sig)
428 int sig;
429{
430 interrupted = 1;
431 signal(SIGINT, intcatcher);
432}
433
434void
435PyOS_InitInterrupts()
436{
437 if (signal(SIGINT, SIG_IGN) != SIG_IGN)
438 signal(SIGINT, intcatcher);
439}
440
Jack Jansena8441de1997-08-08 14:57:37 +0000441void
442PyOS_FiniInterrupts()
443{
444}
445
Jack Jansenee23d6e1995-01-27 14:43:25 +0000446/*
447** This routine scans the event queue looking for cmd-.
448** This is the only way to get an interrupt under THINK (since it
449** doesn't do SIGINT handling), but is also used under MW, when
450** the full-fledged event loop is disabled. This way, we can at least
451** interrupt a runaway python program.
452*/
453static void
454scan_event_queue(flush)
455 int flush;
456{
Jack Jansen6e68a7e2001-05-12 21:31:34 +0000457#if !TARGET_API_MAC_OS8
Jack Jansend7b68022001-01-12 23:42:28 +0000458 if ( CheckEventQueueForUserCancel() )
459 interrupted = 1;
Jack Jansenbb6d83a2000-06-02 21:27:11 +0000460#else
Jack Jansenee23d6e1995-01-27 14:43:25 +0000461 register EvQElPtr q;
462
Jack Jansenefaada71998-02-20 16:03:15 +0000463 q = (EvQElPtr) LMGetEventQueue()->qHead;
Jack Jansenee23d6e1995-01-27 14:43:25 +0000464
465 for (; q; q = (EvQElPtr)q->qLink) {
466 if (q->evtQWhat == keyDown &&
467 (char)q->evtQMessage == '.' &&
468 (q->evtQModifiers & cmdKey) != 0) {
469 if ( flush )
470 FlushEvents(keyDownMask, 0);
471 interrupted = 1;
472 break;
473 }
474 }
Jack Jansenbb6d83a2000-06-02 21:27:11 +0000475#endif
Jack Jansenee23d6e1995-01-27 14:43:25 +0000476}
477
478int
Jack Jansen36ed5061997-06-20 16:18:15 +0000479PyErr_CheckSignals()
Jack Jansenee23d6e1995-01-27 14:43:25 +0000480{
Jack Jansene3ae0df1997-06-03 15:28:29 +0000481 if (schedparams.enabled) {
482 if ( (unsigned long)LMGetTicks() > schedparams.next_check ) {
Jack Jansen36ed5061997-06-20 16:18:15 +0000483 if ( PyMac_Yield() < 0)
484 return -1;
Jack Jansene3ae0df1997-06-03 15:28:29 +0000485 schedparams.next_check = (unsigned long)LMGetTicks()
486 + schedparams.check_interval;
487 if (interrupted) {
Jack Jansencaa7c461997-06-12 10:49:13 +0000488 scan_event_queue(1); /* Eat events up to cmd-. */
Jack Jansene3ae0df1997-06-03 15:28:29 +0000489 interrupted = 0;
Jack Jansen36ed5061997-06-20 16:18:15 +0000490 PyErr_SetNone(PyExc_KeyboardInterrupt);
491 return -1;
Jack Jansene3ae0df1997-06-03 15:28:29 +0000492 }
493 }
Jack Jansenee23d6e1995-01-27 14:43:25 +0000494 }
495 return 0;
496}
497
Jack Jansen36ed5061997-06-20 16:18:15 +0000498int
499PyOS_InterruptOccurred()
500{
501 scan_event_queue(1);
502 return interrupted;
503}
Jack Jansen0194ad52001-05-12 22:46:35 +0000504
Jack Jansenee23d6e1995-01-27 14:43:25 +0000505/* Check whether we are in the foreground */
Jack Jansen9ae898b2000-07-11 21:16:03 +0000506static int
507PyMac_InForeground(void)
Jack Jansenee23d6e1995-01-27 14:43:25 +0000508{
509 static ProcessSerialNumber ours;
510 static inited;
511 ProcessSerialNumber curfg;
512 Boolean eq;
513
Jack Jansene3ae0df1997-06-03 15:28:29 +0000514 if ( inited == 0 ) {
Jack Jansenee23d6e1995-01-27 14:43:25 +0000515 (void)GetCurrentProcess(&ours);
Jack Jansene3ae0df1997-06-03 15:28:29 +0000516 inited = 1;
517 }
Jack Jansenee23d6e1995-01-27 14:43:25 +0000518 if ( GetFrontProcess(&curfg) < 0 )
519 eq = 1;
520 else if ( SameProcess(&ours, &curfg, &eq) < 0 )
521 eq = 1;
522 return (int)eq;
Jack Jansenee23d6e1995-01-27 14:43:25 +0000523}
Jack Jansen0194ad52001-05-12 22:46:35 +0000524#endif
Jack Jansenee23d6e1995-01-27 14:43:25 +0000525
Jack Jansen36ed5061997-06-20 16:18:15 +0000526int
527PyMac_SetEventHandler(PyObject *evh)
528{
529 if ( evh && python_event_handler ) {
530 PyErr_SetString(PyExc_RuntimeError, "Python event handler already set");
531 return 0;
532 }
533 if ( python_event_handler )
534 Py_DECREF(python_event_handler);
535 if ( evh )
536 Py_INCREF(evh);
537 python_event_handler = evh;
538 return 1;
539}
540
Jack Jansenf93c72a1994-12-14 14:07:50 +0000541/*
Jack Jansena76382a1995-02-02 14:25:56 +0000542** Handle an event, either one found in the mainloop eventhandler or
543** one passed back from the python program.
544*/
545void
Jack Jansen36ed5061997-06-20 16:18:15 +0000546PyMac_HandleEventIntern(evp)
Jack Jansena76382a1995-02-02 14:25:56 +0000547 EventRecord *evp;
548{
Jack Jansen6e68a7e2001-05-12 21:31:34 +0000549#if TARGET_API_MAC_OS8
Jack Jansen0c968871997-08-26 13:20:34 +0000550 if ( evp->what == mouseDown ) {
551 WindowPtr wp;
552
553 if ( FindWindow(evp->where, &wp) == inSysWindow ) {
554 SystemClick(evp, wp);
555 return;
556 }
557 }
Jack Jansenbb6d83a2000-06-02 21:27:11 +0000558#endif
Jack Jansena76382a1995-02-02 14:25:56 +0000559#ifdef __MWERKS__
Jack Jansen38e97661995-11-10 14:53:00 +0000560 {
561 int siouxdidit;
562
563 /* If SIOUX wants it we're done */
564 siouxdidit = SIOUXHandleOneEvent(evp);
565 if ( siouxdidit )
566 return;
567 }
Jack Jansena76382a1995-02-02 14:25:56 +0000568#else
Jack Jansen0c968871997-08-26 13:20:34 +0000569 /* Other compilers are just unlucky... */
Jack Jansena76382a1995-02-02 14:25:56 +0000570#endif /* !__MWERKS__ */
Jack Jansen36ed5061997-06-20 16:18:15 +0000571}
572
573/*
574** Handle an event, either through HandleEvent or by passing it to the Python
575** event handler.
576*/
577int
578PyMac_HandleEvent(evp)
579 EventRecord *evp;
580{
581 PyObject *rv;
582
583 if ( python_event_handler ) {
584 rv = PyObject_CallFunction(python_event_handler, "(O&)",
585 PyMac_BuildEventRecord, evp);
586 if ( rv )
587 Py_DECREF(rv);
588 else
589 return -1; /* Propagate exception */
590 } else {
591 PyMac_HandleEventIntern(evp);
592 }
593 return 0;
Jack Jansena76382a1995-02-02 14:25:56 +0000594}
595
Jack Jansen0194ad52001-05-12 22:46:35 +0000596#if !TARGET_API_MAC_OSX
Jack Jansena76382a1995-02-02 14:25:56 +0000597/*
Jack Jansene3ae0df1997-06-03 15:28:29 +0000598** Yield the CPU to other tasks without processing events.
Jack Jansene8e8ae01995-01-26 16:36:45 +0000599*/
Jack Jansen2d1306b2000-04-07 09:10:49 +0000600int
Jack Jansene3ae0df1997-06-03 15:28:29 +0000601PyMac_DoYield(int maxsleep, int maycallpython)
Jack Jansenf93c72a1994-12-14 14:07:50 +0000602{
603 EventRecord ev;
Jack Jansene8e8ae01995-01-26 16:36:45 +0000604 int gotone;
Jack Jansene3ae0df1997-06-03 15:28:29 +0000605 long latest_time_ready;
Jack Jansen36ed5061997-06-20 16:18:15 +0000606 static int in_here = 0;
Jack Jansene8e8ae01995-01-26 16:36:45 +0000607
Jack Jansen36ed5061997-06-20 16:18:15 +0000608 in_here++;
Jack Jansene3ae0df1997-06-03 15:28:29 +0000609 /*
610 ** First check for interrupts, if wanted.
611 ** This sets a flag that will be picked up at an appropriate
612 ** moment in the mainloop.
613 */
614 if (schedparams.check_interrupt)
Jack Jansenee23d6e1995-01-27 14:43:25 +0000615 scan_event_queue(0);
Jack Jansene3ae0df1997-06-03 15:28:29 +0000616
617 /* XXXX Implementing an idle routine goes here */
Jack Jansene8e8ae01995-01-26 16:36:45 +0000618
Jack Jansene3ae0df1997-06-03 15:28:29 +0000619 /*
620 ** Check which of the eventloop cases we have:
621 ** - process events
622 ** - don't process events but do yield
623 ** - do neither
624 */
Jack Jansen36ed5061997-06-20 16:18:15 +0000625 if( in_here > 1 || !schedparams.process_events ||
626 (python_event_handler && !maycallpython) ) {
Jack Jansene3ae0df1997-06-03 15:28:29 +0000627 if ( maxsleep >= 0 ) {
Jack Jansen6e68a7e2001-05-12 21:31:34 +0000628#if TARGET_API_MAC_OS8
Jack Jansene8e8ae01995-01-26 16:36:45 +0000629 SystemTask();
Jack Jansen15f1c082001-04-25 22:07:27 +0000630#else
631 int xxx = 0;
Jack Jansenbb6d83a2000-06-02 21:27:11 +0000632#endif
Jack Jansen15f1c082001-04-25 22:07:27 +0000633 }
Jack Jansene3ae0df1997-06-03 15:28:29 +0000634 } else {
635 latest_time_ready = LMGetTicks() + maxsleep;
Jack Jansen2d1306b2000-04-07 09:10:49 +0000636 do {
Jack Jansen0c968871997-08-26 13:20:34 +0000637 /* XXXX Hack by Jack.
638 ** In time.sleep() you can click to another application
639 ** once only. If you come back to Python you cannot get away
640 ** again.
641 **/
Jack Jansen36ed5061997-06-20 16:18:15 +0000642 gotone = WaitNextEvent(schedparams.process_events, &ev, maxsleep, NULL);
Jack Jansene3ae0df1997-06-03 15:28:29 +0000643 /* Get out quickly if nothing interesting is happening */
644 if ( !gotone || ev.what == nullEvent )
645 break;
Jack Jansen36ed5061997-06-20 16:18:15 +0000646 if ( PyMac_HandleEvent(&ev) < 0 ) {
647 in_here--;
648 return -1;
649 }
Jack Jansene3ae0df1997-06-03 15:28:29 +0000650 maxsleep = latest_time_ready - LMGetTicks();
Jack Jansen2d1306b2000-04-07 09:10:49 +0000651 } while ( maxsleep > 0 );
Jack Jansenf93c72a1994-12-14 14:07:50 +0000652 }
Jack Jansen36ed5061997-06-20 16:18:15 +0000653 in_here--;
654 return 0;
Jack Jansene8e8ae01995-01-26 16:36:45 +0000655}
656
657/*
Jack Jansene3ae0df1997-06-03 15:28:29 +0000658** Process events and/or yield the CPU to other tasks if opportune
Jack Jansene8e8ae01995-01-26 16:36:45 +0000659*/
Jack Jansen36ed5061997-06-20 16:18:15 +0000660int
Jack Jansene8e8ae01995-01-26 16:36:45 +0000661PyMac_Yield() {
Jack Jansene3ae0df1997-06-03 15:28:29 +0000662 unsigned long maxsleep;
Jack Jansene8e8ae01995-01-26 16:36:45 +0000663
Jack Jansene3ae0df1997-06-03 15:28:29 +0000664 if( PyMac_InForeground() )
665 maxsleep = 0;
Jack Jansenee23d6e1995-01-27 14:43:25 +0000666 else
Jack Jansene3ae0df1997-06-03 15:28:29 +0000667 maxsleep = schedparams.bg_yield;
668
Jack Jansen36ed5061997-06-20 16:18:15 +0000669 return PyMac_DoYield(maxsleep, 1);
Jack Jansene8e8ae01995-01-26 16:36:45 +0000670}
671
672/*
Jack Jansene3ae0df1997-06-03 15:28:29 +0000673** Return current scheduler parameters
Jack Jansene8e8ae01995-01-26 16:36:45 +0000674*/
Jack Jansene3ae0df1997-06-03 15:28:29 +0000675void
676PyMac_GetSchedParams(PyMacSchedParams *sp)
Jack Jansene8e8ae01995-01-26 16:36:45 +0000677{
Jack Jansene3ae0df1997-06-03 15:28:29 +0000678 sp->check_interrupt = schedparams.check_interrupt;
679 sp->process_events = schedparams.process_events;
680 sp->besocial = schedparams.besocial;
681 sp->check_interval = schedparams.check_interval / 60.0;
682 sp->bg_yield = schedparams.bg_yield / 60.0;
Jack Jansenf93c72a1994-12-14 14:07:50 +0000683}
Jack Jansenf6865f71996-09-04 15:24:59 +0000684
Jack Jansen74162f31995-02-15 22:58:33 +0000685/*
Jack Jansene3ae0df1997-06-03 15:28:29 +0000686** Set current scheduler parameters
687*/
688void
689PyMac_SetSchedParams(PyMacSchedParams *sp)
690{
691 schedparams.check_interrupt = sp->check_interrupt;
692 schedparams.process_events = sp->process_events;
693 schedparams.besocial = sp->besocial;
694 schedparams.check_interval = (unsigned long)(sp->check_interval*60);
695 schedparams.bg_yield = (unsigned long)(sp->bg_yield*60);
696 if ( schedparams.check_interrupt || schedparams.process_events ||
697 schedparams.besocial )
698 schedparams.enabled = 1;
699 else
700 schedparams.enabled = 0;
701 schedparams.next_check = 0; /* Check immedeately */
702}
Jack Jansencaa7c461997-06-12 10:49:13 +0000703
Jack Jansene3ae0df1997-06-03 15:28:29 +0000704/*
Jack Jansen3469e991996-09-06 00:30:45 +0000705** Install our menu bar.
706*/
707void
708PyMac_InitMenuBar()
709{
Jack Jansen3469e991996-09-06 00:30:45 +0000710 MenuHandle applemenu;
711
Jack Jansen15f1c082001-04-25 22:07:27 +0000712 if ( sioux_mbar ) return;
Jack Jansencaa7c461997-06-12 10:49:13 +0000713 if ( (sioux_mbar=GetMenuBar()) == NULL ) {
714 /* Sioux menu not installed yet. Do so */
715 SIOUXSetupMenus();
716 if ( (sioux_mbar=GetMenuBar()) == NULL )
717 return;
718 }
Jack Jansen08c3be31997-04-08 15:27:00 +0000719 if ( (applemenu=GetMenuHandle(SIOUX_APPLEID)) == NULL ) return;
Jack Jansen3469e991996-09-06 00:30:45 +0000720 SetMenuItemText(applemenu, 1, "\pAbout Python...");
721}
722
723/*
Jack Jansencaa7c461997-06-12 10:49:13 +0000724** Restore sioux menu bar
725*/
726void
727PyMac_RestoreMenuBar()
728{
Jack Jansen15f1c082001-04-25 22:07:27 +0000729#if 1
Jack Jansen657ba272001-02-17 22:02:07 +0000730 /* This doesn't seem to work anymore? Or only for Carbon? */
731 MenuBarHandle curmenubar;
732
733 curmenubar = GetMenuBar();
Jack Janseneda78631997-06-12 15:29:46 +0000734 if ( sioux_mbar ) {
Jack Jansencaa7c461997-06-12 10:49:13 +0000735 SetMenuBar(sioux_mbar);
Jack Janseneda78631997-06-12 15:29:46 +0000736 DrawMenuBar();
Jack Jansen657ba272001-02-17 22:02:07 +0000737 } else {
Jack Jansenefaada71998-02-20 16:03:15 +0000738 PyMac_InitMenuBar();
Jack Jansen657ba272001-02-17 22:02:07 +0000739 DrawMenuBar();
740 }
741#endif
Jack Jansencaa7c461997-06-12 10:49:13 +0000742}
743
Jack Jansen15f1c082001-04-25 22:07:27 +0000744void
745PyMac_RaiseConsoleWindow()
746{
747 /* Note: this is a hack. SIOUXTextWindow is SIOUX's internal structure
748 ** and we happen to know that the first entry is the window pointer.
749 */
750 extern WindowRef *SIOUXTextWindow;
751
752 if ( SIOUXTextWindow == NULL || *SIOUXTextWindow == NULL )
753 return;
754 if ( FrontWindow() != *SIOUXTextWindow )
755 BringToFront(*SIOUXTextWindow);
756}
Jack Jansencaa7c461997-06-12 10:49:13 +0000757
758/*
Jack Jansen3469e991996-09-06 00:30:45 +0000759** Our replacement about box
760*/
Jack Jansen7e1fb7c1998-07-31 09:36:30 +0000761
762#include "patchlevel.h"
763
Jack Jansen3469e991996-09-06 00:30:45 +0000764void
765SIOUXDoAboutBox(void)
766{
767 DialogPtr theDialog;
Jack Jansen7e1fb7c1998-07-31 09:36:30 +0000768 WindowPtr theWindow;
Jack Jansen3469e991996-09-06 00:30:45 +0000769 short item;
Jack Jansen7e1fb7c1998-07-31 09:36:30 +0000770 short fontID;
Jack Jansen3469e991996-09-06 00:30:45 +0000771
772 if( (theDialog = GetNewDialog(ABOUT_ID, NULL, (WindowPtr)-1)) == NULL )
773 return;
Jack Jansend617c571996-09-22 22:14:30 +0000774 theWindow = GetDialogWindow(theDialog);
Jack Jansen7e1fb7c1998-07-31 09:36:30 +0000775 SetPortWindowPort(theWindow);
776 GetFNum("\pPython-Sans", &fontID);
777 if (fontID == 0)
778 fontID = kFontIDGeneva;
779 TextFont(fontID);
780 TextSize(9);
Jack Jansenf60edf82001-08-19 22:32:27 +0000781 ParamText(Pstring(PY_VERSION), "\p", "\p", "\p");
Jack Jansend617c571996-09-22 22:14:30 +0000782 ShowWindow(theWindow);
Jack Jansen3469e991996-09-06 00:30:45 +0000783 ModalDialog(NULL, &item);
784 DisposeDialog(theDialog);
785}
786
Jack Jansen0194ad52001-05-12 22:46:35 +0000787#endif /* !TARGET_API_MAC_OSX */
Jack Janseneda78631997-06-12 15:29:46 +0000788
Jack Jansen0194ad52001-05-12 22:46:35 +0000789#if TARGET_API_MAC_OS8
Jack Janseneda78631997-06-12 15:29:46 +0000790/*
Jack Jansen3ec804a1995-02-20 15:56:10 +0000791** Helper routine for GetDirectory
792*/
Guido van Rossum24a45e31995-02-20 23:45:53 +0000793static pascal short
Jack Jansen819f1771995-08-14 12:35:10 +0000794myhook_proc(short item, DialogPtr theDialog, struct hook_args *dataptr)
Jack Jansen3ec804a1995-02-20 15:56:10 +0000795{
Jack Jansen819f1771995-08-14 12:35:10 +0000796 if ( item == sfHookFirstCall && dataptr->prompt) {
797 Handle prompth;
798 short type;
799 Rect rect;
800
801 GetDialogItem(theDialog, PROMPT_ITEM, &type, &prompth, &rect);
802 if ( prompth )
803 SetDialogItemText(prompth, (unsigned char *)dataptr->prompt);
804 } else
Jack Jansen3ec804a1995-02-20 15:56:10 +0000805 if ( item == SELECTCUR_ITEM ) {
806 item = sfItemCancelButton;
Jack Jansen819f1771995-08-14 12:35:10 +0000807 dataptr->selectcur_hit = 1;
Jack Jansen3ec804a1995-02-20 15:56:10 +0000808 }
809 return item;
810}
Jack Jansen0194ad52001-05-12 22:46:35 +0000811
Jack Jansen3ec804a1995-02-20 15:56:10 +0000812/*
813** Ask the user for a directory. I still can't understand
814** why Apple doesn't provide a standard solution for this...
815*/
816int
Jack Jansen819f1771995-08-14 12:35:10 +0000817PyMac_GetDirectory(dirfss, prompt)
Jack Jansen3ec804a1995-02-20 15:56:10 +0000818 FSSpec *dirfss;
Jack Jansen819f1771995-08-14 12:35:10 +0000819 char *prompt;
Jack Jansen3ec804a1995-02-20 15:56:10 +0000820{
821 static SFTypeList list = {'fldr', 0, 0, 0};
822 static Point where = {-1, -1};
Jack Jansen3ec804a1995-02-20 15:56:10 +0000823 StandardFileReply reply;
Jack Jansen819f1771995-08-14 12:35:10 +0000824 struct hook_args hook_args;
Jack Jansen3ec804a1995-02-20 15:56:10 +0000825
826 if ( !upp_inited ) {
827 myhook_upp = NewDlgHookYDProc(myhook_proc);
828 upp_inited = 1;
829 }
Jack Jansen819f1771995-08-14 12:35:10 +0000830 if ( prompt && *prompt )
831 hook_args.prompt = (char *)Pstring(prompt);
832 else
833 hook_args.prompt = NULL;
834 hook_args.selectcur_hit = 0;
Guido van Rossum24a45e31995-02-20 23:45:53 +0000835 CustomGetFile((FileFilterYDUPP)0, 1, list, &reply, GETDIR_ID, where, myhook_upp,
Jack Jansen819f1771995-08-14 12:35:10 +0000836 NULL, NULL, NULL, (void *)&hook_args);
Jack Jansen3ec804a1995-02-20 15:56:10 +0000837
838 reply.sfFile.name[0] = 0;
839 if( FSMakeFSSpec(reply.sfFile.vRefNum, reply.sfFile.parID, reply.sfFile.name, dirfss) )
840 return 0;
Jack Jansen819f1771995-08-14 12:35:10 +0000841 return hook_args.selectcur_hit;
842}
843
844/*
845** Slightly extended StandardGetFile: accepts a prompt */
846void PyMac_PromptGetFile(short numTypes, ConstSFTypeListPtr typeList,
847 StandardFileReply *reply, char *prompt)
848{
849 static Point where = {-1, -1};
850 struct hook_args hook_args;
851
852 if ( !upp_inited ) {
853 myhook_upp = NewDlgHookYDProc(myhook_proc);
854 upp_inited = 1;
855 }
856 if ( prompt && *prompt )
857 hook_args.prompt = (char *)Pstring(prompt);
858 else
859 hook_args.prompt = NULL;
860 hook_args.selectcur_hit = 0;
861 CustomGetFile((FileFilterYDUPP)0, numTypes, typeList, reply, GETFILEPROMPT_ID, where,
862 myhook_upp, NULL, NULL, NULL, (void *)&hook_args);
Jack Jansen3ec804a1995-02-20 15:56:10 +0000863}
Jack Jansen6e68a7e2001-05-12 21:31:34 +0000864#endif /* TARGET_API_MAC_OS8 */
Jack Jansen5f653091995-01-18 13:53:49 +0000865
Jack Jansen5f653091995-01-18 13:53:49 +0000866