blob: d42484bfbebc0796d453b7d77de7715e915faed3 [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 Jansen3070ee62001-08-27 23:16:34 +0000182#ifndef WITHOUT_UNIX_NEWLINES
183/*
184** Experimental feature (for 2.2a2): allow unix newlines
185** as well as Mac newlines on input. We replace a lowlevel
186** MSL routine to accomplish this
187*/
188void
189__convert_to_newlines(unsigned char * buf, size_t * n_ptr)
190{
191 unsigned char *p;
192 size_t n = *n_ptr;
193
194 for(p=buf; n > 0; p++, n--)
195 if ( *p == '\r' ) *p = '\n';
196}
197#endif /* WITHOUT_UNIX_NEWLINES */
198
Jack Jansen741e0372001-05-19 12:55:57 +0000199/* Given an FSSpec, return the FSSpec of the parent folder */
200
201static OSErr
202get_folder_parent (FSSpec * fss, FSSpec * parent)
203{
204 CInfoPBRec rec;
205 short err;
206
207 * parent = * fss;
208 rec.hFileInfo.ioNamePtr = parent->name;
209 rec.hFileInfo.ioVRefNum = parent->vRefNum;
210 rec.hFileInfo.ioDirID = parent->parID;
211 rec.hFileInfo.ioFDirIndex = -1;
212 rec.hFileInfo.ioFVersNum = 0;
213 if (err = PBGetCatInfoSync (& rec))
214 return err;
215 parent->parID = rec.dirInfo.ioDrParID;
216/* parent->name[0] = 0; */
217 return 0;
218}
219
220/* Given an FSSpec return a full, colon-separated pathname */
221
222OSErr
223PyMac_GetFullPath (FSSpec *fss, char *buf)
224{
225 short err;
226 FSSpec fss_parent, fss_current;
227 char tmpbuf[1024];
228 int plen;
229
230 fss_current = *fss;
231 plen = fss_current.name[0];
232 memcpy(buf, &fss_current.name[1], plen);
233 buf[plen] = 0;
234 /* Special case for disk names */
235 if ( fss_current.parID <= 1 ) {
236 buf[plen++] = ':';
237 buf[plen] = 0;
238 return 0;
239 }
240 while (fss_current.parID > 1) {
241 /* Get parent folder name */
242 if (err = get_folder_parent(&fss_current, &fss_parent))
243 return err;
244 fss_current = fss_parent;
245 /* Prepend path component just found to buf */
246 plen = fss_current.name[0];
247 if (strlen(buf) + plen + 1 > 1024) {
248 /* Oops... Not enough space (shouldn't happen) */
249 *buf = 0;
250 return -1;
251 }
252 memcpy(tmpbuf, &fss_current.name[1], plen);
253 tmpbuf[plen] = ':';
254 strcpy(&tmpbuf[plen+1], buf);
255 strcpy(buf, tmpbuf);
256 }
257 return 0;
258}
Jack Jansen1f9f2f42000-07-24 19:50:16 +0000259
Jack Jansen2d1306b2000-04-07 09:10:49 +0000260#ifdef USE_GUSI1
Jack Jansen378815c1996-03-06 16:21:34 +0000261/*
262** GUSI (1.6.0 and earlier, at the least) do not set the MacOS idea of
263** the working directory. Hence, we call this routine after each call
264** to chdir() to rectify things.
265*/
266void
267PyMac_FixGUSIcd()
268{
269 WDPBRec pb;
270 FSSpec curdirfss;
271
272 if ( Path2FSSpec(":x", &curdirfss) != noErr )
273 return;
274
275 /* Set MacOS "working directory" */
276 pb.ioNamePtr= "\p";
277 pb.ioVRefNum= curdirfss.vRefNum;
278 pb.ioWDDirID= curdirfss.parID;
Jack Jansen08c3be31997-04-08 15:27:00 +0000279 if (PBHSetVolSync(&pb) != noErr)
Jack Jansen378815c1996-03-06 16:21:34 +0000280 return;
Jack Jansen378815c1996-03-06 16:21:34 +0000281}
Jack Jansen2d1306b2000-04-07 09:10:49 +0000282#endif
Jack Jansen7ac70af1996-08-19 11:01:05 +0000283
Jack Jansen2d1306b2000-04-07 09:10:49 +0000284#ifdef USE_GUSI
Jack Jansen7d5f9e81996-09-07 17:09:31 +0000285/*
286** SpinCursor (needed by GUSI) drags in heaps of stuff, so we
287** provide a dummy here.
288*/
Jack Jansencfadbd41996-08-19 11:36:25 +0000289void SpinCursor(short x) { /* Dummy */ }
Jack Jansenefaada71998-02-20 16:03:15 +0000290void RotateCursor(short x) { /* Dummy */ }
Jack Jansencfadbd41996-08-19 11:36:25 +0000291
Jack Jansenf6865f71996-09-04 15:24:59 +0000292/*
293** Replacement GUSI Spin function
294*/
Jack Jansen2d1306b2000-04-07 09:10:49 +0000295#ifdef USE_GUSI1
Jack Jansenf6865f71996-09-04 15:24:59 +0000296static int
297PyMac_GUSISpin(spin_msg msg, long arg)
298{
Jack Jansene3ae0df1997-06-03 15:28:29 +0000299 static Boolean inForeground = true;
300 int maxsleep = 6; /* 6 ticks is "normal" sleeptime */
Jack Jansenf6865f71996-09-04 15:24:59 +0000301
302 if (PyMac_ConsoleIsDead) return 0;
303#if 0
304 if (inForeground)
305 SpinCursor(msg == SP_AUTO_SPIN ? short(arg) : 1);
306#endif
307
308 if (interrupted) return -1;
309
Jack Jansene3ae0df1997-06-03 15:28:29 +0000310 if ( msg == SP_AUTO_SPIN )
311 maxsleep = 0;
312 if ( msg==SP_SLEEP||msg==SP_SELECT )
313 maxsleep = arg;
Jack Jansenf6865f71996-09-04 15:24:59 +0000314
Jack Jansene3ae0df1997-06-03 15:28:29 +0000315 PyMac_DoYield(maxsleep, 0); /* XXXX or is it safe to call python here? */
Jack Jansenf6865f71996-09-04 15:24:59 +0000316
317 return 0;
318}
319
320void
321PyMac_SetGUSISpin() {
322 GUSISetHook(GUSI_SpinHook, (GUSIHook)PyMac_GUSISpin);
323}
Jack Jansen2d1306b2000-04-07 09:10:49 +0000324#endif
Jack Jansenf6865f71996-09-04 15:24:59 +0000325
Jack Jansena39f1b01997-05-23 15:35:14 +0000326/* Called at exit() time thru atexit(), to stop event processing */
327void
328PyMac_StopGUSISpin() {
329 PyMac_ConsoleIsDead = 1;
330}
331
Jack Jansen6e68a7e2001-05-12 21:31:34 +0000332#if TARGET_API_MAC_OS8
Jack Jansena39f1b01997-05-23 15:35:14 +0000333/*
334** Replacement routines for the PLstr... functions so we don't need
Jack Jansen6ba34aa2001-01-11 23:03:56 +0000335** StdCLib.
Jack Jansena39f1b01997-05-23 15:35:14 +0000336*/
Jack Jansen8bb573e1999-12-12 21:37:14 +0000337pascal void
Jack Jansen9ae898b2000-07-11 21:16:03 +0000338PLstrcpy(unsigned char *to, unsigned char *fr)
Jack Jansena39f1b01997-05-23 15:35:14 +0000339{
340 memcpy(to, fr, fr[0]+1);
341}
342
Jack Jansen8bb573e1999-12-12 21:37:14 +0000343pascal int
Jack Jansen9ae898b2000-07-11 21:16:03 +0000344PLstrcmp(unsigned char *s1, unsigned char *s2)
Jack Jansena39f1b01997-05-23 15:35:14 +0000345{
346 int res;
347 int l = s1[0] < s2[0] ? s1[0] : s2[0];
348
349 res = memcmp(s1+1, s2+1, l);
350 if ( res != 0 )
351 return res;
352
Jack Jansen7e1fb7c1998-07-31 09:36:30 +0000353 if ( s1[0] < s2[0] )
Jack Jansena39f1b01997-05-23 15:35:14 +0000354 return -1;
Jack Jansen7e1fb7c1998-07-31 09:36:30 +0000355 else if ( s1[0] > s2[0] )
Jack Jansena39f1b01997-05-23 15:35:14 +0000356 return 1;
357 else
358 return 0;
359}
360
Jack Jansen8bb573e1999-12-12 21:37:14 +0000361pascal unsigned char *
Jack Jansen9ae898b2000-07-11 21:16:03 +0000362PLstrrchr(unsigned char *str, unsigned char chr)
Jack Jansena39f1b01997-05-23 15:35:14 +0000363{
364 unsigned char *ptr = 0;
365 unsigned char *p;
366
367 for(p=str+1; p<str+str[0]; p++)
368 if ( *p == chr )
369 ptr = p;
370 return ptr;
371}
372
Jack Jansen6e68a7e2001-05-12 21:31:34 +0000373#endif /* TARGET_API_MAC_OS8 */
Jack Jansena39f1b01997-05-23 15:35:14 +0000374#endif /* USE_GUSI */
Jack Jansen378815c1996-03-06 16:21:34 +0000375
Jack Jansen819f1771995-08-14 12:35:10 +0000376
Jack Jansen5f653091995-01-18 13:53:49 +0000377/* Convert C to Pascal string. Returns pointer to static buffer. */
378unsigned char *
379Pstring(char *str)
380{
381 static Str255 buf;
382 int len;
383
384 len = strlen(str);
Guido van Rossum9aa3d131995-01-21 13:46:04 +0000385 if (len > 255)
386 len = 255;
Jack Jansen5f653091995-01-18 13:53:49 +0000387 buf[0] = (unsigned char)len;
388 strncpy((char *)buf+1, str, len);
389 return buf;
390}
391
Jack Jansen6e68a7e2001-05-12 21:31:34 +0000392#if TARGET_API_MAC_OS8
Jack Jansen5afad832000-12-12 22:12:14 +0000393void
394c2pstrcpy(unsigned char *dst, const char *src)
395{
396 int len;
397
398 len = strlen(src);
399 if ( len > 255 ) len = 255;
400 strncpy((char *)dst+1, src, len);
401 dst[0] = len;
402}
Jack Jansen6e68a7e2001-05-12 21:31:34 +0000403#endif /* TARGET_API_MAC_OS8 */
Jack Jansen5afad832000-12-12 22:12:14 +0000404
Jack Jansen1ed95291996-07-22 15:25:10 +0000405#ifdef USE_STACKCHECK
406/* Check for stack overflow */
407int
408PyOS_CheckStack()
409{
Jack Jansen14a91712000-08-25 21:57:23 +0000410 char here;
411 static char *sentinel = 0;
Jack Jansen53bafd92000-09-08 22:05:48 +0000412 static PyThreadState *thread_for_sentinel = 0;
Jack Jansen1ed95291996-07-22 15:25:10 +0000413
Jack Jansen340eb882001-02-02 22:40:28 +0000414 if ( sentinel == 0 ) {
415 unsigned long stackspace = StackSpace();
416
417#ifdef MAXIMUM_STACK_SIZE
418 /* See the comment at the definition */
419 if ( stackspace > MAXIMUM_STACK_SIZE )
420 stackspace = MAXIMUM_STACK_SIZE;
421#endif
422 sentinel = &here - stackspace + MINIMUM_STACK_SIZE;
Jack Jansen14a91712000-08-25 21:57:23 +0000423 }
Jack Jansen53bafd92000-09-08 22:05:48 +0000424 if ( thread_for_sentinel == 0 ) {
425 thread_for_sentinel = PyThreadState_Get();
426 }
427 if ( &here < sentinel ) {
428 if (thread_for_sentinel == PyThreadState_Get()) {
429 return -1;
430#if 0
431 } else {
432 /* Else we are unsure... */
433 fprintf(stderr, "Stackcheck in other thread (was %x now %x)\n", thread_for_sentinel,PyThreadState_Get());
434#endif
435 }
436 }
Jack Jansen1ed95291996-07-22 15:25:10 +0000437 return 0;
438}
439#endif /* USE_STACKCHECK */
440
Jack Jansen0194ad52001-05-12 22:46:35 +0000441#if !TARGET_API_MAC_OSX
Jack Jansenee23d6e1995-01-27 14:43:25 +0000442/* The catcher routine (which may not be used for all compilers) */
443static RETSIGTYPE
444intcatcher(sig)
445 int sig;
446{
447 interrupted = 1;
448 signal(SIGINT, intcatcher);
449}
450
451void
452PyOS_InitInterrupts()
453{
454 if (signal(SIGINT, SIG_IGN) != SIG_IGN)
455 signal(SIGINT, intcatcher);
456}
457
Jack Jansena8441de1997-08-08 14:57:37 +0000458void
459PyOS_FiniInterrupts()
460{
461}
462
Jack Jansenee23d6e1995-01-27 14:43:25 +0000463/*
464** This routine scans the event queue looking for cmd-.
465** This is the only way to get an interrupt under THINK (since it
466** doesn't do SIGINT handling), but is also used under MW, when
467** the full-fledged event loop is disabled. This way, we can at least
468** interrupt a runaway python program.
469*/
470static void
471scan_event_queue(flush)
472 int flush;
473{
Jack Jansen6e68a7e2001-05-12 21:31:34 +0000474#if !TARGET_API_MAC_OS8
Jack Jansend7b68022001-01-12 23:42:28 +0000475 if ( CheckEventQueueForUserCancel() )
476 interrupted = 1;
Jack Jansenbb6d83a2000-06-02 21:27:11 +0000477#else
Jack Jansenee23d6e1995-01-27 14:43:25 +0000478 register EvQElPtr q;
479
Jack Jansenefaada71998-02-20 16:03:15 +0000480 q = (EvQElPtr) LMGetEventQueue()->qHead;
Jack Jansenee23d6e1995-01-27 14:43:25 +0000481
482 for (; q; q = (EvQElPtr)q->qLink) {
483 if (q->evtQWhat == keyDown &&
484 (char)q->evtQMessage == '.' &&
485 (q->evtQModifiers & cmdKey) != 0) {
486 if ( flush )
487 FlushEvents(keyDownMask, 0);
488 interrupted = 1;
489 break;
490 }
491 }
Jack Jansenbb6d83a2000-06-02 21:27:11 +0000492#endif
Jack Jansenee23d6e1995-01-27 14:43:25 +0000493}
494
495int
Jack Jansen36ed5061997-06-20 16:18:15 +0000496PyErr_CheckSignals()
Jack Jansenee23d6e1995-01-27 14:43:25 +0000497{
Jack Jansene3ae0df1997-06-03 15:28:29 +0000498 if (schedparams.enabled) {
499 if ( (unsigned long)LMGetTicks() > schedparams.next_check ) {
Jack Jansen36ed5061997-06-20 16:18:15 +0000500 if ( PyMac_Yield() < 0)
501 return -1;
Jack Jansene3ae0df1997-06-03 15:28:29 +0000502 schedparams.next_check = (unsigned long)LMGetTicks()
503 + schedparams.check_interval;
504 if (interrupted) {
Jack Jansencaa7c461997-06-12 10:49:13 +0000505 scan_event_queue(1); /* Eat events up to cmd-. */
Jack Jansene3ae0df1997-06-03 15:28:29 +0000506 interrupted = 0;
Jack Jansen36ed5061997-06-20 16:18:15 +0000507 PyErr_SetNone(PyExc_KeyboardInterrupt);
508 return -1;
Jack Jansene3ae0df1997-06-03 15:28:29 +0000509 }
510 }
Jack Jansenee23d6e1995-01-27 14:43:25 +0000511 }
512 return 0;
513}
514
Jack Jansen36ed5061997-06-20 16:18:15 +0000515int
516PyOS_InterruptOccurred()
517{
518 scan_event_queue(1);
519 return interrupted;
520}
Jack Jansen0194ad52001-05-12 22:46:35 +0000521
Jack Jansenee23d6e1995-01-27 14:43:25 +0000522/* Check whether we are in the foreground */
Jack Jansen9ae898b2000-07-11 21:16:03 +0000523static int
524PyMac_InForeground(void)
Jack Jansenee23d6e1995-01-27 14:43:25 +0000525{
526 static ProcessSerialNumber ours;
527 static inited;
528 ProcessSerialNumber curfg;
529 Boolean eq;
530
Jack Jansene3ae0df1997-06-03 15:28:29 +0000531 if ( inited == 0 ) {
Jack Jansenee23d6e1995-01-27 14:43:25 +0000532 (void)GetCurrentProcess(&ours);
Jack Jansene3ae0df1997-06-03 15:28:29 +0000533 inited = 1;
534 }
Jack Jansenee23d6e1995-01-27 14:43:25 +0000535 if ( GetFrontProcess(&curfg) < 0 )
536 eq = 1;
537 else if ( SameProcess(&ours, &curfg, &eq) < 0 )
538 eq = 1;
539 return (int)eq;
Jack Jansenee23d6e1995-01-27 14:43:25 +0000540}
Jack Jansen0194ad52001-05-12 22:46:35 +0000541#endif
Jack Jansenee23d6e1995-01-27 14:43:25 +0000542
Jack Jansen36ed5061997-06-20 16:18:15 +0000543int
544PyMac_SetEventHandler(PyObject *evh)
545{
546 if ( evh && python_event_handler ) {
547 PyErr_SetString(PyExc_RuntimeError, "Python event handler already set");
548 return 0;
549 }
550 if ( python_event_handler )
551 Py_DECREF(python_event_handler);
552 if ( evh )
553 Py_INCREF(evh);
554 python_event_handler = evh;
555 return 1;
556}
557
Jack Jansenf93c72a1994-12-14 14:07:50 +0000558/*
Jack Jansena76382a1995-02-02 14:25:56 +0000559** Handle an event, either one found in the mainloop eventhandler or
560** one passed back from the python program.
561*/
562void
Jack Jansen36ed5061997-06-20 16:18:15 +0000563PyMac_HandleEventIntern(evp)
Jack Jansena76382a1995-02-02 14:25:56 +0000564 EventRecord *evp;
565{
Jack Jansen6e68a7e2001-05-12 21:31:34 +0000566#if TARGET_API_MAC_OS8
Jack Jansen0c968871997-08-26 13:20:34 +0000567 if ( evp->what == mouseDown ) {
568 WindowPtr wp;
569
570 if ( FindWindow(evp->where, &wp) == inSysWindow ) {
571 SystemClick(evp, wp);
572 return;
573 }
574 }
Jack Jansenbb6d83a2000-06-02 21:27:11 +0000575#endif
Jack Jansena76382a1995-02-02 14:25:56 +0000576#ifdef __MWERKS__
Jack Jansen38e97661995-11-10 14:53:00 +0000577 {
578 int siouxdidit;
579
580 /* If SIOUX wants it we're done */
581 siouxdidit = SIOUXHandleOneEvent(evp);
582 if ( siouxdidit )
583 return;
584 }
Jack Jansena76382a1995-02-02 14:25:56 +0000585#else
Jack Jansen0c968871997-08-26 13:20:34 +0000586 /* Other compilers are just unlucky... */
Jack Jansena76382a1995-02-02 14:25:56 +0000587#endif /* !__MWERKS__ */
Jack Jansen36ed5061997-06-20 16:18:15 +0000588}
589
590/*
591** Handle an event, either through HandleEvent or by passing it to the Python
592** event handler.
593*/
594int
595PyMac_HandleEvent(evp)
596 EventRecord *evp;
597{
598 PyObject *rv;
599
600 if ( python_event_handler ) {
601 rv = PyObject_CallFunction(python_event_handler, "(O&)",
602 PyMac_BuildEventRecord, evp);
603 if ( rv )
604 Py_DECREF(rv);
605 else
606 return -1; /* Propagate exception */
607 } else {
608 PyMac_HandleEventIntern(evp);
609 }
610 return 0;
Jack Jansena76382a1995-02-02 14:25:56 +0000611}
612
Jack Jansen0194ad52001-05-12 22:46:35 +0000613#if !TARGET_API_MAC_OSX
Jack Jansena76382a1995-02-02 14:25:56 +0000614/*
Jack Jansene3ae0df1997-06-03 15:28:29 +0000615** Yield the CPU to other tasks without processing events.
Jack Jansene8e8ae01995-01-26 16:36:45 +0000616*/
Jack Jansen2d1306b2000-04-07 09:10:49 +0000617int
Jack Jansene3ae0df1997-06-03 15:28:29 +0000618PyMac_DoYield(int maxsleep, int maycallpython)
Jack Jansenf93c72a1994-12-14 14:07:50 +0000619{
620 EventRecord ev;
Jack Jansene8e8ae01995-01-26 16:36:45 +0000621 int gotone;
Jack Jansene3ae0df1997-06-03 15:28:29 +0000622 long latest_time_ready;
Jack Jansen36ed5061997-06-20 16:18:15 +0000623 static int in_here = 0;
Jack Jansene8e8ae01995-01-26 16:36:45 +0000624
Jack Jansen36ed5061997-06-20 16:18:15 +0000625 in_here++;
Jack Jansene3ae0df1997-06-03 15:28:29 +0000626 /*
627 ** First check for interrupts, if wanted.
628 ** This sets a flag that will be picked up at an appropriate
629 ** moment in the mainloop.
630 */
631 if (schedparams.check_interrupt)
Jack Jansenee23d6e1995-01-27 14:43:25 +0000632 scan_event_queue(0);
Jack Jansene3ae0df1997-06-03 15:28:29 +0000633
634 /* XXXX Implementing an idle routine goes here */
Jack Jansene8e8ae01995-01-26 16:36:45 +0000635
Jack Jansene3ae0df1997-06-03 15:28:29 +0000636 /*
637 ** Check which of the eventloop cases we have:
638 ** - process events
639 ** - don't process events but do yield
640 ** - do neither
641 */
Jack Jansen36ed5061997-06-20 16:18:15 +0000642 if( in_here > 1 || !schedparams.process_events ||
643 (python_event_handler && !maycallpython) ) {
Jack Jansene3ae0df1997-06-03 15:28:29 +0000644 if ( maxsleep >= 0 ) {
Jack Jansen6e68a7e2001-05-12 21:31:34 +0000645#if TARGET_API_MAC_OS8
Jack Jansene8e8ae01995-01-26 16:36:45 +0000646 SystemTask();
Jack Jansen15f1c082001-04-25 22:07:27 +0000647#else
648 int xxx = 0;
Jack Jansenbb6d83a2000-06-02 21:27:11 +0000649#endif
Jack Jansen15f1c082001-04-25 22:07:27 +0000650 }
Jack Jansene3ae0df1997-06-03 15:28:29 +0000651 } else {
652 latest_time_ready = LMGetTicks() + maxsleep;
Jack Jansen2d1306b2000-04-07 09:10:49 +0000653 do {
Jack Jansen0c968871997-08-26 13:20:34 +0000654 /* XXXX Hack by Jack.
655 ** In time.sleep() you can click to another application
656 ** once only. If you come back to Python you cannot get away
657 ** again.
658 **/
Jack Jansen36ed5061997-06-20 16:18:15 +0000659 gotone = WaitNextEvent(schedparams.process_events, &ev, maxsleep, NULL);
Jack Jansene3ae0df1997-06-03 15:28:29 +0000660 /* Get out quickly if nothing interesting is happening */
661 if ( !gotone || ev.what == nullEvent )
662 break;
Jack Jansen36ed5061997-06-20 16:18:15 +0000663 if ( PyMac_HandleEvent(&ev) < 0 ) {
664 in_here--;
665 return -1;
666 }
Jack Jansene3ae0df1997-06-03 15:28:29 +0000667 maxsleep = latest_time_ready - LMGetTicks();
Jack Jansen2d1306b2000-04-07 09:10:49 +0000668 } while ( maxsleep > 0 );
Jack Jansenf93c72a1994-12-14 14:07:50 +0000669 }
Jack Jansen36ed5061997-06-20 16:18:15 +0000670 in_here--;
671 return 0;
Jack Jansene8e8ae01995-01-26 16:36:45 +0000672}
673
674/*
Jack Jansene3ae0df1997-06-03 15:28:29 +0000675** Process events and/or yield the CPU to other tasks if opportune
Jack Jansene8e8ae01995-01-26 16:36:45 +0000676*/
Jack Jansen36ed5061997-06-20 16:18:15 +0000677int
Jack Jansene8e8ae01995-01-26 16:36:45 +0000678PyMac_Yield() {
Jack Jansene3ae0df1997-06-03 15:28:29 +0000679 unsigned long maxsleep;
Jack Jansene8e8ae01995-01-26 16:36:45 +0000680
Jack Jansene3ae0df1997-06-03 15:28:29 +0000681 if( PyMac_InForeground() )
682 maxsleep = 0;
Jack Jansenee23d6e1995-01-27 14:43:25 +0000683 else
Jack Jansene3ae0df1997-06-03 15:28:29 +0000684 maxsleep = schedparams.bg_yield;
685
Jack Jansen36ed5061997-06-20 16:18:15 +0000686 return PyMac_DoYield(maxsleep, 1);
Jack Jansene8e8ae01995-01-26 16:36:45 +0000687}
688
689/*
Jack Jansene3ae0df1997-06-03 15:28:29 +0000690** Return current scheduler parameters
Jack Jansene8e8ae01995-01-26 16:36:45 +0000691*/
Jack Jansene3ae0df1997-06-03 15:28:29 +0000692void
693PyMac_GetSchedParams(PyMacSchedParams *sp)
Jack Jansene8e8ae01995-01-26 16:36:45 +0000694{
Jack Jansene3ae0df1997-06-03 15:28:29 +0000695 sp->check_interrupt = schedparams.check_interrupt;
696 sp->process_events = schedparams.process_events;
697 sp->besocial = schedparams.besocial;
698 sp->check_interval = schedparams.check_interval / 60.0;
699 sp->bg_yield = schedparams.bg_yield / 60.0;
Jack Jansenf93c72a1994-12-14 14:07:50 +0000700}
Jack Jansenf6865f71996-09-04 15:24:59 +0000701
Jack Jansen74162f31995-02-15 22:58:33 +0000702/*
Jack Jansene3ae0df1997-06-03 15:28:29 +0000703** Set current scheduler parameters
704*/
705void
706PyMac_SetSchedParams(PyMacSchedParams *sp)
707{
708 schedparams.check_interrupt = sp->check_interrupt;
709 schedparams.process_events = sp->process_events;
710 schedparams.besocial = sp->besocial;
711 schedparams.check_interval = (unsigned long)(sp->check_interval*60);
712 schedparams.bg_yield = (unsigned long)(sp->bg_yield*60);
713 if ( schedparams.check_interrupt || schedparams.process_events ||
714 schedparams.besocial )
715 schedparams.enabled = 1;
716 else
717 schedparams.enabled = 0;
718 schedparams.next_check = 0; /* Check immedeately */
719}
Jack Jansencaa7c461997-06-12 10:49:13 +0000720
Jack Jansene3ae0df1997-06-03 15:28:29 +0000721/*
Jack Jansen3469e991996-09-06 00:30:45 +0000722** Install our menu bar.
723*/
724void
725PyMac_InitMenuBar()
726{
Jack Jansen3469e991996-09-06 00:30:45 +0000727 MenuHandle applemenu;
728
Jack Jansen15f1c082001-04-25 22:07:27 +0000729 if ( sioux_mbar ) return;
Jack Jansencaa7c461997-06-12 10:49:13 +0000730 if ( (sioux_mbar=GetMenuBar()) == NULL ) {
731 /* Sioux menu not installed yet. Do so */
732 SIOUXSetupMenus();
733 if ( (sioux_mbar=GetMenuBar()) == NULL )
734 return;
735 }
Jack Jansen08c3be31997-04-08 15:27:00 +0000736 if ( (applemenu=GetMenuHandle(SIOUX_APPLEID)) == NULL ) return;
Jack Jansen3469e991996-09-06 00:30:45 +0000737 SetMenuItemText(applemenu, 1, "\pAbout Python...");
738}
739
740/*
Jack Jansencaa7c461997-06-12 10:49:13 +0000741** Restore sioux menu bar
742*/
743void
744PyMac_RestoreMenuBar()
745{
Jack Jansen15f1c082001-04-25 22:07:27 +0000746#if 1
Jack Jansen657ba272001-02-17 22:02:07 +0000747 /* This doesn't seem to work anymore? Or only for Carbon? */
748 MenuBarHandle curmenubar;
749
750 curmenubar = GetMenuBar();
Jack Janseneda78631997-06-12 15:29:46 +0000751 if ( sioux_mbar ) {
Jack Jansencaa7c461997-06-12 10:49:13 +0000752 SetMenuBar(sioux_mbar);
Jack Janseneda78631997-06-12 15:29:46 +0000753 DrawMenuBar();
Jack Jansen657ba272001-02-17 22:02:07 +0000754 } else {
Jack Jansenefaada71998-02-20 16:03:15 +0000755 PyMac_InitMenuBar();
Jack Jansen657ba272001-02-17 22:02:07 +0000756 DrawMenuBar();
757 }
758#endif
Jack Jansencaa7c461997-06-12 10:49:13 +0000759}
760
Jack Jansen15f1c082001-04-25 22:07:27 +0000761void
762PyMac_RaiseConsoleWindow()
763{
764 /* Note: this is a hack. SIOUXTextWindow is SIOUX's internal structure
765 ** and we happen to know that the first entry is the window pointer.
766 */
767 extern WindowRef *SIOUXTextWindow;
768
769 if ( SIOUXTextWindow == NULL || *SIOUXTextWindow == NULL )
770 return;
771 if ( FrontWindow() != *SIOUXTextWindow )
772 BringToFront(*SIOUXTextWindow);
773}
Jack Jansencaa7c461997-06-12 10:49:13 +0000774
775/*
Jack Jansen3469e991996-09-06 00:30:45 +0000776** Our replacement about box
777*/
Jack Jansen7e1fb7c1998-07-31 09:36:30 +0000778
779#include "patchlevel.h"
780
Jack Jansen3469e991996-09-06 00:30:45 +0000781void
782SIOUXDoAboutBox(void)
783{
784 DialogPtr theDialog;
Jack Jansen7e1fb7c1998-07-31 09:36:30 +0000785 WindowPtr theWindow;
Jack Jansen3469e991996-09-06 00:30:45 +0000786 short item;
Jack Jansen7e1fb7c1998-07-31 09:36:30 +0000787 short fontID;
Jack Jansen3469e991996-09-06 00:30:45 +0000788
789 if( (theDialog = GetNewDialog(ABOUT_ID, NULL, (WindowPtr)-1)) == NULL )
790 return;
Jack Jansend617c571996-09-22 22:14:30 +0000791 theWindow = GetDialogWindow(theDialog);
Jack Jansen7e1fb7c1998-07-31 09:36:30 +0000792 SetPortWindowPort(theWindow);
793 GetFNum("\pPython-Sans", &fontID);
794 if (fontID == 0)
795 fontID = kFontIDGeneva;
796 TextFont(fontID);
797 TextSize(9);
Jack Jansenf60edf82001-08-19 22:32:27 +0000798 ParamText(Pstring(PY_VERSION), "\p", "\p", "\p");
Jack Jansend617c571996-09-22 22:14:30 +0000799 ShowWindow(theWindow);
Jack Jansen3469e991996-09-06 00:30:45 +0000800 ModalDialog(NULL, &item);
801 DisposeDialog(theDialog);
802}
803
Jack Jansen0194ad52001-05-12 22:46:35 +0000804#endif /* !TARGET_API_MAC_OSX */
Jack Janseneda78631997-06-12 15:29:46 +0000805
Jack Jansen0194ad52001-05-12 22:46:35 +0000806#if TARGET_API_MAC_OS8
Jack Janseneda78631997-06-12 15:29:46 +0000807/*
Jack Jansen3ec804a1995-02-20 15:56:10 +0000808** Helper routine for GetDirectory
809*/
Guido van Rossum24a45e31995-02-20 23:45:53 +0000810static pascal short
Jack Jansen819f1771995-08-14 12:35:10 +0000811myhook_proc(short item, DialogPtr theDialog, struct hook_args *dataptr)
Jack Jansen3ec804a1995-02-20 15:56:10 +0000812{
Jack Jansen819f1771995-08-14 12:35:10 +0000813 if ( item == sfHookFirstCall && dataptr->prompt) {
814 Handle prompth;
815 short type;
816 Rect rect;
817
818 GetDialogItem(theDialog, PROMPT_ITEM, &type, &prompth, &rect);
819 if ( prompth )
820 SetDialogItemText(prompth, (unsigned char *)dataptr->prompt);
821 } else
Jack Jansen3ec804a1995-02-20 15:56:10 +0000822 if ( item == SELECTCUR_ITEM ) {
823 item = sfItemCancelButton;
Jack Jansen819f1771995-08-14 12:35:10 +0000824 dataptr->selectcur_hit = 1;
Jack Jansen3ec804a1995-02-20 15:56:10 +0000825 }
826 return item;
827}
Jack Jansen0194ad52001-05-12 22:46:35 +0000828
Jack Jansen3ec804a1995-02-20 15:56:10 +0000829/*
830** Ask the user for a directory. I still can't understand
831** why Apple doesn't provide a standard solution for this...
832*/
833int
Jack Jansen819f1771995-08-14 12:35:10 +0000834PyMac_GetDirectory(dirfss, prompt)
Jack Jansen3ec804a1995-02-20 15:56:10 +0000835 FSSpec *dirfss;
Jack Jansen819f1771995-08-14 12:35:10 +0000836 char *prompt;
Jack Jansen3ec804a1995-02-20 15:56:10 +0000837{
838 static SFTypeList list = {'fldr', 0, 0, 0};
839 static Point where = {-1, -1};
Jack Jansen3ec804a1995-02-20 15:56:10 +0000840 StandardFileReply reply;
Jack Jansen819f1771995-08-14 12:35:10 +0000841 struct hook_args hook_args;
Jack Jansen3ec804a1995-02-20 15:56:10 +0000842
843 if ( !upp_inited ) {
844 myhook_upp = NewDlgHookYDProc(myhook_proc);
845 upp_inited = 1;
846 }
Jack Jansen819f1771995-08-14 12:35:10 +0000847 if ( prompt && *prompt )
848 hook_args.prompt = (char *)Pstring(prompt);
849 else
850 hook_args.prompt = NULL;
851 hook_args.selectcur_hit = 0;
Guido van Rossum24a45e31995-02-20 23:45:53 +0000852 CustomGetFile((FileFilterYDUPP)0, 1, list, &reply, GETDIR_ID, where, myhook_upp,
Jack Jansen819f1771995-08-14 12:35:10 +0000853 NULL, NULL, NULL, (void *)&hook_args);
Jack Jansen3ec804a1995-02-20 15:56:10 +0000854
855 reply.sfFile.name[0] = 0;
856 if( FSMakeFSSpec(reply.sfFile.vRefNum, reply.sfFile.parID, reply.sfFile.name, dirfss) )
857 return 0;
Jack Jansen819f1771995-08-14 12:35:10 +0000858 return hook_args.selectcur_hit;
859}
860
861/*
862** Slightly extended StandardGetFile: accepts a prompt */
863void PyMac_PromptGetFile(short numTypes, ConstSFTypeListPtr typeList,
864 StandardFileReply *reply, char *prompt)
865{
866 static Point where = {-1, -1};
867 struct hook_args hook_args;
868
869 if ( !upp_inited ) {
870 myhook_upp = NewDlgHookYDProc(myhook_proc);
871 upp_inited = 1;
872 }
873 if ( prompt && *prompt )
874 hook_args.prompt = (char *)Pstring(prompt);
875 else
876 hook_args.prompt = NULL;
877 hook_args.selectcur_hit = 0;
878 CustomGetFile((FileFilterYDUPP)0, numTypes, typeList, reply, GETFILEPROMPT_ID, where,
879 myhook_upp, NULL, NULL, NULL, (void *)&hook_args);
Jack Jansen3ec804a1995-02-20 15:56:10 +0000880}
Jack Jansen6e68a7e2001-05-12 21:31:34 +0000881#endif /* TARGET_API_MAC_OS8 */
Jack Jansen5f653091995-01-18 13:53:49 +0000882
Jack Jansen5f653091995-01-18 13:53:49 +0000883