[Pythonmac-SIG] Python RAD tools

Donovan Preston dp@ulaluma.com
Mon, 14 Jan 2002 11:36:42 -0800


--Apple-Mail-2-517548007
Content-Transfer-Encoding: 7bit
Content-Type: text/plain;
	charset=US-ASCII;
	format=flowed


On Sunday, January 13, 2002, at 05:27 AM, Adam Eijdenberg wrote:

> Hello all,
>
> I'm toying around with the idea of developing a Python rapid 
> application development tool, initially just for the Mac. This tool is 
> written in C for Carbon, so it is native in all regards and uses the 
> Unix mach-o version of Python.
>

Sounds cool. Myself, I'm just using Interface Builder -- It already has 
a RAD tool for designing interfaces, and likewise saves them in an XML 
format. Apple has provided as a part of Carbon, IBCarbonRuntime, which 
allows dearchiving of Carbon Interface Builder nibs on both OS X and OS 
9.

I just wrapped the IBCarbonRuntime.h header provided by Apple and it has 
been very easy for me to load nibs and attach event handlers to them 
using Carbon Events.

Here's an example of how little code it takes to use the module:

--------------------
from Carbon import IBCarbon
from Carbon import CarbonEvt					# The CarbonEvents functions
from Carbon import CarbonEvents				# The CarbonEvents constants

windowlist = []

def commandCallback(handler, event):
	# Get the event record describing what command was executed
	result = 
event.GetEventParameter(CarbonEvents.kEventParamDirectObject, 
CarbonEvents.typeHICommand)
	event = result[4:8]
	if event == 'new ':
		# If the user selected new window, load a nib and unarchive a window
		global windowlist
		# Create a reference to the nib named 'main' in my Application Bundle
		nib = IBCarbon.CreateNibReference('main')
		# Unarchive a window from the nib
		window = nib.CreateWindowFromNib('MyWindowNameInTheMainNib')
		# Keep the window from disappearing  after the function falls 
out of scope
		windowlist.append(window)
		window.ShowWindow()

# Get the application event target
AppTarget = CarbonEvt.GetApplicationEventTarget()
# Install a handler for "command" events on the application
# Command events can be set using the inspector panel in Interface 
Builder
# Many basic commands, such as new, quit, copy, paste, are already set 
(and many are handled automatically)
cmdsHandler = target.InstallEventHandler(('cmds', 1), commandCallback)
----------------------

It's great because the window objects that CreateWindowFromNib are 
standard wrapped WindowRef objects in Python, and you have full access 
to the PythonMac toolbox wrappers. Of course, you're programming more at 
a C level but with a little effort, a nicer Python framework API could 
be constructed that used these commands (similar to W. I'm writing my 
own very simple one, dspFramework, for my own purposes.) The nice thing 
about using the PythonMac toolbox wrappers is that there is lots of 
documentation -- any of the C Carbon or C Toolbox documentation can be 
used as a reference, with minor changes for use with python.

I'm attaching the IBCarbonRuntime.c file as well as the bgen files I 
used to generate it, in case anyone wants to play with it. Jack, maybe 
you'd consider putting it in the distribution this time?

Donovan


--Apple-Mail-2-517548007
Content-Disposition: attachment;
	filename=_IBCarbon.c
Content-Transfer-Encoding: 7bit
Content-Type: text/plain;
	x-mac-creator=43574945;
	x-unix-mode=0644;
	x-mac-type=54455854;
	name="_IBCarbon.c"


/* ======================== Module _IBCarbon ======================== */

#include "Python.h"



#ifdef WITHOUT_FRAMEWORKS
#include <IBCarbonRuntime.h>
#else
#include <Carbon/Carbon.h>
#endif /* WITHOUT_FRAMEWORKS */
#include "macglue.h"

#ifdef USE_TOOLBOX_OBJECT_GLUE
extern int _CFStringRefObj_Convert(PyObject *, CFStringRef *);
//#define CFStringRefObj_Convert _CFStringRefObj_Convert
#endif

//extern int CFBundleRefObj_Convert(PyObject *, CFBundleRef *);  // need to wrap CFBundle


static PyObject *IBCarbon_Error;

/* ---------------------- Object type IBNibRef ---------------------- */

PyTypeObject IBNibRef_Type;

#define IBNibRefObj_Check(x) ((x)->ob_type == &IBNibRef_Type)

typedef struct IBNibRefObject {
	PyObject_HEAD
	IBNibRef ob_itself;
} IBNibRefObject;

