PageRenderTime 671ms CodeModel.GetById 222ms app.highlight 222ms RepoModel.GetById 220ms app.codeStats 0ms

/Mac/Modules/MacOS.c

http://unladen-swallow.googlecode.com/
C | 730 lines | 536 code | 120 blank | 74 comment | 90 complexity | ede3df0108238092016359eb41122189 MD5 | raw file
  1/***********************************************************
  2Copyright 1991-1997 by Stichting Mathematisch Centrum, Amsterdam,
  3The Netherlands.
  4
  5                        All Rights Reserved
  6
  7Permission to use, copy, modify, and distribute this software and its 
  8documentation for any purpose and without fee is hereby granted, 
  9provided that the above copyright notice appear in all copies and that
 10both that copyright notice and this permission notice appear in 
 11supporting documentation, and that the names of Stichting Mathematisch
 12Centrum or CWI not be used in advertising or publicity pertaining to
 13distribution of the software without specific, written prior permission.
 14
 15STICHTING MATHEMATISCH CENTRUM DISCLAIMS ALL WARRANTIES WITH REGARD TO
 16THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
 17FITNESS, IN NO EVENT SHALL STICHTING MATHEMATISCH CENTRUM BE LIABLE
 18FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 19WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 20ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
 21OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 22
 23******************************************************************/
 24
 25/* Macintosh OS-specific interface */
 26
 27#include "Python.h"
 28#include "pymactoolbox.h"
 29
 30#include <Carbon/Carbon.h>
 31#include <ApplicationServices/ApplicationServices.h>
 32
 33#ifndef HAVE_OSX105_SDK
 34typedef SInt16	FSIORefNum;
 35#endif
 36
 37static PyObject *MacOS_Error; /* Exception MacOS.Error */
 38
 39#define PATHNAMELEN 1024
 40
 41/* ----------------------------------------------------- */
 42
 43/* Declarations for objects of type Resource fork */
 44
 45typedef struct {
 46	PyObject_HEAD
 47	FSIORefNum fRefNum;
 48	int isclosed;
 49} rfobject;
 50
 51static PyTypeObject Rftype;
 52
 53
 54
 55/* ---------------------------------------------------------------- */
 56
 57static void
 58do_close(rfobject *self)
 59{
 60	if (self->isclosed ) return;
 61	(void)FSCloseFork(self->fRefNum);
 62	self->isclosed = 1;
 63}
 64
 65static char rf_read__doc__[] = 
 66"Read data from resource fork"
 67;
 68
 69static PyObject *
 70rf_read(rfobject *self, PyObject *args)
 71{
 72	long n;
 73	PyObject *v;
 74	OSErr err;
 75	ByteCount n2;
 76	
 77	if (self->isclosed) {
 78		PyErr_SetString(PyExc_ValueError, "Operation on closed file");
 79		return NULL;
 80	}
 81	
 82	if (!PyArg_ParseTuple(args, "l", &n))
 83		return NULL;
 84		
 85	v = PyBytes_FromStringAndSize((char *)NULL, n);
 86	if (v == NULL)
 87		return NULL;
 88		
 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;
 94	}
 95	_PyString_Resize(&v, n2);
 96	return v;
 97}
 98
 99
