This commit was manufactured by cvs2svn to create tag 'r212'.
[python/dscho.git] / Mac / Python / macglue.c
blob5fdfe559efa49c2e72222b8bd25a8a028632a110
1 /***********************************************************
2 Copyright 1991-1997 by Stichting Mathematisch Centrum, Amsterdam,
3 The Netherlands.
5 All Rights Reserved
7 Permission to use, copy, modify, and distribute this software and its
8 documentation for any purpose and without fee is hereby granted,
9 provided that the above copyright notice appear in all copies and that
10 both that copyright notice and this permission notice appear in
11 supporting documentation, and that the names of Stichting Mathematisch
12 Centrum or CWI not be used in advertising or publicity pertaining to
13 distribution of the software without specific, written prior permission.
15 STICHTING MATHEMATISCH CENTRUM DISCLAIMS ALL WARRANTIES WITH REGARD TO
16 THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
17 FITNESS, IN NO EVENT SHALL STICHTING MATHEMATISCH CENTRUM BE LIABLE
18 FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
19 WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
20 ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
21 OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
23 ******************************************************************/
26 #include "Python.h"
28 #include "macglue.h"
29 #include "marshal.h"
30 #include "import.h"
31 #include "importdl.h"
32 #include "pymactoolbox.h"
34 #include "pythonresources.h"
36 #ifdef WITHOUT_FRAMEWORKS
37 #include <OSUtils.h> /* for Set(Current)A5 */
38 #include <Files.h>
39 #include <StandardFile.h>
40 #include <Resources.h>
41 #include <Memory.h>
42 #include <Windows.h>
43 #include <Traps.h>
44 #include <Processes.h>
45 #include <Fonts.h>
46 #include <Menus.h>
47 #include <TextUtils.h>
48 #include <LowMem.h>
49 #ifdef __CFM68K__
50 /* cfm68k InterfaceLib exports GetEventQueue, but Events.h doesn't know this
51 ** and defines it as GetEvQHdr (which is correct for PPC). This fix is for
52 ** CW9, check that the workaround is still needed for the next release.
54 #define GetEvQHdr GetEventQueue
55 #endif /* __CFM68K__ */
57 #include <Events.h>
59 #ifdef __CFM68K__
60 #undef GetEventQueue
61 #endif /* __CFM68K__ */
62 #else
63 #include <Carbon/Carbon.h>
64 #endif
66 #if !TARGET_API_MAC_OS8
67 /* Unfortunately this call is probably slower... */
68 #define LMGetTicks() TickCount()
69 #endif
71 #ifdef __MWERKS__
72 #include <SIOUX.h>
73 extern void SIOUXSetupMenus(void);
74 extern void SIOUXDoAboutBox(void);
75 #endif
76 #ifdef USE_GUSI
77 /* Functions we redefine because they're in obscure libraries */
78 extern void SpinCursor(short x);
79 extern void RotateCursor(short x);
80 extern pascal void PLstrcpy(unsigned char *, unsigned char *);
81 extern pascal int PLstrcmp(unsigned char *, unsigned char *);
82 extern pascal unsigned char *PLstrrchr(unsigned char *, unsigned char);
84 #endif
86 #ifdef USE_GUSI1
87 #include <TFileSpec.h> /* For Path2FSSpec */
88 #include <GUSI.h>
89 #endif
91 /* The ID of the Sioux apple menu */
92 #define SIOUX_APPLEID 32000
94 #include <signal.h>
95 #include <stdio.h>
98 ** When less than this amount of stackspace is left we
99 ** raise a MemoryError.
101 #ifndef MINIMUM_STACK_SIZE
102 #ifdef __powerc
103 #define MINIMUM_STACK_SIZE 8192
104 #else
105 #define MINIMUM_STACK_SIZE 4096
106 #endif
107 #endif
109 #if TARGET_API_MAC_CARBON
111 ** On MacOSX StackSpace() lies: it gives the distance from heap end to stack pointer,
112 ** but the stack cannot grow that far due to rlimit values. We cannot get at this value
113 ** from Carbon, so we set a maximum to the stack here that is based on the default
114 ** stack limit of 512K.
116 #define MAXIMUM_STACK_SIZE (256*1024)
117 #endif
120 ** We have to be careful, since we can't handle
121 ** things like updates (and they'll keep coming back if we don't
122 ** handle them). Note that we don't know who has windows open, so
123 ** even handing updates off to SIOUX under MW isn't going to work.
125 #define MAINLOOP_EVENTMASK (mDownMask|keyDownMask|osMask|activMask)
127 #include <signal.h>
129 /* XXX We should include Errors.h here, but it has a name conflict
130 ** with the python errors.h. */
131 #define fnfErr -43
133 /* Interrupt code variables: */
134 static int interrupted; /* Set to true when cmd-. seen */
135 static RETSIGTYPE intcatcher(int);
137 #if !TARGET_API_MAC_OSX
138 static int PyMac_Yield(void);
139 #endif
142 ** These are the real scheduling parameters that control what we check
143 ** in the event loop, and how often we check. The values are initialized
144 ** from pyMac_SchedParamStruct.
147 struct real_sched_param_struct {
148 int check_interrupt; /* if true check for command-dot */
149 int process_events; /* if nonzero enable evt processing, this mask */
150 int besocial; /* if nonzero be a little social with CPU */
151 unsigned long check_interval; /* how often to check, in ticks */
152 unsigned long bg_yield; /* yield so long when in background */
153 /* these are computed from previous and clock and such */
154 int enabled; /* check_interrupt OR process_event OR yield */
155 unsigned long next_check; /* when to check/yield next, in ticks */
158 static struct real_sched_param_struct schedparams =
159 { 1, MAINLOOP_EVENTMASK, 1, 15, 15, 1, 0};
162 ** Workaround for sioux/gusi combo: set when we are exiting
164 int PyMac_ConsoleIsDead;
167 ** Sioux menu bar, saved early so we can restore it
169 static MenuBarHandle sioux_mbar;
172 ** Some stuff for our GetDirectory and PromptGetFile routines
174 struct hook_args {
175 int selectcur_hit; /* Set to true when "select current" selected */
176 char *prompt; /* The prompt */
178 #if !TARGET_API_MAC_OS8
179 /* The StandardFile hooks don't exist in Carbon. This breaks GetDirectory,
180 ** but the macfsn code will replace it by a NavServices version anyway.
182 #define myhook_upp NULL
183 #else
184 static DlgHookYDUPP myhook_upp;
185 static int upp_inited = 0;
186 #endif
189 ** The python-code event handler
191 static PyObject *python_event_handler;
194 ** Set to true if we're appearance-compliant
196 int PyMac_AppearanceCompliant;
199 ** Find out what the current script is.
200 ** Donated by Fredrik Lund.
202 char *PyMac_getscript()
204 int font, script, lang;
205 font = 0;
206 font = GetSysFont();
207 script = FontToScript(font);
208 switch (script) {
209 case smRoman:
210 lang = GetScriptVariable(script, smScriptLang);
211 if (lang == langIcelandic)
212 return "mac-iceland";
213 else if (lang == langTurkish)
214 return "mac-turkish";
215 else if (lang == langGreek)
216 return "mac-greek";
217 else
218 return "mac-roman";
219 break;
220 #if 0
221 /* We don't have a codec for this, so don't return it */
222 case smJapanese:
223 return "mac-japan";
224 #endif
225 case smGreek:
226 return "mac-greek";
227 case smCyrillic:
228 return "mac-cyrillic";
229 default:
230 return "ascii"; /* better than nothing */
234 /* Given an FSSpec, return the FSSpec of the parent folder */
236 static OSErr
237 get_folder_parent (FSSpec * fss, FSSpec * parent)
239 CInfoPBRec rec;
240 short err;
242 * parent = * fss;
243 rec.hFileInfo.ioNamePtr = parent->name;
244 rec.hFileInfo.ioVRefNum = parent->vRefNum;
245 rec.hFileInfo.ioDirID = parent->parID;
246 rec.hFileInfo.ioFDirIndex = -1;
247 rec.hFileInfo.ioFVersNum = 0;
248 if (err = PBGetCatInfoSync (& rec))
249 return err;
250 parent->parID = rec.dirInfo.ioDrParID;
251 /* parent->name[0] = 0; */
252 return 0;
255 /* Given an FSSpec return a full, colon-separated pathname */
257 OSErr
258 PyMac_GetFullPath (FSSpec *fss, char *buf)
260 short err;
261 FSSpec fss_parent, fss_current;
262 char tmpbuf[1024];
263 int plen;
265 fss_current = *fss;
266 plen = fss_current.name[0];
267 memcpy(buf, &fss_current.name[1], plen);
268 buf[plen] = 0;
269 /* Special case for disk names */
270 if ( fss_current.parID <= 1 ) {
271 buf[plen++] = ':';
272 buf[plen] = 0;
273 return 0;
275 while (fss_current.parID > 1) {
276 /* Get parent folder name */
277 if (err = get_folder_parent(&fss_current, &fss_parent))
278 return err;
279 fss_current = fss_parent;
280 /* Prepend path component just found to buf */
281 plen = fss_current.name[0];
282 if (strlen(buf) + plen + 1 > 1024) {
283 /* Oops... Not enough space (shouldn't happen) */
284 *buf = 0;
285 return -1;
287 memcpy(tmpbuf, &fss_current.name[1], plen);
288 tmpbuf[plen] = ':';
289 strcpy(&tmpbuf[plen+1], buf);
290 strcpy(buf, tmpbuf);
292 return 0;
295 #ifdef USE_GUSI1
297 ** GUSI (1.6.0 and earlier, at the least) do not set the MacOS idea of
298 ** the working directory. Hence, we call this routine after each call
299 ** to chdir() to rectify things.
301 void
302 PyMac_FixGUSIcd()
304 WDPBRec pb;
305 FSSpec curdirfss;
307 if ( Path2FSSpec(":x", &curdirfss) != noErr )
308 return;
310 /* Set MacOS "working directory" */
311 pb.ioNamePtr= "\p";
312 pb.ioVRefNum= curdirfss.vRefNum;
313 pb.ioWDDirID= curdirfss.parID;
314 if (PBHSetVolSync(&pb) != noErr)
315 return;
317 #endif
319 #ifdef USE_GUSI
321 ** SpinCursor (needed by GUSI) drags in heaps of stuff, so we
322 ** provide a dummy here.
324 void SpinCursor(short x) { /* Dummy */ }
325 void RotateCursor(short x) { /* Dummy */ }
328 ** Replacement GUSI Spin function
330 #ifdef USE_GUSI1
331 static int
332 PyMac_GUSISpin(spin_msg msg, long arg)
334 static Boolean inForeground = true;
335 int maxsleep = 6; /* 6 ticks is "normal" sleeptime */
337 if (PyMac_ConsoleIsDead) return 0;
338 #if 0
339 if (inForeground)
340 SpinCursor(msg == SP_AUTO_SPIN ? short(arg) : 1);
341 #endif
343 if (interrupted) return -1;
345 if ( msg == SP_AUTO_SPIN )
346 maxsleep = 0;
347 if ( msg==SP_SLEEP||msg==SP_SELECT )
348 maxsleep = arg;
350 PyMac_DoYield(maxsleep, 0); /* XXXX or is it safe to call python here? */
352 return 0;
355 void
356 PyMac_SetGUSISpin() {
357 GUSISetHook(GUSI_SpinHook, (GUSIHook)PyMac_GUSISpin);
359 #endif
361 /* Called at exit() time thru atexit(), to stop event processing */
362 void
363 PyMac_StopGUSISpin() {
364 PyMac_ConsoleIsDead = 1;
367 #if TARGET_API_MAC_OS8
369 ** Replacement routines for the PLstr... functions so we don't need
370 ** StdCLib.
372 pascal void
373 PLstrcpy(unsigned char *to, unsigned char *fr)
375 memcpy(to, fr, fr[0]+1);
378 pascal int
379 PLstrcmp(unsigned char *s1, unsigned char *s2)
381 int res;
382 int l = s1[0] < s2[0] ? s1[0] : s2[0];
384 res = memcmp(s1+1, s2+1, l);
385 if ( res != 0 )
386 return res;
388 if ( s1[0] < s2[0] )
389 return -1;
390 else if ( s1[0] > s2[0] )
391 return 1;
392 else
393 return 0;
396 pascal unsigned char *
397 PLstrrchr(unsigned char *str, unsigned char chr)
399 unsigned char *ptr = 0;
400 unsigned char *p;
402 for(p=str+1; p<str+str[0]; p++)
403 if ( *p == chr )
404 ptr = p;
405 return ptr;
408 #endif /* TARGET_API_MAC_OS8 */
409 #endif /* USE_GUSI */
412 /* Convert C to Pascal string. Returns pointer to static buffer. */
413 unsigned char *
414 Pstring(char *str)
416 static Str255 buf;
417 int len;
419 len = strlen(str);
420 if (len > 255)
421 len = 255;
422 buf[0] = (unsigned char)len;
423 strncpy((char *)buf+1, str, len);
424 return buf;
427 #if TARGET_API_MAC_OS8
428 void
429 c2pstrcpy(unsigned char *dst, const char *src)
431 int len;
433 len = strlen(src);
434 if ( len > 255 ) len = 255;
435 strncpy((char *)dst+1, src, len);
436 dst[0] = len;
438 #endif /* TARGET_API_MAC_OS8 */
440 /* Like strerror() but for Mac OS error numbers */
441 char *PyMac_StrError(int err)
443 static char buf[256];
444 Handle h;
445 char *str;
447 h = GetResource('Estr', err);
448 if ( h ) {
449 HLock(h);
450 str = (char *)*h;
451 memcpy(buf, str+1, (unsigned char)str[0]);
452 buf[(unsigned char)str[0]] = '\0';
453 HUnlock(h);
454 ReleaseResource(h);
455 } else {
456 sprintf(buf, "Mac OS error code %d", err);
458 return buf;
461 /* Exception object shared by all Mac specific modules for Mac OS errors */
462 PyObject *PyMac_OSErrException;
464 /* Initialize and return PyMac_OSErrException */
465 PyObject *
466 PyMac_GetOSErrException()
468 if (PyMac_OSErrException == NULL)
469 PyMac_OSErrException = PyString_FromString("MacOS.Error");
470 return PyMac_OSErrException;
473 /* Set a MAC-specific error from errno, and return NULL; return None if no error */
474 PyObject *
475 PyErr_Mac(PyObject *eobj, int err)
477 char *msg;
478 PyObject *v;
480 if (err == 0 && !PyErr_Occurred()) {
481 Py_INCREF(Py_None);
482 return Py_None;
484 if (err == -1 && PyErr_Occurred())
485 return NULL;
486 msg = PyMac_StrError(err);
487 v = Py_BuildValue("(is)", err, msg);
488 PyErr_SetObject(eobj, v);
489 Py_DECREF(v);
490 return NULL;
493 /* Call PyErr_Mac with PyMac_OSErrException */
494 PyObject *
495 PyMac_Error(OSErr err)
497 return PyErr_Mac(PyMac_GetOSErrException(), err);
500 #ifdef USE_STACKCHECK
501 /* Check for stack overflow */
503 PyOS_CheckStack()
505 char here;
506 static char *sentinel = 0;
507 static PyThreadState *thread_for_sentinel = 0;
509 if ( sentinel == 0 ) {
510 unsigned long stackspace = StackSpace();
512 #ifdef MAXIMUM_STACK_SIZE
513 /* See the comment at the definition */
514 if ( stackspace > MAXIMUM_STACK_SIZE )
515 stackspace = MAXIMUM_STACK_SIZE;
516 #endif
517 sentinel = &here - stackspace + MINIMUM_STACK_SIZE;
519 if ( thread_for_sentinel == 0 ) {
520 thread_for_sentinel = PyThreadState_Get();
522 if ( &here < sentinel ) {
523 if (thread_for_sentinel == PyThreadState_Get()) {
524 return -1;
525 #if 0
526 } else {
527 /* Else we are unsure... */
528 fprintf(stderr, "Stackcheck in other thread (was %x now %x)\n", thread_for_sentinel,PyThreadState_Get());
529 #endif
532 return 0;
534 #endif /* USE_STACKCHECK */
536 #if !TARGET_API_MAC_OSX
537 /* The catcher routine (which may not be used for all compilers) */
538 static RETSIGTYPE
539 intcatcher(sig)
540 int sig;
542 interrupted = 1;
543 signal(SIGINT, intcatcher);
546 void
547 PyOS_InitInterrupts()
549 if (signal(SIGINT, SIG_IGN) != SIG_IGN)
550 signal(SIGINT, intcatcher);
553 void
554 PyOS_FiniInterrupts()
559 ** This routine scans the event queue looking for cmd-.
560 ** This is the only way to get an interrupt under THINK (since it
561 ** doesn't do SIGINT handling), but is also used under MW, when
562 ** the full-fledged event loop is disabled. This way, we can at least
563 ** interrupt a runaway python program.
565 static void
566 scan_event_queue(flush)
567 int flush;
569 #if !TARGET_API_MAC_OS8
570 if ( CheckEventQueueForUserCancel() )
571 interrupted = 1;
572 #else
573 register EvQElPtr q;
575 q = (EvQElPtr) LMGetEventQueue()->qHead;
577 for (; q; q = (EvQElPtr)q->qLink) {
578 if (q->evtQWhat == keyDown &&
579 (char)q->evtQMessage == '.' &&
580 (q->evtQModifiers & cmdKey) != 0) {
581 if ( flush )
582 FlushEvents(keyDownMask, 0);
583 interrupted = 1;
584 break;
587 #endif
591 PyErr_CheckSignals()
593 if (schedparams.enabled) {
594 if ( (unsigned long)LMGetTicks() > schedparams.next_check ) {
595 if ( PyMac_Yield() < 0)
596 return -1;
597 schedparams.next_check = (unsigned long)LMGetTicks()
598 + schedparams.check_interval;
599 if (interrupted) {
600 scan_event_queue(1); /* Eat events up to cmd-. */
601 interrupted = 0;
602 PyErr_SetNone(PyExc_KeyboardInterrupt);
603 return -1;
607 return 0;
611 PyOS_InterruptOccurred()
613 scan_event_queue(1);
614 return interrupted;
617 /* Check whether we are in the foreground */
618 static int
619 PyMac_InForeground(void)
621 static ProcessSerialNumber ours;
622 static inited;
623 ProcessSerialNumber curfg;
624 Boolean eq;
626 if ( inited == 0 ) {
627 (void)GetCurrentProcess(&ours);
628 inited = 1;
630 if ( GetFrontProcess(&curfg) < 0 )
631 eq = 1;
632 else if ( SameProcess(&ours, &curfg, &eq) < 0 )
633 eq = 1;
634 return (int)eq;
636 #endif
639 PyMac_SetEventHandler(PyObject *evh)
641 if ( evh && python_event_handler ) {
642 PyErr_SetString(PyExc_RuntimeError, "Python event handler already set");
643 return 0;
645 if ( python_event_handler )
646 Py_DECREF(python_event_handler);
647 if ( evh )
648 Py_INCREF(evh);
649 python_event_handler = evh;
650 return 1;
654 ** Handle an event, either one found in the mainloop eventhandler or
655 ** one passed back from the python program.
657 void
658 PyMac_HandleEventIntern(evp)
659 EventRecord *evp;
661 #if TARGET_API_MAC_OS8
662 if ( evp->what == mouseDown ) {
663 WindowPtr wp;
665 if ( FindWindow(evp->where, &wp) == inSysWindow ) {
666 SystemClick(evp, wp);
667 return;
670 #endif
671 #ifdef __MWERKS__
673 int siouxdidit;
675 /* If SIOUX wants it we're done */
676 siouxdidit = SIOUXHandleOneEvent(evp);
677 if ( siouxdidit )
678 return;
680 #else
681 /* Other compilers are just unlucky... */
682 #endif /* !__MWERKS__ */
686 ** Handle an event, either through HandleEvent or by passing it to the Python
687 ** event handler.
690 PyMac_HandleEvent(evp)
691 EventRecord *evp;
693 PyObject *rv;
695 if ( python_event_handler ) {
696 rv = PyObject_CallFunction(python_event_handler, "(O&)",
697 PyMac_BuildEventRecord, evp);
698 if ( rv )
699 Py_DECREF(rv);
700 else
701 return -1; /* Propagate exception */
702 } else {
703 PyMac_HandleEventIntern(evp);
705 return 0;
708 #if !TARGET_API_MAC_OSX
710 ** Yield the CPU to other tasks without processing events.
713 PyMac_DoYield(int maxsleep, int maycallpython)
715 EventRecord ev;
716 int gotone;
717 long latest_time_ready;
718 static int in_here = 0;
720 in_here++;
722 ** First check for interrupts, if wanted.
723 ** This sets a flag that will be picked up at an appropriate
724 ** moment in the mainloop.
726 if (schedparams.check_interrupt)
727 scan_event_queue(0);
729 /* XXXX Implementing an idle routine goes here */
732 ** Check which of the eventloop cases we have:
733 ** - process events
734 ** - don't process events but do yield
735 ** - do neither
737 if( in_here > 1 || !schedparams.process_events ||
738 (python_event_handler && !maycallpython) ) {
739 if ( maxsleep >= 0 ) {
740 #if TARGET_API_MAC_OS8
741 SystemTask();
742 #else
743 int xxx = 0;
744 #endif
746 } else {
747 latest_time_ready = LMGetTicks() + maxsleep;
748 do {
749 /* XXXX Hack by Jack.
750 ** In time.sleep() you can click to another application
751 ** once only. If you come back to Python you cannot get away
752 ** again.
754 gotone = WaitNextEvent(schedparams.process_events, &ev, maxsleep, NULL);
755 /* Get out quickly if nothing interesting is happening */
756 if ( !gotone || ev.what == nullEvent )
757 break;
758 if ( PyMac_HandleEvent(&ev) < 0 ) {
759 in_here--;
760 return -1;
762 maxsleep = latest_time_ready - LMGetTicks();
763 } while ( maxsleep > 0 );
765 in_here--;
766 return 0;
770 ** Process events and/or yield the CPU to other tasks if opportune
773 PyMac_Yield() {
774 unsigned long maxsleep;
776 if( PyMac_InForeground() )
777 maxsleep = 0;
778 else
779 maxsleep = schedparams.bg_yield;
781 return PyMac_DoYield(maxsleep, 1);
785 ** Return current scheduler parameters
787 void
788 PyMac_GetSchedParams(PyMacSchedParams *sp)
790 sp->check_interrupt = schedparams.check_interrupt;
791 sp->process_events = schedparams.process_events;
792 sp->besocial = schedparams.besocial;
793 sp->check_interval = schedparams.check_interval / 60.0;
794 sp->bg_yield = schedparams.bg_yield / 60.0;
798 ** Set current scheduler parameters
800 void
801 PyMac_SetSchedParams(PyMacSchedParams *sp)
803 schedparams.check_interrupt = sp->check_interrupt;
804 schedparams.process_events = sp->process_events;
805 schedparams.besocial = sp->besocial;
806 schedparams.check_interval = (unsigned long)(sp->check_interval*60);
807 schedparams.bg_yield = (unsigned long)(sp->bg_yield*60);
808 if ( schedparams.check_interrupt || schedparams.process_events ||
809 schedparams.besocial )
810 schedparams.enabled = 1;
811 else
812 schedparams.enabled = 0;
813 schedparams.next_check = 0; /* Check immedeately */
817 ** Install our menu bar.
819 void
820 PyMac_InitMenuBar()
822 MenuHandle applemenu;
824 if ( sioux_mbar ) return;
825 if ( (sioux_mbar=GetMenuBar()) == NULL ) {
826 /* Sioux menu not installed yet. Do so */
827 SIOUXSetupMenus();
828 if ( (sioux_mbar=GetMenuBar()) == NULL )
829 return;
831 if ( (applemenu=GetMenuHandle(SIOUX_APPLEID)) == NULL ) return;
832 SetMenuItemText(applemenu, 1, "\pAbout Python...");
836 ** Restore sioux menu bar
838 void
839 PyMac_RestoreMenuBar()
841 #if 1
842 /* This doesn't seem to work anymore? Or only for Carbon? */
843 MenuBarHandle curmenubar;
845 curmenubar = GetMenuBar();
846 if ( sioux_mbar ) {
847 SetMenuBar(sioux_mbar);
848 DrawMenuBar();
849 } else {
850 PyMac_InitMenuBar();
851 DrawMenuBar();
853 #endif
856 void
857 PyMac_RaiseConsoleWindow()
859 /* Note: this is a hack. SIOUXTextWindow is SIOUX's internal structure
860 ** and we happen to know that the first entry is the window pointer.
862 extern WindowRef *SIOUXTextWindow;
864 if ( SIOUXTextWindow == NULL || *SIOUXTextWindow == NULL )
865 return;
866 if ( FrontWindow() != *SIOUXTextWindow )
867 BringToFront(*SIOUXTextWindow);
871 ** Our replacement about box
874 #include "patchlevel.h"
876 void
877 SIOUXDoAboutBox(void)
879 DialogPtr theDialog;
880 WindowPtr theWindow;
881 short item;
882 short fontID;
884 if( (theDialog = GetNewDialog(ABOUT_ID, NULL, (WindowPtr)-1)) == NULL )
885 return;
886 theWindow = GetDialogWindow(theDialog);
887 SetPortWindowPort(theWindow);
888 GetFNum("\pPython-Sans", &fontID);
889 if (fontID == 0)
890 fontID = kFontIDGeneva;
891 TextFont(fontID);
892 TextSize(9);
893 ParamText(Pstring(PATCHLEVEL), "\p", "\p", "\p");
894 ShowWindow(theWindow);
895 ModalDialog(NULL, &item);
896 DisposeDialog(theDialog);
899 #endif /* !TARGET_API_MAC_OSX */
901 #if TARGET_API_MAC_OS8
903 ** Helper routine for GetDirectory
905 static pascal short
906 myhook_proc(short item, DialogPtr theDialog, struct hook_args *dataptr)
908 if ( item == sfHookFirstCall && dataptr->prompt) {
909 Handle prompth;
910 short type;
911 Rect rect;
913 GetDialogItem(theDialog, PROMPT_ITEM, &type, &prompth, &rect);
914 if ( prompth )
915 SetDialogItemText(prompth, (unsigned char *)dataptr->prompt);
916 } else
917 if ( item == SELECTCUR_ITEM ) {
918 item = sfItemCancelButton;
919 dataptr->selectcur_hit = 1;
921 return item;
925 ** Ask the user for a directory. I still can't understand
926 ** why Apple doesn't provide a standard solution for this...
929 PyMac_GetDirectory(dirfss, prompt)
930 FSSpec *dirfss;
931 char *prompt;
933 static SFTypeList list = {'fldr', 0, 0, 0};
934 static Point where = {-1, -1};
935 StandardFileReply reply;
936 struct hook_args hook_args;
938 if ( !upp_inited ) {
939 myhook_upp = NewDlgHookYDProc(myhook_proc);
940 upp_inited = 1;
942 if ( prompt && *prompt )
943 hook_args.prompt = (char *)Pstring(prompt);
944 else
945 hook_args.prompt = NULL;
946 hook_args.selectcur_hit = 0;
947 CustomGetFile((FileFilterYDUPP)0, 1, list, &reply, GETDIR_ID, where, myhook_upp,
948 NULL, NULL, NULL, (void *)&hook_args);
950 reply.sfFile.name[0] = 0;
951 if( FSMakeFSSpec(reply.sfFile.vRefNum, reply.sfFile.parID, reply.sfFile.name, dirfss) )
952 return 0;
953 return hook_args.selectcur_hit;
957 ** Slightly extended StandardGetFile: accepts a prompt */
958 void PyMac_PromptGetFile(short numTypes, ConstSFTypeListPtr typeList,
959 StandardFileReply *reply, char *prompt)
961 static Point where = {-1, -1};
962 struct hook_args hook_args;
964 if ( !upp_inited ) {
965 myhook_upp = NewDlgHookYDProc(myhook_proc);
966 upp_inited = 1;
968 if ( prompt && *prompt )
969 hook_args.prompt = (char *)Pstring(prompt);
970 else
971 hook_args.prompt = NULL;
972 hook_args.selectcur_hit = 0;
973 CustomGetFile((FileFilterYDUPP)0, numTypes, typeList, reply, GETFILEPROMPT_ID, where,
974 myhook_upp, NULL, NULL, NULL, (void *)&hook_args);
976 #endif /* TARGET_API_MAC_OS8 */
978 /* Convert a 4-char string object argument to an OSType value */
980 PyMac_GetOSType(PyObject *v, OSType *pr)
982 if (!PyString_Check(v) || PyString_Size(v) != 4) {
983 PyErr_SetString(PyExc_TypeError,
984 "OSType arg must be string of 4 chars");
985 return 0;
987 memcpy((char *)pr, PyString_AsString(v), 4);
988 return 1;
991 /* Convert an OSType value to a 4-char string object */
992 PyObject *
993 PyMac_BuildOSType(OSType t)
995 return PyString_FromStringAndSize((char *)&t, 4);
998 /* Convert an NumVersion value to a 4-element tuple */
999 PyObject *
1000 PyMac_BuildNumVersion(NumVersion t)
1002 return Py_BuildValue("(hhhh)", t.majorRev, t.minorAndBugRev, t.stage, t.nonRelRev);
1006 /* Convert a Python string object to a Str255 */
1008 PyMac_GetStr255(PyObject *v, Str255 pbuf)
1010 int len;
1011 if (!PyString_Check(v) || (len = PyString_Size(v)) > 255) {
1012 PyErr_SetString(PyExc_TypeError,
1013 "Str255 arg must be string of at most 255 chars");
1014 return 0;
1016 pbuf[0] = len;
1017 memcpy((char *)(pbuf+1), PyString_AsString(v), len);
1018 return 1;
1021 /* Convert a Str255 to a Python string object */
1022 PyObject *
1023 PyMac_BuildStr255(Str255 s)
1025 if ( s == NULL ) {
1026 PyErr_SetString(PyExc_SystemError, "Str255 pointer is NULL");
1027 return NULL;
1029 return PyString_FromStringAndSize((char *)&s[1], (int)s[0]);
1032 PyObject *
1033 PyMac_BuildOptStr255(Str255 s)
1035 if ( s == NULL ) {
1036 Py_INCREF(Py_None);
1037 return Py_None;
1039 return PyString_FromStringAndSize((char *)&s[1], (int)s[0]);
1044 /* Convert a Python object to a Rect.
1045 The object must be a (left, top, right, bottom) tuple.
1046 (This differs from the order in the struct but is consistent with
1047 the arguments to SetRect(), and also with STDWIN). */
1049 PyMac_GetRect(PyObject *v, Rect *r)
1051 return PyArg_Parse(v, "(hhhh)", &r->left, &r->top, &r->right, &r->bottom);
1054 /* Convert a Rect to a Python object */
1055 PyObject *
1056 PyMac_BuildRect(Rect *r)
1058 return Py_BuildValue("(hhhh)", r->left, r->top, r->right, r->bottom);
1062 /* Convert a Python object to a Point.
1063 The object must be a (h, v) tuple.
1064 (This differs from the order in the struct but is consistent with
1065 the arguments to SetPoint(), and also with STDWIN). */
1067 PyMac_GetPoint(PyObject *v, Point *p)
1069 return PyArg_Parse(v, "(hh)", &p->h, &p->v);
1072 /* Convert a Point to a Python object */
1073 PyObject *
1074 PyMac_BuildPoint(Point p)
1076 return Py_BuildValue("(hh)", p.h, p.v);
1080 /* Convert a Python object to an EventRecord.
1081 The object must be a (what, message, when, (v, h), modifiers) tuple. */
1083 PyMac_GetEventRecord(PyObject *v, EventRecord *e)
1085 return PyArg_Parse(v, "(Hll(hh)H)",
1086 &e->what,
1087 &e->message,
1088 &e->when,
1089 &e->where.h,
1090 &e->where.v,
1091 &e->modifiers);
1094 /* Convert a Rect to an EventRecord object */
1095 PyObject *
1096 PyMac_BuildEventRecord(EventRecord *e)
1098 return Py_BuildValue("(hll(hh)h)",
1099 e->what,
1100 e->message,
1101 e->when,
1102 e->where.h,
1103 e->where.v,
1104 e->modifiers);
1107 /* Convert Python object to Fixed */
1109 PyMac_GetFixed(PyObject *v, Fixed *f)
1111 double d;
1113 if( !PyArg_Parse(v, "d", &d))
1114 return 0;
1115 *f = (Fixed)(d * 0x10000);
1116 return 1;
1119 /* Convert a Point to a Python object */
1120 PyObject *
1121 PyMac_BuildFixed(Fixed f)
1123 double d;
1125 d = f;
1126 d = d / 0x10000;
1127 return Py_BuildValue("d", d);
1130 /* Convert wide to/from Python int or (hi, lo) tuple. XXXX Should use Python longs */
1132 PyMac_Getwide(PyObject *v, wide *rv)
1134 if (PyInt_Check(v)) {
1135 rv->hi = 0;
1136 rv->lo = PyInt_AsLong(v);
1137 if( rv->lo & 0x80000000 )
1138 rv->hi = -1;
1139 return 1;
1141 return PyArg_Parse(v, "(ll)", &rv->hi, &rv->lo);
1145 PyObject *
1146 PyMac_Buildwide(wide *w)
1148 if ( (w->hi == 0 && (w->lo & 0x80000000) == 0) ||
1149 (w->hi == -1 && (w->lo & 0x80000000) ) )
1150 return PyInt_FromLong(w->lo);
1151 return Py_BuildValue("(ll)", w->hi, w->lo);
1154 #ifdef USE_TOOLBOX_OBJECT_GLUE
1156 ** Glue together the toolbox objects.
1158 ** Because toolbox modules interdepend on each other, they use each others
1159 ** object types, on MacOSX/MachO this leads to the situation that they
1160 ** cannot be dynamically loaded (or they would all have to be lumped into
1161 ** a single .so, but this would be bad for extensibility).
1163 ** This file defines wrappers for all the _New and _Convert functions,
1164 ** which are the Py_BuildValue and PyArg_ParseTuple helpers. The wrappers
1165 ** check an indirection function pointer, and if it isn't filled in yet
1166 ** they import the appropriate module, whose init routine should fill in
1167 ** the pointer.
1170 #define GLUE_NEW(object, routinename, module) \
1171 PyObject *(*PyMacGluePtr_##routinename)(object); \
1173 PyObject *routinename(object cobj) { \
1174 if (!PyMacGluePtr_##routinename) { \
1175 if (!PyImport_ImportModule(module)) return NULL; \
1176 if (!PyMacGluePtr_##routinename) { \
1177 PyErr_SetString(PyExc_ImportError, "Module did not provide routine: " module ": " #routinename); \
1178 return NULL; \
1181 return (*PyMacGluePtr_##routinename)(cobj); \
1184 #define GLUE_CONVERT(object, routinename, module) \
1185 int (*PyMacGluePtr_##routinename)(PyObject *, object *); \
1187 int routinename(PyObject *pyobj, object *cobj) { \
1188 if (!PyMacGluePtr_##routinename) { \
1189 if (!PyImport_ImportModule(module)) return NULL; \
1190 if (!PyMacGluePtr_##routinename) { \
1191 PyErr_SetString(PyExc_ImportError, "Module did not provide routine: " module ": " #routinename); \
1192 return NULL; \
1195 return (*PyMacGluePtr_##routinename)(pyobj, cobj); \
1198 GLUE_NEW(AppleEvent *, AEDesc_New, "AE") /* XXXX Why by address? */
1199 GLUE_CONVERT(AppleEvent, AEDesc_Convert, "AE")
1201 GLUE_NEW(Component, CmpObj_New, "Cm")
1202 GLUE_CONVERT(Component, CmpObj_Convert, "Cm")
1203 GLUE_NEW(ComponentInstance, CmpInstObj_New, "Cm")
1204 GLUE_CONVERT(ComponentInstance, CmpInstObj_Convert, "Cm")
1206 GLUE_NEW(ControlHandle, CtlObj_New, "Ctl")
1207 GLUE_CONVERT(ControlHandle, CtlObj_Convert, "Ctl")
1209 GLUE_NEW(DialogPtr, DlgObj_New, "Dlg")
1210 GLUE_CONVERT(DialogPtr, DlgObj_Convert, "Dlg")
1211 GLUE_NEW(DialogPtr, DlgObj_WhichDialog, "Dlg")
1213 GLUE_NEW(DragReference, DragObj_New, "Drag")
1214 GLUE_CONVERT(DragReference, DragObj_Convert, "Drag")
1216 GLUE_NEW(ListHandle, ListObj_New, "List")
1217 GLUE_CONVERT(ListHandle, ListObj_Convert, "List")
1219 GLUE_NEW(MenuHandle, MenuObj_New, "Menu")
1220 GLUE_CONVERT(MenuHandle, MenuObj_Convert, "Menu")
1222 GLUE_NEW(GrafPtr, GrafObj_New, "Qd")
1223 GLUE_CONVERT(GrafPtr, GrafObj_Convert, "Qd")
1224 GLUE_NEW(BitMapPtr, BMObj_New, "Qd")
1225 GLUE_CONVERT(BitMapPtr, BMObj_Convert, "Qd")
1226 GLUE_NEW(RGBColor *, QdRGB_New, "Qd") /* XXXX Why? */
1227 GLUE_CONVERT(RGBColor, QdRGB_Convert, "Qd")
1229 GLUE_NEW(GWorldPtr, GWorldObj_New, "Qdoffs")
1230 GLUE_CONVERT(GWorldPtr, GWorldObj_Convert, "Qdoffs")
1232 GLUE_NEW(Track, TrackObj_New, "Qt")
1233 GLUE_CONVERT(Track, TrackObj_Convert, "Qt")
1234 GLUE_NEW(Movie, MovieObj_New, "Qt")
1235 GLUE_CONVERT(Movie, MovieObj_Convert, "Qt")
1236 GLUE_NEW(MovieController, MovieCtlObj_New, "Qt")
1237 GLUE_CONVERT(MovieController, MovieCtlObj_Convert, "Qt")
1238 GLUE_NEW(TimeBase, TimeBaseObj_New, "Qt")
1239 GLUE_CONVERT(TimeBase, TimeBaseObj_Convert, "Qt")
1240 GLUE_NEW(UserData, UserDataObj_New, "Qt")
1241 GLUE_CONVERT(UserData, UserDataObj_Convert, "Qt")
1242 GLUE_NEW(Media, MediaObj_New, "Qt")
1243 GLUE_CONVERT(Media, MediaObj_Convert, "Qt")
1245 GLUE_NEW(Handle, ResObj_New, "Res")
1246 GLUE_CONVERT(Handle, ResObj_Convert, "Res")
1247 GLUE_NEW(Handle, OptResObj_New, "Res")
1248 GLUE_CONVERT(Handle, OptResObj_Convert, "Res")
1250 GLUE_NEW(TEHandle, TEObj_New, "TE")
1251 GLUE_CONVERT(TEHandle, TEObj_Convert, "TE")
1253 GLUE_NEW(WindowPtr, WinObj_New, "Win")
1254 GLUE_CONVERT(WindowPtr, WinObj_Convert, "Win")
1255 GLUE_NEW(WindowPtr, WinObj_WhichWindow, "Win")
1257 #endif /* USE_TOOLBOX_OBJECT_GLUE */