PyObject *IBNibRefObj_New(IBNibRef itself)
{
	IBNibRefObject *it;
	it = PyObject_NEW(IBNibRefObject, &IBNibRef_Type);
	if (it == NULL) return NULL;
	it->ob_itself = itself;
	return (PyObject *)it;
}
int IBNibRefObj_Convert(PyObject *v, IBNibRef *p_itself)
{
	if (!IBNibRefObj_Check(v))
	{
		PyErr_SetString(PyExc_TypeError, "IBNibRef required");
		return 0;
	}
	*p_itself = ((IBNibRefObject *)v)->ob_itself;
	return 1;
}

static void IBNibRefObj_dealloc(IBNibRefObject *self)
{
	DisposeNibReference(self->ob_itself);
	PyMem_DEL(self);
}

static PyObject *IBNibRefObj_CreateWindowFromNib(IBNibRefObject *_self, PyObject *_args)
{
	PyObject *_res = NULL;
	OSStatus _err;
	CFStringRef inName;
	WindowPtr outWindow;
	if (!PyArg_ParseTuple(_args, "O&",
	                      CFStringRefObj_Convert, &inName))
		return NULL;
	Py_BEGIN_ALLOW_THREADS
	_err = CreateWindowFromNib(_self->ob_itself,
	                           inName,
	                           &outWindow);
	Py_END_ALLOW_THREADS
	if (_err != noErr) return PyMac_Error(_err);
	_res = Py_BuildValue("O&",
	                     WinObj_New, outWindow);
	return _res;
}

static PyObject *IBNibRefObj_CreateMenuFromNib(IBNibRefObject *_self, PyObject *_args)
{
	PyObject *_res = NULL;
	OSStatus _err;
	CFStringRef inName;
	MenuHandle outMenuRef;
	if (!PyArg_ParseTuple(_args, "O&",
	                      CFStringRefObj_Convert, &inName))
		return NULL;
	Py_BEGIN_ALLOW_THREADS
	_err = CreateMenuFromNib(_self->ob_itself,
	                         inName,
	                         &outMenuRef);
	Py_END_ALLOW_THREADS
	if (_err != noErr) return PyMac_Error(_err);
	_res = Py_BuildValue("O&",
	                     MenuObj_New, outMenuRef);
	return _res;
}

static PyObject *IBNibRefObj_CreateMenuBarFromNib(IBNibRefObject *_self, PyObject *_args)
{
	PyObject *_res = NULL;
	OSStatus _err;
	CFStringRef inName;
	Handle outMenuBar;
	if (!PyArg_ParseTuple(_args, "O&",
	                      CFStringRefObj_Convert, &inName))
		return NULL;
	Py_BEGIN_ALLOW_THREADS
	_err = CreateMenuBarFromNib(_self->ob_itself,
	                            inName,
	                            &outMenuBar);
	Py_END_ALLOW_THREADS
	if (_err != noErr) return PyMac_Error(_err);
	_res = Py_BuildValue("O&",
	                     ResObj_New, outMenuBar);
	return _res;
}

static PyObject *IBNibRefObj_SetMenuBarFromNib(IBNibRefObject *_self, PyObject *_args)
{
	PyObject *_res = NULL;
	OSStatus _err;
	CFStringRef inName;
	if (!PyArg_ParseTuple(_args, "O&",
	                      CFStringRefObj_Convert, &inName))
		return NULL;
	Py_BEGIN_ALLOW_THREADS
	_err = SetMenuBarFromNib(_self->ob_itself,
	                         inName);
	Py_END_ALLOW_THREADS
	if (_err != noErr) return PyMac_Error(_err);
	Py_INCREF(Py_None);
	_res = Py_None;
	return _res;
}

static PyMethodDef IBNibRefObj_methods[] = {
	{"CreateWindowFromNib", (PyCFunction)IBNibRefObj_CreateWindowFromNib, 1,
	 "(CFStringRef inName) -> (WindowPtr outWindow)"},
	{"CreateMenuFromNib", (PyCFunction)IBNibRefObj_CreateMenuFromNib, 1,
	 "(CFStringRef inName) -> (MenuHandle outMenuRef)"},
	{"CreateMenuBarFromNib", (PyCFunction)IBNibRefObj_CreateMenuBarFromNib, 1,
	 "(CFStringRef inName) -> (Handle outMenuBar)"},
	{"SetMenuBarFromNib", (PyCFunction)IBNibRefObj_SetMenuBarFromNib, 1,
	 "(CFStringRef inName) -> None"},
	{NULL, NULL, 0}
};

PyMethodChain IBNibRefObj_chain = { IBNibRefObj_methods, NULL };