100static char rf_write__doc__[] = 
101"Write to resource fork"
102;
103
104static PyObject *
105rf_write(rfobject *self, PyObject *args)
106{
107	char *buffer;
108	long size;
109	OSErr err;
110	
111	if (self->isclosed) {
112		PyErr_SetString(PyExc_ValueError, "Operation on closed file");
113		return NULL;
114	}
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;
121	}
122	Py_INCREF(Py_None);
123	return Py_None;
124}
125
126
127static char rf_seek__doc__[] = 
128"Set file position"
129;
130
131static PyObject *
132rf_seek(rfobject *self, PyObject *args)
133{
134	long amount;
135	int whence = SEEK_SET;
136	int mode;
137	OSErr err;
138	
139	if (self->isclosed) {
140		PyErr_SetString(PyExc_ValueError, "Operation on closed file");
141		return NULL;
142	}
143	if (!PyArg_ParseTuple(args, "l|i", &amount, &whence)) {
144		return NULL;
145	}
146	
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;
160	}
161
162	err = FSSetForkPosition(self->fRefNum, mode, amount);
163	if (err != noErr) {
164		PyMac_Error(err);
165		return NULL;
166	}
167	Py_INCREF(Py_None);
168	return Py_None;
169}
170
171
172static char rf_tell__doc__[] = 
173"Get file position"
174;
175
176static PyObject *
177rf_tell(rfobject *self, PyObject *args)
178{
179	long long where;
180	OSErr err;
181	
182	if (self->isclosed) {
183		PyErr_SetString(PyExc_ValueError, "Operation on closed file");
184		return NULL;
185	}
186	if (!PyArg_ParseTuple(args, ""))
187		return NULL;
188
189	err = FSGetForkPosition(self->fRefNum, &where);
190	if (err != noErr) {
191		PyMac_Error(err);
192		return NULL;
193	}
194	return PyLong_FromLongLong(where);
195}
196
197static char rf_close__doc__[] = 
198"Close resource fork"
199;
200
201static PyObject *
202rf_close(rfobject *self, PyObject *args)
203{
204	if (!PyArg_ParseTuple(args, ""))
205		return NULL;
206	do_close(self);
207	Py_INCREF(Py_None);
208	return Py_None;
209}
210
211
212static 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__},
218 
219	{NULL,		NULL}		/* sentinel */
220};
221
222/* ---------- */
223
224
225static rfobject *
226newrfobject(void)
227{
228	rfobject *self;
229	
230	self = PyObject_NEW(rfobject, &Rftype);
231	if (self == NULL)
232		return NULL;
233	self->isclosed = 1;
234	return self;
235}
236
237
238static void
239rf_dealloc(rfobject *self)
240{
241	do_close(self);
242	PyObject_DEL(self);
243}
244
245static PyObject *
246rf_getattr(rfobject *self, char *name)
247{
248	return Py_FindMethod(rf_methods, (PyObject *)self, name);
249}
250
251static char Rftype__doc__[] = 
252"Resource fork file object"
253;
254
255static 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*/
274
275	/* Space for future expansion */
276	0L,0L,0L,0L,
277	Rftype__doc__ /* Documentation string */
278};
279
280
281/* End of code for Resource fork objects */
282/* -------------------------------------------------------- */
283
284/*----------------------------------------------------------------------*/
285/* Miscellaneous File System Operations */
286
287static char getcrtp_doc[] = "Get MacOS 4-char creator and type for a file";
288
289static PyObject *
290MacOS_GetCreatorAndType(PyObject *self, PyObject *args)
291{
292	PyObject *creator, *type, *res;
293	OSErr err;
294	FSRef ref;
295	FSCatalogInfo	cataloginfo;
296	FileInfo* finfo;
297
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.
302		 */
303		PyErr_Clear();
304		FSSpec fss;
305		FInfo info;
306
307		if (!PyArg_ParseTuple(args, "O&", PyMac_GetFSSpec, &fss))
308			return NULL;
309
310		if ((err = FSpGetFInfo(&fss, &info)) != noErr) {
311			return PyErr_Mac(MacOS_Error, err);
312		}
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__ */
323	}
324
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;
331	}
332
333	if ((cataloginfo.nodeFlags & kFSNodeIsDirectoryMask) != 0) {
334		/* Directory: doesn't have type/creator info.
335		 *
336		 * The specific error code is for backward compatibility with
337		 * earlier versions.
338		 */
339		PyErr_Mac(MacOS_Error, fnfErr);
340		return NULL;
341
342	} 
343	finfo = (FileInfo*)&(cataloginfo.finderInfo);
344	creator = PyString_FromStringAndSize((char*)&(finfo->fileCreator), 4);
345	type = PyString_FromStringAndSize((char*)&(finfo->fileType), 4);
346
347	res = Py_BuildValue("OO", creator, type);
348	Py_DECREF(creator);
349	Py_DECREF(type);
350	return res;
351}
352
353static char setcrtp_doc[] = "Set MacOS 4-char creator and type for a file";
354
355static PyObject *
356MacOS_SetCreatorAndType(PyObject *self, PyObject *args)
357{
358	ResType creator, type;
359	FSRef ref;
360	FileInfo* finfo;
361	OSErr err;
362	FSCatalogInfo	cataloginfo;
363
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;
370
371		if (!PyArg_ParseTuple(args, "O&O&O&",
372			PyMac_GetFSSpec, &fss, PyMac_GetOSType, &creator, PyMac_GetOSType, &type))
373			return NULL;
374
375		if ((err = FSpGetFInfo(&fss, &info)) != noErr)
376			return PyErr_Mac(MacOS_Error, err);
377
378		info.fdCreator = creator;
379		info.fdType = type;
380
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__ */
388	}
389	
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;
396	}
397
398	if ((cataloginfo.nodeFlags & kFSNodeIsDirectoryMask) != 0) {
399		/* Directory: doesn't have type/creator info.
400		 *
401		 * The specific error code is for backward compatibility with
402		 * earlier versions.
403		 */
404		PyErr_Mac(MacOS_Error, fnfErr);
405		return NULL;
406
407	} 
408	finfo = (FileInfo*)&(cataloginfo.finderInfo);
409	finfo->fileCreator = creator;
410	finfo->fileType = type;
411
412	err = FSSetCatalogInfo(&ref, kFSCatInfoFinderInfo, &cataloginfo);
413	if (err != noErr) {
414		PyErr_Mac(MacOS_Error, fnfErr);
415		return NULL;
416	}
417
418	Py_INCREF(Py_None);
419	return Py_None;
420}
421
422
423static char geterr_doc[] = "Convert OSErr number to string";
424
425static PyObject *
426MacOS_GetErrorString(PyObject *self, PyObject *args)
427{
428	int err;
429	char buf[256];
430	Handle h;
431	char *str;
432	static int errors_loaded;
433	
434	if (!PyArg_ParseTuple(args, "i", &err))
435		return NULL;
436
437	h = GetResource('Estr', err);
438	if (!h && !errors_loaded) {
439		/*
440		** Attempt to open the resource file containing the
441		** Estr resources. We ignore all errors. We also try
442		** this only once.
443		*/
444		PyObject *m, *rv;
445		errors_loaded = 1;
446		
447		m = PyImport_ImportModuleNoBlock("macresource");
448		if (!m) {
449			if (Py_VerboseFlag)
450				PyErr_Print();
451			PyErr_Clear();
452		}
453		else {
454			rv = PyObject_CallMethod(m, "open_error_resource", "");
455			if (!rv) {
456				if (Py_VerboseFlag)
457					PyErr_Print();
458				PyErr_Clear();
459			}
460			else {
461				Py_DECREF(rv);
462				/* And try again... */
463				h = GetResource('Estr', err);
464			}
465			Py_DECREF(m);
466		}
467	}
468	/*
469	** Whether the code above succeeded or not, we won't try
470	** again.
471	*/
472	errors_loaded = 1;
473		
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);
481	}
482	else {
483		PyOS_snprintf(buf, sizeof(buf), "Mac OS error code %d", err);
484	}
485
486	return Py_BuildValue("s", buf);
487}
488
489
490#ifndef __LP64__
491
492static char splash_doc[] = "Open a splash-screen dialog by resource-id (0=close)";
493
494static PyObject *
495MacOS_splash(PyObject *self, PyObject *args)
496{
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
505	
506	if (!PyArg_ParseTuple(args, "|i", &resid))
507		return NULL;
508	olddialog = curdialog;
509	curdialog = NULL;
510
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);
527		}
528	}
529	if (olddialog)
530		DisposeDialog(olddialog);
531	Py_INCREF(Py_None);
532	return Py_None;
533}
534
535static char DebugStr_doc[] = "Switch to low-level debugger with a message";
536
537static PyObject *
538MacOS_DebugStr(PyObject *self, PyObject *args)
539{
540	Str255 message;
541	PyObject *object = 0;
542	
543	if (!PyArg_ParseTuple(args, "O&|O", PyMac_GetStr255, message, &object))
544		return NULL;
545	
546	DebugStr(message);
547	Py_INCREF(Py_None);
548	return Py_None;
549}
550
551
552static char SysBeep_doc[] = "BEEEEEP!!!";
553
554static PyObject *
555MacOS_SysBeep(PyObject *self, PyObject *args)
556{
557	int duration = 6;
558	
559	if (!PyArg_ParseTuple(args, "|i", &duration))
560		return NULL;
561	SysBeep(duration);
562	Py_INCREF(Py_None);
563	return Py_None;
564}
565
566#endif /* __LP64__ */
567
568static 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."
571	;
572
573static PyObject *
574MacOS_WMAvailable(PyObject *self, PyObject *args)
575{
576	static PyObject *rv = NULL;
577	
578	if (!PyArg_ParseTuple(args, ""))
579		return NULL;
580	if (!rv) {
581		ProcessSerialNumber psn;
582		
583		/*
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.
589		*/
590#ifdef kCGNullDirectDisplay
591		/* On 10.1 CGMainDisplayID() isn't available, and
592		** kCGNullDirectDisplay isn't defined.
593		*/
594		if (CGMainDisplayID() == 0) {
595			rv = Py_False;
596		} else {
597#else
598		{
599#endif
600			if (GetCurrentProcess(&psn) < 0 ||
601				SetFrontProcess(&psn) < 0) {
602				rv = Py_False;
603			} else {
604				rv = Py_True;
605			}
606		}
607	}
608	Py_INCREF(rv);
609	return rv;
610}
611
612static char GetTicks_doc[] = "Return number of ticks since bootup";
613
614static PyObject *
615MacOS_GetTicks(PyObject *self, PyObject *args)
616{
617	return Py_BuildValue("i", (int)TickCount());
618}
619
620static char openrf_doc[] = "Open resource fork of a file";
621
622static PyObject *
623MacOS_openrf(PyObject *self, PyObject *args)
624{
625	OSErr err;
626	char *mode = "r";
627	FSRef ref;
628	SInt8 permission = fsRdPerm;
629	rfobject *fp;
630	HFSUniStr255 name;
631		
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;
643		}
644	}
645
646	err = FSGetResourceForkName(&name);
647	if (err != noErr) {
648		PyMac_Error(err);
649		return NULL;
650	}
651	
652	if ( (fp = newrfobject()) == NULL )
653		return NULL;
654
655	
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;
661	}
662	fp->isclosed = 0;
663	return (PyObject *)fp;
664}
665
666
667
668static 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 */
681};
682
683
684void
685initMacOS(void)
686{
687	PyObject *m, *d;
688	
689	if (PyErr_WarnPy3k("In 3.x, MacOS is removed.", 1))
690		return;
691	
692	m = Py_InitModule("MacOS", MacOS_Methods);
693	d = PyModule_GetDict(m);
694	
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;
703	/*
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:-(
707	*/
708	{
709		PyStringObject *p = 0;
710		long off = (long)&(p->ob_sval[0]);
711		
712		if( PyDict_SetItemString(d, "string_id_to_buffer", Py_BuildValue("i", off)) != 0)
713			return;
714	}
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;
729
730}