mirror of
				https://github.com/python/cpython.git
				synced 2025-10-30 21:21:22 +00:00 
			
		
		
		
	
		
			
	
	
		
			210 lines
		
	
	
	
		
			5.1 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
		
		
			
		
	
	
			210 lines
		
	
	
	
		
			5.1 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
|   | /*
 | ||
|  | ** 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); | ||
|  | } | ||
|  | GUSISIOUXSocket::~GUSISIOUXSocket() | ||
|  | { | ||
|  | 	if ( !initialized ) return; | ||
|  | 	RemoveConsole(); | ||
|  | } | ||
|  | ssize_t GUSISIOUXSocket::read(const GUSIScatterer & buffer) | ||
|  | { | ||
|  | 	if ( !initialized ) Initialize(); | ||
|  | 	GUSIStdioFlush(); | ||
|  | 	PyMac_OutputSeen(); | ||
|  | 	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); | ||
|  | } |