mirror of
				https://github.com/python/cpython.git
				synced 2025-11-04 11:49:12 +00:00 
			
		
		
		
	- Better handling of menu bar save/restore. - Override abort() so it honours the "keep console window" flag.
		
			
				
	
	
		
			211 lines
		
	
	
	
		
			5.2 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			211 lines
		
	
	
	
		
			5.2 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);
 | 
						|
	PyMac_InitMenuBar();
 | 
						|
}
 | 
						|
GUSISIOUXSocket::~GUSISIOUXSocket()
 | 
						|
{
 | 
						|
	if ( !initialized ) return;
 | 
						|
	RemoveConsole();
 | 
						|
}
 | 
						|
ssize_t GUSISIOUXSocket::read(const GUSIScatterer & buffer)
 | 
						|
{
 | 
						|
	if ( !initialized ) Initialize();
 | 
						|
	GUSIStdioFlush();
 | 
						|
	PyMac_OutputSeen();
 | 
						|
	PyMac_RaiseConsoleWindow();
 | 
						|
	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);
 | 
						|
}
 |