blob: d05009e71b20ff2af2eee43fcf657a206d0fbc67 [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;
176 if (PBHSetVol(&pb, 0) != noErr)
177 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 Jansen378815c1996-03-06 16:21:34 +0000218#endif
219
Jack Jansen819f1771995-08-14 12:35:10 +0000220
Jack Jansen5f653091995-01-18 13:53:49 +0000221/* Convert C to Pascal string. Returns pointer to static buffer. */
222unsigned char *
223Pstring(char *str)
224{
225 static Str255 buf;
226 int len;
227
228 len = strlen(str);
Guido van Rossum9aa3d131995-01-21 13:46:04 +0000229 if (len > 255)
230 len = 255;
Jack Jansen5f653091995-01-18 13:53:49 +0000231 buf[0] = (unsigned char)len;
232 strncpy((char *)buf+1, str, len);
233 return buf;
234}
235
Guido van Rossumc3d1c8e1995-02-18 15:01:31 +0000236/* Like strerror() but for Mac OS error numbers */
237char *PyMac_StrError(int err)
Jack Jansenf93c72a1994-12-14 14:07:50 +0000238{
239 static char buf[256];
240 Handle h;
241 char *str;
242
243 h = GetResource('Estr', err);
244 if ( h ) {
245 HLock(h);
246 str = (char *)*h;
247 memcpy(buf, str+1, (unsigned char)str[0]);
Guido van Rossumcc9bc8f1995-02-13 16:17:03 +0000248 buf[(unsigned char)str[0]] = '\0';
Jack Jansenf93c72a1994-12-14 14:07:50 +0000249 HUnlock(h);
250 ReleaseResource(h);
251 } else {
252 sprintf(buf, "Mac OS error code %d", err);
253 }
254 return buf;
255}
256
Guido van Rossumcf27c2d1995-01-25 23:06:44 +0000257/* Exception object shared by all Mac specific modules for Mac OS errors */
258PyObject *PyMac_OSErrException;
259
260/* Initialize and return PyMac_OSErrException */
261PyObject *
262PyMac_GetOSErrException()
263{
264 if (PyMac_OSErrException == NULL)
265 PyMac_OSErrException = PyString_FromString("Mac OS Error");
266 return PyMac_OSErrException;
267}
268
Jack Jansenf93c72a1994-12-14 14:07:50 +0000269/* Set a MAC-specific error from errno, and return NULL; return None if no error */
270PyObject *
Guido van Rossumfffb8bb1995-01-12 12:37:24 +0000271PyErr_Mac(PyObject *eobj, int err)
Jack Jansenf93c72a1994-12-14 14:07:50 +0000272{
273 char *msg;
274 PyObject *v;
Jack Jansenf93c72a1994-12-14 14:07:50 +0000275
Guido van Rossum8f691791995-01-18 23:57:26 +0000276 if (err == 0 && !PyErr_Occurred()) {
Jack Jansenf93c72a1994-12-14 14:07:50 +0000277 Py_INCREF(Py_None);
278 return Py_None;
279 }
Guido van Rossum8f691791995-01-18 23:57:26 +0000280 if (err == -1 && PyErr_Occurred())
281 return NULL;
Guido van Rossumc3d1c8e1995-02-18 15:01:31 +0000282 msg = PyMac_StrError(err);
Jack Jansenf93c72a1994-12-14 14:07:50 +0000283 v = Py_BuildValue("(is)", err, msg);
284 PyErr_SetObject(eobj, v);
285 Py_DECREF(v);
286 return NULL;
287}
288
Guido van Rossumcf27c2d1995-01-25 23:06:44 +0000289/* Call PyErr_Mac with PyMac_OSErrException */
290PyObject *
291PyMac_Error(OSErr err)
292{
293 return PyErr_Mac(PyMac_GetOSErrException(), err);
294}
295
Jack Jansen1ed95291996-07-22 15:25:10 +0000296#ifdef USE_STACKCHECK
297/* Check for stack overflow */
298int
299PyOS_CheckStack()
300{
301 long left;
302
303 left = StackSpace();
Jack Jansend1f06311996-08-01 15:23:54 +0000304 if ( left < MINIMUM_STACK_SIZE )
Jack Jansen1ed95291996-07-22 15:25:10 +0000305 return -1;
306 return 0;
307}
308#endif /* USE_STACKCHECK */
309
Jack Jansenee23d6e1995-01-27 14:43:25 +0000310/* The catcher routine (which may not be used for all compilers) */
311static RETSIGTYPE
312intcatcher(sig)
313 int sig;
314{
315 interrupted = 1;
316 signal(SIGINT, intcatcher);
317}
318
319void
320PyOS_InitInterrupts()
321{
322 if (signal(SIGINT, SIG_IGN) != SIG_IGN)
323 signal(SIGINT, intcatcher);
324}
325
326/*
327** This routine scans the event queue looking for cmd-.
328** This is the only way to get an interrupt under THINK (since it
329** doesn't do SIGINT handling), but is also used under MW, when
330** the full-fledged event loop is disabled. This way, we can at least
331** interrupt a runaway python program.
332*/
333static void
334scan_event_queue(flush)
335 int flush;
336{
337 register EvQElPtr q;
338
Jack Jansencfadbd41996-08-19 11:36:25 +0000339 q = (EvQElPtr) GetEventQueue()->qHead;
Jack Jansenee23d6e1995-01-27 14:43:25 +0000340
341 for (; q; q = (EvQElPtr)q->qLink) {
342 if (q->evtQWhat == keyDown &&
343 (char)q->evtQMessage == '.' &&
344 (q->evtQModifiers & cmdKey) != 0) {
345 if ( flush )
346 FlushEvents(keyDownMask, 0);
347 interrupted = 1;
348 break;
349 }
350 }
351}
352
Jack Jansen7e944041997-02-20 15:23:18 +0000353#define TICKCOUNT 6
354
Jack Jansenee23d6e1995-01-27 14:43:25 +0000355int
356PyOS_InterruptOccurred()
357{
Jack Jansen7e944041997-02-20 15:23:18 +0000358 static unsigned long nextticktime;
359 unsigned long curticktime;
360
Guido van Rossume7134aa1995-02-26 10:20:53 +0000361 if (PyMac_DoYieldEnabled < 0)
362 return 0;
Jack Jansen7e944041997-02-20 15:23:18 +0000363 curticktime = (unsigned long)LMGetTicks();
364 if ( curticktime < nextticktime )
365 return 0;
366 nextticktime = curticktime + TICKCOUNT;
Jack Jansenee23d6e1995-01-27 14:43:25 +0000367#ifdef THINK_C
368 scan_event_queue(1);
369#endif
370 PyMac_Yield();
371 if (interrupted) {
372 interrupted = 0;
373 return 1;
374 }
375 return 0;
376}
377
378/* intrpeek() is like intrcheck(), but it doesn't flush the events. The
379** idea is that you call intrpeek() somewhere in a busy-wait loop, and return
380** None as soon as it returns 1. The mainloop will then pick up the cmd-. soon
381** thereafter.
382*/
383static int
384intrpeek()
385{
386#ifdef THINK_C
387 scan_event_queue(0);
388#endif
389 return interrupted;
390}
391
392/* Check whether we are in the foreground */
393int
394PyMac_InForeground()
395{
396 static ProcessSerialNumber ours;
397 static inited;
398 ProcessSerialNumber curfg;
399 Boolean eq;
400
401 if ( inited == 0 )
402 (void)GetCurrentProcess(&ours);
403 inited = 1;
404 if ( GetFrontProcess(&curfg) < 0 )
405 eq = 1;
406 else if ( SameProcess(&ours, &curfg, &eq) < 0 )
407 eq = 1;
408 return (int)eq;
409
410}
411
Jack Jansenf93c72a1994-12-14 14:07:50 +0000412/*
Jack Jansene8e8ae01995-01-26 16:36:45 +0000413** Set yield timeouts
Jack Jansenf93c72a1994-12-14 14:07:50 +0000414*/
Jack Jansene8e8ae01995-01-26 16:36:45 +0000415void
416PyMac_SetYield(long fgi, long fgy, long bgi, long bgy)
417{
418 interval_fg = fgi;
419 yield_fg = fgy;
420 interval_bg = bgi;
421 yield_bg = bgy;
422}
423
424/*
Jack Jansena76382a1995-02-02 14:25:56 +0000425** Handle an event, either one found in the mainloop eventhandler or
426** one passed back from the python program.
427*/
428void
429PyMac_HandleEvent(evp)
430 EventRecord *evp;
431{
Jack Jansena76382a1995-02-02 14:25:56 +0000432
433#ifdef __MWERKS__
Jack Jansen38e97661995-11-10 14:53:00 +0000434 {
435 int siouxdidit;
436
437 /* If SIOUX wants it we're done */
438 siouxdidit = SIOUXHandleOneEvent(evp);
439 if ( siouxdidit )
440 return;
441 }
Jack Jansena76382a1995-02-02 14:25:56 +0000442#else
443 /* Other compilers are just unlucky: we only weed out clicks in other applications */
444 if ( evp->what == mouseDown ) {
Jack Jansen847e89e1995-08-31 13:57:40 +0000445 WindowPtr wp;
446
Jack Jansen38e97661995-11-10 14:53:00 +0000447 if ( FindWindow(evp->where, &wp) == inSysWindow ) {
Jack Jansena76382a1995-02-02 14:25:56 +0000448 SystemClick(evp, wp);
Jack Jansen38e97661995-11-10 14:53:00 +0000449 return;
450 }
Jack Jansena76382a1995-02-02 14:25:56 +0000451 }
452#endif /* !__MWERKS__ */
453}
454
455/*
Jack Jansene8e8ae01995-01-26 16:36:45 +0000456** Yield the CPU to other tasks.
457*/
Jack Jansencfadbd41996-08-19 11:36:25 +0000458static void
Jack Jansenf6865f71996-09-04 15:24:59 +0000459PyMac_DoYield(int maysleep)
Jack Jansenf93c72a1994-12-14 14:07:50 +0000460{
461 EventRecord ev;
Jack Jansene8e8ae01995-01-26 16:36:45 +0000462 long yield;
Jack Jansene8e8ae01995-01-26 16:36:45 +0000463 static int no_waitnextevent = -1;
464 int gotone;
465
466 if ( no_waitnextevent < 0 ) {
467 no_waitnextevent = (NGetTrapAddress(_WaitNextEvent, ToolTrap) ==
468 NGetTrapAddress(_Unimplemented, ToolTrap));
469 }
Jack Jansenf93c72a1994-12-14 14:07:50 +0000470
Jack Jansenf6865f71996-09-04 15:24:59 +0000471 lastyield = TickCount();
Jack Jansenee23d6e1995-01-27 14:43:25 +0000472#ifndef THINK_C
Jack Jansenf6865f71996-09-04 15:24:59 +0000473 /* Under think this has been done before in intrcheck() or intrpeek() */
474 if (PyMac_DoYieldEnabled >= 0)
Jack Jansenee23d6e1995-01-27 14:43:25 +0000475 scan_event_queue(0);
476#endif
Jack Jansenf6865f71996-09-04 15:24:59 +0000477 if (PyMac_DoYieldEnabled == 0)
Jack Jansene8e8ae01995-01-26 16:36:45 +0000478 return;
479
Jack Jansenee23d6e1995-01-27 14:43:25 +0000480 in_foreground = PyMac_InForeground();
Jack Jansenf6865f71996-09-04 15:24:59 +0000481 if ( maysleep ) {
482 if ( in_foreground )
483 yield = yield_fg;
484 else
485 yield = yield_bg;
486 } else {
487 yield = 0;
488 }
489
Jack Jansene8e8ae01995-01-26 16:36:45 +0000490 while ( 1 ) {
491 if ( no_waitnextevent ) {
492 SystemTask();
Jack Jansenee23d6e1995-01-27 14:43:25 +0000493 gotone = GetNextEvent(MAINLOOP_EVENTMASK, &ev);
Jack Jansene8e8ae01995-01-26 16:36:45 +0000494 } else {
Jack Jansenee23d6e1995-01-27 14:43:25 +0000495 gotone = WaitNextEvent(MAINLOOP_EVENTMASK, &ev, yield, NULL);
Jack Jansene8e8ae01995-01-26 16:36:45 +0000496 }
497 /* Get out quickly if nothing interesting is happening */
498 if ( !gotone || ev.what == nullEvent )
499 break;
Jack Jansena76382a1995-02-02 14:25:56 +0000500 PyMac_HandleEvent(&ev);
Jack Jansenf93c72a1994-12-14 14:07:50 +0000501 }
Jack Jansene8e8ae01995-01-26 16:36:45 +0000502}
503
504/*
505** Yield the CPU to other tasks if opportune
506*/
507void
508PyMac_Yield() {
509 long iv;
510
Jack Jansenee23d6e1995-01-27 14:43:25 +0000511 if ( in_foreground )
Jack Jansene8e8ae01995-01-26 16:36:45 +0000512 iv = interval_fg;
Jack Jansenee23d6e1995-01-27 14:43:25 +0000513 else
514 iv = interval_bg;
Jack Jansene8e8ae01995-01-26 16:36:45 +0000515 if ( TickCount() > lastyield + iv )
Jack Jansenf6865f71996-09-04 15:24:59 +0000516 PyMac_DoYield(1);
Jack Jansene8e8ae01995-01-26 16:36:45 +0000517}
518
Jack Jansenf6865f71996-09-04 15:24:59 +0000519#ifdef USE_MACTCP
Jack Jansene8e8ae01995-01-26 16:36:45 +0000520/*
521** Idle routine for busy-wait loops.
522** Gives up CPU, handles events and returns true if an interrupt is pending
523** (but not actually handled yet).
524*/
525int
526PyMac_Idle()
527{
Jack Jansenf6865f71996-09-04 15:24:59 +0000528 PyMac_DoYield(1);
Jack Jansene8e8ae01995-01-26 16:36:45 +0000529 return intrpeek();
Jack Jansenf93c72a1994-12-14 14:07:50 +0000530}
Jack Jansenf6865f71996-09-04 15:24:59 +0000531#endif
532
Jack Jansen74162f31995-02-15 22:58:33 +0000533/*
Jack Jansen3469e991996-09-06 00:30:45 +0000534** Install our menu bar.
535*/
536void
537PyMac_InitMenuBar()
538{
539 Handle bar;
540 MenuHandle applemenu;
541
542 if ( (bar=GetMenuBar()) == NULL ) return;
543 if ( (applemenu=GetMHandle(SIOUX_APPLEID)) == NULL ) return;
544 SetMenuItemText(applemenu, 1, "\pAbout Python...");
545}
546
547/*
548** Our replacement about box
549*/
550void
551SIOUXDoAboutBox(void)
552{
553 DialogPtr theDialog;
Jack Jansend617c571996-09-22 22:14:30 +0000554 WindowRef theWindow;
555 CGrafPtr thePort;
Jack Jansen3469e991996-09-06 00:30:45 +0000556 short item;
Jack Jansend617c571996-09-22 22:14:30 +0000557 short xpos, ypos, width, height, swidth, sheight;
Jack Jansen3469e991996-09-06 00:30:45 +0000558
559 if( (theDialog = GetNewDialog(ABOUT_ID, NULL, (WindowPtr)-1)) == NULL )
560 return;
Jack Jansend617c571996-09-22 22:14:30 +0000561 theWindow = GetDialogWindow(theDialog);
562 thePort = GetWindowPort(theWindow);
563 width = thePort->portRect.right - thePort->portRect.left;
564 height = thePort->portRect.bottom - thePort->portRect.top;
565 swidth = qd.screenBits.bounds.right - qd.screenBits.bounds.left;
566 sheight = qd.screenBits.bounds.bottom - qd.screenBits.bounds.top - LMGetMBarHeight();
567 xpos = (swidth-width)/2;
Jack Jansen0e06e7e1996-09-23 15:51:06 +0000568 ypos = (sheight-height)/5 + LMGetMBarHeight();
Jack Jansend617c571996-09-22 22:14:30 +0000569 MoveWindow(theWindow, xpos, ypos, 0);
570 ShowWindow(theWindow);
Jack Jansen3469e991996-09-06 00:30:45 +0000571 ModalDialog(NULL, &item);
572 DisposeDialog(theDialog);
573}
574
575/*
Jack Jansen74162f31995-02-15 22:58:33 +0000576** Returns true if the argument has a resource fork, and it contains
577** a 'PYC ' resource of the correct name
578*/
579int
580PyMac_FindResourceModule(module, filename)
581char *module;
582char *filename;
583{
584 FSSpec fss;
585 FInfo finfo;
586 short oldrh, filerh;
587 int ok;
588 Handle h;
589
Jack Jansen8096daa1996-11-09 18:43:44 +0000590 if ( strcmp(filename, PyMac_ApplicationPath) == 0 ) {
591 /*
592 ** Special case: the application itself. Use a shortcut to
593 ** forestall opening and closing the application numerous times
594 ** (which is dead slow when running from CDROM)
595 */
596 oldrh = CurResFile();
597 UseResFile(PyMac_AppRefNum);
598 filerh = -1;
599 } else {
600 if ( FSMakeFSSpec(0, 0, Pstring(filename), &fss) != noErr )
601 return 0; /* It doesn't exist */
602 if ( FSpGetFInfo(&fss, &finfo) != noErr )
603 return 0; /* shouldn't happen, I guess */
604 oldrh = CurResFile();
605 filerh = FSpOpenResFile(&fss, fsRdPerm);
606 if ( filerh == -1 )
607 return 0;
608 UseResFile(filerh);
609 }
Jack Jansen74162f31995-02-15 22:58:33 +0000610 SetResLoad(0);
611 h = Get1NamedResource('PYC ', Pstring(module));
612 SetResLoad(1);
613 ok = (h != NULL);
Jack Jansen8096daa1996-11-09 18:43:44 +0000614 if ( filerh != -1 )
615 CloseResFile(filerh);
Jack Jansen74162f31995-02-15 22:58:33 +0000616 UseResFile(oldrh);
617 return ok;
618}
619
620/*
621** Load the specified module from a resource
622*/
623PyObject *
624PyMac_LoadResourceModule(module, filename)
625char *module;
626char *filename;
627{
628 FSSpec fss;
629 FInfo finfo;
630 short oldrh, filerh;
Jack Jansen74162f31995-02-15 22:58:33 +0000631 Handle h;
632 OSErr err;
633 PyObject *m, *co;
634 long num, size;
635
Jack Jansen8096daa1996-11-09 18:43:44 +0000636 if ( strcmp(filename, PyMac_ApplicationPath) == 0 ) {
637 /*
638 ** Special case: the application itself. Use a shortcut to
639 ** forestall opening and closing the application numerous times
640 ** (which is dead slow when running from CDROM)
641 */
642 oldrh = CurResFile();
643 UseResFile(PyMac_AppRefNum);
644 filerh = -1;
645 } else {
646 if ( (err=FSMakeFSSpec(0, 0, Pstring(filename), &fss)) != noErr )
647 goto error;
648 if ( (err=FSpGetFInfo(&fss, &finfo)) != noErr )
649 goto error;
650 oldrh = CurResFile();
651 filerh = FSpOpenResFile(&fss, fsRdPerm);
652 if ( filerh == -1 ) {
653 err = ResError();
654 goto error;
655 }
656 UseResFile(filerh);
Jack Jansen74162f31995-02-15 22:58:33 +0000657 }
Jack Jansen74162f31995-02-15 22:58:33 +0000658 h = Get1NamedResource('PYC ', Pstring(module));
659 if ( h == NULL ) {
660 err = ResError();
661 goto error;
662 }
663 HLock(h);
664 /*
665 ** XXXX The next few lines are intimately tied to the format of pyc
666 ** files. I'm not sure whether this code should be here or in import.c -- Jack
667 */
668 size = GetHandleSize(h);
669 if ( size < 8 ) {
670 PyErr_SetString(PyExc_ImportError, "Resource too small");
Guido van Rossumc3d1c8e1995-02-18 15:01:31 +0000671 co = NULL;
Jack Jansen74162f31995-02-15 22:58:33 +0000672 } else {
673 num = (*h)[0] & 0xff;
674 num = num | (((*h)[1] & 0xff) << 8);
675 num = num | (((*h)[2] & 0xff) << 16);
676 num = num | (((*h)[3] & 0xff) << 24);
677 if ( num != PyImport_GetMagicNumber() ) {
678 PyErr_SetString(PyExc_ImportError, "Bad MAGIC in resource");
679 co = NULL;
680 } else {
681 co = PyMarshal_ReadObjectFromString((*h)+8, size-8);
682 }
683 }
684 HUnlock(h);
Jack Jansen8096daa1996-11-09 18:43:44 +0000685 if ( filerh != -1 )
686 CloseResFile(filerh);
Jack Jansen74162f31995-02-15 22:58:33 +0000687 UseResFile(oldrh);
688 if ( co ) {
689 m = PyImport_ExecCodeModule(module, co);
690 Py_DECREF(co);
691 } else {
692 m = NULL;
693 }
694 return m;
695error:
696 {
697 char buf[512];
698
Guido van Rossumc3d1c8e1995-02-18 15:01:31 +0000699 sprintf(buf, "%s: %s", filename, PyMac_StrError(err));
Jack Jansen74162f31995-02-15 22:58:33 +0000700 PyErr_SetString(PyExc_ImportError, buf);
701 return NULL;
702 }
703}
Guido van Rossum24a45e31995-02-20 23:45:53 +0000704
Jack Jansen3ec804a1995-02-20 15:56:10 +0000705/*
706** Helper routine for GetDirectory
707*/
Guido van Rossum24a45e31995-02-20 23:45:53 +0000708static pascal short
Jack Jansen819f1771995-08-14 12:35:10 +0000709myhook_proc(short item, DialogPtr theDialog, struct hook_args *dataptr)
Jack Jansen3ec804a1995-02-20 15:56:10 +0000710{
Jack Jansen819f1771995-08-14 12:35:10 +0000711 if ( item == sfHookFirstCall && dataptr->prompt) {
712 Handle prompth;
713 short type;
714 Rect rect;
715
716 GetDialogItem(theDialog, PROMPT_ITEM, &type, &prompth, &rect);
717 if ( prompth )
718 SetDialogItemText(prompth, (unsigned char *)dataptr->prompt);
719 } else
Jack Jansen3ec804a1995-02-20 15:56:10 +0000720 if ( item == SELECTCUR_ITEM ) {
721 item = sfItemCancelButton;
Jack Jansen819f1771995-08-14 12:35:10 +0000722 dataptr->selectcur_hit = 1;
Jack Jansen3ec804a1995-02-20 15:56:10 +0000723 }
724 return item;
725}
726
727/*
728** Ask the user for a directory. I still can't understand
729** why Apple doesn't provide a standard solution for this...
730*/
731int
Jack Jansen819f1771995-08-14 12:35:10 +0000732PyMac_GetDirectory(dirfss, prompt)
Jack Jansen3ec804a1995-02-20 15:56:10 +0000733 FSSpec *dirfss;
Jack Jansen819f1771995-08-14 12:35:10 +0000734 char *prompt;
Jack Jansen3ec804a1995-02-20 15:56:10 +0000735{
736 static SFTypeList list = {'fldr', 0, 0, 0};
737 static Point where = {-1, -1};
Jack Jansen3ec804a1995-02-20 15:56:10 +0000738 StandardFileReply reply;
Jack Jansen819f1771995-08-14 12:35:10 +0000739 struct hook_args hook_args;
Jack Jansen3ec804a1995-02-20 15:56:10 +0000740
741 if ( !upp_inited ) {
742 myhook_upp = NewDlgHookYDProc(myhook_proc);
743 upp_inited = 1;
744 }
Jack Jansen819f1771995-08-14 12:35:10 +0000745 if ( prompt && *prompt )
746 hook_args.prompt = (char *)Pstring(prompt);
747 else
748 hook_args.prompt = NULL;
749 hook_args.selectcur_hit = 0;
Guido van Rossum24a45e31995-02-20 23:45:53 +0000750 CustomGetFile((FileFilterYDUPP)0, 1, list, &reply, GETDIR_ID, where, myhook_upp,
Jack Jansen819f1771995-08-14 12:35:10 +0000751 NULL, NULL, NULL, (void *)&hook_args);
Jack Jansen3ec804a1995-02-20 15:56:10 +0000752
753 reply.sfFile.name[0] = 0;
754 if( FSMakeFSSpec(reply.sfFile.vRefNum, reply.sfFile.parID, reply.sfFile.name, dirfss) )
755 return 0;
Jack Jansen819f1771995-08-14 12:35:10 +0000756 return hook_args.selectcur_hit;
757}
758
759/*
760** Slightly extended StandardGetFile: accepts a prompt */
761void PyMac_PromptGetFile(short numTypes, ConstSFTypeListPtr typeList,
762 StandardFileReply *reply, char *prompt)
763{
764 static Point where = {-1, -1};
765 struct hook_args hook_args;
766
767 if ( !upp_inited ) {
768 myhook_upp = NewDlgHookYDProc(myhook_proc);
769 upp_inited = 1;
770 }
771 if ( prompt && *prompt )
772 hook_args.prompt = (char *)Pstring(prompt);
773 else
774 hook_args.prompt = NULL;
775 hook_args.selectcur_hit = 0;
776 CustomGetFile((FileFilterYDUPP)0, numTypes, typeList, reply, GETFILEPROMPT_ID, where,
777 myhook_upp, NULL, NULL, NULL, (void *)&hook_args);
Jack Jansen3ec804a1995-02-20 15:56:10 +0000778}
Jack Jansen5f653091995-01-18 13:53:49 +0000779
Guido van Rossumcf27c2d1995-01-25 23:06:44 +0000780/* Convert a 4-char string object argument to an OSType value */
Jack Jansen5f653091995-01-18 13:53:49 +0000781int
Guido van Rossumcf27c2d1995-01-25 23:06:44 +0000782PyMac_GetOSType(PyObject *v, OSType *pr)
Jack Jansen5f653091995-01-18 13:53:49 +0000783{
784 if (!PyString_Check(v) || PyString_Size(v) != 4) {
785 PyErr_SetString(PyExc_TypeError,
786 "OSType arg must be string of 4 chars");
787 return 0;
788 }
789 memcpy((char *)pr, PyString_AsString(v), 4);
790 return 1;
791}
792
Guido van Rossumcf27c2d1995-01-25 23:06:44 +0000793/* Convert an OSType value to a 4-char string object */
794PyObject *
795PyMac_BuildOSType(OSType t)
796{
797 return PyString_FromStringAndSize((char *)&t, 4);
798}
799
Jack Jansend1f06311996-08-01 15:23:54 +0000800/* Convert an NumVersion value to a 4-element tuple */
801PyObject *
802PyMac_BuildNumVersion(NumVersion t)
803{
804 return Py_BuildValue("(hhhh)", t.majorRev, t.minorAndBugRev, t.stage, t.nonRelRev);
805}
806
Guido van Rossumcf27c2d1995-01-25 23:06:44 +0000807
808/* Convert a Python string object to a Str255 */
Jack Jansen5f653091995-01-18 13:53:49 +0000809int
Guido van Rossum8f691791995-01-18 23:57:26 +0000810PyMac_GetStr255(PyObject *v, Str255 pbuf)
Jack Jansen5f653091995-01-18 13:53:49 +0000811{
812 int len;
813 if (!PyString_Check(v) || (len = PyString_Size(v)) > 255) {
814 PyErr_SetString(PyExc_TypeError,
815 "Str255 arg must be string of at most 255 chars");
816 return 0;
817 }
818 pbuf[0] = len;
819 memcpy((char *)(pbuf+1), PyString_AsString(v), len);
820 return 1;
821}
822
Guido van Rossumcf27c2d1995-01-25 23:06:44 +0000823/* Convert a Str255 to a Python string object */
824PyObject *
825PyMac_BuildStr255(Str255 s)
826{
827 return PyString_FromStringAndSize((char *)&s[1], (int)s[0]);
828}
829
830
Jack Jansen5f653091995-01-18 13:53:49 +0000831/*
Guido van Rossumcf27c2d1995-01-25 23:06:44 +0000832** Convert a Python object to an FSSpec.
833** The object may either be a full pathname or a triple
834** (vrefnum, dirid, path).
Jack Jansen5f653091995-01-18 13:53:49 +0000835** NOTE: This routine will fail on pre-sys7 machines.
836** The caller is responsible for not calling this routine
837** in those cases (which is fine, since everyone calling
838** this is probably sys7 dependent anyway).
839*/
840int
Guido van Rossum8f691791995-01-18 23:57:26 +0000841PyMac_GetFSSpec(PyObject *v, FSSpec *fs)
Jack Jansen5f653091995-01-18 13:53:49 +0000842{
843 Str255 path;
844 short refnum;
845 long parid;
846 OSErr err;
Jack Jansene8e8ae01995-01-26 16:36:45 +0000847 FSSpec *fs2;
Jack Jansen5f653091995-01-18 13:53:49 +0000848
Jack Jansene8e8ae01995-01-26 16:36:45 +0000849 /* first check whether it already is an FSSpec */
850 fs2 = mfs_GetFSSpecFSSpec(v);
851 if ( fs2 ) {
Jack Jansen3ec804a1995-02-20 15:56:10 +0000852 (void)FSMakeFSSpec(fs2->vRefNum, fs2->parID, fs2->name, fs);
Jack Jansene8e8ae01995-01-26 16:36:45 +0000853 return 1;
854 }
Jack Jansen5f653091995-01-18 13:53:49 +0000855 if ( PyString_Check(v) ) {
856 /* It's a pathname */
Guido van Rossum9aa3d131995-01-21 13:46:04 +0000857 if( !PyArg_Parse(v, "O&", PyMac_GetStr255, &path) )
Jack Jansen5f653091995-01-18 13:53:49 +0000858 return 0;
Jack Jansen378815c1996-03-06 16:21:34 +0000859 refnum = 0; /* XXXX Should get CurWD here?? */
Jack Jansen5f653091995-01-18 13:53:49 +0000860 parid = 0;
861 } else {
Guido van Rossum9aa3d131995-01-21 13:46:04 +0000862 if( !PyArg_Parse(v, "(hlO&); FSSpec should be fullpath or (vrefnum,dirid,path)",
863 &refnum, &parid, PyMac_GetStr255, &path)) {
Jack Jansen5f653091995-01-18 13:53:49 +0000864 return 0;
Guido van Rossum9aa3d131995-01-21 13:46:04 +0000865 }
Jack Jansen5f653091995-01-18 13:53:49 +0000866 }
867 err = FSMakeFSSpec(refnum, parid, path, fs);
868 if ( err && err != fnfErr ) {
Guido van Rossum9aa3d131995-01-21 13:46:04 +0000869 PyErr_Mac(PyExc_ValueError, err);
Jack Jansen5f653091995-01-18 13:53:49 +0000870 return 0;
871 }
872 return 1;
873}
874
Guido van Rossum8f691791995-01-18 23:57:26 +0000875
Guido van Rossumcf27c2d1995-01-25 23:06:44 +0000876/* Convert a Python object to a Rect.
Guido van Rossum5279ec61995-01-26 22:56:59 +0000877 The object must be a (left, top, right, bottom) tuple.
878 (This differs from the order in the struct but is consistent with
879 the arguments to SetRect(), and also with STDWIN). */
Guido van Rossumcf27c2d1995-01-25 23:06:44 +0000880int
881PyMac_GetRect(PyObject *v, Rect *r)
Guido van Rossum8f691791995-01-18 23:57:26 +0000882{
Guido van Rossum5279ec61995-01-26 22:56:59 +0000883 return PyArg_Parse(v, "(hhhh)", &r->left, &r->top, &r->right, &r->bottom);
Guido van Rossum8f691791995-01-18 23:57:26 +0000884}
Guido van Rossumb3404661995-01-22 18:36:13 +0000885
Guido van Rossumcf27c2d1995-01-25 23:06:44 +0000886/* Convert a Rect to a Python object */
Guido van Rossumb3404661995-01-22 18:36:13 +0000887PyObject *
Guido van Rossumcf27c2d1995-01-25 23:06:44 +0000888PyMac_BuildRect(Rect *r)
Guido van Rossumb3404661995-01-22 18:36:13 +0000889{
Guido van Rossum5279ec61995-01-26 22:56:59 +0000890 return Py_BuildValue("(hhhh)", r->left, r->top, r->right, r->bottom);
Guido van Rossumcf27c2d1995-01-25 23:06:44 +0000891}
892
893
894/* Convert a Python object to a Point.
Guido van Rossum5279ec61995-01-26 22:56:59 +0000895 The object must be a (h, v) tuple.
896 (This differs from the order in the struct but is consistent with
897 the arguments to SetPoint(), and also with STDWIN). */
Guido van Rossumcf27c2d1995-01-25 23:06:44 +0000898int
899PyMac_GetPoint(PyObject *v, Point *p)
900{
Guido van Rossum5279ec61995-01-26 22:56:59 +0000901 return PyArg_Parse(v, "(hh)", &p->h, &p->v);
Guido van Rossumcf27c2d1995-01-25 23:06:44 +0000902}
903
904/* Convert a Point to a Python object */
905PyObject *
906PyMac_BuildPoint(Point p)
907{
Guido van Rossum5279ec61995-01-26 22:56:59 +0000908 return Py_BuildValue("(hh)", p.h, p.v);
Guido van Rossumcf27c2d1995-01-25 23:06:44 +0000909}
910
911
912/* Convert a Python object to an EventRecord.
913 The object must be a (what, message, when, (v, h), modifiers) tuple. */
914int
915PyMac_GetEventRecord(PyObject *v, EventRecord *e)
916{
917 return PyArg_Parse(v, "(hll(hh)h)",
918 &e->what,
919 &e->message,
920 &e->when,
Guido van Rossumcf27c2d1995-01-25 23:06:44 +0000921 &e->where.h,
Guido van Rossum5279ec61995-01-26 22:56:59 +0000922 &e->where.v,
Guido van Rossumcf27c2d1995-01-25 23:06:44 +0000923 &e->modifiers);
924}
925
926/* Convert a Rect to an EventRecord object */
927PyObject *
928PyMac_BuildEventRecord(EventRecord *e)
929{
930 return Py_BuildValue("(hll(hh)h)",
931 e->what,
932 e->message,
933 e->when,
Guido van Rossumcf27c2d1995-01-25 23:06:44 +0000934 e->where.h,
Guido van Rossum5279ec61995-01-26 22:56:59 +0000935 e->where.v,
Guido van Rossumcf27c2d1995-01-25 23:06:44 +0000936 e->modifiers);
Guido van Rossumb3404661995-01-22 18:36:13 +0000937}
Jack Jansenfa4d5d01995-11-15 15:19:29 +0000938
939/* Convert Python object to Fixed */
940int
941PyMac_GetFixed(PyObject *v, Fixed *f)
942{
943 double d;
944
945 if( !PyArg_Parse(v, "d", &d))
946 return 0;
947 *f = (Fixed)(d * 0x10000);
Jack Jansen31dd5c01996-05-31 13:01:39 +0000948 return 1;
Jack Jansenfa4d5d01995-11-15 15:19:29 +0000949}
950
951/* Convert a Point to a Python object */
952PyObject *
953PyMac_BuildFixed(Fixed f)
954{
955 double d;
956
957 d = f;
958 d = d / 0x10000;
959 return Py_BuildValue("d", d);
960}
961