blob: 40670d8227880023067d540aa7fac039a49f655a [file] [log] [blame]
Jack Jansen8a387142001-02-11 01:08:04 +00001/*
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"
31extern Boolean SIOUXUseWaitNextEvent;
32
Jack Jansena0472f72001-10-08 15:35:38 +000033static PyReadHandler sInConsole = 0L;
34static PyWriteHandler sOutConsole = 0L;
35static PyWriteHandler sErrConsole = 0L;
36
37inline bool hasCustomConsole(void) { return sInConsole != 0L; }
38
Jack Jansen8a387142001-02-11 01:08:04 +000039class GUSISIOUXSocket : public GUSISocket {
40public:
41 ~GUSISIOUXSocket();
42
43
44ssize_t read(const GUSIScatterer & buffer);
45ssize_t write(const GUSIGatherer & buffer);
46virtual int ioctl(unsigned int request, va_list arg);
47virtual int fstat(struct stat * buf);
48virtual int isatty();
49bool select(bool * canRead, bool * canWrite, bool *);
50
Jack Jansena0472f72001-10-08 15:35:38 +000051 static GUSISIOUXSocket * Instance(int fd);
52private:
53 GUSISIOUXSocket(int fd);
54 static bool initialized;
55 static void Initialize();
56 int fFd;
Jack Jansen8a387142001-02-11 01:08:04 +000057};
58class GUSISIOUXDevice : public GUSIDevice {
59public:
60 static GUSISIOUXDevice * Instance();
61
62
63virtual bool Want(GUSIFileToken & file);
64virtual GUSISocket * open(GUSIFileToken &, int flags);
65private:
66 GUSISIOUXDevice() {}
67
68 static GUSISIOUXDevice * sInstance;
69};
Jack Jansen8a387142001-02-11 01:08:04 +000070
Jack Jansena0472f72001-10-08 15:35:38 +000071GUSISIOUXSocket * GUSISIOUXSocket::Instance(int fd)
Jack Jansen8a387142001-02-11 01:08:04 +000072{
Jack Jansena0472f72001-10-08 15:35:38 +000073 return new GUSISIOUXSocket(fd);
Jack Jansen8a387142001-02-11 01:08:04 +000074}
75// This declaration lies about the return type
76extern "C" void SIOUXHandleOneEvent(EventRecord *userevent);
77
Jack Jansena0472f72001-10-08 15:35:38 +000078bool GUSISIOUXSocket::initialized = false;
79
80GUSISIOUXSocket::GUSISIOUXSocket(int fd) : fFd(fd)
Jack Jansen8a387142001-02-11 01:08:04 +000081{
Jack Jansena0472f72001-10-08 15:35:38 +000082 if (!PyMac_GetDelayConsoleFlag() && !hasCustomConsole() && !initialized)
Jack Jansen8a387142001-02-11 01:08:04 +000083 Initialize();
84 /* Tell the upper layers there's no unseen output */
85 PyMac_OutputSeen();
86}
87
88void
89GUSISIOUXSocket::Initialize()
90{
Jack Jansena0472f72001-10-08 15:35:38 +000091 if(!initialized && !hasCustomConsole())
92 {
93 initialized = true;
94 InstallConsole(0);
95 GUSISetHook(GUSI_EventHook+nullEvent, (GUSIHook)SIOUXHandleOneEvent);
96 GUSISetHook(GUSI_EventHook+mouseDown, (GUSIHook)SIOUXHandleOneEvent);
97 GUSISetHook(GUSI_EventHook+mouseUp, (GUSIHook)SIOUXHandleOneEvent);
98 GUSISetHook(GUSI_EventHook+updateEvt, (GUSIHook)SIOUXHandleOneEvent);
99 GUSISetHook(GUSI_EventHook+diskEvt, (GUSIHook)SIOUXHandleOneEvent);
100 GUSISetHook(GUSI_EventHook+activateEvt, (GUSIHook)SIOUXHandleOneEvent);
101 GUSISetHook(GUSI_EventHook+osEvt, (GUSIHook)SIOUXHandleOneEvent);
102 PyMac_InitMenuBar();
103 }
Jack Jansen8a387142001-02-11 01:08:04 +0000104}
105GUSISIOUXSocket::~GUSISIOUXSocket()
106{
Jack Jansena0472f72001-10-08 15:35:38 +0000107 if ( !initialized || hasCustomConsole() )
108 return;
109
110 initialized = false;
Jack Jansen8a387142001-02-11 01:08:04 +0000111 RemoveConsole();
112}
113ssize_t GUSISIOUXSocket::read(const GUSIScatterer & buffer)
114{
Jack Jansena0472f72001-10-08 15:35:38 +0000115 if(hasCustomConsole())
116 {
117 if(fFd == 0)
118 return buffer.SetLength(
119 sInConsole((char *) buffer.Buffer(), (int)buffer.Length()));
120
121 return 0;
122 }
123
Jack Jansen8a387142001-02-11 01:08:04 +0000124 if ( !initialized ) Initialize();
125 GUSIStdioFlush();
126 PyMac_OutputSeen();
Jack Jansen15f1c082001-04-25 22:07:27 +0000127 PyMac_RaiseConsoleWindow();
Jack Jansen8a387142001-02-11 01:08:04 +0000128 return buffer.SetLength(
129 ReadCharsFromConsole((char *) buffer.Buffer(), (int)buffer.Length()));
130 GUSIContext::Yield(kGUSIPoll);
131}
132ssize_t GUSISIOUXSocket::write(const GUSIGatherer & buffer)
133{
Jack Jansena0472f72001-10-08 15:35:38 +0000134 if(hasCustomConsole())
135 {
136 if(fFd == 1)
137 return sOutConsole((char *) buffer.Buffer(), (int)buffer.Length());
138 else if(fFd == 2)
139 return sErrConsole((char *) buffer.Buffer(), (int)buffer.Length());
140
141 return 0;
142 }
143
Jack Jansen8a387142001-02-11 01:08:04 +0000144 ssize_t rv;
145
146 if ( !initialized ) Initialize();
147 PyMac_OutputNotSeen();
148 SIOUXUseWaitNextEvent = false;
149 rv = WriteCharsToConsole((char *) buffer.Buffer(), (int)buffer.Length());
150 GUSIContext::Yield(kGUSIPoll);
151 return rv;
152}
153int GUSISIOUXSocket::ioctl(unsigned int request, va_list)
154{
155 switch (request) {
156 case FIOINTERACTIVE:
157 return 0;
158 default:
159 return GUSISetPosixError(EOPNOTSUPP);
160 }
161}
162int GUSISIOUXSocket::fstat(struct stat * buf)
163{
164 GUSISocket::fstat(buf);
165 buf->st_mode = S_IFCHR | 0666;
166
167 return 0;
168}
169int GUSISIOUXSocket::isatty()
170{
171 return 1;
172}
173static bool input_pending()
174{
175#if !TARGET_API_MAC_CARBON
176 // Jack thinks that completely removing this code is a bit
177 // too much...
178 QHdrPtr eventQueue = LMGetEventQueue();
179 EvQElPtr element = (EvQElPtr)eventQueue->qHead;
180
181 // now, count the number of pending keyDown events.
182 while (element != nil) {
183 if (element->evtQWhat == keyDown || element->evtQWhat == autoKey)
184 return true;
185 element = (EvQElPtr)element->qLink;
186 }
187#endif
188 return false;
189}
190
191bool GUSISIOUXSocket::select(bool * canRead, bool * canWrite, bool *)
192{
193 if ( !initialized ) Initialize();
194 bool cond = false;
195 if (canRead)
196 if (*canRead = input_pending())
197 cond = true;
198 if (canWrite)
199 cond = *canWrite = true;
200
201 return cond;
202}
203GUSISIOUXDevice * GUSISIOUXDevice::sInstance;
204GUSISIOUXDevice * GUSISIOUXDevice::Instance()
205{
206 if (!sInstance)
207 sInstance = new GUSISIOUXDevice();
208 return sInstance;
209}
210bool GUSISIOUXDevice::Want(GUSIFileToken & file)
211{
212 switch (file.WhichRequest()) {
213 case GUSIFileToken::kWillOpen:
214 return file.IsDevice() && (file.StrStdStream(file.Path()) > -1);
215 default:
216 return false;
217 }
218}
219GUSISocket * GUSISIOUXDevice::open(GUSIFileToken &, int)
220{
Jack Jansena0472f72001-10-08 15:35:38 +0000221 return GUSISIOUXSocket::Instance(1);
Jack Jansen8a387142001-02-11 01:08:04 +0000222}
223void GUSISetupConsoleDescriptors()
224{
225 GUSIDescriptorTable * table = GUSIDescriptorTable::Instance();
Jack Jansen8a387142001-02-11 01:08:04 +0000226
Jack Jansena0472f72001-10-08 15:35:38 +0000227 table->InstallSocket(GUSISIOUXSocket::Instance(0));
228 table->InstallSocket(GUSISIOUXSocket::Instance(1));
229 table->InstallSocket(GUSISIOUXSocket::Instance(2));
230}
231
232void PyMac_SetConsoleHandler(PyReadHandler stdinH, PyWriteHandler stdoutH, PyWriteHandler stderrH)
233{
234 if(stdinH && stdoutH && stderrH)
235 {
236 sInConsole = stdinH;
237 sOutConsole = stdoutH;
238 sErrConsole = stderrH;
239 }
240}
241
242long PyMac_DummyReadHandler(char *buffer, long n)
243{
244 return 0;
245}
246
247long PyMac_DummyWriteHandler(char *buffer, long n)
248{
249 return 0;
Jack Jansen8a387142001-02-11 01:08:04 +0000250}