blob: 4e63ebe616e13c2261cc9db6f77a476e3b2525ae [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 Jansen00638bd2002-01-11 10:24:23 +000082 if (!hasCustomConsole()) {
83 if (!PyMac_GetDelayConsoleFlag() && !initialized)
84 Initialize();
85 /* Tell the upper layers there's no unseen output */
86 PyMac_OutputSeen();
87 }
Jack Jansen8a387142001-02-11 01:08:04 +000088}
89
90void
91GUSISIOUXSocket::Initialize()
92{
Jack Jansena0472f72001-10-08 15:35:38 +000093 if(!initialized && !hasCustomConsole())
94 {
95 initialized = true;
96 InstallConsole(0);
97 GUSISetHook(GUSI_EventHook+nullEvent, (GUSIHook)SIOUXHandleOneEvent);
98 GUSISetHook(GUSI_EventHook+mouseDown, (GUSIHook)SIOUXHandleOneEvent);
99 GUSISetHook(GUSI_EventHook+mouseUp, (GUSIHook)SIOUXHandleOneEvent);
100 GUSISetHook(GUSI_EventHook+updateEvt, (GUSIHook)SIOUXHandleOneEvent);
101 GUSISetHook(GUSI_EventHook+diskEvt, (GUSIHook)SIOUXHandleOneEvent);
102 GUSISetHook(GUSI_EventHook+activateEvt, (GUSIHook)SIOUXHandleOneEvent);
103 GUSISetHook(GUSI_EventHook+osEvt, (GUSIHook)SIOUXHandleOneEvent);
104 PyMac_InitMenuBar();
105 }
Jack Jansen8a387142001-02-11 01:08:04 +0000106}
107GUSISIOUXSocket::~GUSISIOUXSocket()
108{
Jack Jansena0472f72001-10-08 15:35:38 +0000109 if ( !initialized || hasCustomConsole() )
110 return;
111
112 initialized = false;
Jack Jansen8a387142001-02-11 01:08:04 +0000113 RemoveConsole();
114}
115ssize_t GUSISIOUXSocket::read(const GUSIScatterer & buffer)
116{
Jack Jansena0472f72001-10-08 15:35:38 +0000117 if(hasCustomConsole())
118 {
119 if(fFd == 0)
120 return buffer.SetLength(
121 sInConsole((char *) buffer.Buffer(), (int)buffer.Length()));
122
123 return 0;
124 }
125
Jack Jansen8a387142001-02-11 01:08:04 +0000126 if ( !initialized ) Initialize();
127 GUSIStdioFlush();
128 PyMac_OutputSeen();
Jack Jansen15f1c082001-04-25 22:07:27 +0000129 PyMac_RaiseConsoleWindow();
Jack Jansen8a387142001-02-11 01:08:04 +0000130 return buffer.SetLength(
131 ReadCharsFromConsole((char *) buffer.Buffer(), (int)buffer.Length()));
132 GUSIContext::Yield(kGUSIPoll);
133}
134ssize_t GUSISIOUXSocket::write(const GUSIGatherer & buffer)
135{
Jack Jansena0472f72001-10-08 15:35:38 +0000136 if(hasCustomConsole())
137 {
138 if(fFd == 1)
139 return sOutConsole((char *) buffer.Buffer(), (int)buffer.Length());
140 else if(fFd == 2)
141 return sErrConsole((char *) buffer.Buffer(), (int)buffer.Length());
142
143 return 0;
144 }
145
Jack Jansen8a387142001-02-11 01:08:04 +0000146 ssize_t rv;
147
148 if ( !initialized ) Initialize();
149 PyMac_OutputNotSeen();
150 SIOUXUseWaitNextEvent = false;
151 rv = WriteCharsToConsole((char *) buffer.Buffer(), (int)buffer.Length());
152 GUSIContext::Yield(kGUSIPoll);
153 return rv;
154}
155int GUSISIOUXSocket::ioctl(unsigned int request, va_list)
156{
157 switch (request) {
158 case FIOINTERACTIVE:
159 return 0;
160 default:
161 return GUSISetPosixError(EOPNOTSUPP);
162 }
163}
164int GUSISIOUXSocket::fstat(struct stat * buf)
165{
166 GUSISocket::fstat(buf);
167 buf->st_mode = S_IFCHR | 0666;
168
169 return 0;
170}
171int GUSISIOUXSocket::isatty()
172{
173 return 1;
174}
175static bool input_pending()
176{
Jack Jansen8a387142001-02-11 01:08:04 +0000177 return false;
178}
179
180bool GUSISIOUXSocket::select(bool * canRead, bool * canWrite, bool *)
181{
182 if ( !initialized ) Initialize();
183 bool cond = false;
184 if (canRead)
185 if (*canRead = input_pending())
186 cond = true;
187 if (canWrite)
188 cond = *canWrite = true;
189
190 return cond;
191}
192GUSISIOUXDevice * GUSISIOUXDevice::sInstance;
193GUSISIOUXDevice * GUSISIOUXDevice::Instance()
194{
195 if (!sInstance)
196 sInstance = new GUSISIOUXDevice();
197 return sInstance;
198}
199bool GUSISIOUXDevice::Want(GUSIFileToken & file)
200{
201 switch (file.WhichRequest()) {
202 case GUSIFileToken::kWillOpen:
203 return file.IsDevice() && (file.StrStdStream(file.Path()) > -1);
204 default:
205 return false;
206 }
207}
208GUSISocket * GUSISIOUXDevice::open(GUSIFileToken &, int)
209{
Jack Jansena0472f72001-10-08 15:35:38 +0000210 return GUSISIOUXSocket::Instance(1);
Jack Jansen8a387142001-02-11 01:08:04 +0000211}
212void GUSISetupConsoleDescriptors()
213{
214 GUSIDescriptorTable * table = GUSIDescriptorTable::Instance();
Jack Jansen8a387142001-02-11 01:08:04 +0000215
Jack Jansena0472f72001-10-08 15:35:38 +0000216 table->InstallSocket(GUSISIOUXSocket::Instance(0));
217 table->InstallSocket(GUSISIOUXSocket::Instance(1));
218 table->InstallSocket(GUSISIOUXSocket::Instance(2));
219}
220
221void PyMac_SetConsoleHandler(PyReadHandler stdinH, PyWriteHandler stdoutH, PyWriteHandler stderrH)
222{
223 if(stdinH && stdoutH && stderrH)
224 {
225 sInConsole = stdinH;
226 sOutConsole = stdoutH;
227 sErrConsole = stderrH;
228 }
229}
230
231long PyMac_DummyReadHandler(char *buffer, long n)
232{
233 return 0;
234}
235
236long PyMac_DummyWriteHandler(char *buffer, long n)
237{
238 return 0;
Jack Jansen8a387142001-02-11 01:08:04 +0000239}