| 
									
										
										
										
											2001-02-11 01:08:04 +00:00
										 |  |  | /*
 | 
					
						
							|  |  |  | ** Modified version of GUSISIOUX.cp especially for Python. | 
					
						
							|  |  |  | ** Changes (by Jack): | 
					
						
							|  |  |  | ** - Optionally delay the console window until something is written to it. | 
					
						
							|  |  |  | ** - Tell the upper layers whether the last command was a read or a write. | 
					
						
							|  |  |  | ** - Tell SIOUX not to use WaitNextEvent (both Python and SIOUX trying to be | 
					
						
							|  |  |  | **   nice to background apps means we're yielding almost 100% of the time). | 
					
						
							|  |  |  | ** - Make sure signals are processed when returning from read/write. | 
					
						
							|  |  |  | */ | 
					
						
							|  |  |  | #define GUSI_SOURCE
 | 
					
						
							|  |  |  | #include "GUSIInternal.h"
 | 
					
						
							|  |  |  | #include "GUSISIOUX.h"
 | 
					
						
							|  |  |  | #include "GUSIDevice.h"
 | 
					
						
							|  |  |  | #include "GUSIDescriptor.h"
 | 
					
						
							|  |  |  | #include "GUSIBasics.h"
 | 
					
						
							|  |  |  | #include "GUSIDiag.h"
 | 
					
						
							|  |  |  | //#ifndef WITHOUT_JACK_MODS
 | 
					
						
							|  |  |  | //#include "GUSIConfig.h"
 | 
					
						
							|  |  |  | //#endif
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #include <LowMem.h>
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #include <fcntl.h>
 | 
					
						
							|  |  |  | #include <sys/stat.h>
 | 
					
						
							|  |  |  | #include <sys/ioctl.h>
 | 
					
						
							|  |  |  | #include <errno.h>
 | 
					
						
							|  |  |  | #include <console.h>
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #include "Python.h"
 | 
					
						
							|  |  |  | #include "macglue.h"
 | 
					
						
							|  |  |  | extern Boolean SIOUXUseWaitNextEvent; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | class GUSISIOUXSocket : public GUSISocket { | 
					
						
							|  |  |  | public: | 
					
						
							|  |  |  | 	~GUSISIOUXSocket(); | 
					
						
							|  |  |  | 	 | 
					
						
							|  |  |  | 	 | 
					
						
							|  |  |  | ssize_t	read(const GUSIScatterer & buffer); | 
					
						
							|  |  |  | ssize_t write(const GUSIGatherer & buffer); | 
					
						
							|  |  |  | virtual int	ioctl(unsigned int request, va_list arg); | 
					
						
							|  |  |  | virtual int	fstat(struct stat * buf); | 
					
						
							|  |  |  | virtual int	isatty(); | 
					
						
							|  |  |  | bool select(bool * canRead, bool * canWrite, bool *); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	static GUSISIOUXSocket *	Instance(); | 
					
						
							|  |  |  | private: | 
					
						
							|  |  |  | 	static GUSISIOUXSocket *	sInstance; | 
					
						
							|  |  |  | 	 | 
					
						
							|  |  |  | 	GUSISIOUXSocket(); | 
					
						
							|  |  |  | 	bool initialized; | 
					
						
							|  |  |  | 	void Initialize(); | 
					
						
							|  |  |  | 	bool fDelayConsole; | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | class GUSISIOUXDevice : public GUSIDevice { | 
					
						
							|  |  |  | public: | 
					
						
							|  |  |  | 	static GUSISIOUXDevice *	Instance(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	 | 
					
						
							|  |  |  | virtual bool Want(GUSIFileToken & file); | 
					
						
							|  |  |  | virtual GUSISocket * open(GUSIFileToken &, int flags); | 
					
						
							|  |  |  | private: | 
					
						
							|  |  |  | 	GUSISIOUXDevice() 								{} | 
					
						
							|  |  |  | 	 | 
					
						
							|  |  |  | 	static GUSISIOUXDevice *	sInstance; | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | GUSISIOUXSocket * GUSISIOUXSocket::sInstance; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | GUSISIOUXSocket * GUSISIOUXSocket::Instance() | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	if (!sInstance) | 
					
						
							|  |  |  | 		if (sInstance = new GUSISIOUXSocket) | 
					
						
							|  |  |  | 			sInstance->AddReference(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return sInstance; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | // This declaration lies about the return type
 | 
					
						
							|  |  |  | extern "C" void SIOUXHandleOneEvent(EventRecord *userevent); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | GUSISIOUXSocket::GUSISIOUXSocket()  | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	if (PyMac_GetDelayConsoleFlag()) | 
					
						
							|  |  |  | 		fDelayConsole = true; | 
					
						
							|  |  |  | 	else | 
					
						
							|  |  |  | 		fDelayConsole = false; | 
					
						
							|  |  |  | 	if ( fDelayConsole ) | 
					
						
							|  |  |  | 		initialized = 0; | 
					
						
							|  |  |  | 	else | 
					
						
							|  |  |  | 		Initialize(); | 
					
						
							|  |  |  | 	/* Tell the upper layers there's no unseen output */ | 
					
						
							|  |  |  | 	PyMac_OutputSeen(); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void | 
					
						
							|  |  |  | GUSISIOUXSocket::Initialize() | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	initialized = 1; | 
					
						
							|  |  |  | 	InstallConsole(0); | 
					
						
							|  |  |  | 	GUSISetHook(GUSI_EventHook+nullEvent, 	(GUSIHook)SIOUXHandleOneEvent); | 
					
						
							|  |  |  | 	GUSISetHook(GUSI_EventHook+mouseDown, 	(GUSIHook)SIOUXHandleOneEvent); | 
					
						
							|  |  |  | 	GUSISetHook(GUSI_EventHook+mouseUp, 	(GUSIHook)SIOUXHandleOneEvent); | 
					
						
							|  |  |  | 	GUSISetHook(GUSI_EventHook+updateEvt, 	(GUSIHook)SIOUXHandleOneEvent); | 
					
						
							|  |  |  | 	GUSISetHook(GUSI_EventHook+diskEvt, 	(GUSIHook)SIOUXHandleOneEvent); | 
					
						
							|  |  |  | 	GUSISetHook(GUSI_EventHook+activateEvt, (GUSIHook)SIOUXHandleOneEvent); | 
					
						
							|  |  |  | 	GUSISetHook(GUSI_EventHook+osEvt, 		(GUSIHook)SIOUXHandleOneEvent); | 
					
						
							| 
									
										
										
										
											2001-04-25 22:07:27 +00:00
										 |  |  | 	PyMac_InitMenuBar(); | 
					
						
							| 
									
										
										
										
											2001-02-11 01:08:04 +00:00
										 |  |  | } | 
					
						
							|  |  |  | GUSISIOUXSocket::~GUSISIOUXSocket() | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	if ( !initialized ) return; | 
					
						
							|  |  |  | 	RemoveConsole(); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | ssize_t GUSISIOUXSocket::read(const GUSIScatterer & buffer) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	if ( !initialized ) Initialize(); | 
					
						
							|  |  |  | 	GUSIStdioFlush(); | 
					
						
							|  |  |  | 	PyMac_OutputSeen(); | 
					
						
							| 
									
										
										
										
											2001-04-25 22:07:27 +00:00
										 |  |  | 	PyMac_RaiseConsoleWindow(); | 
					
						
							| 
									
										
										
										
											2001-02-11 01:08:04 +00:00
										 |  |  | 	return buffer.SetLength( | 
					
						
							|  |  |  | 		ReadCharsFromConsole((char *) buffer.Buffer(), (int)buffer.Length())); | 
					
						
							|  |  |  | 	GUSIContext::Yield(kGUSIPoll); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | ssize_t GUSISIOUXSocket::write(const GUSIGatherer & buffer) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	ssize_t rv; | 
					
						
							|  |  |  | 			 | 
					
						
							|  |  |  | 	if ( !initialized ) Initialize(); | 
					
						
							|  |  |  | 	PyMac_OutputNotSeen(); | 
					
						
							|  |  |  | 	SIOUXUseWaitNextEvent = false; | 
					
						
							|  |  |  | 	rv = WriteCharsToConsole((char *) buffer.Buffer(), (int)buffer.Length()); | 
					
						
							|  |  |  | 	GUSIContext::Yield(kGUSIPoll); | 
					
						
							|  |  |  | 	return rv; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | int GUSISIOUXSocket::ioctl(unsigned int request, va_list) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	switch (request)	{ | 
					
						
							|  |  |  | 	case FIOINTERACTIVE: | 
					
						
							|  |  |  | 		return 0; | 
					
						
							|  |  |  | 	default: | 
					
						
							|  |  |  | 		return GUSISetPosixError(EOPNOTSUPP); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | int	GUSISIOUXSocket::fstat(struct stat * buf) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	GUSISocket::fstat(buf); | 
					
						
							|  |  |  | 	buf->st_mode =	S_IFCHR | 0666; | 
					
						
							|  |  |  | 	 | 
					
						
							|  |  |  | 	return 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | int GUSISIOUXSocket::isatty() | 
					
						
							|  |  |  | {  | 
					
						
							|  |  |  | 	return 1; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | static bool input_pending() | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | #if !TARGET_API_MAC_CARBON
 | 
					
						
							|  |  |  | 	// Jack thinks that completely removing this code is a bit
 | 
					
						
							|  |  |  | 	// too much...
 | 
					
						
							|  |  |  | 	QHdrPtr eventQueue = LMGetEventQueue(); | 
					
						
							|  |  |  | 	EvQElPtr element = (EvQElPtr)eventQueue->qHead; | 
					
						
							|  |  |  | 	 | 
					
						
							|  |  |  | 	// now, count the number of pending keyDown events.
 | 
					
						
							|  |  |  | 	while (element != nil) { | 
					
						
							|  |  |  | 		if (element->evtQWhat == keyDown || element->evtQWhat == autoKey) | 
					
						
							|  |  |  | 			return true; | 
					
						
							|  |  |  | 		element = (EvQElPtr)element->qLink; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | #endif
 | 
					
						
							|  |  |  | 	return false; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | bool GUSISIOUXSocket::select(bool * canRead, bool * canWrite, bool *) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	if ( !initialized ) Initialize(); | 
					
						
							|  |  |  | 	bool cond = false; | 
					
						
							|  |  |  | 	if (canRead) | 
					
						
							|  |  |  | 		if (*canRead = input_pending()) | 
					
						
							|  |  |  | 			cond = true; | 
					
						
							|  |  |  | 	if (canWrite) | 
					
						
							|  |  |  | 		cond = *canWrite = true; | 
					
						
							|  |  |  | 		 | 
					
						
							|  |  |  | 	return cond; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | GUSISIOUXDevice * GUSISIOUXDevice::sInstance; | 
					
						
							|  |  |  | GUSISIOUXDevice * GUSISIOUXDevice::Instance() | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	if (!sInstance) | 
					
						
							|  |  |  | 		sInstance = new GUSISIOUXDevice(); | 
					
						
							|  |  |  | 	return sInstance; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | bool GUSISIOUXDevice::Want(GUSIFileToken & file) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	switch (file.WhichRequest()) { | 
					
						
							|  |  |  | 	case GUSIFileToken::kWillOpen: | 
					
						
							|  |  |  | 		return file.IsDevice() && (file.StrStdStream(file.Path()) > -1); | 
					
						
							|  |  |  | 	default: | 
					
						
							|  |  |  | 		return false; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | GUSISocket * GUSISIOUXDevice::open(GUSIFileToken &, int) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	return GUSISIOUXSocket::Instance(); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | void GUSISetupConsoleDescriptors() | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	GUSIDescriptorTable * table = GUSIDescriptorTable::Instance(); | 
					
						
							|  |  |  | 	GUSISIOUXSocket *     SIOUX = GUSISIOUXSocket::Instance(); | 
					
						
							|  |  |  | 	 | 
					
						
							|  |  |  | 	table->InstallSocket(SIOUX); | 
					
						
							|  |  |  | 	table->InstallSocket(SIOUX); | 
					
						
							|  |  |  | 	table->InstallSocket(SIOUX); | 
					
						
							|  |  |  | } |