blob: 480b7419ffe405373140736834cbdea1e5df03eb [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#ifdef __CFM68K__
26/* cfm68k InterfaceLib exports GetEventQueue, but Events.h doesn't know this
27** and defines it as GetEvQHdr (which is correct for PPC). This fix is for
28** CW9, check that the workaround is still needed for the next release.
29*/
30#define GetEvQHdr GetEventQueue
31#endif /* __CFM68K__ */
32
33#include <Events.h>
34
35#ifdef __CFM68K__
36#undef GetEventQueue
37#endif /* __CFM68K__ */
38
Jack Jansenf93c72a1994-12-14 14:07:50 +000039#include "Python.h"
Guido van Rossumbecdbec1995-02-14 01:27:24 +000040
Jack Jansenf93c72a1994-12-14 14:07:50 +000041#include "macglue.h"
Jack Jansen74162f31995-02-15 22:58:33 +000042#include "marshal.h"
43#include "import.h"
Jack Jansenf93c72a1994-12-14 14:07:50 +000044
Jack Jansen819f1771995-08-14 12:35:10 +000045#include "pythonresources.h"
46
Jack Jansenf93c72a1994-12-14 14:07:50 +000047#include <OSUtils.h> /* for Set(Current)A5 */
Jack Jansene8e8ae01995-01-26 16:36:45 +000048#include <Files.h>
Jack Jansen8cd2b721995-02-13 11:33:28 +000049#include <StandardFile.h>
Jack Jansenf93c72a1994-12-14 14:07:50 +000050#include <Resources.h>
51#include <Memory.h>
Jack Jansenf93c72a1994-12-14 14:07:50 +000052#include <Windows.h>
Jack Jansene8e8ae01995-01-26 16:36:45 +000053#include <Traps.h>
Jack Jansenee23d6e1995-01-27 14:43:25 +000054#include <Processes.h>
Guido van Rossumc3d1c8e1995-02-18 15:01:31 +000055#include <Fonts.h>
56#include <Menus.h>
Jack Jansen08305501995-06-18 20:03:40 +000057#include <TextUtils.h>
Guido van Rossumcc0d8791995-01-30 08:57:13 +000058#ifdef THINK_C
59#include <OSEvents.h> /* For EvQElPtr */
60#endif
Jack Jansen16df2aa1995-02-27 16:17:28 +000061#ifdef __MWERKS__
62#include <SIOUX.h>
63#endif
Jack Jansen911ad6b1996-03-05 16:56:24 +000064#ifdef USE_GUSI
65#include <TFileSpec.h> /* For Path2FSSpec */
Jack Jansen378815c1996-03-06 16:21:34 +000066#include <LowMem.h> /* For SetSFCurDir, etc */
Jack Jansenf6865f71996-09-04 15:24:59 +000067#include <GUSI.h>
Jack Jansen911ad6b1996-03-05 16:56:24 +000068#endif
Jack Jansenee23d6e1995-01-27 14:43:25 +000069
Jack Jansen3469e991996-09-06 00:30:45 +000070/* The ID of the Sioux apple menu */
71#define SIOUX_APPLEID 32000
72
Guido van Rossumc3d1c8e1995-02-18 15:01:31 +000073#ifndef HAVE_UNIVERSAL_HEADERS
74#define GetResourceSizeOnDisk(x) SizeResource(x)
Guido van Rossum24a45e31995-02-20 23:45:53 +000075typedef DlgHookYDProcPtr DlgHookYDUPP;
76#define NewDlgHookYDProc(userRoutine) ((DlgHookYDUPP) (userRoutine))
77typedef FileFilterYDProcPtr FileFilterYDUPP;
Guido van Rossumc3d1c8e1995-02-18 15:01:31 +000078#endif
79
Jack Jansenee23d6e1995-01-27 14:43:25 +000080#include <signal.h>
Jack Jansen74162f31995-02-15 22:58:33 +000081#include <stdio.h>
Jack Jansene8e8ae01995-01-26 16:36:45 +000082
Jack Jansenee23d6e1995-01-27 14:43:25 +000083/*
Jack Jansend1f06311996-08-01 15:23:54 +000084** When less than this amount of stackspace is left we
85** raise a MemoryError.
86*/
87#ifndef MINIMUM_STACK_SIZE
88#ifdef __powerc
89#define MINIMUM_STACK_SIZE 8192
90#else
91#define MINIMUM_STACK_SIZE 4096
92#endif
93#endif
94
95/*
Jack Jansen16df2aa1995-02-27 16:17:28 +000096** We have to be careful, since we can't handle
Jack Jansenee23d6e1995-01-27 14:43:25 +000097** things like updates (and they'll keep coming back if we don't
Jack Jansen16df2aa1995-02-27 16:17:28 +000098** handle them). Note that we don't know who has windows open, so
99** even handing updates off to SIOUX under MW isn't going to work.
Jack Jansenee23d6e1995-01-27 14:43:25 +0000100*/
101#define MAINLOOP_EVENTMASK (mDownMask|keyDownMask|osMask)
Jack Jansene8e8ae01995-01-26 16:36:45 +0000102
103#include <signal.h>
Jack Jansenf93c72a1994-12-14 14:07:50 +0000104
Guido van Rossumb3404661995-01-22 18:36:13 +0000105/* XXX We should include Errors.h here, but it has a name conflict
Jack Jansen5f653091995-01-18 13:53:49 +0000106** with the python errors.h. */
107#define fnfErr -43
108
Jack Jansene8e8ae01995-01-26 16:36:45 +0000109/* Declared in macfsmodule.c: */
110extern FSSpec *mfs_GetFSSpecFSSpec();
111
Jack Jansenee23d6e1995-01-27 14:43:25 +0000112/* Interrupt code variables: */
113static int interrupted; /* Set to true when cmd-. seen */
114static RETSIGTYPE intcatcher Py_PROTO((int));
115
Jack Jansenf6865f71996-09-04 15:24:59 +0000116static void PyMac_DoYield Py_PROTO((int));
117
Jack Jansene8e8ae01995-01-26 16:36:45 +0000118/*
119** We attempt to be a good citizen by giving up the CPU periodically.
120** When in the foreground we do this less often and for shorter periods
121** than when in the background. At this time we also check for events and
Jack Jansenee23d6e1995-01-27 14:43:25 +0000122** pass them off to SIOUX, if compiling with mwerks.
Jack Jansene8e8ae01995-01-26 16:36:45 +0000123** The counts here are in ticks of 1/60th second.
124** XXXX The initial values here are not based on anything.
125** FG-python gives up the cpu for 1/60th 5 times per second,
126** BG-python for .2 second 10 times per second.
127*/
128static long interval_fg = 12;
129static long interval_bg = 6;
130static long yield_fg = 1;
Jack Jansend617c571996-09-22 22:14:30 +0000131static long yield_bg = 2;
Jack Jansenee23d6e1995-01-27 14:43:25 +0000132static long lastyield;
133static int in_foreground;
134
Guido van Rossume7134aa1995-02-26 10:20:53 +0000135/*
136** When > 0, do full scanning for events (program is not event aware)
137** when == 0, only scan for Command-period
138** when < 0, don't do any event scanning
139*/
140int PyMac_DoYieldEnabled = 1;
Jack Jansenee23d6e1995-01-27 14:43:25 +0000141
Jack Jansen819f1771995-08-14 12:35:10 +0000142/*
Jack Jansenf6865f71996-09-04 15:24:59 +0000143** Workaround for sioux/gusi combo: set when we are exiting
144*/
145int PyMac_ConsoleIsDead;
146
147/*
Jack Jansen819f1771995-08-14 12:35:10 +0000148** Some stuff for our GetDirectory and PromptGetFile routines
149*/
150struct hook_args {
151 int selectcur_hit; /* Set to true when "select current" selected */
152 char *prompt; /* The prompt */
153};
154static DlgHookYDUPP myhook_upp;
155static int upp_inited = 0;
156
Jack Jansen378815c1996-03-06 16:21:34 +0000157#ifdef USE_GUSI
158/*
159** GUSI (1.6.0 and earlier, at the least) do not set the MacOS idea of
160** the working directory. Hence, we call this routine after each call
161** to chdir() to rectify things.
162*/
163void
164PyMac_FixGUSIcd()
165{
166 WDPBRec pb;
167 FSSpec curdirfss;
168
169 if ( Path2FSSpec(":x", &curdirfss) != noErr )
170 return;
171
172 /* Set MacOS "working directory" */
173 pb.ioNamePtr= "\p";
174 pb.ioVRefNum= curdirfss.vRefNum;
175 pb.ioWDDirID= curdirfss.parID;
Jack Jansen08c3be31997-04-08 15:27:00 +0000176 if (PBHSetVolSync(&pb) != noErr)
Jack Jansen378815c1996-03-06 16:21:34 +0000177 return;
Jack Jansen378815c1996-03-06 16:21:34 +0000178}
Jack Jansen7ac70af1996-08-19 11:01:05 +0000179
Jack Jansen7d5f9e81996-09-07 17:09:31 +0000180/*
181** SpinCursor (needed by GUSI) drags in heaps of stuff, so we
182** provide a dummy here.
183*/
Jack Jansencfadbd41996-08-19 11:36:25 +0000184void SpinCursor(short x) { /* Dummy */ }
Jack Jansencfadbd41996-08-19 11:36:25 +0000185
Jack Jansenf6865f71996-09-04 15:24:59 +0000186/*
187** Replacement GUSI Spin function
188*/
189static int
190PyMac_GUSISpin(spin_msg msg, long arg)
191{
192 static Boolean inForeground = true;
Jack Jansenf6865f71996-09-04 15:24:59 +0000193 int maysleep;
194
195 if (PyMac_ConsoleIsDead) return 0;
196#if 0
197 if (inForeground)
198 SpinCursor(msg == SP_AUTO_SPIN ? short(arg) : 1);
199#endif
200
201 if (interrupted) return -1;
202
203 if ( msg == SP_AUTO_SPIN || ((msg==SP_SLEEP||msg==SP_SELECT) && arg <= yield_fg))
204 maysleep = 0;
205 else
206 maysleep = 0;
207
208 PyMac_DoYield(maysleep);
209
210 return 0;
211}
212
213void
214PyMac_SetGUSISpin() {
215 GUSISetHook(GUSI_SpinHook, (GUSIHook)PyMac_GUSISpin);
216}
217
Jack Jansena39f1b01997-05-23 15:35:14 +0000218/* Called at exit() time thru atexit(), to stop event processing */
219void
220PyMac_StopGUSISpin() {
221 PyMac_ConsoleIsDead = 1;
222}
223
224/*
225** Replacement routines for the PLstr... functions so we don't need
226** StdCLib. Moreover, that implementation is broken under cfm68k...
227*/
228void
229PLstrcpy(to, fr)
230 unsigned char *to, *fr;
231{
232 memcpy(to, fr, fr[0]+1);
233}
234
235int
236PLstrcmp(s1, s2)
237 unsigned char *s1, *s2;
238{
239 int res;
240 int l = s1[0] < s2[0] ? s1[0] : s2[0];
241
242 res = memcmp(s1+1, s2+1, l);
243 if ( res != 0 )
244 return res;
245
246 if ( s1 < s2 )
247 return -1;
248 else if ( s1 > s2 )
249 return 1;
250 else
251 return 0;
252}
253
254unsigned char *
255PLstrrchr(str, chr)
256 unsigned char *str;
257 unsigned char chr;
258{
259 unsigned char *ptr = 0;
260 unsigned char *p;
261
262 for(p=str+1; p<str+str[0]; p++)
263 if ( *p == chr )
264 ptr = p;
265 return ptr;
266}
267
268#endif /* USE_GUSI */
Jack Jansen378815c1996-03-06 16:21:34 +0000269
Jack Jansen819f1771995-08-14 12:35:10 +0000270
Jack Jansen5f653091995-01-18 13:53:49 +0000271/* Convert C to Pascal string. Returns pointer to static buffer. */
272unsigned char *
273Pstring(char *str)
274{
275 static Str255 buf;
276 int len;
277
278 len = strlen(str);
Guido van Rossum9aa3d131995-01-21 13:46:04 +0000279 if (len > 255)
280 len = 255;
Jack Jansen5f653091995-01-18 13:53:49 +0000281 buf[0] = (unsigned char)len;
282 strncpy((char *)buf+1, str, len);
283 return buf;
284}
285
Guido van Rossumc3d1c8e1995-02-18 15:01:31 +0000286/* Like strerror() but for Mac OS error numbers */
287char *PyMac_StrError(int err)
Jack Jansenf93c72a1994-12-14 14:07:50 +0000288{
289 static char buf[256];
290 Handle h;
291 char *str;
292
293 h = GetResource('Estr', err);
294 if ( h ) {
295 HLock(h);
296 str = (char *)*h;
297 memcpy(buf, str+1, (unsigned char)str[0]);
Guido van Rossumcc9bc8f1995-02-13 16:17:03 +0000298 buf[(unsigned char)str[0]] = '\0';
Jack Jansenf93c72a1994-12-14 14:07:50 +0000299 HUnlock(h);
300 ReleaseResource(h);
301 } else {
302 sprintf(buf, "Mac OS error code %d", err);
303 }
304 return buf;
305}
306
Guido van Rossumcf27c2d1995-01-25 23:06:44 +0000307/* Exception object shared by all Mac specific modules for Mac OS errors */
308PyObject *PyMac_OSErrException;
309
310/* Initialize and return PyMac_OSErrException */
311PyObject *
312PyMac_GetOSErrException()
313{
314 if (PyMac_OSErrException == NULL)
315 PyMac_OSErrException = PyString_FromString("Mac OS Error");
316 return PyMac_OSErrException;
317}
318
Jack Jansenf93c72a1994-12-14 14:07:50 +0000319/* Set a MAC-specific error from errno, and return NULL; return None if no error */
320PyObject *
Guido van Rossumfffb8bb1995-01-12 12:37:24 +0000321PyErr_Mac(PyObject *eobj, int err)
Jack Jansenf93c72a1994-12-14 14:07:50 +0000322{
323 char *msg;
324 PyObject *v;
Jack Jansenf93c72a1994-12-14 14:07:50 +0000325
Guido van Rossum8f691791995-01-18 23:57:26 +0000326 if (err == 0 && !PyErr_Occurred()) {
Jack Jansenf93c72a1994-12-14 14:07:50 +0000327 Py_INCREF(Py_None);
328 return Py_None;
329 }
Guido van Rossum8f691791995-01-18 23:57:26 +0000330 if (err == -1 && PyErr_Occurred())
331 return NULL;
Guido van Rossumc3d1c8e1995-02-18 15:01:31 +0000332 msg = PyMac_StrError(err);
Jack Jansenf93c72a1994-12-14 14:07:50 +0000333 v = Py_BuildValue("(is)", err, msg);
334 PyErr_SetObject(eobj, v);
335 Py_DECREF(v);
336 return NULL;
337}
338
Guido van Rossumcf27c2d1995-01-25 23:06:44 +0000339/* Call PyErr_Mac with PyMac_OSErrException */
340PyObject *
341PyMac_Error(OSErr err)
342{
343 return PyErr_Mac(PyMac_GetOSErrException(), err);
344}
345
Jack Jansen1ed95291996-07-22 15:25:10 +0000346#ifdef USE_STACKCHECK
347/* Check for stack overflow */
348int
349PyOS_CheckStack()
350{
351 long left;
352
353 left = StackSpace();
Jack Jansend1f06311996-08-01 15:23:54 +0000354 if ( left < MINIMUM_STACK_SIZE )
Jack Jansen1ed95291996-07-22 15:25:10 +0000355 return -1;
356 return 0;
357}
358#endif /* USE_STACKCHECK */
359
Jack Jansenee23d6e1995-01-27 14:43:25 +0000360/* The catcher routine (which may not be used for all compilers) */
361static RETSIGTYPE
362intcatcher(sig)
363 int sig;
364{
365 interrupted = 1;
366 signal(SIGINT, intcatcher);
367}
368
369void
370PyOS_InitInterrupts()
371{
372 if (signal(SIGINT, SIG_IGN) != SIG_IGN)
373 signal(SIGINT, intcatcher);
374}
375
376/*
377** This routine scans the event queue looking for cmd-.
378** This is the only way to get an interrupt under THINK (since it
379** doesn't do SIGINT handling), but is also used under MW, when
380** the full-fledged event loop is disabled. This way, we can at least
381** interrupt a runaway python program.
382*/
383static void
384scan_event_queue(flush)
385 int flush;
386{
387 register EvQElPtr q;
388
Jack Jansencfadbd41996-08-19 11:36:25 +0000389 q = (EvQElPtr) GetEventQueue()->qHead;
Jack Jansenee23d6e1995-01-27 14:43:25 +0000390
391 for (; q; q = (EvQElPtr)q->qLink) {
392 if (q->evtQWhat == keyDown &&
393 (char)q->evtQMessage == '.' &&
394 (q->evtQModifiers & cmdKey) != 0) {
395 if ( flush )
396 FlushEvents(keyDownMask, 0);
397 interrupted = 1;
398 break;
399 }
400 }
401}
402
Jack Jansen7e944041997-02-20 15:23:18 +0000403#define TICKCOUNT 6
404
Jack Jansenee23d6e1995-01-27 14:43:25 +0000405int
406PyOS_InterruptOccurred()
407{
Jack Jansen7e944041997-02-20 15:23:18 +0000408 static unsigned long nextticktime;
409 unsigned long curticktime;
410
Guido van Rossume7134aa1995-02-26 10:20:53 +0000411 if (PyMac_DoYieldEnabled < 0)
412 return 0;
Jack Jansen7e944041997-02-20 15:23:18 +0000413 curticktime = (unsigned long)LMGetTicks();
414 if ( curticktime < nextticktime )
415 return 0;
416 nextticktime = curticktime + TICKCOUNT;
Jack Jansenee23d6e1995-01-27 14:43:25 +0000417#ifdef THINK_C
418 scan_event_queue(1);
419#endif
420 PyMac_Yield();
421 if (interrupted) {
422 interrupted = 0;
423 return 1;
424 }
425 return 0;
426}
427
428/* intrpeek() is like intrcheck(), but it doesn't flush the events. The
429** idea is that you call intrpeek() somewhere in a busy-wait loop, and return
430** None as soon as it returns 1. The mainloop will then pick up the cmd-. soon
431** thereafter.
432*/
433static int
434intrpeek()
435{
436#ifdef THINK_C
437 scan_event_queue(0);
438#endif
439 return interrupted;
440}
441
442/* Check whether we are in the foreground */
443int
444PyMac_InForeground()
445{
446 static ProcessSerialNumber ours;
447 static inited;
448 ProcessSerialNumber curfg;
449 Boolean eq;
450
451 if ( inited == 0 )
452 (void)GetCurrentProcess(&ours);
453 inited = 1;
454 if ( GetFrontProcess(&curfg) < 0 )
455 eq = 1;
456 else if ( SameProcess(&ours, &curfg, &eq) < 0 )
457 eq = 1;
458 return (int)eq;
459
460}
461
Jack Jansenf93c72a1994-12-14 14:07:50 +0000462/*
Jack Jansene8e8ae01995-01-26 16:36:45 +0000463** Set yield timeouts
Jack Jansenf93c72a1994-12-14 14:07:50 +0000464*/
Jack Jansene8e8ae01995-01-26 16:36:45 +0000465void
466PyMac_SetYield(long fgi, long fgy, long bgi, long bgy)
467{
468 interval_fg = fgi;
469 yield_fg = fgy;
470 interval_bg = bgi;
471 yield_bg = bgy;
472}
473
474/*
Jack Jansena76382a1995-02-02 14:25:56 +0000475** Handle an event, either one found in the mainloop eventhandler or
476** one passed back from the python program.
477*/
478void
479PyMac_HandleEvent(evp)
480 EventRecord *evp;
481{
Jack Jansena76382a1995-02-02 14:25:56 +0000482
483#ifdef __MWERKS__
Jack Jansen38e97661995-11-10 14:53:00 +0000484 {
485 int siouxdidit;
486
487 /* If SIOUX wants it we're done */
488 siouxdidit = SIOUXHandleOneEvent(evp);
489 if ( siouxdidit )
490 return;
491 }
Jack Jansena76382a1995-02-02 14:25:56 +0000492#else
493 /* Other compilers are just unlucky: we only weed out clicks in other applications */
494 if ( evp->what == mouseDown ) {
Jack Jansen847e89e1995-08-31 13:57:40 +0000495 WindowPtr wp;
496
Jack Jansen38e97661995-11-10 14:53:00 +0000497 if ( FindWindow(evp->where, &wp) == inSysWindow ) {
Jack Jansena76382a1995-02-02 14:25:56 +0000498 SystemClick(evp, wp);
Jack Jansen38e97661995-11-10 14:53:00 +0000499 return;
500 }
Jack Jansena76382a1995-02-02 14:25:56 +0000501 }
502#endif /* !__MWERKS__ */
503}
504
505/*
Jack Jansene8e8ae01995-01-26 16:36:45 +0000506** Yield the CPU to other tasks.
507*/
Jack Jansencfadbd41996-08-19 11:36:25 +0000508static void
Jack Jansenf6865f71996-09-04 15:24:59 +0000509PyMac_DoYield(int maysleep)
Jack Jansenf93c72a1994-12-14 14:07:50 +0000510{
511 EventRecord ev;
Jack Jansene8e8ae01995-01-26 16:36:45 +0000512 long yield;
Jack Jansene8e8ae01995-01-26 16:36:45 +0000513 static int no_waitnextevent = -1;
514 int gotone;
515
516 if ( no_waitnextevent < 0 ) {
517 no_waitnextevent = (NGetTrapAddress(_WaitNextEvent, ToolTrap) ==
518 NGetTrapAddress(_Unimplemented, ToolTrap));
519 }
Jack Jansenf93c72a1994-12-14 14:07:50 +0000520
Jack Jansenf6865f71996-09-04 15:24:59 +0000521 lastyield = TickCount();
Jack Jansenee23d6e1995-01-27 14:43:25 +0000522#ifndef THINK_C
Jack Jansenf6865f71996-09-04 15:24:59 +0000523 /* Under think this has been done before in intrcheck() or intrpeek() */
524 if (PyMac_DoYieldEnabled >= 0)
Jack Jansenee23d6e1995-01-27 14:43:25 +0000525 scan_event_queue(0);
526#endif
Jack Jansenf6865f71996-09-04 15:24:59 +0000527 if (PyMac_DoYieldEnabled == 0)
Jack Jansene8e8ae01995-01-26 16:36:45 +0000528 return;
529
Jack Jansenee23d6e1995-01-27 14:43:25 +0000530 in_foreground = PyMac_InForeground();
Jack Jansenf6865f71996-09-04 15:24:59 +0000531 if ( maysleep ) {
532 if ( in_foreground )
533 yield = yield_fg;
534 else
535 yield = yield_bg;
536 } else {
537 yield = 0;
538 }
539
Jack Jansene8e8ae01995-01-26 16:36:45 +0000540 while ( 1 ) {
541 if ( no_waitnextevent ) {
542 SystemTask();
Jack Jansenee23d6e1995-01-27 14:43:25 +0000543 gotone = GetNextEvent(MAINLOOP_EVENTMASK, &ev);
Jack Jansene8e8ae01995-01-26 16:36:45 +0000544 } else {
Jack Jansenee23d6e1995-01-27 14:43:25 +0000545 gotone = WaitNextEvent(MAINLOOP_EVENTMASK, &ev, yield, NULL);
Jack Jansene8e8ae01995-01-26 16:36:45 +0000546 }
547 /* Get out quickly if nothing interesting is happening */
548 if ( !gotone || ev.what == nullEvent )
549 break;
Jack Jansena76382a1995-02-02 14:25:56 +0000550 PyMac_HandleEvent(&ev);
Jack Jansenf93c72a1994-12-14 14:07:50 +0000551 }
Jack Jansene8e8ae01995-01-26 16:36:45 +0000552}
553
554/*
555** Yield the CPU to other tasks if opportune
556*/
557void
558PyMac_Yield() {
559 long iv;
560
Jack Jansenee23d6e1995-01-27 14:43:25 +0000561 if ( in_foreground )
Jack Jansene8e8ae01995-01-26 16:36:45 +0000562 iv = interval_fg;
Jack Jansenee23d6e1995-01-27 14:43:25 +0000563 else
564 iv = interval_bg;
Jack Jansene8e8ae01995-01-26 16:36:45 +0000565 if ( TickCount() > lastyield + iv )
Jack Jansenf6865f71996-09-04 15:24:59 +0000566 PyMac_DoYield(1);
Jack Jansene8e8ae01995-01-26 16:36:45 +0000567}
568
Jack Jansenf6865f71996-09-04 15:24:59 +0000569#ifdef USE_MACTCP
Jack Jansene8e8ae01995-01-26 16:36:45 +0000570/*
571** Idle routine for busy-wait loops.
572** Gives up CPU, handles events and returns true if an interrupt is pending
573** (but not actually handled yet).
574*/
575int
576PyMac_Idle()
577{
Jack Jansenf6865f71996-09-04 15:24:59 +0000578 PyMac_DoYield(1);
Jack Jansene8e8ae01995-01-26 16:36:45 +0000579 return intrpeek();
Jack Jansenf93c72a1994-12-14 14:07:50 +0000580}
Jack Jansenf6865f71996-09-04 15:24:59 +0000581#endif
582
Jack Jansen74162f31995-02-15 22:58:33 +0000583/*
Jack Jansen3469e991996-09-06 00:30:45 +0000584** Install our menu bar.
585*/
586void
587PyMac_InitMenuBar()
588{
589 Handle bar;
590 MenuHandle applemenu;
591
592 if ( (bar=GetMenuBar()) == NULL ) return;
Jack Jansen08c3be31997-04-08 15:27:00 +0000593 if ( (applemenu=GetMenuHandle(SIOUX_APPLEID)) == NULL ) return;
Jack Jansen3469e991996-09-06 00:30:45 +0000594 SetMenuItemText(applemenu, 1, "\pAbout Python...");
595}
596
597/*
598** Our replacement about box
599*/
600void
601SIOUXDoAboutBox(void)
602{
603 DialogPtr theDialog;
Jack Jansend617c571996-09-22 22:14:30 +0000604 WindowRef theWindow;
605 CGrafPtr thePort;
Jack Jansen3469e991996-09-06 00:30:45 +0000606 short item;
Jack Jansend617c571996-09-22 22:14:30 +0000607 short xpos, ypos, width, height, swidth, sheight;
Jack Jansen3469e991996-09-06 00:30:45 +0000608
609 if( (theDialog = GetNewDialog(ABOUT_ID, NULL, (WindowPtr)-1)) == NULL )
610 return;
Jack Jansend617c571996-09-22 22:14:30 +0000611 theWindow = GetDialogWindow(theDialog);
612 thePort = GetWindowPort(theWindow);
613 width = thePort->portRect.right - thePort->portRect.left;
614 height = thePort->portRect.bottom - thePort->portRect.top;
615 swidth = qd.screenBits.bounds.right - qd.screenBits.bounds.left;
616 sheight = qd.screenBits.bounds.bottom - qd.screenBits.bounds.top - LMGetMBarHeight();
617 xpos = (swidth-width)/2;
Jack Jansen0e06e7e1996-09-23 15:51:06 +0000618 ypos = (sheight-height)/5 + LMGetMBarHeight();
Jack Jansend617c571996-09-22 22:14:30 +0000619 MoveWindow(theWindow, xpos, ypos, 0);
620 ShowWindow(theWindow);
Jack Jansen3469e991996-09-06 00:30:45 +0000621 ModalDialog(NULL, &item);
622 DisposeDialog(theDialog);
623}
624
625/*
Jack Jansen74162f31995-02-15 22:58:33 +0000626** Returns true if the argument has a resource fork, and it contains
627** a 'PYC ' resource of the correct name
628*/
629int
630PyMac_FindResourceModule(module, filename)
631char *module;
632char *filename;
633{
634 FSSpec fss;
635 FInfo finfo;
636 short oldrh, filerh;
637 int ok;
638 Handle h;
639
Jack Jansen8096daa1996-11-09 18:43:44 +0000640 if ( strcmp(filename, PyMac_ApplicationPath) == 0 ) {
641 /*
642 ** Special case: the application itself. Use a shortcut to
643 ** forestall opening and closing the application numerous times
644 ** (which is dead slow when running from CDROM)
645 */
646 oldrh = CurResFile();
647 UseResFile(PyMac_AppRefNum);
648 filerh = -1;
649 } else {
650 if ( FSMakeFSSpec(0, 0, Pstring(filename), &fss) != noErr )
651 return 0; /* It doesn't exist */
652 if ( FSpGetFInfo(&fss, &finfo) != noErr )
653 return 0; /* shouldn't happen, I guess */
654 oldrh = CurResFile();
655 filerh = FSpOpenResFile(&fss, fsRdPerm);
656 if ( filerh == -1 )
657 return 0;
658 UseResFile(filerh);
659 }
Jack Jansen74162f31995-02-15 22:58:33 +0000660 SetResLoad(0);
661 h = Get1NamedResource('PYC ', Pstring(module));
662 SetResLoad(1);
663 ok = (h != NULL);
Jack Jansen8096daa1996-11-09 18:43:44 +0000664 if ( filerh != -1 )
665 CloseResFile(filerh);
Jack Jansen74162f31995-02-15 22:58:33 +0000666 UseResFile(oldrh);
667 return ok;
668}
669
670/*
671** Load the specified module from a resource
672*/
673PyObject *
674PyMac_LoadResourceModule(module, filename)
675char *module;
676char *filename;
677{
678 FSSpec fss;
679 FInfo finfo;
680 short oldrh, filerh;
Jack Jansen74162f31995-02-15 22:58:33 +0000681 Handle h;
682 OSErr err;
683 PyObject *m, *co;
684 long num, size;
685
Jack Jansen8096daa1996-11-09 18:43:44 +0000686 if ( strcmp(filename, PyMac_ApplicationPath) == 0 ) {
687 /*
688 ** Special case: the application itself. Use a shortcut to
689 ** forestall opening and closing the application numerous times
690 ** (which is dead slow when running from CDROM)
691 */
692 oldrh = CurResFile();
693 UseResFile(PyMac_AppRefNum);
694 filerh = -1;
695 } else {
696 if ( (err=FSMakeFSSpec(0, 0, Pstring(filename), &fss)) != noErr )
697 goto error;
698 if ( (err=FSpGetFInfo(&fss, &finfo)) != noErr )
699 goto error;
700 oldrh = CurResFile();
701 filerh = FSpOpenResFile(&fss, fsRdPerm);
702 if ( filerh == -1 ) {
703 err = ResError();
704 goto error;
705 }
706 UseResFile(filerh);
Jack Jansen74162f31995-02-15 22:58:33 +0000707 }
Jack Jansen74162f31995-02-15 22:58:33 +0000708 h = Get1NamedResource('PYC ', Pstring(module));
709 if ( h == NULL ) {
710 err = ResError();
711 goto error;
712 }
713 HLock(h);
714 /*
715 ** XXXX The next few lines are intimately tied to the format of pyc
716 ** files. I'm not sure whether this code should be here or in import.c -- Jack
717 */
718 size = GetHandleSize(h);
719 if ( size < 8 ) {
720 PyErr_SetString(PyExc_ImportError, "Resource too small");
Guido van Rossumc3d1c8e1995-02-18 15:01:31 +0000721 co = NULL;
Jack Jansen74162f31995-02-15 22:58:33 +0000722 } else {
723 num = (*h)[0] & 0xff;
724 num = num | (((*h)[1] & 0xff) << 8);
725 num = num | (((*h)[2] & 0xff) << 16);
726 num = num | (((*h)[3] & 0xff) << 24);
727 if ( num != PyImport_GetMagicNumber() ) {
728 PyErr_SetString(PyExc_ImportError, "Bad MAGIC in resource");
729 co = NULL;
730 } else {
731 co = PyMarshal_ReadObjectFromString((*h)+8, size-8);
732 }
733 }
734 HUnlock(h);
Jack Jansen8096daa1996-11-09 18:43:44 +0000735 if ( filerh != -1 )
736 CloseResFile(filerh);
Jack Jansen74162f31995-02-15 22:58:33 +0000737 UseResFile(oldrh);
738 if ( co ) {
739 m = PyImport_ExecCodeModule(module, co);
740 Py_DECREF(co);
741 } else {
742 m = NULL;
743 }
744 return m;
745error:
746 {
747 char buf[512];
748
Guido van Rossumc3d1c8e1995-02-18 15:01:31 +0000749 sprintf(buf, "%s: %s", filename, PyMac_StrError(err));
Jack Jansen74162f31995-02-15 22:58:33 +0000750 PyErr_SetString(PyExc_ImportError, buf);
751 return NULL;
752 }
753}
Guido van Rossum24a45e31995-02-20 23:45:53 +0000754
Jack Jansen3ec804a1995-02-20 15:56:10 +0000755/*
756** Helper routine for GetDirectory
757*/
Guido van Rossum24a45e31995-02-20 23:45:53 +0000758static pascal short
Jack Jansen819f1771995-08-14 12:35:10 +0000759myhook_proc(short item, DialogPtr theDialog, struct hook_args *dataptr)
Jack Jansen3ec804a1995-02-20 15:56:10 +0000760{
Jack Jansen819f1771995-08-14 12:35:10 +0000761 if ( item == sfHookFirstCall && dataptr->prompt) {
762 Handle prompth;
763 short type;
764 Rect rect;
765
766 GetDialogItem(theDialog, PROMPT_ITEM, &type, &prompth, &rect);
767 if ( prompth )
768 SetDialogItemText(prompth, (unsigned char *)dataptr->prompt);
769 } else
Jack Jansen3ec804a1995-02-20 15:56:10 +0000770 if ( item == SELECTCUR_ITEM ) {
771 item = sfItemCancelButton;
Jack Jansen819f1771995-08-14 12:35:10 +0000772 dataptr->selectcur_hit = 1;
Jack Jansen3ec804a1995-02-20 15:56:10 +0000773 }
774 return item;
775}
776
777/*
778** Ask the user for a directory. I still can't understand
779** why Apple doesn't provide a standard solution for this...
780*/
781int
Jack Jansen819f1771995-08-14 12:35:10 +0000782PyMac_GetDirectory(dirfss, prompt)
Jack Jansen3ec804a1995-02-20 15:56:10 +0000783 FSSpec *dirfss;
Jack Jansen819f1771995-08-14 12:35:10 +0000784 char *prompt;
Jack Jansen3ec804a1995-02-20 15:56:10 +0000785{
786 static SFTypeList list = {'fldr', 0, 0, 0};
787 static Point where = {-1, -1};
Jack Jansen3ec804a1995-02-20 15:56:10 +0000788 StandardFileReply reply;
Jack Jansen819f1771995-08-14 12:35:10 +0000789 struct hook_args hook_args;
Jack Jansen3ec804a1995-02-20 15:56:10 +0000790
791 if ( !upp_inited ) {
792 myhook_upp = NewDlgHookYDProc(myhook_proc);
793 upp_inited = 1;
794 }
Jack Jansen819f1771995-08-14 12:35:10 +0000795 if ( prompt && *prompt )
796 hook_args.prompt = (char *)Pstring(prompt);
797 else
798 hook_args.prompt = NULL;
799 hook_args.selectcur_hit = 0;
Guido van Rossum24a45e31995-02-20 23:45:53 +0000800 CustomGetFile((FileFilterYDUPP)0, 1, list, &reply, GETDIR_ID, where, myhook_upp,
Jack Jansen819f1771995-08-14 12:35:10 +0000801 NULL, NULL, NULL, (void *)&hook_args);
Jack Jansen3ec804a1995-02-20 15:56:10 +0000802
803 reply.sfFile.name[0] = 0;
804 if( FSMakeFSSpec(reply.sfFile.vRefNum, reply.sfFile.parID, reply.sfFile.name, dirfss) )
805 return 0;
Jack Jansen819f1771995-08-14 12:35:10 +0000806 return hook_args.selectcur_hit;
807}
808
809/*
810** Slightly extended StandardGetFile: accepts a prompt */
811void PyMac_PromptGetFile(short numTypes, ConstSFTypeListPtr typeList,
812 StandardFileReply *reply, char *prompt)
813{
814 static Point where = {-1, -1};
815 struct hook_args hook_args;
816
817 if ( !upp_inited ) {
818 myhook_upp = NewDlgHookYDProc(myhook_proc);
819 upp_inited = 1;
820 }
821 if ( prompt && *prompt )
822 hook_args.prompt = (char *)Pstring(prompt);
823 else
824 hook_args.prompt = NULL;
825 hook_args.selectcur_hit = 0;
826 CustomGetFile((FileFilterYDUPP)0, numTypes, typeList, reply, GETFILEPROMPT_ID, where,
827 myhook_upp, NULL, NULL, NULL, (void *)&hook_args);
Jack Jansen3ec804a1995-02-20 15:56:10 +0000828}
Jack Jansen5f653091995-01-18 13:53:49 +0000829
Guido van Rossumcf27c2d1995-01-25 23:06:44 +0000830/* Convert a 4-char string object argument to an OSType value */
Jack Jansen5f653091995-01-18 13:53:49 +0000831int
Guido van Rossumcf27c2d1995-01-25 23:06:44 +0000832PyMac_GetOSType(PyObject *v, OSType *pr)
Jack Jansen5f653091995-01-18 13:53:49 +0000833{
834 if (!PyString_Check(v) || PyString_Size(v) != 4) {
835 PyErr_SetString(PyExc_TypeError,
836 "OSType arg must be string of 4 chars");
837 return 0;
838 }
839 memcpy((char *)pr, PyString_AsString(v), 4);
840 return 1;
841}
842
Guido van Rossumcf27c2d1995-01-25 23:06:44 +0000843/* Convert an OSType value to a 4-char string object */
844PyObject *
845PyMac_BuildOSType(OSType t)
846{
847 return PyString_FromStringAndSize((char *)&t, 4);
848}
849
Jack Jansend1f06311996-08-01 15:23:54 +0000850/* Convert an NumVersion value to a 4-element tuple */
851PyObject *
852PyMac_BuildNumVersion(NumVersion t)
853{
854 return Py_BuildValue("(hhhh)", t.majorRev, t.minorAndBugRev, t.stage, t.nonRelRev);
855}
856
Guido van Rossumcf27c2d1995-01-25 23:06:44 +0000857
858/* Convert a Python string object to a Str255 */
Jack Jansen5f653091995-01-18 13:53:49 +0000859int
Guido van Rossum8f691791995-01-18 23:57:26 +0000860PyMac_GetStr255(PyObject *v, Str255 pbuf)
Jack Jansen5f653091995-01-18 13:53:49 +0000861{
862 int len;
863 if (!PyString_Check(v) || (len = PyString_Size(v)) > 255) {
864 PyErr_SetString(PyExc_TypeError,
865 "Str255 arg must be string of at most 255 chars");
866 return 0;
867 }
868 pbuf[0] = len;
869 memcpy((char *)(pbuf+1), PyString_AsString(v), len);
870 return 1;
871}
872
Guido van Rossumcf27c2d1995-01-25 23:06:44 +0000873/* Convert a Str255 to a Python string object */
874PyObject *
875PyMac_BuildStr255(Str255 s)
876{
877 return PyString_FromStringAndSize((char *)&s[1], (int)s[0]);
878}
879
880
Jack Jansen5f653091995-01-18 13:53:49 +0000881/*
Guido van Rossumcf27c2d1995-01-25 23:06:44 +0000882** Convert a Python object to an FSSpec.
883** The object may either be a full pathname or a triple
884** (vrefnum, dirid, path).
Jack Jansen5f653091995-01-18 13:53:49 +0000885** NOTE: This routine will fail on pre-sys7 machines.
886** The caller is responsible for not calling this routine
887** in those cases (which is fine, since everyone calling
888** this is probably sys7 dependent anyway).
889*/
890int
Guido van Rossum8f691791995-01-18 23:57:26 +0000891PyMac_GetFSSpec(PyObject *v, FSSpec *fs)
Jack Jansen5f653091995-01-18 13:53:49 +0000892{
893 Str255 path;
894 short refnum;
895 long parid;
896 OSErr err;
Jack Jansene8e8ae01995-01-26 16:36:45 +0000897 FSSpec *fs2;
Jack Jansen5f653091995-01-18 13:53:49 +0000898
Jack Jansene8e8ae01995-01-26 16:36:45 +0000899 /* first check whether it already is an FSSpec */
900 fs2 = mfs_GetFSSpecFSSpec(v);
901 if ( fs2 ) {
Jack Jansen3ec804a1995-02-20 15:56:10 +0000902 (void)FSMakeFSSpec(fs2->vRefNum, fs2->parID, fs2->name, fs);
Jack Jansene8e8ae01995-01-26 16:36:45 +0000903 return 1;
904 }
Jack Jansen5f653091995-01-18 13:53:49 +0000905 if ( PyString_Check(v) ) {
906 /* It's a pathname */
Guido van Rossum9aa3d131995-01-21 13:46:04 +0000907 if( !PyArg_Parse(v, "O&", PyMac_GetStr255, &path) )
Jack Jansen5f653091995-01-18 13:53:49 +0000908 return 0;
Jack Jansen378815c1996-03-06 16:21:34 +0000909 refnum = 0; /* XXXX Should get CurWD here?? */
Jack Jansen5f653091995-01-18 13:53:49 +0000910 parid = 0;
911 } else {
Guido van Rossum9aa3d131995-01-21 13:46:04 +0000912 if( !PyArg_Parse(v, "(hlO&); FSSpec should be fullpath or (vrefnum,dirid,path)",
913 &refnum, &parid, PyMac_GetStr255, &path)) {
Jack Jansen5f653091995-01-18 13:53:49 +0000914 return 0;
Guido van Rossum9aa3d131995-01-21 13:46:04 +0000915 }
Jack Jansen5f653091995-01-18 13:53:49 +0000916 }
917 err = FSMakeFSSpec(refnum, parid, path, fs);
918 if ( err && err != fnfErr ) {
Guido van Rossum9aa3d131995-01-21 13:46:04 +0000919 PyErr_Mac(PyExc_ValueError, err);
Jack Jansen5f653091995-01-18 13:53:49 +0000920 return 0;
921 }
922 return 1;
923}
924
Guido van Rossum8f691791995-01-18 23:57:26 +0000925
Guido van Rossumcf27c2d1995-01-25 23:06:44 +0000926/* Convert a Python object to a Rect.
Guido van Rossum5279ec61995-01-26 22:56:59 +0000927 The object must be a (left, top, right, bottom) tuple.
928 (This differs from the order in the struct but is consistent with
929 the arguments to SetRect(), and also with STDWIN). */
Guido van Rossumcf27c2d1995-01-25 23:06:44 +0000930int
931PyMac_GetRect(PyObject *v, Rect *r)
Guido van Rossum8f691791995-01-18 23:57:26 +0000932{
Guido van Rossum5279ec61995-01-26 22:56:59 +0000933 return PyArg_Parse(v, "(hhhh)", &r->left, &r->top, &r->right, &r->bottom);
Guido van Rossum8f691791995-01-18 23:57:26 +0000934}
Guido van Rossumb3404661995-01-22 18:36:13 +0000935
Guido van Rossumcf27c2d1995-01-25 23:06:44 +0000936/* Convert a Rect to a Python object */
Guido van Rossumb3404661995-01-22 18:36:13 +0000937PyObject *
Guido van Rossumcf27c2d1995-01-25 23:06:44 +0000938PyMac_BuildRect(Rect *r)
Guido van Rossumb3404661995-01-22 18:36:13 +0000939{
Guido van Rossum5279ec61995-01-26 22:56:59 +0000940 return Py_BuildValue("(hhhh)", r->left, r->top, r->right, r->bottom);
Guido van Rossumcf27c2d1995-01-25 23:06:44 +0000941}
942
943
944/* Convert a Python object to a Point.
Guido van Rossum5279ec61995-01-26 22:56:59 +0000945 The object must be a (h, v) tuple.
946 (This differs from the order in the struct but is consistent with
947 the arguments to SetPoint(), and also with STDWIN). */
Guido van Rossumcf27c2d1995-01-25 23:06:44 +0000948int
949PyMac_GetPoint(PyObject *v, Point *p)
950{
Guido van Rossum5279ec61995-01-26 22:56:59 +0000951 return PyArg_Parse(v, "(hh)", &p->h, &p->v);
Guido van Rossumcf27c2d1995-01-25 23:06:44 +0000952}
953
954/* Convert a Point to a Python object */
955PyObject *
956PyMac_BuildPoint(Point p)
957{
Guido van Rossum5279ec61995-01-26 22:56:59 +0000958 return Py_BuildValue("(hh)", p.h, p.v);
Guido van Rossumcf27c2d1995-01-25 23:06:44 +0000959}
960
961
962/* Convert a Python object to an EventRecord.
963 The object must be a (what, message, when, (v, h), modifiers) tuple. */
964int
965PyMac_GetEventRecord(PyObject *v, EventRecord *e)
966{
967 return PyArg_Parse(v, "(hll(hh)h)",
968 &e->what,
969 &e->message,
970 &e->when,
Guido van Rossumcf27c2d1995-01-25 23:06:44 +0000971 &e->where.h,
Guido van Rossum5279ec61995-01-26 22:56:59 +0000972 &e->where.v,
Guido van Rossumcf27c2d1995-01-25 23:06:44 +0000973 &e->modifiers);
974}
975
976/* Convert a Rect to an EventRecord object */
977PyObject *
978PyMac_BuildEventRecord(EventRecord *e)
979{
980 return Py_BuildValue("(hll(hh)h)",
981 e->what,
982 e->message,
983 e->when,
Guido van Rossumcf27c2d1995-01-25 23:06:44 +0000984 e->where.h,
Guido van Rossum5279ec61995-01-26 22:56:59 +0000985 e->where.v,
Guido van Rossumcf27c2d1995-01-25 23:06:44 +0000986 e->modifiers);
Guido van Rossumb3404661995-01-22 18:36:13 +0000987}
Jack Jansenfa4d5d01995-11-15 15:19:29 +0000988
989/* Convert Python object to Fixed */
990int
991PyMac_GetFixed(PyObject *v, Fixed *f)
992{
993 double d;
994
995 if( !PyArg_Parse(v, "d", &d))
996 return 0;
997 *f = (Fixed)(d * 0x10000);
Jack Jansen31dd5c01996-05-31 13:01:39 +0000998 return 1;
Jack Jansenfa4d5d01995-11-15 15:19:29 +0000999}
1000
1001/* Convert a Point to a Python object */
1002PyObject *
1003PyMac_BuildFixed(Fixed f)
1004{
1005 double d;
1006
1007 d = f;
1008 d = d / 0x10000;
1009 return Py_BuildValue("d", d);
1010}
1011