static PyObject *IBNibRefObj_getattr(IBNibRefObject *self, char *name)
{
	return Py_FindMethodInChain(&IBNibRefObj_chain, (PyObject *)self, name);
}

#define IBNibRefObj_setattr NULL

#define IBNibRefObj_compare NULL

#define IBNibRefObj_repr NULL

#define IBNibRefObj_hash NULL

PyTypeObject IBNibRef_Type = {
	PyObject_HEAD_INIT(NULL)
	0, /*ob_size*/
	"_IBCarbon.IBNibRef", /*tp_name*/
	sizeof(IBNibRefObject), /*tp_basicsize*/
	0, /*tp_itemsize*/
	/* methods */
	(destructor) IBNibRefObj_dealloc, /*tp_dealloc*/
	0, /*tp_print*/
	(getattrfunc) IBNibRefObj_getattr, /*tp_getattr*/
	(setattrfunc) IBNibRefObj_setattr, /*tp_setattr*/
	(cmpfunc) IBNibRefObj_compare, /*tp_compare*/
	(reprfunc) IBNibRefObj_repr, /*tp_repr*/
	(PyNumberMethods *)0, /* tp_as_number */
	(PySequenceMethods *)0, /* tp_as_sequence */
	(PyMappingMethods *)0, /* tp_as_mapping */
	(hashfunc) IBNibRefObj_hash, /*tp_hash*/
};

/* -------------------- End object type IBNibRef -------------------- */


static PyObject *IBCarbon_CreateNibReference(PyObject *_self, PyObject *_args)
{
	PyObject *_res = NULL;
	OSStatus _err;
	CFStringRef inNibName;
	IBNibRef outNibRef;
	if (!PyArg_ParseTuple(_args, "O&",
	                      CFStringRefObj_Convert, &inNibName))
		return NULL;
	Py_BEGIN_ALLOW_THREADS
	_err = CreateNibReference(inNibName,
	                          &outNibRef);
	Py_END_ALLOW_THREADS
	if (_err != noErr) return PyMac_Error(_err);
	_res = Py_BuildValue("O&",
	                     IBNibRefObj_New, outNibRef);
	return _res;
}

static PyMethodDef IBCarbon_methods[] = {
	{"CreateNibReference", (PyCFunction)IBCarbon_CreateNibReference, 1,
	 "(CFStringRef inNibName) -> (IBNibRef outNibRef)"},
	{NULL, NULL, 0}
};




void init_IBCarbon(void)
{
	PyObject *m;
	PyObject *d;





	m = Py_InitModule("_IBCarbon", IBCarbon_methods);
	d = PyModule_GetDict(m);
	IBCarbon_Error = PyMac_GetOSErrException();
	if (IBCarbon_Error == NULL ||
	    PyDict_SetItemString(d, "Error", IBCarbon_Error) != 0)
		return;
	IBNibRef_Type.ob_type = &PyType_Type;
	Py_INCREF(&IBNibRef_Type);
	if (PyDict_SetItemString(d, "IBNibRefType", (PyObject *)&IBNibRef_Type) != 0)
		Py_FatalError("can't initialize IBNibRefType");
}

/* ====================== End module _IBCarbon ====================== */


--Apple-Mail-2-517548007
Content-Disposition: attachment
Content-Type: multipart/appledouble;
	boundary=Apple-Mail-3-517548009


--Apple-Mail-3-517548009
Content-Disposition: attachment;
	filename=IBCarbonscan.py
Content-Transfer-Encoding: base64
Content-Type: application/applefile;
	name="IBCarbonscan.py"

AAUWBwACAAAAAAAAAAAAAAAAAAAAAAAAAAMAAAAJAAAAPgAAAAoAAAADAAAASAAAAA8AAAACAAAA
VwAAAX5URVhUUipjaAEASUJDYXJib25zY2FuLnB5AAABAAAAAUwAAABMAAAAMgAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAEgACU1vbmFjbwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAYABABPAAMCvwJ9AE8AAwK/
An24aG9uAAABggAAAYIAAAAAAQAAAAEAAAABTAAAAEwAAAAyACbAkAH7AAAAHAAyAABNUFNSAAAA
CgPt//8AAAAAAh9UwA==

--Apple-Mail-3-517548009
Content-Disposition: attachment;
	filename=IBCarbonscan.py
Content-Transfer-Encoding: 7bit
Content-Type: application/text;
	x-mac-creator=522A6368;
	x-unix-mode=0644;
	x-mac-type=54455854;
	name="IBCarbonscan.py"

# IBCarbonscan.py

import sys
import os
import string
import MacOS

