blob: feb148feecb7371ec78b683e1f5126151e76b254 [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 Jansen3469e991996-09-06 00:30:45 +000074/* The ID of the Sioux apple menu */
75#define SIOUX_APPLEID 32000
76
Jack Jansenee23d6e1995-01-27 14:43:25 +000077#include <signal.h>
Jack Jansen74162f31995-02-15 22:58:33 +000078#include <stdio.h>
Jack Jansene8e8ae01995-01-26 16:36:45 +000079
Jack Jansenee23d6e1995-01-27 14:43:25 +000080/*
Jack Jansend1f06311996-08-01 15:23:54 +000081** When less than this amount of stackspace is left we
82** raise a MemoryError.
83*/
84#ifndef MINIMUM_STACK_SIZE
Jack Jansend1f06311996-08-01 15:23:54 +000085#define MINIMUM_STACK_SIZE 8192
Jack Jansend1f06311996-08-01 15:23:54 +000086#endif
87
Jack Jansen340eb882001-02-02 22:40:28 +000088#if TARGET_API_MAC_CARBON
89/*
90** On MacOSX StackSpace() lies: it gives the distance from heap end to stack pointer,
91** but the stack cannot grow that far due to rlimit values. We cannot get at this value
92** from Carbon, so we set a maximum to the stack here that is based on the default
93** stack limit of 512K.
94*/
95#define MAXIMUM_STACK_SIZE (256*1024)
96#endif
97
Jack Jansend1f06311996-08-01 15:23:54 +000098/*
Jack Jansen16df2aa1995-02-27 16:17:28 +000099** We have to be careful, since we can't handle
Jack Jansenee23d6e1995-01-27 14:43:25 +0000100** things like updates (and they'll keep coming back if we don't
Jack Jansen16df2aa1995-02-27 16:17:28 +0000101** handle them). Note that we don't know who has windows open, so
102** even handing updates off to SIOUX under MW isn't going to work.
Jack Jansenee23d6e1995-01-27 14:43:25 +0000103*/
Jack Jansen0c968871997-08-26 13:20:34 +0000104#define MAINLOOP_EVENTMASK (mDownMask|keyDownMask|osMask|activMask)
Jack Jansene8e8ae01995-01-26 16:36:45 +0000105
106#include <signal.h>
Jack Jansenf93c72a1994-12-14 14:07:50 +0000107
Guido van Rossumb3404661995-01-22 18:36:13 +0000108/* XXX We should include Errors.h here, but it has a name conflict
Jack Jansen5f653091995-01-18 13:53:49 +0000109** with the python errors.h. */
110#define fnfErr -43
111
Jack Jansenee23d6e1995-01-27 14:43:25 +0000112/* Interrupt code variables: */
113static int interrupted; /* Set to true when cmd-. seen */
Jack Jansend88296d2000-07-11 19:51:05 +0000114static RETSIGTYPE intcatcher(int);
Jack Jansenee23d6e1995-01-27 14:43:25 +0000115
Jack Jansen0194ad52001-05-12 22:46:35 +0000116#if !TARGET_API_MAC_OSX
Jack Jansend88296d2000-07-11 19:51:05 +0000117static int PyMac_Yield(void);
Jack Jansen0194ad52001-05-12 22:46:35 +0000118#endif
Jack Jansenf6865f71996-09-04 15:24:59 +0000119
Jack Jansene8e8ae01995-01-26 16:36:45 +0000120/*
Jack Jansene3ae0df1997-06-03 15:28:29 +0000121** These are the real scheduling parameters that control what we check
122** in the event loop, and how often we check. The values are initialized
123** from pyMac_SchedParamStruct.
124*/
125
126struct real_sched_param_struct {
127 int check_interrupt; /* if true check for command-dot */
128 int process_events; /* if nonzero enable evt processing, this mask */
129 int besocial; /* if nonzero be a little social with CPU */
130 unsigned long check_interval; /* how often to check, in ticks */
131 unsigned long bg_yield; /* yield so long when in background */
132 /* these are computed from previous and clock and such */
133 int enabled; /* check_interrupt OR process_event OR yield */
134 unsigned long next_check; /* when to check/yield next, in ticks */
135};
136
137static struct real_sched_param_struct schedparams =
138 { 1, MAINLOOP_EVENTMASK, 1, 15, 15, 1, 0};
139
Jack Jansen819f1771995-08-14 12:35:10 +0000140/*
Jack Jansenf6865f71996-09-04 15:24:59 +0000141** Workaround for sioux/gusi combo: set when we are exiting
142*/
143int PyMac_ConsoleIsDead;
144
145/*
Jack Jansencaa7c461997-06-12 10:49:13 +0000146** Sioux menu bar, saved early so we can restore it
147*/
Jack Jansen657ba272001-02-17 22:02:07 +0000148static MenuBarHandle sioux_mbar;
Jack Jansencaa7c461997-06-12 10:49:13 +0000149
150/*
Jack Jansen819f1771995-08-14 12:35:10 +0000151** Some stuff for our GetDirectory and PromptGetFile routines
152*/
153struct hook_args {
154 int selectcur_hit; /* Set to true when "select current" selected */
155 char *prompt; /* The prompt */
156};
Jack Jansen6e68a7e2001-05-12 21:31:34 +0000157#if !TARGET_API_MAC_OS8
Jack Jansenbb6d83a2000-06-02 21:27:11 +0000158/* The StandardFile hooks don't exist in Carbon. This breaks GetDirectory,
159** but the macfsn code will replace it by a NavServices version anyway.
160*/
161#define myhook_upp NULL
162#else
Jack Jansen819f1771995-08-14 12:35:10 +0000163static DlgHookYDUPP myhook_upp;
164static int upp_inited = 0;
Jack Jansenbb6d83a2000-06-02 21:27:11 +0000165#endif
Jack Jansen819f1771995-08-14 12:35:10 +0000166
Jack Jansen36ed5061997-06-20 16:18:15 +0000167/*
168** The python-code event handler
169*/
170static PyObject *python_event_handler;
171
Jack Jansen741e0372001-05-19 12:55:57 +0000172/* Given an FSSpec, return the FSSpec of the parent folder */
173
174static OSErr
175get_folder_parent (FSSpec * fss, FSSpec * parent)
176{
177 CInfoPBRec rec;
178 short err;
179
180 * parent = * fss;
181 rec.hFileInfo.ioNamePtr = parent->name;
182 rec.hFileInfo.ioVRefNum = parent->vRefNum;
183 rec.hFileInfo.ioDirID = parent->parID;
184 rec.hFileInfo.ioFDirIndex = -1;
185 rec.hFileInfo.ioFVersNum = 0;
186 if (err = PBGetCatInfoSync (& rec))
187 return err;
188 parent->parID = rec.dirInfo.ioDrParID;
189/* parent->name[0] = 0; */
190 return 0;
191}
192
193/* Given an FSSpec return a full, colon-separated pathname */
194
195OSErr
Jack Jansencf031932001-09-11 09:22:19 +0000196PyMac_GetFullPathname (FSSpec *fss, char *buf, int length)
Jack Jansen741e0372001-05-19 12:55:57 +0000197{
198 short err;
199 FSSpec fss_parent, fss_current;
200 char tmpbuf[1024];
201 int plen;
202
203 fss_current = *fss;
204 plen = fss_current.name[0];
Jack Jansencf031932001-09-11 09:22:19 +0000205 if ( plen+2 > length ) {
206 *buf = 0;
207 return errFSNameTooLong;
208 }
Jack Jansen741e0372001-05-19 12:55:57 +0000209 memcpy(buf, &fss_current.name[1], plen);
210 buf[plen] = 0;
211 /* Special case for disk names */
212 if ( fss_current.parID <= 1 ) {
213 buf[plen++] = ':';
214 buf[plen] = 0;
215 return 0;
216 }
217 while (fss_current.parID > 1) {
218 /* Get parent folder name */
Jack Jansencf031932001-09-11 09:22:19 +0000219 if (err = get_folder_parent(&fss_current, &fss_parent)) {
220 *buf = 0;
Jack Jansen741e0372001-05-19 12:55:57 +0000221 return err;
Jack Jansencf031932001-09-11 09:22:19 +0000222 }
Jack Jansen741e0372001-05-19 12:55:57 +0000223 fss_current = fss_parent;
224 /* Prepend path component just found to buf */
225 plen = fss_current.name[0];
226 if (strlen(buf) + plen + 1 > 1024) {
227 /* Oops... Not enough space (shouldn't happen) */
228 *buf = 0;
Jack Jansencf031932001-09-11 09:22:19 +0000229 return errFSNameTooLong;
Jack Jansen741e0372001-05-19 12:55:57 +0000230 }
231 memcpy(tmpbuf, &fss_current.name[1], plen);
232 tmpbuf[plen] = ':';
233 strcpy(&tmpbuf[plen+1], buf);
Jack Jansencf031932001-09-11 09:22:19 +0000234 if ( strlen(tmpbuf) > length ) {
235 *buf = 0;
236 return errFSNameTooLong;
237 }
Jack Jansen741e0372001-05-19 12:55:57 +0000238 strcpy(buf, tmpbuf);
239 }
240 return 0;
241}
Jack Jansen1f9f2f42000-07-24 19:50:16 +0000242
Jack Jansen7ac70af1996-08-19 11:01:05 +0000243
Jack Jansen2d1306b2000-04-07 09:10:49 +0000244#ifdef USE_GUSI
Jack Jansen7d5f9e81996-09-07 17:09:31 +0000245/*
246** SpinCursor (needed by GUSI) drags in heaps of stuff, so we
247** provide a dummy here.
248*/
Jack Jansencfadbd41996-08-19 11:36:25 +0000249void SpinCursor(short x) { /* Dummy */ }
Jack Jansenefaada71998-02-20 16:03:15 +0000250void RotateCursor(short x) { /* Dummy */ }
Jack Jansencfadbd41996-08-19 11:36:25 +0000251
Jack Jansenf6865f71996-09-04 15:24:59 +0000252
Jack Jansena39f1b01997-05-23 15:35:14 +0000253/* Called at exit() time thru atexit(), to stop event processing */
254void
255PyMac_StopGUSISpin() {
256 PyMac_ConsoleIsDead = 1;
257}
258
Jack Jansen6e68a7e2001-05-12 21:31:34 +0000259#if TARGET_API_MAC_OS8
Jack Jansena39f1b01997-05-23 15:35:14 +0000260/*
261** Replacement routines for the PLstr... functions so we don't need
Jack Jansen6ba34aa2001-01-11 23:03:56 +0000262** StdCLib.
Jack Jansena39f1b01997-05-23 15:35:14 +0000263*/
Jack Jansen8bb573e1999-12-12 21:37:14 +0000264pascal void
Jack Jansen9ae898b2000-07-11 21:16:03 +0000265PLstrcpy(unsigned char *to, unsigned char *fr)
Jack Jansena39f1b01997-05-23 15:35:14 +0000266{
267 memcpy(to, fr, fr[0]+1);
268}
269
Jack Jansen8bb573e1999-12-12 21:37:14 +0000270pascal int
Jack Jansen9ae898b2000-07-11 21:16:03 +0000271PLstrcmp(unsigned char *s1, unsigned char *s2)
Jack Jansena39f1b01997-05-23 15:35:14 +0000272{
273 int res;
274 int l = s1[0] < s2[0] ? s1[0] : s2[0];
275
276 res = memcmp(s1+1, s2+1, l);
277 if ( res != 0 )
278 return res;
279
Jack Jansen7e1fb7c1998-07-31 09:36:30 +0000280 if ( s1[0] < s2[0] )
Jack Jansena39f1b01997-05-23 15:35:14 +0000281 return -1;
Jack Jansen7e1fb7c1998-07-31 09:36:30 +0000282 else if ( s1[0] > s2[0] )
Jack Jansena39f1b01997-05-23 15:35:14 +0000283 return 1;
284 else
285 return 0;
286}
287
Jack Jansen8bb573e1999-12-12 21:37:14 +0000288pascal unsigned char *
Jack Jansen9ae898b2000-07-11 21:16:03 +0000289PLstrrchr(unsigned char *str, unsigned char chr)
Jack Jansena39f1b01997-05-23 15:35:14 +0000290{
291 unsigned char *ptr = 0;
292 unsigned char *p;
293
294 for(p=str+1; p<str+str[0]; p++)
295 if ( *p == chr )
296 ptr = p;
297 return ptr;
298}
299
Jack Jansen6e68a7e2001-05-12 21:31:34 +0000300#endif /* TARGET_API_MAC_OS8 */
Jack Jansena39f1b01997-05-23 15:35:14 +0000301#endif /* USE_GUSI */
Jack Jansen378815c1996-03-06 16:21:34 +0000302
Jack Jansen819f1771995-08-14 12:35:10 +0000303
Jack Jansen5f653091995-01-18 13:53:49 +0000304/* Convert C to Pascal string. Returns pointer to static buffer. */
305unsigned char *
306Pstring(char *str)
307{
308 static Str255 buf;
309 int len;
310
311 len = strlen(str);
Guido van Rossum9aa3d131995-01-21 13:46:04 +0000312 if (len > 255)
313 len = 255;
Jack Jansen5f653091995-01-18 13:53:49 +0000314 buf[0] = (unsigned char)len;
315 strncpy((char *)buf+1, str, len);
316 return buf;
317}
318
Jack Jansen6e68a7e2001-05-12 21:31:34 +0000319#if TARGET_API_MAC_OS8
Jack Jansenb9526512001-12-27 23:01:18 +0000320Point
321LMGetMouse(void)
322{
323 return LMGetMouseLocation();
324}
325
326long LMGetExpandMem(void)
327{
328 return 0;
329}
330
Jack Jansen5afad832000-12-12 22:12:14 +0000331void
332c2pstrcpy(unsigned char *dst, const char *src)
333{
334 int len;
335
336 len = strlen(src);
337 if ( len > 255 ) len = 255;
338 strncpy((char *)dst+1, src, len);
339 dst[0] = len;
340}
Jack Jansen6e68a7e2001-05-12 21:31:34 +0000341#endif /* TARGET_API_MAC_OS8 */
Jack Jansen5afad832000-12-12 22:12:14 +0000342
Jack Jansen1ed95291996-07-22 15:25:10 +0000343#ifdef USE_STACKCHECK
344/* Check for stack overflow */
345int
346PyOS_CheckStack()
347{
Jack Jansen14a91712000-08-25 21:57:23 +0000348 char here;
349 static char *sentinel = 0;
Jack Jansen53bafd92000-09-08 22:05:48 +0000350 static PyThreadState *thread_for_sentinel = 0;
Jack Jansen1ed95291996-07-22 15:25:10 +0000351
Jack Jansen340eb882001-02-02 22:40:28 +0000352 if ( sentinel == 0 ) {
353 unsigned long stackspace = StackSpace();
354
355#ifdef MAXIMUM_STACK_SIZE
356 /* See the comment at the definition */
357 if ( stackspace > MAXIMUM_STACK_SIZE )
358 stackspace = MAXIMUM_STACK_SIZE;
359#endif
360 sentinel = &here - stackspace + MINIMUM_STACK_SIZE;
Jack Jansen14a91712000-08-25 21:57:23 +0000361 }
Jack Jansen53bafd92000-09-08 22:05:48 +0000362 if ( thread_for_sentinel == 0 ) {
363 thread_for_sentinel = PyThreadState_Get();
364 }
365 if ( &here < sentinel ) {
366 if (thread_for_sentinel == PyThreadState_Get()) {
367 return -1;
Jack Jansen53bafd92000-09-08 22:05:48 +0000368 }
369 }
Jack Jansen1ed95291996-07-22 15:25:10 +0000370 return 0;
371}
372#endif /* USE_STACKCHECK */
373
Jack Jansen0194ad52001-05-12 22:46:35 +0000374#if !TARGET_API_MAC_OSX
Jack Jansenee23d6e1995-01-27 14:43:25 +0000375/* The catcher routine (which may not be used for all compilers) */
376static RETSIGTYPE
377intcatcher(sig)
378 int sig;
379{
380 interrupted = 1;
381 signal(SIGINT, intcatcher);
382}
383
384void
385PyOS_InitInterrupts()
386{
387 if (signal(SIGINT, SIG_IGN) != SIG_IGN)
388 signal(SIGINT, intcatcher);
389}
390
Jack Jansena8441de1997-08-08 14:57:37 +0000391void
392PyOS_FiniInterrupts()
393{
394}
395
Jack Jansenee23d6e1995-01-27 14:43:25 +0000396/* Check whether we are in the foreground */
Jack Jansen9ae898b2000-07-11 21:16:03 +0000397static int
398PyMac_InForeground(void)
Jack Jansenee23d6e1995-01-27 14:43:25 +0000399{
400 static ProcessSerialNumber ours;
401 static inited;
402 ProcessSerialNumber curfg;
403 Boolean eq;
404
Jack Jansene3ae0df1997-06-03 15:28:29 +0000405 if ( inited == 0 ) {
Jack Jansenee23d6e1995-01-27 14:43:25 +0000406 (void)GetCurrentProcess(&ours);
Jack Jansene3ae0df1997-06-03 15:28:29 +0000407 inited = 1;
408 }
Jack Jansenee23d6e1995-01-27 14:43:25 +0000409 if ( GetFrontProcess(&curfg) < 0 )
410 eq = 1;
411 else if ( SameProcess(&ours, &curfg, &eq) < 0 )
412 eq = 1;
413 return (int)eq;
Jack Jansenee23d6e1995-01-27 14:43:25 +0000414}
Jack Jansen439eaa92001-11-10 00:41:43 +0000415
416/*
417** This routine scans the event queue looking for cmd-.
418*/
419static void
420scan_event_queue(force)
421 int force;
422{
423#if !TARGET_API_MAC_OS8
424 if ( interrupted || (!schedparams.check_interrupt && !force) )
425 return;
426 if ( CheckEventQueueForUserCancel() )
427 interrupted = 1;
428#else
429 register EvQElPtr q;
430
431 if ( interrupted || (!schedparams.check_interrupt && !force) || !PyMac_InForeground() )
432 return;
433 q = (EvQElPtr) LMGetEventQueue()->qHead;
434
435 for (; q; q = (EvQElPtr)q->qLink) {
436 if (q->evtQWhat == keyDown &&
437 (char)q->evtQMessage == '.' &&
438 (q->evtQModifiers & cmdKey) != 0) {
Jack Jansenb3be2162001-11-30 14:16:36 +0000439 FlushEvents(keyDownMask, 0);
Jack Jansen439eaa92001-11-10 00:41:43 +0000440 interrupted = 1;
441 break;
442 }
443 }
444#endif
445}
446
447int
448PyErr_CheckSignals()
449{
Jack Jansen439eaa92001-11-10 00:41:43 +0000450 if (schedparams.enabled) {
451 if ( interrupted || (unsigned long)LMGetTicks() > schedparams.next_check ) {
452 scan_event_queue(0);
453 if (interrupted) {
454 interrupted = 0;
455 PyErr_SetNone(PyExc_KeyboardInterrupt);
456 return -1;
457 }
458 if ( PyMac_Yield() < 0)
459 return -1;
Jack Jansen439eaa92001-11-10 00:41:43 +0000460 schedparams.next_check = (unsigned long)LMGetTicks()
461 + schedparams.check_interval;
462 }
463 }
464 return 0;
465}
466
467int
468PyOS_InterruptOccurred()
469{
470 scan_event_queue(0);
471 if ( !interrupted )
472 return 0;
473 interrupted = 0;
474 return 1;
475}
Jack Jansen0194ad52001-05-12 22:46:35 +0000476#endif
Jack Jansenee23d6e1995-01-27 14:43:25 +0000477
Jack Jansen36ed5061997-06-20 16:18:15 +0000478int
479PyMac_SetEventHandler(PyObject *evh)
480{
481 if ( evh && python_event_handler ) {
482 PyErr_SetString(PyExc_RuntimeError, "Python event handler already set");
483 return 0;
484 }
485 if ( python_event_handler )
486 Py_DECREF(python_event_handler);
487 if ( evh )
488 Py_INCREF(evh);
489 python_event_handler = evh;
490 return 1;
491}
492
Jack Jansenf93c72a1994-12-14 14:07:50 +0000493/*
Jack Jansena76382a1995-02-02 14:25:56 +0000494** Handle an event, either one found in the mainloop eventhandler or
495** one passed back from the python program.
496*/
497void
Jack Jansen36ed5061997-06-20 16:18:15 +0000498PyMac_HandleEventIntern(evp)
Jack Jansena76382a1995-02-02 14:25:56 +0000499 EventRecord *evp;
500{
Jack Jansen6e68a7e2001-05-12 21:31:34 +0000501#if TARGET_API_MAC_OS8
Jack Jansen0c968871997-08-26 13:20:34 +0000502 if ( evp->what == mouseDown ) {
503 WindowPtr wp;
504
505 if ( FindWindow(evp->where, &wp) == inSysWindow ) {
506 SystemClick(evp, wp);
507 return;
508 }
509 }
Jack Jansenbb6d83a2000-06-02 21:27:11 +0000510#endif
Jack Jansena76382a1995-02-02 14:25:56 +0000511#ifdef __MWERKS__
Jack Jansen38e97661995-11-10 14:53:00 +0000512 {
513 int siouxdidit;
514
515 /* If SIOUX wants it we're done */
516 siouxdidit = SIOUXHandleOneEvent(evp);
517 if ( siouxdidit )
518 return;
519 }
Jack Jansena76382a1995-02-02 14:25:56 +0000520#else
Jack Jansen0c968871997-08-26 13:20:34 +0000521 /* Other compilers are just unlucky... */
Jack Jansena76382a1995-02-02 14:25:56 +0000522#endif /* !__MWERKS__ */
Jack Jansen36ed5061997-06-20 16:18:15 +0000523}
524
525/*
526** Handle an event, either through HandleEvent or by passing it to the Python
527** event handler.
528*/
529int
530PyMac_HandleEvent(evp)
531 EventRecord *evp;
532{
533 PyObject *rv;
534
535 if ( python_event_handler ) {
536 rv = PyObject_CallFunction(python_event_handler, "(O&)",
537 PyMac_BuildEventRecord, evp);
538 if ( rv )
539 Py_DECREF(rv);
540 else
541 return -1; /* Propagate exception */
542 } else {
543 PyMac_HandleEventIntern(evp);
544 }
545 return 0;
Jack Jansena76382a1995-02-02 14:25:56 +0000546}
547
Jack Jansen0194ad52001-05-12 22:46:35 +0000548#if !TARGET_API_MAC_OSX
Jack Jansena76382a1995-02-02 14:25:56 +0000549/*
Jack Jansene3ae0df1997-06-03 15:28:29 +0000550** Yield the CPU to other tasks without processing events.
Jack Jansene8e8ae01995-01-26 16:36:45 +0000551*/
Jack Jansen2d1306b2000-04-07 09:10:49 +0000552int
Jack Jansene3ae0df1997-06-03 15:28:29 +0000553PyMac_DoYield(int maxsleep, int maycallpython)
Jack Jansenf93c72a1994-12-14 14:07:50 +0000554{
555 EventRecord ev;
Jack Jansene8e8ae01995-01-26 16:36:45 +0000556 int gotone;
Jack Jansene3ae0df1997-06-03 15:28:29 +0000557 long latest_time_ready;
Jack Jansen36ed5061997-06-20 16:18:15 +0000558 static int in_here = 0;
Jack Jansene8e8ae01995-01-26 16:36:45 +0000559
Jack Jansen36ed5061997-06-20 16:18:15 +0000560 in_here++;
Jack Jansene8e8ae01995-01-26 16:36:45 +0000561
Jack Jansene3ae0df1997-06-03 15:28:29 +0000562 /*
563 ** Check which of the eventloop cases we have:
564 ** - process events
565 ** - don't process events but do yield
566 ** - do neither
567 */
Jack Jansen36ed5061997-06-20 16:18:15 +0000568 if( in_here > 1 || !schedparams.process_events ||
569 (python_event_handler && !maycallpython) ) {
Jack Jansene3ae0df1997-06-03 15:28:29 +0000570 if ( maxsleep >= 0 ) {
Jack Jansen6e68a7e2001-05-12 21:31:34 +0000571#if TARGET_API_MAC_OS8
Jack Jansene8e8ae01995-01-26 16:36:45 +0000572 SystemTask();
Jack Jansen15f1c082001-04-25 22:07:27 +0000573#else
574 int xxx = 0;
Jack Jansenbb6d83a2000-06-02 21:27:11 +0000575#endif
Jack Jansen15f1c082001-04-25 22:07:27 +0000576 }
Jack Jansene3ae0df1997-06-03 15:28:29 +0000577 } else {
578 latest_time_ready = LMGetTicks() + maxsleep;
Jack Jansen2d1306b2000-04-07 09:10:49 +0000579 do {
Jack Jansen0c968871997-08-26 13:20:34 +0000580 /* XXXX Hack by Jack.
581 ** In time.sleep() you can click to another application
582 ** once only. If you come back to Python you cannot get away
583 ** again.
584 **/
Jack Jansen36ed5061997-06-20 16:18:15 +0000585 gotone = WaitNextEvent(schedparams.process_events, &ev, maxsleep, NULL);
Jack Jansene3ae0df1997-06-03 15:28:29 +0000586 /* Get out quickly if nothing interesting is happening */
587 if ( !gotone || ev.what == nullEvent )
588 break;
Jack Jansen36ed5061997-06-20 16:18:15 +0000589 if ( PyMac_HandleEvent(&ev) < 0 ) {
590 in_here--;
591 return -1;
592 }
Jack Jansene3ae0df1997-06-03 15:28:29 +0000593 maxsleep = latest_time_ready - LMGetTicks();
Jack Jansen2d1306b2000-04-07 09:10:49 +0000594 } while ( maxsleep > 0 );
Jack Jansenf93c72a1994-12-14 14:07:50 +0000595 }
Jack Jansen36ed5061997-06-20 16:18:15 +0000596 in_here--;
597 return 0;
Jack Jansene8e8ae01995-01-26 16:36:45 +0000598}
599
600/*
Jack Jansene3ae0df1997-06-03 15:28:29 +0000601** Process events and/or yield the CPU to other tasks if opportune
Jack Jansene8e8ae01995-01-26 16:36:45 +0000602*/
Jack Jansen36ed5061997-06-20 16:18:15 +0000603int
Jack Jansene8e8ae01995-01-26 16:36:45 +0000604PyMac_Yield() {
Jack Jansene3ae0df1997-06-03 15:28:29 +0000605 unsigned long maxsleep;
Jack Jansene8e8ae01995-01-26 16:36:45 +0000606
Jack Jansene3ae0df1997-06-03 15:28:29 +0000607 if( PyMac_InForeground() )
608 maxsleep = 0;
Jack Jansenee23d6e1995-01-27 14:43:25 +0000609 else
Jack Jansene3ae0df1997-06-03 15:28:29 +0000610 maxsleep = schedparams.bg_yield;
611
Jack Jansen36ed5061997-06-20 16:18:15 +0000612 return PyMac_DoYield(maxsleep, 1);
Jack Jansene8e8ae01995-01-26 16:36:45 +0000613}
614
615/*
Jack Jansene3ae0df1997-06-03 15:28:29 +0000616** Return current scheduler parameters
Jack Jansene8e8ae01995-01-26 16:36:45 +0000617*/
Jack Jansene3ae0df1997-06-03 15:28:29 +0000618void
619PyMac_GetSchedParams(PyMacSchedParams *sp)
Jack Jansene8e8ae01995-01-26 16:36:45 +0000620{
Jack Jansene3ae0df1997-06-03 15:28:29 +0000621 sp->check_interrupt = schedparams.check_interrupt;
622 sp->process_events = schedparams.process_events;
623 sp->besocial = schedparams.besocial;
624 sp->check_interval = schedparams.check_interval / 60.0;
625 sp->bg_yield = schedparams.bg_yield / 60.0;
Jack Jansenf93c72a1994-12-14 14:07:50 +0000626}
Jack Jansenf6865f71996-09-04 15:24:59 +0000627
Jack Jansen74162f31995-02-15 22:58:33 +0000628/*
Jack Jansene3ae0df1997-06-03 15:28:29 +0000629** Set current scheduler parameters
630*/
631void
632PyMac_SetSchedParams(PyMacSchedParams *sp)
633{
634 schedparams.check_interrupt = sp->check_interrupt;
635 schedparams.process_events = sp->process_events;
636 schedparams.besocial = sp->besocial;
637 schedparams.check_interval = (unsigned long)(sp->check_interval*60);
638 schedparams.bg_yield = (unsigned long)(sp->bg_yield*60);
639 if ( schedparams.check_interrupt || schedparams.process_events ||
640 schedparams.besocial )
641 schedparams.enabled = 1;
642 else
643 schedparams.enabled = 0;
644 schedparams.next_check = 0; /* Check immedeately */
645}
Jack Jansencaa7c461997-06-12 10:49:13 +0000646
Jack Jansene3ae0df1997-06-03 15:28:29 +0000647/*
Jack Jansen3469e991996-09-06 00:30:45 +0000648** Install our menu bar.
649*/
650void
651PyMac_InitMenuBar()
652{
Jack Jansen3469e991996-09-06 00:30:45 +0000653 MenuHandle applemenu;
Jack Jansen52306a72001-12-10 16:08:14 +0000654 Str255 about_text;
655 static unsigned char about_sioux[] = "\pAbout SIOUX";
Jack Jansen3469e991996-09-06 00:30:45 +0000656
Jack Jansen15f1c082001-04-25 22:07:27 +0000657 if ( sioux_mbar ) return;
Jack Jansenb3be2162001-11-30 14:16:36 +0000658 if ( (sioux_mbar=GetMenuBar()) == NULL || GetMenuHandle(SIOUX_APPLEID) == NULL) {
Jack Jansencaa7c461997-06-12 10:49:13 +0000659 /* Sioux menu not installed yet. Do so */
660 SIOUXSetupMenus();
661 if ( (sioux_mbar=GetMenuBar()) == NULL )
662 return;
663 }
Jack Jansen08c3be31997-04-08 15:27:00 +0000664 if ( (applemenu=GetMenuHandle(SIOUX_APPLEID)) == NULL ) return;
Jack Jansen52306a72001-12-10 16:08:14 +0000665 GetMenuItemText(applemenu, 1, about_text);
666 if ( about_text[0] == about_sioux[0] &&
667 strncmp((char *)(about_text+1), (char *)(about_sioux+1), about_text[0]) == 0 )
668 SetMenuItemText(applemenu, 1, "\pAbout Python...");
Jack Jansen3469e991996-09-06 00:30:45 +0000669}
670
671/*
Jack Jansencaa7c461997-06-12 10:49:13 +0000672** Restore sioux menu bar
673*/
674void
675PyMac_RestoreMenuBar()
676{
Jack Jansen657ba272001-02-17 22:02:07 +0000677 MenuBarHandle curmenubar;
678
679 curmenubar = GetMenuBar();
Jack Janseneda78631997-06-12 15:29:46 +0000680 if ( sioux_mbar ) {
Jack Jansencaa7c461997-06-12 10:49:13 +0000681 SetMenuBar(sioux_mbar);
Jack Janseneda78631997-06-12 15:29:46 +0000682 DrawMenuBar();
Jack Jansen657ba272001-02-17 22:02:07 +0000683 } else {
Jack Jansenefaada71998-02-20 16:03:15 +0000684 PyMac_InitMenuBar();
Jack Jansen657ba272001-02-17 22:02:07 +0000685 DrawMenuBar();
686 }
Jack Jansencaa7c461997-06-12 10:49:13 +0000687}
688
Jack Jansen15f1c082001-04-25 22:07:27 +0000689void
690PyMac_RaiseConsoleWindow()
691{
692 /* Note: this is a hack. SIOUXTextWindow is SIOUX's internal structure
693 ** and we happen to know that the first entry is the window pointer.
694 */
695 extern WindowRef *SIOUXTextWindow;
696
697 if ( SIOUXTextWindow == NULL || *SIOUXTextWindow == NULL )
698 return;
699 if ( FrontWindow() != *SIOUXTextWindow )
700 BringToFront(*SIOUXTextWindow);
701}
Jack Jansencaa7c461997-06-12 10:49:13 +0000702
703/*
Jack Jansen3469e991996-09-06 00:30:45 +0000704** Our replacement about box
705*/
Jack Jansen7e1fb7c1998-07-31 09:36:30 +0000706
707#include "patchlevel.h"
708
Jack Jansen3469e991996-09-06 00:30:45 +0000709void
710SIOUXDoAboutBox(void)
711{
712 DialogPtr theDialog;
Jack Jansen7e1fb7c1998-07-31 09:36:30 +0000713 WindowPtr theWindow;
Jack Jansen3469e991996-09-06 00:30:45 +0000714 short item;
Jack Jansen7e1fb7c1998-07-31 09:36:30 +0000715 short fontID;
Jack Jansen3469e991996-09-06 00:30:45 +0000716
717 if( (theDialog = GetNewDialog(ABOUT_ID, NULL, (WindowPtr)-1)) == NULL )
718 return;
Jack Jansend617c571996-09-22 22:14:30 +0000719 theWindow = GetDialogWindow(theDialog);
Jack Jansen7e1fb7c1998-07-31 09:36:30 +0000720 SetPortWindowPort(theWindow);
721 GetFNum("\pPython-Sans", &fontID);
722 if (fontID == 0)
723 fontID = kFontIDGeneva;
724 TextFont(fontID);
725 TextSize(9);
Jack Jansenf60edf82001-08-19 22:32:27 +0000726 ParamText(Pstring(PY_VERSION), "\p", "\p", "\p");
Jack Jansend617c571996-09-22 22:14:30 +0000727 ShowWindow(theWindow);
Jack Jansen3469e991996-09-06 00:30:45 +0000728 ModalDialog(NULL, &item);
729 DisposeDialog(theDialog);
730}
731
Jack Jansen0194ad52001-05-12 22:46:35 +0000732#endif /* !TARGET_API_MAC_OSX */
Jack Janseneda78631997-06-12 15:29:46 +0000733
Jack Jansen0194ad52001-05-12 22:46:35 +0000734#if TARGET_API_MAC_OS8
Jack Janseneda78631997-06-12 15:29:46 +0000735/*
Jack Jansen3ec804a1995-02-20 15:56:10 +0000736** Helper routine for GetDirectory
737*/
Guido van Rossum24a45e31995-02-20 23:45:53 +0000738static pascal short
Jack Jansen819f1771995-08-14 12:35:10 +0000739myhook_proc(short item, DialogPtr theDialog, struct hook_args *dataptr)
Jack Jansen3ec804a1995-02-20 15:56:10 +0000740{
Jack Jansen819f1771995-08-14 12:35:10 +0000741 if ( item == sfHookFirstCall && dataptr->prompt) {
742 Handle prompth;
743 short type;
744 Rect rect;
745
746 GetDialogItem(theDialog, PROMPT_ITEM, &type, &prompth, &rect);
747 if ( prompth )
748 SetDialogItemText(prompth, (unsigned char *)dataptr->prompt);
749 } else
Jack Jansen3ec804a1995-02-20 15:56:10 +0000750 if ( item == SELECTCUR_ITEM ) {
751 item = sfItemCancelButton;
Jack Jansen819f1771995-08-14 12:35:10 +0000752 dataptr->selectcur_hit = 1;
Jack Jansen3ec804a1995-02-20 15:56:10 +0000753 }
754 return item;
755}
Jack Jansen0194ad52001-05-12 22:46:35 +0000756
Jack Jansen3ec804a1995-02-20 15:56:10 +0000757/*
758** Ask the user for a directory. I still can't understand
759** why Apple doesn't provide a standard solution for this...
760*/
761int
Jack Jansen819f1771995-08-14 12:35:10 +0000762PyMac_GetDirectory(dirfss, prompt)
Jack Jansen3ec804a1995-02-20 15:56:10 +0000763 FSSpec *dirfss;
Jack Jansen819f1771995-08-14 12:35:10 +0000764 char *prompt;
Jack Jansen3ec804a1995-02-20 15:56:10 +0000765{
766 static SFTypeList list = {'fldr', 0, 0, 0};
767 static Point where = {-1, -1};
Jack Jansen3ec804a1995-02-20 15:56:10 +0000768 StandardFileReply reply;
Jack Jansen819f1771995-08-14 12:35:10 +0000769 struct hook_args hook_args;
Jack Jansen3ec804a1995-02-20 15:56:10 +0000770
771 if ( !upp_inited ) {
772 myhook_upp = NewDlgHookYDProc(myhook_proc);
773 upp_inited = 1;
774 }
Jack Jansen819f1771995-08-14 12:35:10 +0000775 if ( prompt && *prompt )
776 hook_args.prompt = (char *)Pstring(prompt);
777 else
778 hook_args.prompt = NULL;
779 hook_args.selectcur_hit = 0;
Guido van Rossum24a45e31995-02-20 23:45:53 +0000780 CustomGetFile((FileFilterYDUPP)0, 1, list, &reply, GETDIR_ID, where, myhook_upp,
Jack Jansen819f1771995-08-14 12:35:10 +0000781 NULL, NULL, NULL, (void *)&hook_args);
Jack Jansen3ec804a1995-02-20 15:56:10 +0000782
783 reply.sfFile.name[0] = 0;
784 if( FSMakeFSSpec(reply.sfFile.vRefNum, reply.sfFile.parID, reply.sfFile.name, dirfss) )
785 return 0;
Jack Jansen819f1771995-08-14 12:35:10 +0000786 return hook_args.selectcur_hit;
787}
788
789/*
790** Slightly extended StandardGetFile: accepts a prompt */
791void PyMac_PromptGetFile(short numTypes, ConstSFTypeListPtr typeList,
792 StandardFileReply *reply, char *prompt)
793{
794 static Point where = {-1, -1};
795 struct hook_args hook_args;
796
797 if ( !upp_inited ) {
798 myhook_upp = NewDlgHookYDProc(myhook_proc);
799 upp_inited = 1;
800 }
801 if ( prompt && *prompt )
802 hook_args.prompt = (char *)Pstring(prompt);
803 else
804 hook_args.prompt = NULL;
805 hook_args.selectcur_hit = 0;
806 CustomGetFile((FileFilterYDUPP)0, numTypes, typeList, reply, GETFILEPROMPT_ID, where,
807 myhook_upp, NULL, NULL, NULL, (void *)&hook_args);
Jack Jansen3ec804a1995-02-20 15:56:10 +0000808}
Jack Jansen6e68a7e2001-05-12 21:31:34 +0000809#endif /* TARGET_API_MAC_OS8 */
Jack Jansen5f653091995-01-18 13:53:49 +0000810
Jack Jansen5f653091995-01-18 13:53:49 +0000811