1 /***********************************************************
2 Copyright 1991-1997 by Stichting Mathematisch Centrum, Amsterdam,
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 */
28 #include "pymactoolbox.h"
30 #include <Carbon/Carbon.h>
31 #include <ApplicationServices/ApplicationServices.h>
33 #ifndef HAVE_MACOS105_SDK
34 typedef SInt16 FSIORefNum
;
37 static PyObject
*MacOS_Error
; /* Exception MacOS.Error */
39 #define PATHNAMELEN 1024
41 /* ----------------------------------------------------- */
43 /* Declarations for objects of type Resource fork */
51 static PyTypeObject Rftype
;
55 /* ---------------------------------------------------------------- */
58 do_close(rfobject
*self
)
60 if (self
->isclosed
) return;
61 (void)FSCloseFork(self
->fRefNum
);
65 static char rf_read__doc__
[] =
66 "Read data from resource fork"
70 rf_read(rfobject
*self
, PyObject
*args
)
78 PyErr_SetString(PyExc_ValueError
, "Operation on closed file");
82 if (!PyArg_ParseTuple(args
, "l", &n
))
85 v
= PyBytes_FromStringAndSize((char *)NULL
, n
);
89 err
= FSReadFork(self
->fRefNum
, fsAtMark
, 0, n
, PyString_AsString(v
), &n2
);
90 if (err
&& err
!= eofErr
) {
95 _PyString_Resize(&v
, n2
);
100 static char rf_write__doc__
[] =
101 "Write to resource fork"
105 rf_write(rfobject
*self
, PyObject
*args
)
111 if (self
->isclosed
) {
112 PyErr_SetString(PyExc_ValueError
, "Operation on closed file");
115 if (!PyArg_ParseTuple(args
, "s#", &buffer
, &size
))
117 err
= FSWriteFork(self
->fRefNum
, fsAtMark
, 0, size
, buffer
, NULL
);
127 static char rf_seek__doc__
[] =
132 rf_seek(rfobject
*self
, PyObject
*args
)
135 int whence
= SEEK_SET
;
139 if (self
->isclosed
) {
140 PyErr_SetString(PyExc_ValueError
, "Operation on closed file");
143 if (!PyArg_ParseTuple(args
, "l|i", &amount
, &whence
)) {
162 err
= FSSetForkPosition(self
->fRefNum
, mode
, amount
);
172 static char rf_tell__doc__
[] =
177 rf_tell(rfobject
*self
, PyObject
*args
)
182 if (self
->isclosed
) {
183 PyErr_SetString(PyExc_ValueError
, "Operation on closed file");
186 if (!PyArg_ParseTuple(args
, ""))
189 err
= FSGetForkPosition(self
->fRefNum
, &where
);
194 return PyLong_FromLongLong(where
);
197 static char rf_close__doc__
[] =
198 "Close resource fork"
202 rf_close(rfobject
*self
, PyObject
*args
)
204 if (!PyArg_ParseTuple(args
, ""))
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 */
230 self
= PyObject_NEW(rfobject
, &Rftype
);
239 rf_dealloc(rfobject
*self
)
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
)
258 "MacOS.ResourceFork", /*tp_name*/
259 sizeof(rfobject
), /*tp_basicsize*/
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*/
269 0, /*tp_as_sequence*/
271 (hashfunc
)0, /*tp_hash*/
272 (ternaryfunc
)0, /*tp_call*/
273 (reprfunc
)0, /*tp_str*/
275 /* Space for future expansion */
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";
290 MacOS_GetCreatorAndType(PyObject
*self
, PyObject
*args
)
292 PyObject
*creator
, *type
, *res
;
295 FSCatalogInfo cataloginfo
;
298 if (!PyArg_ParseTuple(args
, "O&", PyMac_GetFSRef
, &ref
)) {
300 /* This function is documented to take an FSSpec as well,
301 * which only works in 32-bit mode.
307 if (!PyArg_ParseTuple(args
, "O&", PyMac_GetFSSpec
, &fss
))
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
);
322 #endif /* __LP64__ */
325 err
= FSGetCatalogInfo(&ref
,
326 kFSCatInfoFinderInfo
|kFSCatInfoNodeFlags
, &cataloginfo
,
329 PyErr_Mac(MacOS_Error
, err
);
333 if ((cataloginfo
.nodeFlags
& kFSNodeIsDirectoryMask
) != 0) {
334 /* Directory: doesn't have type/creator info.
336 * The specific error code is for backward compatibility with
339 PyErr_Mac(MacOS_Error
, fnfErr
);
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
);
353 static char setcrtp_doc
[] = "Set MacOS 4-char creator and type for a file";
356 MacOS_SetCreatorAndType(PyObject
*self
, PyObject
*args
)
358 ResType creator
, type
;
362 FSCatalogInfo cataloginfo
;
364 if (!PyArg_ParseTuple(args
, "O&O&O&",
365 PyMac_GetFSRef
, &ref
, PyMac_GetOSType
, &creator
, PyMac_GetOSType
, &type
)) {
367 /* Try to handle FSSpec arguments, for backward compatibility */
371 if (!PyArg_ParseTuple(args
, "O&O&O&",
372 PyMac_GetFSSpec
, &fss
, PyMac_GetOSType
, &creator
, PyMac_GetOSType
, &type
))
375 if ((err
= FSpGetFInfo(&fss
, &info
)) != noErr
)
376 return PyErr_Mac(MacOS_Error
, err
);
378 info
.fdCreator
= creator
;
381 if ((err
= FSpSetFInfo(&fss
, &info
)) != noErr
)
382 return PyErr_Mac(MacOS_Error
, err
);
387 #endif /* __LP64__ */
390 err
= FSGetCatalogInfo(&ref
,
391 kFSCatInfoFinderInfo
|kFSCatInfoNodeFlags
, &cataloginfo
,
394 PyErr_Mac(MacOS_Error
, err
);
398 if ((cataloginfo
.nodeFlags
& kFSNodeIsDirectoryMask
) != 0) {
399 /* Directory: doesn't have type/creator info.
401 * The specific error code is for backward compatibility with
404 PyErr_Mac(MacOS_Error
, fnfErr
);
408 finfo
= (FileInfo
*)&(cataloginfo
.finderInfo
);
409 finfo
->fileCreator
= creator
;
410 finfo
->fileType
= type
;
412 err
= FSSetCatalogInfo(&ref
, kFSCatInfoFinderInfo
, &cataloginfo
);
414 PyErr_Mac(MacOS_Error
, fnfErr
);
423 static char geterr_doc
[] = "Convert OSErr number to string";
426 MacOS_GetErrorString(PyObject
*self
, PyObject
*args
)
432 static int errors_loaded
;
434 if (!PyArg_ParseTuple(args
, "i", &err
))
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
447 m
= PyImport_ImportModuleNoBlock("macresource");
454 rv
= PyObject_CallMethod(m
, "open_error_resource", "");
462 /* And try again... */
463 h
= GetResource('Estr', err
);
469 ** Whether the code above succeeded or not, we won't try
477 memcpy(buf
, str
+1, (unsigned char)str
[0]);
478 buf
[(unsigned char)str
[0]] = '\0';
483 PyOS_snprintf(buf
, sizeof(buf
), "Mac OS error code %d", err
);
486 return Py_BuildValue("s", buf
);
492 static char splash_doc
[] = "Open a splash-screen dialog by resource-id (0=close)";
495 MacOS_splash(PyObject
*self
, PyObject
*args
)
498 static DialogPtr curdialog
= NULL
;
503 short xpos
, ypos
, width
, height
, swidth
, sheight
;
506 if (!PyArg_ParseTuple(args
, "|i", &resid
))
508 olddialog
= curdialog
;
512 curdialog
= GetNewDialog(resid
, NULL
, (WindowPtr
)-1);
514 theWindow
= GetDialogWindow(curdialog
);
515 thePort
= GetWindowPort(theWindow
);
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
);
526 DrawDialog(curdialog
);
530 DisposeDialog(olddialog
);
535 static char DebugStr_doc
[] = "Switch to low-level debugger with a message";
538 MacOS_DebugStr(PyObject
*self
, PyObject
*args
)
541 PyObject
*object
= 0;
543 if (!PyArg_ParseTuple(args
, "O&|O", PyMac_GetStr255
, message
, &object
))
552 static char SysBeep_doc
[] = "BEEEEEP!!!";
555 MacOS_SysBeep(PyObject
*self
, PyObject
*args
)
559 if (!PyArg_ParseTuple(args
, "|i", &duration
))
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."
574 MacOS_WMAvailable(PyObject
*self
, PyObject
*args
)
576 static PyObject
*rv
= NULL
;
578 if (!PyArg_ParseTuple(args
, ""))
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) {
600 if (GetCurrentProcess(&psn
) < 0 ||
601 SetFrontProcess(&psn
) < 0) {
612 static char GetTicks_doc
[] = "Return number of ticks since bootup";
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";
623 MacOS_openrf(PyObject
*self
, PyObject
*args
)
628 SInt8 permission
= fsRdPerm
;
632 if (!PyArg_ParseTuple(args
, "O&|s", PyMac_GetFSRef
, &ref
, &mode
))
637 case 'r': permission
= fsRdPerm
; break;
638 case 'w': permission
= fsWrPerm
; break;
646 err
= FSGetResourceForkName(&name
);
652 if ( (fp
= newrfobject()) == NULL
)
656 err
= FSOpenFork(&ref
, name
.length
, name
.unicode
, permission
, &fp
->fRefNum
);
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
},
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 */
689 if (PyErr_WarnPy3k("In 3.x, MacOS is removed.", 1))
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)
699 Rftype
.ob_type
= &PyType_Type
;
701 if (PyDict_SetItemString(d
, "ResourceForkType", (PyObject
*)&Rftype
) != 0)
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)
715 #define PY_RUNTIMEMODEL "macho"
716 if (PyDict_SetItemString(d
, "runtimemodel",
717 Py_BuildValue("s", PY_RUNTIMEMODEL
)) != 0)
719 #if defined(WITH_NEXT_FRAMEWORK)
720 #define PY_LINKMODEL "framework"
721 #elif defined(Py_ENABLE_SHARED)
722 #define PY_LINKMODEL "shared"
724 #define PY_LINKMODEL "static"
726 if (PyDict_SetItemString(d
, "linkmodel",
727 Py_BuildValue("s", PY_LINKMODEL
)) != 0)