blob: f9c9affcc1891fddb56df55c9ad04119a7c4b8bc [file] [log] [blame]
Guido van Rossumb3404661995-01-22 18:36:13 +00001/***********************************************************
Jack Jansen42218ce1997-01-31 16:15:11 +00002Copyright 1991-1997 by Stichting Mathematisch Centrum, Amsterdam,
Guido van Rossumb3404661995-01-22 18:36:13 +00003The Netherlands.
4
5 All Rights Reserved
6
7Permission to use, copy, modify, and distribute this software and its
8documentation for any purpose and without fee is hereby granted,
9provided that the above copyright notice appear in all copies and that
10both that copyright notice and this permission notice appear in
11supporting documentation, and that the names of Stichting Mathematisch
12Centrum or CWI not be used in advertising or publicity pertaining to
13distribution of the software without specific, written prior permission.
14
15STICHTING MATHEMATISCH CENTRUM DISCLAIMS ALL WARRANTIES WITH REGARD TO
16THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
17FITNESS, IN NO EVENT SHALL STICHTING MATHEMATISCH CENTRUM BE LIABLE
18FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
19WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
20ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
21OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
22
23******************************************************************/
Jack Jansenf93c72a1994-12-14 14:07:50 +000024
Jack Jansenbf05d4c1996-08-19 15:11:45 +000025
Jack Jansenf93c72a1994-12-14 14:07:50 +000026#include "Python.h"
Guido van Rossumbecdbec1995-02-14 01:27:24 +000027
Jack Jansenf93c72a1994-12-14 14:07:50 +000028#include "macglue.h"
Jack Jansen74162f31995-02-15 22:58:33 +000029#include "marshal.h"
30#include "import.h"
Jack Janseneda78631997-06-12 15:29:46 +000031#include "importdl.h"
Jack Jansen8bb1dc12001-05-19 12:31:09 +000032#include "pymactoolbox.h"
Jack Jansenf93c72a1994-12-14 14:07:50 +000033
Jack Jansen819f1771995-08-14 12:35:10 +000034#include "pythonresources.h"
35
Jack Jansen0194ad52001-05-12 22:46:35 +000036#ifdef WITHOUT_FRAMEWORKS
Jack Jansenf93c72a1994-12-14 14:07:50 +000037#include <OSUtils.h> /* for Set(Current)A5 */
Jack Jansene8e8ae01995-01-26 16:36:45 +000038#include <Files.h>
Jack Jansen8cd2b721995-02-13 11:33:28 +000039#include <StandardFile.h>
Jack Jansenf93c72a1994-12-14 14:07:50 +000040#include <Resources.h>
41#include <Memory.h>
Jack Jansenf93c72a1994-12-14 14:07:50 +000042#include <Windows.h>
Jack Jansene8e8ae01995-01-26 16:36:45 +000043#include <Traps.h>
Jack Jansenee23d6e1995-01-27 14:43:25 +000044#include <Processes.h>
Guido van Rossumc3d1c8e1995-02-18 15:01:31 +000045#include <Fonts.h>
46#include <Menus.h>
Jack Jansen08305501995-06-18 20:03:40 +000047#include <TextUtils.h>
Jack Jansen0194ad52001-05-12 22:46:35 +000048#include <LowMem.h>
Jack Jansen0194ad52001-05-12 22:46:35 +000049#include <Events.h>
Jack Jansen0194ad52001-05-12 22:46:35 +000050#else
51#include <Carbon/Carbon.h>
52#endif
53
54#if !TARGET_API_MAC_OS8
55/* Unfortunately this call is probably slower... */
56#define LMGetTicks() TickCount()
57#endif
58
Jack Jansen16df2aa1995-02-27 16:17:28 +000059#ifdef __MWERKS__
60#include <SIOUX.h>
Jack Jansen9ae898b2000-07-11 21:16:03 +000061extern void SIOUXSetupMenus(void);
62extern void SIOUXDoAboutBox(void);
Jack Jansen16df2aa1995-02-27 16:17:28 +000063#endif
Jack Jansen9ae898b2000-07-11 21:16:03 +000064#ifdef USE_GUSI
65/* Functions we redefine because they're in obscure libraries */
66extern void SpinCursor(short x);
67extern void RotateCursor(short x);
68extern pascal void PLstrcpy(unsigned char *, unsigned char *);
69extern pascal int PLstrcmp(unsigned char *, unsigned char *);
70extern pascal unsigned char *PLstrrchr(unsigned char *, unsigned char);
71
72#endif
73
Jack Jansen2d1306b2000-04-07 09:10:49 +000074#ifdef USE_GUSI1
Jack Jansen911ad6b1996-03-05 16:56:24 +000075#include <TFileSpec.h> /* For Path2FSSpec */
Jack Jansenf6865f71996-09-04 15:24:59 +000076#include <GUSI.h>
Jack Jansen911ad6b1996-03-05 16:56:24 +000077#endif
Jack Jansenee23d6e1995-01-27 14:43:25 +000078
Jack Jansen3469e991996-09-06 00:30:45 +000079/* The ID of the Sioux apple menu */
80#define SIOUX_APPLEID 32000
81
Jack Jansenee23d6e1995-01-27 14:43:25 +000082#include <signal.h>
Jack Jansen74162f31995-02-15 22:58:33 +000083#include <stdio.h>
Jack Jansene8e8ae01995-01-26 16:36:45 +000084
Jack Jansenee23d6e1995-01-27 14:43:25 +000085/*
Jack Jansend1f06311996-08-01 15:23:54 +000086** When less than this amount of stackspace is left we
87** raise a MemoryError.
88*/
89#ifndef MINIMUM_STACK_SIZE
Jack Jansend1f06311996-08-01 15:23:54 +000090#define MINIMUM_STACK_SIZE 8192
Jack Jansend1f06311996-08-01 15:23:54 +000091#endif
92
Jack Jansen340eb882001-02-02 22:40:28 +000093#if TARGET_API_MAC_CARBON
94/*
95** On MacOSX StackSpace() lies: it gives the distance from heap end to stack pointer,
96** but the stack cannot grow that far due to rlimit values. We cannot get at this value
97** from Carbon, so we set a maximum to the stack here that is based on the default
98** stack limit of 512K.
99*/
100#define MAXIMUM_STACK_SIZE (256*1024)
101#endif
102
Jack Jansend1f06311996-08-01 15:23:54 +0000103/*
Jack Jansen16df2aa1995-02-27 16:17:28 +0000104** We have to be careful, since we can't handle
Jack Jansenee23d6e1995-01-27 14:43:25 +0000105** things like updates (and they'll keep coming back if we don't
Jack Jansen16df2aa1995-02-27 16:17:28 +0000106** handle them). Note that we don't know who has windows open, so
107** even handing updates off to SIOUX under MW isn't going to work.
Jack Jansenee23d6e1995-01-27 14:43:25 +0000108*/
Jack Jansen0c968871997-08-26 13:20:34 +0000109#define MAINLOOP_EVENTMASK (mDownMask|keyDownMask|osMask|activMask)
Jack Jansene8e8ae01995-01-26 16:36:45 +0000110
111#include <signal.h>
Jack Jansenf93c72a1994-12-14 14:07:50 +0000112
Guido van Rossumb3404661995-01-22 18:36:13 +0000113/* XXX We should include Errors.h here, but it has a name conflict
Jack Jansen5f653091995-01-18 13:53:49 +0000114** with the python errors.h. */
115#define fnfErr -43
116
Jack Jansenee23d6e1995-01-27 14:43:25 +0000117/* Interrupt code variables: */
118static int interrupted; /* Set to true when cmd-. seen */
Jack Jansend88296d2000-07-11 19:51:05 +0000119static RETSIGTYPE intcatcher(int);
Jack Jansenee23d6e1995-01-27 14:43:25 +0000120
Jack Jansen0194ad52001-05-12 22:46:35 +0000121#if !TARGET_API_MAC_OSX
Jack Jansend88296d2000-07-11 19:51:05 +0000122static int PyMac_Yield(void);
Jack Jansen0194ad52001-05-12 22:46:35 +0000123#endif
Jack Jansenf6865f71996-09-04 15:24:59 +0000124
Jack Jansene8e8ae01995-01-26 16:36:45 +0000125/*
Jack Jansene3ae0df1997-06-03 15:28:29 +0000126** These are the real scheduling parameters that control what we check
127** in the event loop, and how often we check. The values are initialized
128** from pyMac_SchedParamStruct.
129*/
130
131struct real_sched_param_struct {
132 int check_interrupt; /* if true check for command-dot */
133 int process_events; /* if nonzero enable evt processing, this mask */
134 int besocial; /* if nonzero be a little social with CPU */
135 unsigned long check_interval; /* how often to check, in ticks */
136 unsigned long bg_yield; /* yield so long when in background */
137 /* these are computed from previous and clock and such */
138 int enabled; /* check_interrupt OR process_event OR yield */
139 unsigned long next_check; /* when to check/yield next, in ticks */
140};
141
142static struct real_sched_param_struct schedparams =
143 { 1, MAINLOOP_EVENTMASK, 1, 15, 15, 1, 0};
144
Jack Jansen819f1771995-08-14 12:35:10 +0000145/*
Jack Jansenf6865f71996-09-04 15:24:59 +0000146** Workaround for sioux/gusi combo: set when we are exiting
147*/
148int PyMac_ConsoleIsDead;
149
150/*
Jack Jansencaa7c461997-06-12 10:49:13 +0000151** Sioux menu bar, saved early so we can restore it
152*/
Jack Jansen657ba272001-02-17 22:02:07 +0000153static MenuBarHandle sioux_mbar;
Jack Jansencaa7c461997-06-12 10:49:13 +0000154
155/*
Jack Jansen819f1771995-08-14 12:35:10 +0000156** Some stuff for our GetDirectory and PromptGetFile routines
157*/
158struct hook_args {
159 int selectcur_hit; /* Set to true when "select current" selected */
160 char *prompt; /* The prompt */
161};
Jack Jansen6e68a7e2001-05-12 21:31:34 +0000162#if !TARGET_API_MAC_OS8
Jack Jansenbb6d83a2000-06-02 21:27:11 +0000163/* The StandardFile hooks don't exist in Carbon. This breaks GetDirectory,
164** but the macfsn code will replace it by a NavServices version anyway.
165*/
166#define myhook_upp NULL
167#else
Jack Jansen819f1771995-08-14 12:35:10 +0000168static DlgHookYDUPP myhook_upp;
169static int upp_inited = 0;
Jack Jansenbb6d83a2000-06-02 21:27:11 +0000170#endif
Jack Jansen819f1771995-08-14 12:35:10 +0000171
Jack Jansen36ed5061997-06-20 16:18:15 +0000172/*
173** The python-code event handler
174*/
175static PyObject *python_event_handler;
176
Jack Jansen8f5725a1999-12-07 23:08:10 +0000177/*
178** Set to true if we're appearance-compliant
179*/
180int PyMac_AppearanceCompliant;
181
Jack Jansen741e0372001-05-19 12:55:57 +0000182/* Given an FSSpec, return the FSSpec of the parent folder */
183
184static OSErr
185get_folder_parent (FSSpec * fss, FSSpec * parent)
186{
187 CInfoPBRec rec;
188 short err;
189
190 * parent = * fss;
191 rec.hFileInfo.ioNamePtr = parent->name;
192 rec.hFileInfo.ioVRefNum = parent->vRefNum;
193 rec.hFileInfo.ioDirID = parent->parID;
194 rec.hFileInfo.ioFDirIndex = -1;
195 rec.hFileInfo.ioFVersNum = 0;
196 if (err = PBGetCatInfoSync (& rec))
197 return err;
198 parent->parID = rec.dirInfo.ioDrParID;
199/* parent->name[0] = 0; */
200 return 0;
201}
202
203/* Given an FSSpec return a full, colon-separated pathname */
204
205OSErr
Jack Jansencf031932001-09-11 09:22:19 +0000206PyMac_GetFullPathname (FSSpec *fss, char *buf, int length)
Jack Jansen741e0372001-05-19 12:55:57 +0000207{
208 short err;
209 FSSpec fss_parent, fss_current;
210 char tmpbuf[1024];
211 int plen;
212
213 fss_current = *fss;
214 plen = fss_current.name[0];
Jack Jansencf031932001-09-11 09:22:19 +0000215 if ( plen+2 > length ) {
216 *buf = 0;
217 return errFSNameTooLong;
218 }
Jack Jansen741e0372001-05-19 12:55:57 +0000219 memcpy(buf, &fss_current.name[1], plen);
220 buf[plen] = 0;
221 /* Special case for disk names */
222 if ( fss_current.parID <= 1 ) {
223 buf[plen++] = ':';
224 buf[plen] = 0;
225 return 0;
226 }
227 while (fss_current.parID > 1) {
228 /* Get parent folder name */
Jack Jansencf031932001-09-11 09:22:19 +0000229 if (err = get_folder_parent(&fss_current, &fss_parent)) {
230 *buf = 0;
Jack Jansen741e0372001-05-19 12:55:57 +0000231 return err;
Jack Jansencf031932001-09-11 09:22:19 +0000232 }
Jack Jansen741e0372001-05-19 12:55:57 +0000233 fss_current = fss_parent;
234 /* Prepend path component just found to buf */
235 plen = fss_current.name[0];
236 if (strlen(buf) + plen + 1 > 1024) {
237 /* Oops... Not enough space (shouldn't happen) */
238 *buf = 0;
Jack Jansencf031932001-09-11 09:22:19 +0000239 return errFSNameTooLong;
Jack Jansen741e0372001-05-19 12:55:57 +0000240 }
241 memcpy(tmpbuf, &fss_current.name[1], plen);
242 tmpbuf[plen] = ':';
243 strcpy(&tmpbuf[plen+1], buf);
Jack Jansencf031932001-09-11 09:22:19 +0000244 if ( strlen(tmpbuf) > length ) {
245 *buf = 0;
246 return errFSNameTooLong;
247 }
Jack Jansen741e0372001-05-19 12:55:57 +0000248 strcpy(buf, tmpbuf);
249 }
250 return 0;
251}
Jack Jansen1f9f2f42000-07-24 19:50:16 +0000252
Jack Jansen2d1306b2000-04-07 09:10:49 +0000253#ifdef USE_GUSI1
Jack Jansen378815c1996-03-06 16:21:34 +0000254/*
255** GUSI (1.6.0 and earlier, at the least) do not set the MacOS idea of
256** the working directory. Hence, we call this routine after each call
257** to chdir() to rectify things.
258*/
259void
260PyMac_FixGUSIcd()
261{
262 WDPBRec pb;
263 FSSpec curdirfss;
264
265 if ( Path2FSSpec(":x", &curdirfss) != noErr )
266 return;
267
268 /* Set MacOS "working directory" */
269 pb.ioNamePtr= "\p";
270 pb.ioVRefNum= curdirfss.vRefNum;
271 pb.ioWDDirID= curdirfss.parID;
Jack Jansen08c3be31997-04-08 15:27:00 +0000272 if (PBHSetVolSync(&pb) != noErr)
Jack Jansen378815c1996-03-06 16:21:34 +0000273 return;
Jack Jansen378815c1996-03-06 16:21:34 +0000274}
Jack Jansen2d1306b2000-04-07 09:10:49 +0000275#endif
Jack Jansen7ac70af1996-08-19 11:01:05 +0000276
Jack Jansen2d1306b2000-04-07 09:10:49 +0000277#ifdef USE_GUSI
Jack Jansen7d5f9e81996-09-07 17:09:31 +0000278/*
279** SpinCursor (needed by GUSI) drags in heaps of stuff, so we
280** provide a dummy here.
281*/
Jack Jansencfadbd41996-08-19 11:36:25 +0000282void SpinCursor(short x) { /* Dummy */ }
Jack Jansenefaada71998-02-20 16:03:15 +0000283void RotateCursor(short x) { /* Dummy */ }
Jack Jansencfadbd41996-08-19 11:36:25 +0000284
Jack Jansenf6865f71996-09-04 15:24:59 +0000285/*
286** Replacement GUSI Spin function
287*/
Jack Jansen2d1306b2000-04-07 09:10:49 +0000288#ifdef USE_GUSI1
Jack Jansenf6865f71996-09-04 15:24:59 +0000289static int
290PyMac_GUSISpin(spin_msg msg, long arg)
291{
Jack Jansene3ae0df1997-06-03 15:28:29 +0000292 static Boolean inForeground = true;
293 int maxsleep = 6; /* 6 ticks is "normal" sleeptime */
Jack Jansenf6865f71996-09-04 15:24:59 +0000294
295 if (PyMac_ConsoleIsDead) return 0;
296#if 0
297 if (inForeground)
298 SpinCursor(msg == SP_AUTO_SPIN ? short(arg) : 1);
299#endif
300
Jack Jansenf6865f71996-09-04 15:24:59 +0000301
Jack Jansene3ae0df1997-06-03 15:28:29 +0000302 if ( msg == SP_AUTO_SPIN )
303 maxsleep = 0;
Jack Jansen439eaa92001-11-10 00:41:43 +0000304 if ( msg==SP_SLEEP||msg==SP_SELECT ) {
Jack Jansene3ae0df1997-06-03 15:28:29 +0000305 maxsleep = arg;
Jack Jansen439eaa92001-11-10 00:41:43 +0000306 /*
307 ** We force-scan for interrupts. Not pretty, but otherwise
308 ** a program may hang in select or sleep forever.
309 */
310 scan_event_queue(1);
311 }
312 if (interrupted) {
313 interrupted = 0;
314 return -1;
315 }
Jack Jansenf6865f71996-09-04 15:24:59 +0000316
Jack Jansene3ae0df1997-06-03 15:28:29 +0000317 PyMac_DoYield(maxsleep, 0); /* XXXX or is it safe to call python here? */
Jack Jansenf6865f71996-09-04 15:24:59 +0000318
319 return 0;
320}
321
322void
323PyMac_SetGUSISpin() {
324 GUSISetHook(GUSI_SpinHook, (GUSIHook)PyMac_GUSISpin);
325}
Jack Jansen2d1306b2000-04-07 09:10:49 +0000326#endif
Jack Jansenf6865f71996-09-04 15:24:59 +0000327
Jack Jansena39f1b01997-05-23 15:35:14 +0000328/* Called at exit() time thru atexit(), to stop event processing */
329void
330PyMac_StopGUSISpin() {
331 PyMac_ConsoleIsDead = 1;
332}
333
Jack Jansen6e68a7e2001-05-12 21:31:34 +0000334#if TARGET_API_MAC_OS8
Jack Jansena39f1b01997-05-23 15:35:14 +0000335/*
336** Replacement routines for the PLstr... functions so we don't need
Jack Jansen6ba34aa2001-01-11 23:03:56 +0000337** StdCLib.
Jack Jansena39f1b01997-05-23 15:35:14 +0000338*/
Jack Jansen8bb573e1999-12-12 21:37:14 +0000339pascal void
Jack Jansen9ae898b2000-07-11 21:16:03 +0000340PLstrcpy(unsigned char *to, unsigned char *fr)
Jack Jansena39f1b01997-05-23 15:35:14 +0000341{
342 memcpy(to, fr, fr[0]+1);
343}
344
Jack Jansen8bb573e1999-12-12 21:37:14 +0000345pascal int
Jack Jansen9ae898b2000-07-11 21:16:03 +0000346PLstrcmp(unsigned char *s1, unsigned char *s2)
Jack Jansena39f1b01997-05-23 15:35:14 +0000347{
348 int res;
349 int l = s1[0] < s2[0] ? s1[0] : s2[0];
350
351 res = memcmp(s1+1, s2+1, l);
352 if ( res != 0 )
353 return res;
354
Jack Jansen7e1fb7c1998-07-31 09:36:30 +0000355 if ( s1[0] < s2[0] )
Jack Jansena39f1b01997-05-23 15:35:14 +0000356 return -1;
Jack Jansen7e1fb7c1998-07-31 09:36:30 +0000357 else if ( s1[0] > s2[0] )
Jack Jansena39f1b01997-05-23 15:35:14 +0000358 return 1;
359 else
360 return 0;
361}
362
Jack Jansen8bb573e1999-12-12 21:37:14 +0000363pascal unsigned char *
Jack Jansen9ae898b2000-07-11 21:16:03 +0000364PLstrrchr(unsigned char *str, unsigned char chr)
Jack Jansena39f1b01997-05-23 15:35:14 +0000365{
366 unsigned char *ptr = 0;
367 unsigned char *p;
368
369 for(p=str+1; p<str+str[0]; p++)
370 if ( *p == chr )
371 ptr = p;
372 return ptr;
373}
374
Jack Jansen6e68a7e2001-05-12 21:31:34 +0000375#endif /* TARGET_API_MAC_OS8 */
Jack Jansena39f1b01997-05-23 15:35:14 +0000376#endif /* USE_GUSI */
Jack Jansen378815c1996-03-06 16:21:34 +0000377
Jack Jansen819f1771995-08-14 12:35:10 +0000378
Jack Jansen5f653091995-01-18 13:53:49 +0000379/* Convert C to Pascal string. Returns pointer to static buffer. */
380unsigned char *
381Pstring(char *str)
382{
383 static Str255 buf;
384 int len;
385
386 len = strlen(str);
Guido van Rossum9aa3d131995-01-21 13:46:04 +0000387 if (len > 255)
388 len = 255;
Jack Jansen5f653091995-01-18 13:53:49 +0000389 buf[0] = (unsigned char)len;
390 strncpy((char *)buf+1, str, len);
391 return buf;
392}
393
Jack Jansen6e68a7e2001-05-12 21:31:34 +0000394#if TARGET_API_MAC_OS8
Jack Jansen5afad832000-12-12 22:12:14 +0000395void
396c2pstrcpy(unsigned char *dst, const char *src)
397{
398 int len;
399
400 len = strlen(src);
401 if ( len > 255 ) len = 255;
402 strncpy((char *)dst+1, src, len);
403 dst[0] = len;
404}
Jack Jansen6e68a7e2001-05-12 21:31:34 +0000405#endif /* TARGET_API_MAC_OS8 */
Jack Jansen5afad832000-12-12 22:12:14 +0000406
Jack Jansen1ed95291996-07-22 15:25:10 +0000407#ifdef USE_STACKCHECK
408/* Check for stack overflow */
409int
410PyOS_CheckStack()
411{
Jack Jansen14a91712000-08-25 21:57:23 +0000412 char here;
413 static char *sentinel = 0;
Jack Jansen53bafd92000-09-08 22:05:48 +0000414 static PyThreadState *thread_for_sentinel = 0;
Jack Jansen1ed95291996-07-22 15:25:10 +0000415
Jack Jansen340eb882001-02-02 22:40:28 +0000416 if ( sentinel == 0 ) {
417 unsigned long stackspace = StackSpace();
418
419#ifdef MAXIMUM_STACK_SIZE
420 /* See the comment at the definition */
421 if ( stackspace > MAXIMUM_STACK_SIZE )
422 stackspace = MAXIMUM_STACK_SIZE;
423#endif
424 sentinel = &here - stackspace + MINIMUM_STACK_SIZE;
Jack Jansen14a91712000-08-25 21:57:23 +0000425 }
Jack Jansen53bafd92000-09-08 22:05:48 +0000426 if ( thread_for_sentinel == 0 ) {
427 thread_for_sentinel = PyThreadState_Get();
428 }
429 if ( &here < sentinel ) {
430 if (thread_for_sentinel == PyThreadState_Get()) {
431 return -1;
432#if 0
433 } else {
434 /* Else we are unsure... */
435 fprintf(stderr, "Stackcheck in other thread (was %x now %x)\n", thread_for_sentinel,PyThreadState_Get());
436#endif
437 }
438 }
Jack Jansen1ed95291996-07-22 15:25:10 +0000439 return 0;
440}
441#endif /* USE_STACKCHECK */
442
Jack Jansen0194ad52001-05-12 22:46:35 +0000443#if !TARGET_API_MAC_OSX
Jack Jansenee23d6e1995-01-27 14:43:25 +0000444/* The catcher routine (which may not be used for all compilers) */
445static RETSIGTYPE
446intcatcher(sig)
447 int sig;
448{
449 interrupted = 1;
450 signal(SIGINT, intcatcher);
451}
452
453void
454PyOS_InitInterrupts()
455{
456 if (signal(SIGINT, SIG_IGN) != SIG_IGN)
457 signal(SIGINT, intcatcher);
458}
459
Jack Jansena8441de1997-08-08 14:57:37 +0000460void
461PyOS_FiniInterrupts()
462{
463}
464
Jack Jansenee23d6e1995-01-27 14:43:25 +0000465/* Check whether we are in the foreground */
Jack Jansen9ae898b2000-07-11 21:16:03 +0000466static int
467PyMac_InForeground(void)
Jack Jansenee23d6e1995-01-27 14:43:25 +0000468{
469 static ProcessSerialNumber ours;
470 static inited;
471 ProcessSerialNumber curfg;
472 Boolean eq;
473
Jack Jansene3ae0df1997-06-03 15:28:29 +0000474 if ( inited == 0 ) {
Jack Jansenee23d6e1995-01-27 14:43:25 +0000475 (void)GetCurrentProcess(&ours);
Jack Jansene3ae0df1997-06-03 15:28:29 +0000476 inited = 1;
477 }
Jack Jansenee23d6e1995-01-27 14:43:25 +0000478 if ( GetFrontProcess(&curfg) < 0 )
479 eq = 1;
480 else if ( SameProcess(&ours, &curfg, &eq) < 0 )
481 eq = 1;
482 return (int)eq;
Jack Jansenee23d6e1995-01-27 14:43:25 +0000483}
Jack Jansen439eaa92001-11-10 00:41:43 +0000484
485/*
486** This routine scans the event queue looking for cmd-.
487*/
488static void
489scan_event_queue(force)
490 int force;
491{
492#if !TARGET_API_MAC_OS8
493 if ( interrupted || (!schedparams.check_interrupt && !force) )
494 return;
495 if ( CheckEventQueueForUserCancel() )
496 interrupted = 1;
497#else
498 register EvQElPtr q;
499
500 if ( interrupted || (!schedparams.check_interrupt && !force) || !PyMac_InForeground() )
501 return;
502 q = (EvQElPtr) LMGetEventQueue()->qHead;
503
504 for (; q; q = (EvQElPtr)q->qLink) {
505 if (q->evtQWhat == keyDown &&
506 (char)q->evtQMessage == '.' &&
507 (q->evtQModifiers & cmdKey) != 0) {
Jack Jansenb3be2162001-11-30 14:16:36 +0000508 FlushEvents(keyDownMask, 0);
Jack Jansen439eaa92001-11-10 00:41:43 +0000509 interrupted = 1;
510 break;
511 }
512 }
513#endif
514}
515
516int
517PyErr_CheckSignals()
518{
Jack Jansen439eaa92001-11-10 00:41:43 +0000519 if (schedparams.enabled) {
520 if ( interrupted || (unsigned long)LMGetTicks() > schedparams.next_check ) {
521 scan_event_queue(0);
522 if (interrupted) {
523 interrupted = 0;
524 PyErr_SetNone(PyExc_KeyboardInterrupt);
525 return -1;
526 }
527 if ( PyMac_Yield() < 0)
528 return -1;
Jack Jansen439eaa92001-11-10 00:41:43 +0000529 schedparams.next_check = (unsigned long)LMGetTicks()
530 + schedparams.check_interval;
531 }
532 }
533 return 0;
534}
535
536int
537PyOS_InterruptOccurred()
538{
539 scan_event_queue(0);
540 if ( !interrupted )
541 return 0;
542 interrupted = 0;
543 return 1;
544}
Jack Jansen0194ad52001-05-12 22:46:35 +0000545#endif
Jack Jansenee23d6e1995-01-27 14:43:25 +0000546
Jack Jansen36ed5061997-06-20 16:18:15 +0000547int
548PyMac_SetEventHandler(PyObject *evh)
549{
550 if ( evh && python_event_handler ) {
551 PyErr_SetString(PyExc_RuntimeError, "Python event handler already set");
552 return 0;
553 }
554 if ( python_event_handler )
555 Py_DECREF(python_event_handler);
556 if ( evh )
557 Py_INCREF(evh);
558 python_event_handler = evh;
559 return 1;
560}
561
Jack Jansenf93c72a1994-12-14 14:07:50 +0000562/*
Jack Jansena76382a1995-02-02 14:25:56 +0000563** Handle an event, either one found in the mainloop eventhandler or
564** one passed back from the python program.
565*/
566void
Jack Jansen36ed5061997-06-20 16:18:15 +0000567PyMac_HandleEventIntern(evp)
Jack Jansena76382a1995-02-02 14:25:56 +0000568 EventRecord *evp;
569{
Jack Jansen6e68a7e2001-05-12 21:31:34 +0000570#if TARGET_API_MAC_OS8
Jack Jansen0c968871997-08-26 13:20:34 +0000571 if ( evp->what == mouseDown ) {
572 WindowPtr wp;
573
574 if ( FindWindow(evp->where, &wp) == inSysWindow ) {
575 SystemClick(evp, wp);
576 return;
577 }
578 }
Jack Jansenbb6d83a2000-06-02 21:27:11 +0000579#endif
Jack Jansena76382a1995-02-02 14:25:56 +0000580#ifdef __MWERKS__
Jack Jansen38e97661995-11-10 14:53:00 +0000581 {
582 int siouxdidit;
583
584 /* If SIOUX wants it we're done */
585 siouxdidit = SIOUXHandleOneEvent(evp);
586 if ( siouxdidit )
587 return;
588 }
Jack Jansena76382a1995-02-02 14:25:56 +0000589#else
Jack Jansen0c968871997-08-26 13:20:34 +0000590 /* Other compilers are just unlucky... */
Jack Jansena76382a1995-02-02 14:25:56 +0000591#endif /* !__MWERKS__ */
Jack Jansen36ed5061997-06-20 16:18:15 +0000592}
593
594/*
595** Handle an event, either through HandleEvent or by passing it to the Python
596** event handler.
597*/
598int
599PyMac_HandleEvent(evp)
600 EventRecord *evp;
601{
602 PyObject *rv;
603
604 if ( python_event_handler ) {
605 rv = PyObject_CallFunction(python_event_handler, "(O&)",
606 PyMac_BuildEventRecord, evp);
607 if ( rv )
608 Py_DECREF(rv);
609 else
610 return -1; /* Propagate exception */
611 } else {
612 PyMac_HandleEventIntern(evp);
613 }
614 return 0;
Jack Jansena76382a1995-02-02 14:25:56 +0000615}
616
Jack Jansen0194ad52001-05-12 22:46:35 +0000617#if !TARGET_API_MAC_OSX
Jack Jansena76382a1995-02-02 14:25:56 +0000618/*
Jack Jansene3ae0df1997-06-03 15:28:29 +0000619** Yield the CPU to other tasks without processing events.
Jack Jansene8e8ae01995-01-26 16:36:45 +0000620*/
Jack Jansen2d1306b2000-04-07 09:10:49 +0000621int
Jack Jansene3ae0df1997-06-03 15:28:29 +0000622PyMac_DoYield(int maxsleep, int maycallpython)
Jack Jansenf93c72a1994-12-14 14:07:50 +0000623{
624 EventRecord ev;
Jack Jansene8e8ae01995-01-26 16:36:45 +0000625 int gotone;
Jack Jansene3ae0df1997-06-03 15:28:29 +0000626 long latest_time_ready;
Jack Jansen36ed5061997-06-20 16:18:15 +0000627 static int in_here = 0;
Jack Jansene8e8ae01995-01-26 16:36:45 +0000628
Jack Jansen36ed5061997-06-20 16:18:15 +0000629 in_here++;
Jack Jansene8e8ae01995-01-26 16:36:45 +0000630
Jack Jansene3ae0df1997-06-03 15:28:29 +0000631 /*
632 ** Check which of the eventloop cases we have:
633 ** - process events
634 ** - don't process events but do yield
635 ** - do neither
636 */
Jack Jansen36ed5061997-06-20 16:18:15 +0000637 if( in_here > 1 || !schedparams.process_events ||
638 (python_event_handler && !maycallpython) ) {
Jack Jansene3ae0df1997-06-03 15:28:29 +0000639 if ( maxsleep >= 0 ) {
Jack Jansen6e68a7e2001-05-12 21:31:34 +0000640#if TARGET_API_MAC_OS8
Jack Jansene8e8ae01995-01-26 16:36:45 +0000641 SystemTask();
Jack Jansen15f1c082001-04-25 22:07:27 +0000642#else
643 int xxx = 0;
Jack Jansenbb6d83a2000-06-02 21:27:11 +0000644#endif
Jack Jansen15f1c082001-04-25 22:07:27 +0000645 }
Jack Jansene3ae0df1997-06-03 15:28:29 +0000646 } else {
647 latest_time_ready = LMGetTicks() + maxsleep;
Jack Jansen2d1306b2000-04-07 09:10:49 +0000648 do {
Jack Jansen0c968871997-08-26 13:20:34 +0000649 /* XXXX Hack by Jack.
650 ** In time.sleep() you can click to another application
651 ** once only. If you come back to Python you cannot get away
652 ** again.
653 **/
Jack Jansen36ed5061997-06-20 16:18:15 +0000654 gotone = WaitNextEvent(schedparams.process_events, &ev, maxsleep, NULL);
Jack Jansene3ae0df1997-06-03 15:28:29 +0000655 /* Get out quickly if nothing interesting is happening */
656 if ( !gotone || ev.what == nullEvent )
657 break;
Jack Jansen36ed5061997-06-20 16:18:15 +0000658 if ( PyMac_HandleEvent(&ev) < 0 ) {
659 in_here--;
660 return -1;
661 }
Jack Jansene3ae0df1997-06-03 15:28:29 +0000662 maxsleep = latest_time_ready - LMGetTicks();
Jack Jansen2d1306b2000-04-07 09:10:49 +0000663 } while ( maxsleep > 0 );
Jack Jansenf93c72a1994-12-14 14:07:50 +0000664 }
Jack Jansen36ed5061997-06-20 16:18:15 +0000665 in_here--;
666 return 0;
Jack Jansene8e8ae01995-01-26 16:36:45 +0000667}
668
669/*
Jack Jansene3ae0df1997-06-03 15:28:29 +0000670** Process events and/or yield the CPU to other tasks if opportune
Jack Jansene8e8ae01995-01-26 16:36:45 +0000671*/
Jack Jansen36ed5061997-06-20 16:18:15 +0000672int
Jack Jansene8e8ae01995-01-26 16:36:45 +0000673PyMac_Yield() {
Jack Jansene3ae0df1997-06-03 15:28:29 +0000674 unsigned long maxsleep;
Jack Jansene8e8ae01995-01-26 16:36:45 +0000675
Jack Jansene3ae0df1997-06-03 15:28:29 +0000676 if( PyMac_InForeground() )
677 maxsleep = 0;
Jack Jansenee23d6e1995-01-27 14:43:25 +0000678 else
Jack Jansene3ae0df1997-06-03 15:28:29 +0000679 maxsleep = schedparams.bg_yield;
680
Jack Jansen36ed5061997-06-20 16:18:15 +0000681 return PyMac_DoYield(maxsleep, 1);
Jack Jansene8e8ae01995-01-26 16:36:45 +0000682}
683
684/*
Jack Jansene3ae0df1997-06-03 15:28:29 +0000685** Return current scheduler parameters
Jack Jansene8e8ae01995-01-26 16:36:45 +0000686*/
Jack Jansene3ae0df1997-06-03 15:28:29 +0000687void
688PyMac_GetSchedParams(PyMacSchedParams *sp)
Jack Jansene8e8ae01995-01-26 16:36:45 +0000689{
Jack Jansene3ae0df1997-06-03 15:28:29 +0000690 sp->check_interrupt = schedparams.check_interrupt;
691 sp->process_events = schedparams.process_events;
692 sp->besocial = schedparams.besocial;
693 sp->check_interval = schedparams.check_interval / 60.0;
694 sp->bg_yield = schedparams.bg_yield / 60.0;
Jack Jansenf93c72a1994-12-14 14:07:50 +0000695}
Jack Jansenf6865f71996-09-04 15:24:59 +0000696
Jack Jansen74162f31995-02-15 22:58:33 +0000697/*
Jack Jansene3ae0df1997-06-03 15:28:29 +0000698** Set current scheduler parameters
699*/
700void
701PyMac_SetSchedParams(PyMacSchedParams *sp)
702{
703 schedparams.check_interrupt = sp->check_interrupt;
704 schedparams.process_events = sp->process_events;
705 schedparams.besocial = sp->besocial;
706 schedparams.check_interval = (unsigned long)(sp->check_interval*60);
707 schedparams.bg_yield = (unsigned long)(sp->bg_yield*60);
708 if ( schedparams.check_interrupt || schedparams.process_events ||
709 schedparams.besocial )
710 schedparams.enabled = 1;
711 else
712 schedparams.enabled = 0;
713 schedparams.next_check = 0; /* Check immedeately */
714}
Jack Jansencaa7c461997-06-12 10:49:13 +0000715
Jack Jansene3ae0df1997-06-03 15:28:29 +0000716/*
Jack Jansen3469e991996-09-06 00:30:45 +0000717** Install our menu bar.
718*/
719void
720PyMac_InitMenuBar()
721{
Jack Jansen3469e991996-09-06 00:30:45 +0000722 MenuHandle applemenu;
723
Jack Jansen15f1c082001-04-25 22:07:27 +0000724 if ( sioux_mbar ) return;
Jack Jansen95837f12001-11-01 23:17:35 +0000725#if 0
726 /* This code does not seem to work anymore: apparently
727 ** we now always have a menubar (since MacOS9?).
728 ** So we simply always setup the Sioux menus here.
729 */
Jack Jansencaa7c461997-06-12 10:49:13 +0000730 if ( (sioux_mbar=GetMenuBar()) == NULL ) {
Jack Jansen95837f12001-11-01 23:17:35 +0000731#else
Jack Jansenb3be2162001-11-30 14:16:36 +0000732 if ( (sioux_mbar=GetMenuBar()) == NULL || GetMenuHandle(SIOUX_APPLEID) == NULL) {
Jack Jansen95837f12001-11-01 23:17:35 +0000733#endif
Jack Jansencaa7c461997-06-12 10:49:13 +0000734 /* Sioux menu not installed yet. Do so */
735 SIOUXSetupMenus();
736 if ( (sioux_mbar=GetMenuBar()) == NULL )
737 return;
738 }
Jack Jansen08c3be31997-04-08 15:27:00 +0000739 if ( (applemenu=GetMenuHandle(SIOUX_APPLEID)) == NULL ) return;
Jack Jansen3469e991996-09-06 00:30:45 +0000740 SetMenuItemText(applemenu, 1, "\pAbout Python...");
741}
742
743/*
Jack Jansencaa7c461997-06-12 10:49:13 +0000744** Restore sioux menu bar
745*/
746void
747PyMac_RestoreMenuBar()
748{
Jack Jansen15f1c082001-04-25 22:07:27 +0000749#if 1
Jack Jansen657ba272001-02-17 22:02:07 +0000750 /* This doesn't seem to work anymore? Or only for Carbon? */
751 MenuBarHandle curmenubar;
752
753 curmenubar = GetMenuBar();
Jack Janseneda78631997-06-12 15:29:46 +0000754 if ( sioux_mbar ) {
Jack Jansencaa7c461997-06-12 10:49:13 +0000755 SetMenuBar(sioux_mbar);
Jack Janseneda78631997-06-12 15:29:46 +0000756 DrawMenuBar();
Jack Jansen657ba272001-02-17 22:02:07 +0000757 } else {
Jack Jansenefaada71998-02-20 16:03:15 +0000758 PyMac_InitMenuBar();
Jack Jansen657ba272001-02-17 22:02:07 +0000759 DrawMenuBar();
760 }
761#endif
Jack Jansencaa7c461997-06-12 10:49:13 +0000762}
763
Jack Jansen15f1c082001-04-25 22:07:27 +0000764void
765PyMac_RaiseConsoleWindow()
766{
767 /* Note: this is a hack. SIOUXTextWindow is SIOUX's internal structure
768 ** and we happen to know that the first entry is the window pointer.
769 */
770 extern WindowRef *SIOUXTextWindow;
771
772 if ( SIOUXTextWindow == NULL || *SIOUXTextWindow == NULL )
773 return;
774 if ( FrontWindow() != *SIOUXTextWindow )
775 BringToFront(*SIOUXTextWindow);
776}
Jack Jansencaa7c461997-06-12 10:49:13 +0000777
778/*
Jack Jansen3469e991996-09-06 00:30:45 +0000779** Our replacement about box
780*/
Jack Jansen7e1fb7c1998-07-31 09:36:30 +0000781
782#include "patchlevel.h"
783
Jack Jansen3469e991996-09-06 00:30:45 +0000784void
785SIOUXDoAboutBox(void)
786{
787 DialogPtr theDialog;
Jack Jansen7e1fb7c1998-07-31 09:36:30 +0000788 WindowPtr theWindow;
Jack Jansen3469e991996-09-06 00:30:45 +0000789 short item;
Jack Jansen7e1fb7c1998-07-31 09:36:30 +0000790 short fontID;
Jack Jansen3469e991996-09-06 00:30:45 +0000791
792 if( (theDialog = GetNewDialog(ABOUT_ID, NULL, (WindowPtr)-1)) == NULL )
793 return;
Jack Jansend617c571996-09-22 22:14:30 +0000794 theWindow = GetDialogWindow(theDialog);
Jack Jansen7e1fb7c1998-07-31 09:36:30 +0000795 SetPortWindowPort(theWindow);
796 GetFNum("\pPython-Sans", &fontID);
797 if (fontID == 0)
798 fontID = kFontIDGeneva;
799 TextFont(fontID);
800 TextSize(9);
Jack Jansenf60edf82001-08-19 22:32:27 +0000801 ParamText(Pstring(PY_VERSION), "\p", "\p", "\p");
Jack Jansend617c571996-09-22 22:14:30 +0000802 ShowWindow(theWindow);
Jack Jansen3469e991996-09-06 00:30:45 +0000803 ModalDialog(NULL, &item);
804 DisposeDialog(theDialog);
805}
806
Jack Jansen0194ad52001-05-12 22:46:35 +0000807#endif /* !TARGET_API_MAC_OSX */
Jack Janseneda78631997-06-12 15:29:46 +0000808
Jack Jansen0194ad52001-05-12 22:46:35 +0000809#if TARGET_API_MAC_OS8
Jack Janseneda78631997-06-12 15:29:46 +0000810/*
Jack Jansen3ec804a1995-02-20 15:56:10 +0000811** Helper routine for GetDirectory
812*/
Guido van Rossum24a45e31995-02-20 23:45:53 +0000813static pascal short
Jack Jansen819f1771995-08-14 12:35:10 +0000814myhook_proc(short item, DialogPtr theDialog, struct hook_args *dataptr)
Jack Jansen3ec804a1995-02-20 15:56:10 +0000815{
Jack Jansen819f1771995-08-14 12:35:10 +0000816 if ( item == sfHookFirstCall && dataptr->prompt) {
817 Handle prompth;
818 short type;
819 Rect rect;
820
821 GetDialogItem(theDialog, PROMPT_ITEM, &type, &prompth, &rect);
822 if ( prompth )
823 SetDialogItemText(prompth, (unsigned char *)dataptr->prompt);
824 } else
Jack Jansen3ec804a1995-02-20 15:56:10 +0000825 if ( item == SELECTCUR_ITEM ) {
826 item = sfItemCancelButton;
Jack Jansen819f1771995-08-14 12:35:10 +0000827 dataptr->selectcur_hit = 1;
Jack Jansen3ec804a1995-02-20 15:56:10 +0000828 }
829 return item;
830}
Jack Jansen0194ad52001-05-12 22:46:35 +0000831
Jack Jansen3ec804a1995-02-20 15:56:10 +0000832/*
833** Ask the user for a directory. I still can't understand
834** why Apple doesn't provide a standard solution for this...
835*/
836int
Jack Jansen819f1771995-08-14 12:35:10 +0000837PyMac_GetDirectory(dirfss, prompt)
Jack Jansen3ec804a1995-02-20 15:56:10 +0000838 FSSpec *dirfss;
Jack Jansen819f1771995-08-14 12:35:10 +0000839 char *prompt;
Jack Jansen3ec804a1995-02-20 15:56:10 +0000840{
841 static SFTypeList list = {'fldr', 0, 0, 0};
842 static Point where = {-1, -1};
Jack Jansen3ec804a1995-02-20 15:56:10 +0000843 StandardFileReply reply;
Jack Jansen819f1771995-08-14 12:35:10 +0000844 struct hook_args hook_args;
Jack Jansen3ec804a1995-02-20 15:56:10 +0000845
846 if ( !upp_inited ) {
847 myhook_upp = NewDlgHookYDProc(myhook_proc);
848 upp_inited = 1;
849 }
Jack Jansen819f1771995-08-14 12:35:10 +0000850 if ( prompt && *prompt )
851 hook_args.prompt = (char *)Pstring(prompt);
852 else
853 hook_args.prompt = NULL;
854 hook_args.selectcur_hit = 0;
Guido van Rossum24a45e31995-02-20 23:45:53 +0000855 CustomGetFile((FileFilterYDUPP)0, 1, list, &reply, GETDIR_ID, where, myhook_upp,
Jack Jansen819f1771995-08-14 12:35:10 +0000856 NULL, NULL, NULL, (void *)&hook_args);
Jack Jansen3ec804a1995-02-20 15:56:10 +0000857
858 reply.sfFile.name[0] = 0;
859 if( FSMakeFSSpec(reply.sfFile.vRefNum, reply.sfFile.parID, reply.sfFile.name, dirfss) )
860 return 0;
Jack Jansen819f1771995-08-14 12:35:10 +0000861 return hook_args.selectcur_hit;
862}
863
864/*
865** Slightly extended StandardGetFile: accepts a prompt */
866void PyMac_PromptGetFile(short numTypes, ConstSFTypeListPtr typeList,
867 StandardFileReply *reply, char *prompt)
868{
869 static Point where = {-1, -1};
870 struct hook_args hook_args;
871
872 if ( !upp_inited ) {
873 myhook_upp = NewDlgHookYDProc(myhook_proc);
874 upp_inited = 1;
875 }
876 if ( prompt && *prompt )
877 hook_args.prompt = (char *)Pstring(prompt);
878 else
879 hook_args.prompt = NULL;
880 hook_args.selectcur_hit = 0;
881 CustomGetFile((FileFilterYDUPP)0, numTypes, typeList, reply, GETFILEPROMPT_ID, where,
882 myhook_upp, NULL, NULL, NULL, (void *)&hook_args);
Jack Jansen3ec804a1995-02-20 15:56:10 +0000883}
Jack Jansen6e68a7e2001-05-12 21:31:34 +0000884#endif /* TARGET_API_MAC_OS8 */
Jack Jansen5f653091995-01-18 13:53:49 +0000885
Jack Jansen5f653091995-01-18 13:53:49 +0000886