This reverts r63675 based on the discussion in this thread:
[python.git] / Mac / Modules / MacOS.c
blob07a3434bd87c70bf9b92df5958fec1b7a5a0ba66
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 ******************************************************************/
25 /* Macintosh OS-specific interface */
27 #include "Python.h"
28 #include "pymactoolbox.h"
30 #include <Carbon/Carbon.h>
31 #include <ApplicationServices/ApplicationServices.h>
33 #ifndef HAVE_MACOS105_SDK
34 typedef SInt16 FSIORefNum;
35 #endif
37 static PyObject *MacOS_Error; /* Exception MacOS.Error */
39 #define PATHNAMELEN 1024
41 /* ----------------------------------------------------- */
43 /* Declarations for objects of type Resource fork */
45 typedef struct {
46 PyObject_HEAD
47 FSIORefNum fRefNum;
48 int isclosed;
49 } rfobject;
51 static PyTypeObject Rftype;
55 /* ---------------------------------------------------------------- */
57 static void
58 do_close(rfobject *self)
60 if (self->isclosed ) return;
61 (void)FSCloseFork(self->fRefNum);
62 self->isclosed = 1;
65 static char rf_read__doc__[] =
66 "Read data from resource fork"
69 static PyObject *
70 rf_read(rfobject *self, PyObject *args)
72 long n;
73 PyObject *v;
74 OSErr err;
75 ByteCount n2;
77 if (self->isclosed) {
78 PyErr_SetString(PyExc_ValueError, "Operation on closed file");
79 return NULL;
82 if (!PyArg_ParseTuple(args, "l", &n))
83 return NULL;
85 v = PyBytes_FromStringAndSize((char *)NULL, n);
86 if (v == NULL)
87 return NULL;
89 err = FSReadFork(self->fRefNum, fsAtMark, 0, n, PyString_AsString(v), &n2);
90 if (err && err != eofErr) {
91 PyMac_Error(err);
92 Py_DECREF(v);
93 return NULL;
95 _PyString_Resize(&v, n2);
96 return v;
100 static char rf_write__doc__[] =
101 "Write to resource fork"
104 static PyObject *
105 rf_write(rfobject *self, PyObject *args)
107 char *buffer;
108 long size;
109 OSErr err;
111 if (self->isclosed) {
112 PyErr_SetString(PyExc_ValueError, "Operation on closed file");
113 return NULL;
115 if (!PyArg_ParseTuple(args, "s#", &buffer, &size))
116 return NULL;
117 err = FSWriteFork(self->fRefNum, fsAtMark, 0, size, buffer, NULL);
118 if (err) {
119 PyMac_Error(err);
120 return NULL;
122 Py_INCREF(Py_None);
123 return Py_None;
127 static char rf_seek__doc__[] =
128 "Set file position"
131 static PyObject *
132 rf_seek(rfobject *self, PyObject *args)
134 long amount;
135 int whence = SEEK_SET;
136 int mode;
137 OSErr err;
139 if (self->isclosed) {
140 PyErr_SetString(PyExc_ValueError, "Operation on closed file");
141 return NULL;
143 if (!PyArg_ParseTuple(args, "l|i", &amount, &whence)) {
144 return NULL;
147 switch (whence) {
148 case SEEK_CUR:
149 mode = fsFromMark;
150 break;
151 case SEEK_END:
152 mode = fsFromLEOF;
153 break;
154 case SEEK_SET:
155 mode = fsFromStart;
156 break;
157 default:
158 PyErr_BadArgument();
159 return NULL;
162 err = FSSetForkPosition(self->fRefNum, mode, amount);
163 if (err != noErr) {
164 PyMac_Error(err);
165 return NULL;
167 Py_INCREF(Py_None);
168 return Py_None;
172 static char rf_tell__doc__[] =
173 "Get file position"
176 static PyObject *
177 rf_tell(rfobject *self, PyObject *args)
179 long long where;
180 OSErr err;
182 if (self->isclosed) {
183 PyErr_SetString(PyExc_ValueError, "Operation on closed file");
184 return NULL;
186 if (!PyArg_ParseTuple(args, ""))
187 return NULL;
189 err = FSGetForkPosition(self->fRefNum, &where);
190 if (err != noErr) {
191 PyMac_Error(err);
192 return NULL;
194 return PyLong_FromLongLong(where);
197 static char rf_close__doc__[] =
198 "Close resource fork"
201 static PyObject *
202 rf_close(rfobject *self, PyObject *args)
204 if (!PyArg_ParseTuple(args, ""))
205 return NULL;
206 do_close(self);
207 Py_INCREF(Py_None);
208 return Py_None;
212 static struct PyMethodDef rf_methods[] = {
213 {"read", (PyCFunction)rf_read, 1, rf_read__doc__},
214 {"write", (PyCFunction)rf_write, 1, rf_write__doc__},
215 {"seek", (PyCFunction)rf_seek, 1, rf_seek__doc__},
216 {"tell", (PyCFunction)rf_tell, 1, rf_tell__doc__},
217 {"close", (PyCFunction)rf_close, 1, rf_close__doc__},
219 {NULL, NULL} /* sentinel */
222 /* ---------- */
225 static rfobject *
226 newrfobject(void)
228 rfobject *self;
230 self = PyObject_NEW(rfobject, &Rftype);
231 if (self == NULL)
232 return NULL;
233 self->isclosed = 1;
234 return self;
238 static void
239 rf_dealloc(rfobject *self)
241 do_close(self);
242 PyObject_DEL(self);
245 static PyObject *
246 rf_getattr(rfobject *self, char *name)
248 return Py_FindMethod(rf_methods, (PyObject *)self, name);
251 static char Rftype__doc__[] =
252 "Resource fork file object"
255 static PyTypeObject Rftype = {
256 PyObject_HEAD_INIT(&PyType_Type)
257 0, /*ob_size*/
258 "MacOS.ResourceFork", /*tp_name*/
259 sizeof(rfobject), /*tp_basicsize*/
260 0, /*tp_itemsize*/
261 /* methods */
262 (destructor)rf_dealloc, /*tp_dealloc*/
263 (printfunc)0, /*tp_print*/
264 (getattrfunc)rf_getattr, /*tp_getattr*/
265 (setattrfunc)0, /*tp_setattr*/
266 (cmpfunc)0, /*tp_compare*/
267 (reprfunc)0, /*tp_repr*/
268 0, /*tp_as_number*/
269 0, /*tp_as_sequence*/
270 0, /*tp_as_mapping*/
271 (hashfunc)0, /*tp_hash*/
272 (ternaryfunc)0, /*tp_call*/
273 (reprfunc)0, /*tp_str*/
275 /* Space for future expansion */
276 0L,0L,0L,0L,
277 Rftype__doc__ /* Documentation string */
281 /* End of code for Resource fork objects */
282 /* -------------------------------------------------------- */
284 /*----------------------------------------------------------------------*/
285 /* Miscellaneous File System Operations */
287 static char getcrtp_doc[] = "Get MacOS 4-char creator and type for a file";
289 static PyObject *
290 MacOS_GetCreatorAndType(PyObject *self, PyObject *args)
292 PyObject *creator, *type, *res;
293 OSErr err;
294 FSRef ref;
295 FSCatalogInfo cataloginfo;
296 FileInfo* finfo;
298 if (!PyArg_ParseTuple(args, "O&", PyMac_GetFSRef, &ref)) {
299 #ifndef __LP64__
300 /* This function is documented to take an FSSpec as well,
301 * which only works in 32-bit mode.
303 PyErr_Clear();
304 FSSpec fss;
305 FInfo info;
307 if (!PyArg_ParseTuple(args, "O&", PyMac_GetFSSpec, &fss))
308 return NULL;
310 if ((err = FSpGetFInfo(&fss, &info)) != noErr) {
311 return PyErr_Mac(MacOS_Error, err);
313 creator = PyString_FromStringAndSize(
314 (char *)&info.fdCreator, 4);
315 type = PyString_FromStringAndSize((char *)&info.fdType, 4);
316 res = Py_BuildValue("OO", creator, type);
317 Py_DECREF(creator);
318 Py_DECREF(type);
319 return res;
320 #else /* __LP64__ */
321 return NULL;
322 #endif /* __LP64__ */
325 err = FSGetCatalogInfo(&ref,
326 kFSCatInfoFinderInfo|kFSCatInfoNodeFlags, &cataloginfo,
327 NULL, NULL, NULL);
328 if (err != noErr) {
329 PyErr_Mac(MacOS_Error, err);
330 return NULL;
333 if ((cataloginfo.nodeFlags & kFSNodeIsDirectoryMask) != 0) {
334 /* Directory: doesn't have type/creator info.
336 * The specific error code is for backward compatibility with
337 * earlier versions.
339 PyErr_Mac(MacOS_Error, fnfErr);
340 return NULL;
343 finfo = (FileInfo*)&(cataloginfo.finderInfo);
344 creator = PyString_FromStringAndSize((char*)&(finfo->fileCreator), 4);
345 type = PyString_FromStringAndSize((char*)&(finfo->fileType), 4);
347 res = Py_BuildValue("OO", creator, type);
348 Py_DECREF(creator);
349 Py_DECREF(type);
350 return res;
353 static char setcrtp_doc[] = "Set MacOS 4-char creator and type for a file";
355 static PyObject *
356 MacOS_SetCreatorAndType(PyObject *self, PyObject *args)
358 ResType creator, type;
359 FSRef ref;
360 FileInfo* finfo;
361 OSErr err;
362 FSCatalogInfo cataloginfo;
364 if (!PyArg_ParseTuple(args, "O&O&O&",
365 PyMac_GetFSRef, &ref, PyMac_GetOSType, &creator, PyMac_GetOSType, &type)) {
366 #ifndef __LP64__
367 /* Try to handle FSSpec arguments, for backward compatibility */
368 FSSpec fss;
369 FInfo info;
371 if (!PyArg_ParseTuple(args, "O&O&O&",
372 PyMac_GetFSSpec, &fss, PyMac_GetOSType, &creator, PyMac_GetOSType, &type))
373 return NULL;
375 if ((err = FSpGetFInfo(&fss, &info)) != noErr)
376 return PyErr_Mac(MacOS_Error, err);
378 info.fdCreator = creator;
379 info.fdType = type;
381 if ((err = FSpSetFInfo(&fss, &info)) != noErr)
382 return PyErr_Mac(MacOS_Error, err);
383 Py_INCREF(Py_None);
384 return Py_None;
385 #else /* __LP64__ */
386 return NULL;
387 #endif /* __LP64__ */
390 err = FSGetCatalogInfo(&ref,
391 kFSCatInfoFinderInfo|kFSCatInfoNodeFlags, &cataloginfo,
392 NULL, NULL, NULL);
393 if (err != noErr) {
394 PyErr_Mac(MacOS_Error, err);
395 return NULL;
398 if ((cataloginfo.nodeFlags & kFSNodeIsDirectoryMask) != 0) {
399 /* Directory: doesn't have type/creator info.
401 * The specific error code is for backward compatibility with
402 * earlier versions.
404 PyErr_Mac(MacOS_Error, fnfErr);
405 return NULL;
408 finfo = (FileInfo*)&(cataloginfo.finderInfo);
409 finfo->fileCreator = creator;
410 finfo->fileType = type;
412 err = FSSetCatalogInfo(&ref, kFSCatInfoFinderInfo, &cataloginfo);
413 if (err != noErr) {
414 PyErr_Mac(MacOS_Error, fnfErr);
415 return NULL;
418 Py_INCREF(Py_None);
419 return Py_None;
423 static char geterr_doc[] = "Convert OSErr number to string";
425 static PyObject *
426 MacOS_GetErrorString(PyObject *self, PyObject *args)
428 int err;
429 char buf[256];
430 Handle h;
431 char *str;
432 static int errors_loaded;
434 if (!PyArg_ParseTuple(args, "i", &err))
435 return NULL;
437 h = GetResource('Estr', err);
438 if (!h && !errors_loaded) {
440 ** Attempt to open the resource file containing the
441 ** Estr resources. We ignore all errors. We also try
442 ** this only once.
444 PyObject *m, *rv;
445 errors_loaded = 1;
447 m = PyImport_ImportModuleNoBlock("macresource");
448 if (!m) {
449 if (Py_VerboseFlag)
450 PyErr_Print();
451 PyErr_Clear();
453 else {
454 rv = PyObject_CallMethod(m, "open_error_resource", "");
455 if (!rv) {
456 if (Py_VerboseFlag)
457 PyErr_Print();
458 PyErr_Clear();
460 else {
461 Py_DECREF(rv);
462 /* And try again... */
463 h = GetResource('Estr', err);
465 Py_DECREF(m);
469 ** Whether the code above succeeded or not, we won't try
470 ** again.
472 errors_loaded = 1;
474 if (h) {
475 HLock(h);
476 str = (char *)*h;
477 memcpy(buf, str+1, (unsigned char)str[0]);
478 buf[(unsigned char)str[0]] = '\0';
479 HUnlock(h);
480 ReleaseResource(h);
482 else {
483 PyOS_snprintf(buf, sizeof(buf), "Mac OS error code %d", err);
486 return Py_BuildValue("s", buf);
490 #ifndef __LP64__
492 static char splash_doc[] = "Open a splash-screen dialog by resource-id (0=close)";
494 static PyObject *
495 MacOS_splash(PyObject *self, PyObject *args)
497 int resid = -1;
498 static DialogPtr curdialog = NULL;
499 DialogPtr olddialog;
500 WindowRef theWindow;
501 CGrafPtr thePort;
502 #if 0
503 short xpos, ypos, width, height, swidth, sheight;
504 #endif
506 if (!PyArg_ParseTuple(args, "|i", &resid))
507 return NULL;
508 olddialog = curdialog;
509 curdialog = NULL;
511 if ( resid != -1 ) {
512 curdialog = GetNewDialog(resid, NULL, (WindowPtr)-1);
513 if ( curdialog ) {
514 theWindow = GetDialogWindow(curdialog);
515 thePort = GetWindowPort(theWindow);
516 #if 0
517 width = thePort->portRect.right - thePort->portRect.left;
518 height = thePort->portRect.bottom - thePort->portRect.top;
519 swidth = qd.screenBits.bounds.right - qd.screenBits.bounds.left;
520 sheight = qd.screenBits.bounds.bottom - qd.screenBits.bounds.top - LMGetMBarHeight();
521 xpos = (swidth-width)/2;
522 ypos = (sheight-height)/5 + LMGetMBarHeight();
523 MoveWindow(theWindow, xpos, ypos, 0);
524 ShowWindow(theWindow);
525 #endif
526 DrawDialog(curdialog);
529 if (olddialog)
530 DisposeDialog(olddialog);
531 Py_INCREF(Py_None);
532 return Py_None;
535 static char DebugStr_doc[] = "Switch to low-level debugger with a message";
537 static PyObject *
538 MacOS_DebugStr(PyObject *self, PyObject *args)
540 Str255 message;
541 PyObject *object = 0;
543 if (!PyArg_ParseTuple(args, "O&|O", PyMac_GetStr255, message, &object))
544 return NULL;
546 DebugStr(message);
547 Py_INCREF(Py_None);
548 return Py_None;
552 static char SysBeep_doc[] = "BEEEEEP!!!";
554 static PyObject *
555 MacOS_SysBeep(PyObject *self, PyObject *args)
557 int duration = 6;
559 if (!PyArg_ParseTuple(args, "|i", &duration))
560 return NULL;
561 SysBeep(duration);
562 Py_INCREF(Py_None);
563 return Py_None;
566 #endif /* __LP64__ */
568 static char WMAvailable_doc[] =
569 "True if this process can interact with the display."
570 "Will foreground the application on the first call as a side-effect."
573 static PyObject *
574 MacOS_WMAvailable(PyObject *self, PyObject *args)
576 static PyObject *rv = NULL;
578 if (!PyArg_ParseTuple(args, ""))
579 return NULL;
580 if (!rv) {
581 ProcessSerialNumber psn;
584 ** This is a fairly innocuous call to make if we don't have a window
585 ** manager, or if we have no permission to talk to it. It will print
586 ** a message on stderr, but at least it won't abort the process.
587 ** It appears the function caches the result itself, and it's cheap, so
588 ** no need for us to cache.
590 #ifdef kCGNullDirectDisplay
591 /* On 10.1 CGMainDisplayID() isn't available, and
592 ** kCGNullDirectDisplay isn't defined.
594 if (CGMainDisplayID() == 0) {
595 rv = Py_False;
596 } else {
597 #else
599 #endif
600 if (GetCurrentProcess(&psn) < 0 ||
601 SetFrontProcess(&psn) < 0) {
602 rv = Py_False;
603 } else {
604 rv = Py_True;
608 Py_INCREF(rv);
609 return rv;
612 static char GetTicks_doc[] = "Return number of ticks since bootup";
614 static PyObject *
615 MacOS_GetTicks(PyObject *self, PyObject *args)
617 return Py_BuildValue("i", (int)TickCount());
620 static char openrf_doc[] = "Open resource fork of a file";
622 static PyObject *
623 MacOS_openrf(PyObject *self, PyObject *args)
625 OSErr err;
626 char *mode = "r";
627 FSRef ref;
628 SInt8 permission = fsRdPerm;
629 rfobject *fp;
630 HFSUniStr255 name;
632 if (!PyArg_ParseTuple(args, "O&|s", PyMac_GetFSRef, &ref, &mode))
633 return NULL;
634 while (*mode) {
635 switch (*mode++) {
636 case '*': break;
637 case 'r': permission = fsRdPerm; break;
638 case 'w': permission = fsWrPerm; break;
639 case 'b': break;
640 default:
641 PyErr_BadArgument();
642 return NULL;
646 err = FSGetResourceForkName(&name);
647 if (err != noErr) {
648 PyMac_Error(err);
649 return NULL;
652 if ( (fp = newrfobject()) == NULL )
653 return NULL;
656 err = FSOpenFork(&ref, name.length, name.unicode, permission, &fp->fRefNum);
657 if (err != noErr) {
658 Py_DECREF(fp);
659 PyMac_Error(err);
660 return NULL;
662 fp->isclosed = 0;
663 return (PyObject *)fp;
668 static PyMethodDef MacOS_Methods[] = {
669 {"GetCreatorAndType", MacOS_GetCreatorAndType, 1, getcrtp_doc},
670 {"SetCreatorAndType", MacOS_SetCreatorAndType, 1, setcrtp_doc},
671 {"GetErrorString", MacOS_GetErrorString, 1, geterr_doc},
672 {"openrf", MacOS_openrf, 1, openrf_doc},
673 #ifndef __LP64__
674 {"splash", MacOS_splash, 1, splash_doc},
675 {"DebugStr", MacOS_DebugStr, 1, DebugStr_doc},
676 {"SysBeep", MacOS_SysBeep, 1, SysBeep_doc},
677 #endif /* __LP64__ */
678 {"GetTicks", MacOS_GetTicks, 1, GetTicks_doc},
679 {"WMAvailable", MacOS_WMAvailable, 1, WMAvailable_doc},
680 {NULL, NULL} /* Sentinel */
684 void
685 initMacOS(void)
687 PyObject *m, *d;
689 if (PyErr_WarnPy3k("In 3.x, MacOS is removed.", 1))
690 return;
692 m = Py_InitModule("MacOS", MacOS_Methods);
693 d = PyModule_GetDict(m);
695 /* Initialize MacOS.Error exception */
696 MacOS_Error = PyMac_GetOSErrException();
697 if (MacOS_Error == NULL || PyDict_SetItemString(d, "Error", MacOS_Error) != 0)
698 return;
699 Rftype.ob_type = &PyType_Type;
700 Py_INCREF(&Rftype);
701 if (PyDict_SetItemString(d, "ResourceForkType", (PyObject *)&Rftype) != 0)
702 return;
704 ** This is a hack: the following constant added to the id() of a string
705 ** object gives you the address of the data. Unfortunately, it is needed for
706 ** some of the image and sound processing interfaces on the mac:-(
709 PyStringObject *p = 0;
710 long off = (long)&(p->ob_sval[0]);
712 if( PyDict_SetItemString(d, "string_id_to_buffer", Py_BuildValue("i", off)) != 0)
713 return;
715 #define PY_RUNTIMEMODEL "macho"
716 if (PyDict_SetItemString(d, "runtimemodel",
717 Py_BuildValue("s", PY_RUNTIMEMODEL)) != 0)
718 return;
719 #if defined(WITH_NEXT_FRAMEWORK)
720 #define PY_LINKMODEL "framework"
721 #elif defined(Py_ENABLE_SHARED)
722 #define PY_LINKMODEL "shared"
723 #else
724 #define PY_LINKMODEL "static"
725 #endif
726 if (PyDict_SetItemString(d, "linkmodel",
727 Py_BuildValue("s", PY_LINKMODEL)) != 0)
728 return;