BGENDIR= '/Users/dp/python/dist/src/Tools/bgen/bgen'
sys.path.append(BGENDIR)
print sys.path, sys.prefix
from bgenlocations import TOOLBOXDIR

from scantools import Scanner_OSX

def main():
	print "---Scanning IBCarbonRuntime.h---"
	input = ["IBCarbonRuntime.h"]
	output = "IBCarbongen.py"
	defsoutput = TOOLBOXDIR + "IBCarbonRuntime.py"
	scanner = IBCarbon_Scanner(input, output, defsoutput)
	scanner.scan()
	scanner.close()
	print "--done scanning, importing--"
	import IBCarbonsupport
	print "done"

class IBCarbon_Scanner(Scanner_OSX):
	def destination(self, type, name, arglist):
		classname = "IBCarbonFunction"
		listname = "functions"
		if arglist:
			t, n, m = arglist[0]
			if t == "IBNibRef" and m == "InMode":
				classname = "IBCarbonMethod"
				listname = "methods"
		return classname, listname

	def makeblacklistnames(self):
		return [
			"DisposeNibReference",				# taken care of by destructor
			"CreateNibReferenceWithCFBundle",  ## need to wrap CFBundle.h properly first
			]

if __name__ == "__main__":
	main()

--Apple-Mail-3-517548009--

--Apple-Mail-2-517548007
Content-Disposition: attachment
Content-Type: multipart/appledouble;
	boundary=Apple-Mail-4-517548011


--Apple-Mail-4-517548011
Content-Disposition: attachment;
	filename=IBCarbonsupport.py
Content-Transfer-Encoding: base64
Content-Type: application/applefile;
	name="IBCarbonsupport.py"

AAUWBwACAAAAAAAAAAAAAAAAAAAAAAAAAAMAAAAJAAAAPgAAAAoAAAADAAAASAAAABIAAAACAAAA
WgAAAX5URVhUUipjaAEASUJDYXJib25zdXBwb3J0LnB5AAABAAAAAUwAAABMAAAAMgAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAEgACU1vbmFjbwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAYABABTAJgCvQMSAFMA
mAK9AxK4aHCPAAABdAAAAXQAAAAAAQAAAAEAAAABTAAAAEwAAAAyACbAkALQAAAAHAAyAABNUFNS
AAAACgPt//8AAAAAAh9GpA==

--Apple-Mail-4-517548011
Content-Disposition: attachment;
	filename=IBCarbonsupport.py
Content-Transfer-Encoding: 7bit
Content-Type: application/text;
	x-mac-creator=522A6368;
	x-unix-mode=0644;
	x-mac-type=54455854;
	name="IBCarbonsupport.py"

# IBCarbonsupport.py

from macsupport import *

CFStringRef = OpaqueByValueType('CFStringRef', 'CFStringRefObj')
IBNibRef = OpaqueByValueType('IBNibRef', 'IBNibRefObj')
#CFBundleRef = OpaqueByValueType('CFBundleRef')

IBCarbonFunction = OSErrFunctionGenerator
IBCarbonMethod = OSErrMethodGenerator

includestuff = """
#ifdef WITHOUT_FRAMEWORKS
#include <IBCarbonRuntime.h>
#else
#include <Carbon/Carbon.h>
#endif /* WITHOUT_FRAMEWORKS */
#include "macglue.h"

#ifdef USE_TOOLBOX_OBJECT_GLUE
extern int _CFStringRefObj_Convert(PyObject *, CFStringRef *);
//#define CFStringRefObj_Convert _CFStringRefObj_Convert
#endif

//extern int CFBundleRefObj_Convert(PyObject *, CFBundleRef *);  // need to wrap CFBundle

"""

initstuff = """

"""

module = MacModule('_IBCarbon', 'IBCarbon', includestuff, finalstuff, initstuff)

class CFReleaserObject(GlobalObjectDefinition):
	def outputFreeIt(self, name):
		Output("CFRelease(%s);" % name)

class CFNibDesc(GlobalObjectDefinition):
	def outputFreeIt(self, name):
		Output("DisposeNibReference(%s);" % name)

#cfstringobject = CFReleaserObject("CFStringRef")
#module.addobject(cfstringobject)
#cfbundleobject = CFReleaserObject("CFBundleRef")
#module.addobject(cfbundleobject)
ibnibobject = CFNibDesc("IBNibRef", "IBNibRefObj")
module.addobject(ibnibobject)

functions = []
methods = []

execfile('IBCarbongen.py')

for f in functions: module.add(f)
for m in methods: ibnibobject.add(m)

SetOutputFileName('_IBCarbon.c')
module.generate()

--Apple-Mail-4-517548011--

--Apple-Mail-2-517548007--