| Jack Jansen | 8a38714 | 2001-02-11 01:08:04 +0000 | [diff] [blame] | 1 | /* | 
 | 2 | ** Modified version of GUSISIOUX.cp especially for Python. | 
 | 3 | ** Changes (by Jack): | 
 | 4 | ** - Optionally delay the console window until something is written to it. | 
 | 5 | ** - Tell the upper layers whether the last command was a read or a write. | 
 | 6 | ** - Tell SIOUX not to use WaitNextEvent (both Python and SIOUX trying to be | 
 | 7 | **   nice to background apps means we're yielding almost 100% of the time). | 
 | 8 | ** - Make sure signals are processed when returning from read/write. | 
 | 9 | */ | 
 | 10 | #define GUSI_SOURCE | 
 | 11 | #include "GUSIInternal.h" | 
 | 12 | #include "GUSISIOUX.h" | 
 | 13 | #include "GUSIDevice.h" | 
 | 14 | #include "GUSIDescriptor.h" | 
 | 15 | #include "GUSIBasics.h" | 
 | 16 | #include "GUSIDiag.h" | 
 | 17 | //#ifndef WITHOUT_JACK_MODS | 
 | 18 | //#include "GUSIConfig.h" | 
 | 19 | //#endif | 
 | 20 |  | 
 | 21 | #include <LowMem.h> | 
 | 22 |  | 
 | 23 | #include <fcntl.h> | 
 | 24 | #include <sys/stat.h> | 
 | 25 | #include <sys/ioctl.h> | 
 | 26 | #include <errno.h> | 
 | 27 | #include <console.h> | 
 | 28 |  | 
 | 29 | #include "Python.h" | 
 | 30 | #include "macglue.h" | 
 | 31 | extern Boolean SIOUXUseWaitNextEvent; | 
 | 32 |  | 
 | 33 | class GUSISIOUXSocket : public GUSISocket { | 
 | 34 | public: | 
 | 35 | 	~GUSISIOUXSocket(); | 
 | 36 | 	 | 
 | 37 | 	 | 
 | 38 | ssize_t	read(const GUSIScatterer & buffer); | 
 | 39 | ssize_t write(const GUSIGatherer & buffer); | 
 | 40 | virtual int	ioctl(unsigned int request, va_list arg); | 
 | 41 | virtual int	fstat(struct stat * buf); | 
 | 42 | virtual int	isatty(); | 
 | 43 | bool select(bool * canRead, bool * canWrite, bool *); | 
 | 44 |  | 
 | 45 | 	static GUSISIOUXSocket *	Instance(); | 
 | 46 | private: | 
 | 47 | 	static GUSISIOUXSocket *	sInstance; | 
 | 48 | 	 | 
 | 49 | 	GUSISIOUXSocket(); | 
 | 50 | 	bool initialized; | 
 | 51 | 	void Initialize(); | 
 | 52 | 	bool fDelayConsole; | 
 | 53 | }; | 
 | 54 | class GUSISIOUXDevice : public GUSIDevice { | 
 | 55 | public: | 
 | 56 | 	static GUSISIOUXDevice *	Instance(); | 
 | 57 |  | 
 | 58 | 	 | 
 | 59 | virtual bool Want(GUSIFileToken & file); | 
 | 60 | virtual GUSISocket * open(GUSIFileToken &, int flags); | 
 | 61 | private: | 
 | 62 | 	GUSISIOUXDevice() 								{} | 
 | 63 | 	 | 
 | 64 | 	static GUSISIOUXDevice *	sInstance; | 
 | 65 | }; | 
 | 66 | GUSISIOUXSocket * GUSISIOUXSocket::sInstance; | 
 | 67 |  | 
 | 68 | GUSISIOUXSocket * GUSISIOUXSocket::Instance() | 
 | 69 | { | 
 | 70 | 	if (!sInstance) | 
 | 71 | 		if (sInstance = new GUSISIOUXSocket) | 
 | 72 | 			sInstance->AddReference(); | 
 | 73 |  | 
 | 74 | 	return sInstance; | 
 | 75 | } | 
 | 76 | // This declaration lies about the return type | 
 | 77 | extern "C" void SIOUXHandleOneEvent(EventRecord *userevent); | 
 | 78 |  | 
 | 79 | GUSISIOUXSocket::GUSISIOUXSocket()  | 
 | 80 | { | 
 | 81 | 	if (PyMac_GetDelayConsoleFlag()) | 
 | 82 | 		fDelayConsole = true; | 
 | 83 | 	else | 
 | 84 | 		fDelayConsole = false; | 
 | 85 | 	if ( fDelayConsole ) | 
 | 86 | 		initialized = 0; | 
 | 87 | 	else | 
 | 88 | 		Initialize(); | 
 | 89 | 	/* Tell the upper layers there's no unseen output */ | 
 | 90 | 	PyMac_OutputSeen(); | 
 | 91 | } | 
 | 92 |  | 
 | 93 | void | 
 | 94 | GUSISIOUXSocket::Initialize() | 
 | 95 | { | 
 | 96 | 	initialized = 1; | 
 | 97 | 	InstallConsole(0); | 
 | 98 | 	GUSISetHook(GUSI_EventHook+nullEvent, 	(GUSIHook)SIOUXHandleOneEvent); | 
 | 99 | 	GUSISetHook(GUSI_EventHook+mouseDown, 	(GUSIHook)SIOUXHandleOneEvent); | 
 | 100 | 	GUSISetHook(GUSI_EventHook+mouseUp, 	(GUSIHook)SIOUXHandleOneEvent); | 
 | 101 | 	GUSISetHook(GUSI_EventHook+updateEvt, 	(GUSIHook)SIOUXHandleOneEvent); | 
 | 102 | 	GUSISetHook(GUSI_EventHook+diskEvt, 	(GUSIHook)SIOUXHandleOneEvent); | 
 | 103 | 	GUSISetHook(GUSI_EventHook+activateEvt, (GUSIHook)SIOUXHandleOneEvent); | 
 | 104 | 	GUSISetHook(GUSI_EventHook+osEvt, 		(GUSIHook)SIOUXHandleOneEvent); | 
| Jack Jansen | 15f1c08 | 2001-04-25 22:07:27 +0000 | [diff] [blame] | 105 | 	PyMac_InitMenuBar(); | 
| Jack Jansen | 8a38714 | 2001-02-11 01:08:04 +0000 | [diff] [blame] | 106 | } | 
 | 107 | GUSISIOUXSocket::~GUSISIOUXSocket() | 
 | 108 | { | 
 | 109 | 	if ( !initialized ) return; | 
 | 110 | 	RemoveConsole(); | 
 | 111 | } | 
 | 112 | ssize_t GUSISIOUXSocket::read(const GUSIScatterer & buffer) | 
 | 113 | { | 
 | 114 | 	if ( !initialized ) Initialize(); | 
 | 115 | 	GUSIStdioFlush(); | 
 | 116 | 	PyMac_OutputSeen(); | 
| Jack Jansen | 15f1c08 | 2001-04-25 22:07:27 +0000 | [diff] [blame] | 117 | 	PyMac_RaiseConsoleWindow(); | 
| Jack Jansen | 8a38714 | 2001-02-11 01:08:04 +0000 | [diff] [blame] | 118 | 	return buffer.SetLength( | 
 | 119 | 		ReadCharsFromConsole((char *) buffer.Buffer(), (int)buffer.Length())); | 
 | 120 | 	GUSIContext::Yield(kGUSIPoll); | 
 | 121 | } | 
 | 122 | ssize_t GUSISIOUXSocket::write(const GUSIGatherer & buffer) | 
 | 123 | { | 
 | 124 | 	ssize_t rv; | 
 | 125 | 			 | 
 | 126 | 	if ( !initialized ) Initialize(); | 
 | 127 | 	PyMac_OutputNotSeen(); | 
 | 128 | 	SIOUXUseWaitNextEvent = false; | 
 | 129 | 	rv = WriteCharsToConsole((char *) buffer.Buffer(), (int)buffer.Length()); | 
 | 130 | 	GUSIContext::Yield(kGUSIPoll); | 
 | 131 | 	return rv; | 
 | 132 | } | 
 | 133 | int GUSISIOUXSocket::ioctl(unsigned int request, va_list) | 
 | 134 | { | 
 | 135 | 	switch (request)	{ | 
 | 136 | 	case FIOINTERACTIVE: | 
 | 137 | 		return 0; | 
 | 138 | 	default: | 
 | 139 | 		return GUSISetPosixError(EOPNOTSUPP); | 
 | 140 | 	} | 
 | 141 | } | 
 | 142 | int	GUSISIOUXSocket::fstat(struct stat * buf) | 
 | 143 | { | 
 | 144 | 	GUSISocket::fstat(buf); | 
 | 145 | 	buf->st_mode =	S_IFCHR | 0666; | 
 | 146 | 	 | 
 | 147 | 	return 0; | 
 | 148 | } | 
 | 149 | int GUSISIOUXSocket::isatty() | 
 | 150 | {  | 
 | 151 | 	return 1; | 
 | 152 | } | 
 | 153 | static bool input_pending() | 
 | 154 | { | 
 | 155 | #if !TARGET_API_MAC_CARBON | 
 | 156 | 	// Jack thinks that completely removing this code is a bit | 
 | 157 | 	// too much... | 
 | 158 | 	QHdrPtr eventQueue = LMGetEventQueue(); | 
 | 159 | 	EvQElPtr element = (EvQElPtr)eventQueue->qHead; | 
 | 160 | 	 | 
 | 161 | 	// now, count the number of pending keyDown events. | 
 | 162 | 	while (element != nil) { | 
 | 163 | 		if (element->evtQWhat == keyDown || element->evtQWhat == autoKey) | 
 | 164 | 			return true; | 
 | 165 | 		element = (EvQElPtr)element->qLink; | 
 | 166 | 	} | 
 | 167 | #endif | 
 | 168 | 	return false; | 
 | 169 | } | 
 | 170 |  | 
 | 171 | bool GUSISIOUXSocket::select(bool * canRead, bool * canWrite, bool *) | 
 | 172 | { | 
 | 173 | 	if ( !initialized ) Initialize(); | 
 | 174 | 	bool cond = false; | 
 | 175 | 	if (canRead) | 
 | 176 | 		if (*canRead = input_pending()) | 
 | 177 | 			cond = true; | 
 | 178 | 	if (canWrite) | 
 | 179 | 		cond = *canWrite = true; | 
 | 180 | 		 | 
 | 181 | 	return cond; | 
 | 182 | } | 
 | 183 | GUSISIOUXDevice * GUSISIOUXDevice::sInstance; | 
 | 184 | GUSISIOUXDevice * GUSISIOUXDevice::Instance() | 
 | 185 | { | 
 | 186 | 	if (!sInstance) | 
 | 187 | 		sInstance = new GUSISIOUXDevice(); | 
 | 188 | 	return sInstance; | 
 | 189 | } | 
 | 190 | bool GUSISIOUXDevice::Want(GUSIFileToken & file) | 
 | 191 | { | 
 | 192 | 	switch (file.WhichRequest()) { | 
 | 193 | 	case GUSIFileToken::kWillOpen: | 
 | 194 | 		return file.IsDevice() && (file.StrStdStream(file.Path()) > -1); | 
 | 195 | 	default: | 
 | 196 | 		return false; | 
 | 197 | 	} | 
 | 198 | } | 
 | 199 | GUSISocket * GUSISIOUXDevice::open(GUSIFileToken &, int) | 
 | 200 | { | 
 | 201 | 	return GUSISIOUXSocket::Instance(); | 
 | 202 | } | 
 | 203 | void GUSISetupConsoleDescriptors() | 
 | 204 | { | 
 | 205 | 	GUSIDescriptorTable * table = GUSIDescriptorTable::Instance(); | 
 | 206 | 	GUSISIOUXSocket *     SIOUX = GUSISIOUXSocket::Instance(); | 
 | 207 | 	 | 
 | 208 | 	table->InstallSocket(SIOUX); | 
 | 209 | 	table->InstallSocket(SIOUX); | 
 | 210 | 	table->InstallSocket(SIOUX); | 
 | 211 | } |