blob: a99023b433d376dacce59a1c14ff833751fa689d [file] [log] [blame]
Guido van Rossumb3404661995-01-22 18:36:13 +00001/***********************************************************
2Copyright 1991-1995 by Stichting Mathematisch Centrum, Amsterdam,
3The 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
25#include "Python.h"
26#include "macglue.h"
27
28#include <OSUtils.h> /* for Set(Current)A5 */
Jack Jansene8e8ae01995-01-26 16:36:45 +000029#include <Files.h>
Jack Jansenf93c72a1994-12-14 14:07:50 +000030#include <Resources.h>
31#include <Memory.h>
32#include <Events.h>
33#include <Windows.h>
34#include <Desk.h>
Jack Jansene8e8ae01995-01-26 16:36:45 +000035#include <Traps.h>
Jack Jansenee23d6e1995-01-27 14:43:25 +000036#include <Processes.h>
Guido van Rossumcc0d8791995-01-30 08:57:13 +000037#ifdef THINK_C
38#include <OSEvents.h> /* For EvQElPtr */
39#endif
Jack Jansenee23d6e1995-01-27 14:43:25 +000040
41#include <signal.h>
Jack Jansene8e8ae01995-01-26 16:36:45 +000042
43#ifdef __MWERKS__
Jack Jansenee23d6e1995-01-27 14:43:25 +000044/*
45** With MW we can pass the event off to the console window, so
46** we might as well handle all events.
47*/
Jack Jansene8e8ae01995-01-26 16:36:45 +000048#include <SIOUX.h>
Jack Jansenee23d6e1995-01-27 14:43:25 +000049#define MAINLOOP_EVENTMASK everyEvent
50#else
51/*
52** For other compilers we're more careful, since we can't handle
53** things like updates (and they'll keep coming back if we don't
54** handle them)
55*/
56#define MAINLOOP_EVENTMASK (mDownMask|keyDownMask|osMask)
Jack Jansene8e8ae01995-01-26 16:36:45 +000057#endif /* __MWERKS__ */
58
59#include <signal.h>
Jack Jansenf93c72a1994-12-14 14:07:50 +000060
Guido van Rossumb3404661995-01-22 18:36:13 +000061/* XXX We should include Errors.h here, but it has a name conflict
Jack Jansen5f653091995-01-18 13:53:49 +000062** with the python errors.h. */
63#define fnfErr -43
64
Jack Jansene8e8ae01995-01-26 16:36:45 +000065/* Declared in macfsmodule.c: */
66extern FSSpec *mfs_GetFSSpecFSSpec();
67
Jack Jansenee23d6e1995-01-27 14:43:25 +000068/* Interrupt code variables: */
69static int interrupted; /* Set to true when cmd-. seen */
70static RETSIGTYPE intcatcher Py_PROTO((int));
71
Jack Jansene8e8ae01995-01-26 16:36:45 +000072/*
73** We attempt to be a good citizen by giving up the CPU periodically.
74** When in the foreground we do this less often and for shorter periods
75** than when in the background. At this time we also check for events and
Jack Jansenee23d6e1995-01-27 14:43:25 +000076** pass them off to SIOUX, if compiling with mwerks.
Jack Jansene8e8ae01995-01-26 16:36:45 +000077** The counts here are in ticks of 1/60th second.
78** XXXX The initial values here are not based on anything.
79** FG-python gives up the cpu for 1/60th 5 times per second,
80** BG-python for .2 second 10 times per second.
81*/
82static long interval_fg = 12;
83static long interval_bg = 6;
84static long yield_fg = 1;
85static long yield_bg = 12;
Jack Jansenee23d6e1995-01-27 14:43:25 +000086static long lastyield;
87static int in_foreground;
88
89int PyMac_DoYieldEnabled = 1; /* Don't do eventloop when false */
90
Jack Jansene8e8ae01995-01-26 16:36:45 +000091
Jack Jansen5f653091995-01-18 13:53:49 +000092/* Convert C to Pascal string. Returns pointer to static buffer. */
93unsigned char *
94Pstring(char *str)
95{
96 static Str255 buf;
97 int len;
98
99 len = strlen(str);
Guido van Rossum9aa3d131995-01-21 13:46:04 +0000100 if (len > 255)
101 len = 255;
Jack Jansen5f653091995-01-18 13:53:49 +0000102 buf[0] = (unsigned char)len;
103 strncpy((char *)buf+1, str, len);
104 return buf;
105}
106
Jack Jansenf93c72a1994-12-14 14:07:50 +0000107/* Replace strerror with something that might work */
108char *macstrerror(int err)
109{
110 static char buf[256];
111 Handle h;
112 char *str;
113
114 h = GetResource('Estr', err);
115 if ( h ) {
116 HLock(h);
117 str = (char *)*h;
118 memcpy(buf, str+1, (unsigned char)str[0]);
119 HUnlock(h);
120 ReleaseResource(h);
121 } else {
122 sprintf(buf, "Mac OS error code %d", err);
123 }
124 return buf;
125}
126
Guido van Rossumcf27c2d1995-01-25 23:06:44 +0000127/* Exception object shared by all Mac specific modules for Mac OS errors */
128PyObject *PyMac_OSErrException;
129
130/* Initialize and return PyMac_OSErrException */
131PyObject *
132PyMac_GetOSErrException()
133{
134 if (PyMac_OSErrException == NULL)
135 PyMac_OSErrException = PyString_FromString("Mac OS Error");
136 return PyMac_OSErrException;
137}
138
Jack Jansenf93c72a1994-12-14 14:07:50 +0000139/* Set a MAC-specific error from errno, and return NULL; return None if no error */
140PyObject *
Guido van Rossumfffb8bb1995-01-12 12:37:24 +0000141PyErr_Mac(PyObject *eobj, int err)
Jack Jansenf93c72a1994-12-14 14:07:50 +0000142{
143 char *msg;
144 PyObject *v;
Jack Jansenf93c72a1994-12-14 14:07:50 +0000145
Guido van Rossum8f691791995-01-18 23:57:26 +0000146 if (err == 0 && !PyErr_Occurred()) {
Jack Jansenf93c72a1994-12-14 14:07:50 +0000147 Py_INCREF(Py_None);
148 return Py_None;
149 }
Guido van Rossum8f691791995-01-18 23:57:26 +0000150 if (err == -1 && PyErr_Occurred())
151 return NULL;
Jack Jansenf93c72a1994-12-14 14:07:50 +0000152 msg = macstrerror(err);
153 v = Py_BuildValue("(is)", err, msg);
154 PyErr_SetObject(eobj, v);
155 Py_DECREF(v);
156 return NULL;
157}
158
Guido van Rossumcf27c2d1995-01-25 23:06:44 +0000159/* Call PyErr_Mac with PyMac_OSErrException */
160PyObject *
161PyMac_Error(OSErr err)
162{
163 return PyErr_Mac(PyMac_GetOSErrException(), err);
164}
165
Jack Jansenee23d6e1995-01-27 14:43:25 +0000166/* The catcher routine (which may not be used for all compilers) */
167static RETSIGTYPE
168intcatcher(sig)
169 int sig;
170{
171 interrupted = 1;
172 signal(SIGINT, intcatcher);
173}
174
175void
176PyOS_InitInterrupts()
177{
178 if (signal(SIGINT, SIG_IGN) != SIG_IGN)
179 signal(SIGINT, intcatcher);
180}
181
182/*
183** This routine scans the event queue looking for cmd-.
184** This is the only way to get an interrupt under THINK (since it
185** doesn't do SIGINT handling), but is also used under MW, when
186** the full-fledged event loop is disabled. This way, we can at least
187** interrupt a runaway python program.
188*/
189static void
190scan_event_queue(flush)
191 int flush;
192{
193 register EvQElPtr q;
194
195 q = (EvQElPtr) GetEvQHdr()->qHead;
196
197 for (; q; q = (EvQElPtr)q->qLink) {
198 if (q->evtQWhat == keyDown &&
199 (char)q->evtQMessage == '.' &&
200 (q->evtQModifiers & cmdKey) != 0) {
201 if ( flush )
202 FlushEvents(keyDownMask, 0);
203 interrupted = 1;
204 break;
205 }
206 }
207}
208
209int
210PyOS_InterruptOccurred()
211{
212#ifdef THINK_C
213 scan_event_queue(1);
214#endif
215 PyMac_Yield();
216 if (interrupted) {
217 interrupted = 0;
218 return 1;
219 }
220 return 0;
221}
222
223/* intrpeek() is like intrcheck(), but it doesn't flush the events. The
224** idea is that you call intrpeek() somewhere in a busy-wait loop, and return
225** None as soon as it returns 1. The mainloop will then pick up the cmd-. soon
226** thereafter.
227*/
228static int
229intrpeek()
230{
231#ifdef THINK_C
232 scan_event_queue(0);
233#endif
234 return interrupted;
235}
236
237/* Check whether we are in the foreground */
238int
239PyMac_InForeground()
240{
241 static ProcessSerialNumber ours;
242 static inited;
243 ProcessSerialNumber curfg;
244 Boolean eq;
245
246 if ( inited == 0 )
247 (void)GetCurrentProcess(&ours);
248 inited = 1;
249 if ( GetFrontProcess(&curfg) < 0 )
250 eq = 1;
251 else if ( SameProcess(&ours, &curfg, &eq) < 0 )
252 eq = 1;
253 return (int)eq;
254
255}
256
Jack Jansenf93c72a1994-12-14 14:07:50 +0000257/*
Jack Jansene8e8ae01995-01-26 16:36:45 +0000258** Set yield timeouts
Jack Jansenf93c72a1994-12-14 14:07:50 +0000259*/
Jack Jansene8e8ae01995-01-26 16:36:45 +0000260void
261PyMac_SetYield(long fgi, long fgy, long bgi, long bgy)
262{
263 interval_fg = fgi;
264 yield_fg = fgy;
265 interval_bg = bgi;
266 yield_bg = bgy;
267}
268
269/*
270** Yield the CPU to other tasks.
271*/
272static
273PyMac_DoYield()
Jack Jansenf93c72a1994-12-14 14:07:50 +0000274{
275 EventRecord ev;
276 WindowPtr wp;
Jack Jansene8e8ae01995-01-26 16:36:45 +0000277 long yield;
Jack Jansene8e8ae01995-01-26 16:36:45 +0000278 static int no_waitnextevent = -1;
279 int gotone;
280
281 if ( no_waitnextevent < 0 ) {
282 no_waitnextevent = (NGetTrapAddress(_WaitNextEvent, ToolTrap) ==
283 NGetTrapAddress(_Unimplemented, ToolTrap));
284 }
Jack Jansenf93c72a1994-12-14 14:07:50 +0000285
Jack Jansenee23d6e1995-01-27 14:43:25 +0000286 if ( !PyMac_DoYieldEnabled ) {
287#ifndef THINK_C
288 /* Under think this has been done before in intrcheck() or intrpeek() */
289 scan_event_queue(0);
290#endif
Jack Jansene8e8ae01995-01-26 16:36:45 +0000291 return;
Jack Jansenee23d6e1995-01-27 14:43:25 +0000292 }
Jack Jansene8e8ae01995-01-26 16:36:45 +0000293
Jack Jansenee23d6e1995-01-27 14:43:25 +0000294 in_foreground = PyMac_InForeground();
295 if ( in_foreground )
Jack Jansene8e8ae01995-01-26 16:36:45 +0000296 yield = yield_fg;
Jack Jansenee23d6e1995-01-27 14:43:25 +0000297 else
298 yield = yield_bg;
Jack Jansene8e8ae01995-01-26 16:36:45 +0000299 while ( 1 ) {
300 if ( no_waitnextevent ) {
301 SystemTask();
Jack Jansenee23d6e1995-01-27 14:43:25 +0000302 gotone = GetNextEvent(MAINLOOP_EVENTMASK, &ev);
Jack Jansene8e8ae01995-01-26 16:36:45 +0000303 } else {
Jack Jansenee23d6e1995-01-27 14:43:25 +0000304 gotone = WaitNextEvent(MAINLOOP_EVENTMASK, &ev, yield, NULL);
Jack Jansene8e8ae01995-01-26 16:36:45 +0000305 }
306 /* Get out quickly if nothing interesting is happening */
307 if ( !gotone || ev.what == nullEvent )
308 break;
309
Jack Jansene8e8ae01995-01-26 16:36:45 +0000310#ifdef __MWERKS__
311 /* If SIOUX wants it we're done too */
312 (void)SIOUXHandleOneEvent(&ev);
313#else
314 /* Other compilers are just unlucky: we only weed out clicks in other applications */
Jack Jansenf93c72a1994-12-14 14:07:50 +0000315 if ( ev.what == mouseDown ) {
316 if ( FindWindow(ev.where, &wp) == inSysWindow )
317 SystemClick(&ev, wp);
318 }
Jack Jansene8e8ae01995-01-26 16:36:45 +0000319#endif /* !__MWERKS__ */
Jack Jansenf93c72a1994-12-14 14:07:50 +0000320 }
Jack Jansene8e8ae01995-01-26 16:36:45 +0000321 lastyield = TickCount();
322}
323
324/*
325** Yield the CPU to other tasks if opportune
326*/
327void
328PyMac_Yield() {
329 long iv;
330
Jack Jansenee23d6e1995-01-27 14:43:25 +0000331 if ( in_foreground )
Jack Jansene8e8ae01995-01-26 16:36:45 +0000332 iv = interval_fg;
Jack Jansenee23d6e1995-01-27 14:43:25 +0000333 else
334 iv = interval_bg;
Jack Jansene8e8ae01995-01-26 16:36:45 +0000335 if ( TickCount() > lastyield + iv )
336 PyMac_DoYield();
337}
338
339/*
340** Idle routine for busy-wait loops.
341** Gives up CPU, handles events and returns true if an interrupt is pending
342** (but not actually handled yet).
343*/
344int
345PyMac_Idle()
346{
347 PyMac_DoYield();
348 return intrpeek();
Jack Jansenf93c72a1994-12-14 14:07:50 +0000349}
350
Jack Jansen5f653091995-01-18 13:53:49 +0000351
Guido van Rossumcf27c2d1995-01-25 23:06:44 +0000352/* Convert a 4-char string object argument to an OSType value */
Jack Jansen5f653091995-01-18 13:53:49 +0000353int
Guido van Rossumcf27c2d1995-01-25 23:06:44 +0000354PyMac_GetOSType(PyObject *v, OSType *pr)
Jack Jansen5f653091995-01-18 13:53:49 +0000355{
356 if (!PyString_Check(v) || PyString_Size(v) != 4) {
357 PyErr_SetString(PyExc_TypeError,
358 "OSType arg must be string of 4 chars");
359 return 0;
360 }
361 memcpy((char *)pr, PyString_AsString(v), 4);
362 return 1;
363}
364
Guido van Rossumcf27c2d1995-01-25 23:06:44 +0000365/* Convert an OSType value to a 4-char string object */
366PyObject *
367PyMac_BuildOSType(OSType t)
368{
369 return PyString_FromStringAndSize((char *)&t, 4);
370}
371
372
373/* Convert a Python string object to a Str255 */
Jack Jansen5f653091995-01-18 13:53:49 +0000374int
Guido van Rossum8f691791995-01-18 23:57:26 +0000375PyMac_GetStr255(PyObject *v, Str255 pbuf)
Jack Jansen5f653091995-01-18 13:53:49 +0000376{
377 int len;
378 if (!PyString_Check(v) || (len = PyString_Size(v)) > 255) {
379 PyErr_SetString(PyExc_TypeError,
380 "Str255 arg must be string of at most 255 chars");
381 return 0;
382 }
383 pbuf[0] = len;
384 memcpy((char *)(pbuf+1), PyString_AsString(v), len);
385 return 1;
386}
387
Guido van Rossumcf27c2d1995-01-25 23:06:44 +0000388/* Convert a Str255 to a Python string object */
389PyObject *
390PyMac_BuildStr255(Str255 s)
391{
392 return PyString_FromStringAndSize((char *)&s[1], (int)s[0]);
393}
394
395
Jack Jansen5f653091995-01-18 13:53:49 +0000396/*
Guido van Rossumcf27c2d1995-01-25 23:06:44 +0000397** Convert a Python object to an FSSpec.
398** The object may either be a full pathname or a triple
399** (vrefnum, dirid, path).
Jack Jansen5f653091995-01-18 13:53:49 +0000400** NOTE: This routine will fail on pre-sys7 machines.
401** The caller is responsible for not calling this routine
402** in those cases (which is fine, since everyone calling
403** this is probably sys7 dependent anyway).
404*/
405int
Guido van Rossum8f691791995-01-18 23:57:26 +0000406PyMac_GetFSSpec(PyObject *v, FSSpec *fs)
Jack Jansen5f653091995-01-18 13:53:49 +0000407{
408 Str255 path;
409 short refnum;
410 long parid;
411 OSErr err;
Jack Jansene8e8ae01995-01-26 16:36:45 +0000412 FSSpec *fs2;
Jack Jansen5f653091995-01-18 13:53:49 +0000413
Jack Jansene8e8ae01995-01-26 16:36:45 +0000414 /* first check whether it already is an FSSpec */
415 fs2 = mfs_GetFSSpecFSSpec(v);
416 if ( fs2 ) {
417 fs = fs2;
418 return 1;
419 }
Jack Jansen5f653091995-01-18 13:53:49 +0000420 if ( PyString_Check(v) ) {
421 /* It's a pathname */
Guido van Rossum9aa3d131995-01-21 13:46:04 +0000422 if( !PyArg_Parse(v, "O&", PyMac_GetStr255, &path) )
Jack Jansen5f653091995-01-18 13:53:49 +0000423 return 0;
424 refnum = 0; /* XXXX Should get CurWD here... */
425 parid = 0;
426 } else {
Guido van Rossum9aa3d131995-01-21 13:46:04 +0000427 if( !PyArg_Parse(v, "(hlO&); FSSpec should be fullpath or (vrefnum,dirid,path)",
428 &refnum, &parid, PyMac_GetStr255, &path)) {
Jack Jansen5f653091995-01-18 13:53:49 +0000429 return 0;
Guido van Rossum9aa3d131995-01-21 13:46:04 +0000430 }
Jack Jansen5f653091995-01-18 13:53:49 +0000431 }
432 err = FSMakeFSSpec(refnum, parid, path, fs);
433 if ( err && err != fnfErr ) {
Guido van Rossum9aa3d131995-01-21 13:46:04 +0000434 PyErr_Mac(PyExc_ValueError, err);
Jack Jansen5f653091995-01-18 13:53:49 +0000435 return 0;
436 }
437 return 1;
438}
439
Guido van Rossum8f691791995-01-18 23:57:26 +0000440
Guido van Rossumcf27c2d1995-01-25 23:06:44 +0000441
442/* Convert a Python object to a Rect.
Guido van Rossum5279ec61995-01-26 22:56:59 +0000443 The object must be a (left, top, right, bottom) tuple.
444 (This differs from the order in the struct but is consistent with
445 the arguments to SetRect(), and also with STDWIN). */
Guido van Rossumcf27c2d1995-01-25 23:06:44 +0000446int
447PyMac_GetRect(PyObject *v, Rect *r)
Guido van Rossum8f691791995-01-18 23:57:26 +0000448{
Guido van Rossum5279ec61995-01-26 22:56:59 +0000449 return PyArg_Parse(v, "(hhhh)", &r->left, &r->top, &r->right, &r->bottom);
Guido van Rossum8f691791995-01-18 23:57:26 +0000450}
Guido van Rossumb3404661995-01-22 18:36:13 +0000451
Guido van Rossumcf27c2d1995-01-25 23:06:44 +0000452/* Convert a Rect to a Python object */
Guido van Rossumb3404661995-01-22 18:36:13 +0000453PyObject *
Guido van Rossumcf27c2d1995-01-25 23:06:44 +0000454PyMac_BuildRect(Rect *r)
Guido van Rossumb3404661995-01-22 18:36:13 +0000455{
Guido van Rossum5279ec61995-01-26 22:56:59 +0000456 return Py_BuildValue("(hhhh)", r->left, r->top, r->right, r->bottom);
Guido van Rossumcf27c2d1995-01-25 23:06:44 +0000457}
458
459
460/* Convert a Python object to a Point.
Guido van Rossum5279ec61995-01-26 22:56:59 +0000461 The object must be a (h, v) tuple.
462 (This differs from the order in the struct but is consistent with
463 the arguments to SetPoint(), and also with STDWIN). */
Guido van Rossumcf27c2d1995-01-25 23:06:44 +0000464int
465PyMac_GetPoint(PyObject *v, Point *p)
466{
Guido van Rossum5279ec61995-01-26 22:56:59 +0000467 return PyArg_Parse(v, "(hh)", &p->h, &p->v);
Guido van Rossumcf27c2d1995-01-25 23:06:44 +0000468}
469
470/* Convert a Point to a Python object */
471PyObject *
472PyMac_BuildPoint(Point p)
473{
Guido van Rossum5279ec61995-01-26 22:56:59 +0000474 return Py_BuildValue("(hh)", p.h, p.v);
Guido van Rossumcf27c2d1995-01-25 23:06:44 +0000475}
476
477
478/* Convert a Python object to an EventRecord.
479 The object must be a (what, message, when, (v, h), modifiers) tuple. */
480int
481PyMac_GetEventRecord(PyObject *v, EventRecord *e)
482{
483 return PyArg_Parse(v, "(hll(hh)h)",
484 &e->what,
485 &e->message,
486 &e->when,
Guido van Rossumcf27c2d1995-01-25 23:06:44 +0000487 &e->where.h,
Guido van Rossum5279ec61995-01-26 22:56:59 +0000488 &e->where.v,
Guido van Rossumcf27c2d1995-01-25 23:06:44 +0000489 &e->modifiers);
490}
491
492/* Convert a Rect to an EventRecord object */
493PyObject *
494PyMac_BuildEventRecord(EventRecord *e)
495{
496 return Py_BuildValue("(hll(hh)h)",
497 e->what,
498 e->message,
499 e->when,
Guido van Rossumcf27c2d1995-01-25 23:06:44 +0000500 e->where.h,
Guido van Rossum5279ec61995-01-26 22:56:59 +0000501 e->where.v,
Guido van Rossumcf27c2d1995-01-25 23:06:44 +0000502 e->modifiers);
Guido van Rossumb3404661995-01-22 18:36:13 +0000503}