blob: 795e10e0e47b0a88017450fd073b39eb93940f6d [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
33class GUSISIOUXSocket : public GUSISocket {
34public:
35 ~GUSISIOUXSocket();
36
37
38ssize_t read(const GUSIScatterer & buffer);
39ssize_t write(const GUSIGatherer & buffer);
40virtual int ioctl(unsigned int request, va_list arg);
41virtual int fstat(struct stat * buf);
42virtual int isatty();
43bool select(bool * canRead, bool * canWrite, bool *);
44
45 static GUSISIOUXSocket * Instance();
46private:
47 static GUSISIOUXSocket * sInstance;
48
49 GUSISIOUXSocket();
50 bool initialized;
51 void Initialize();
52 bool fDelayConsole;
53};
54class GUSISIOUXDevice : public GUSIDevice {
55public:
56 static GUSISIOUXDevice * Instance();
57
58
59virtual bool Want(GUSIFileToken & file);
60virtual GUSISocket * open(GUSIFileToken &, int flags);
61private:
62 GUSISIOUXDevice() {}
63
64 static GUSISIOUXDevice * sInstance;
65};
66GUSISIOUXSocket * GUSISIOUXSocket::sInstance;
67
68GUSISIOUXSocket * 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
77extern "C" void SIOUXHandleOneEvent(EventRecord *userevent);
78
79GUSISIOUXSocket::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
93void
94GUSISIOUXSocket::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);
105}
106GUSISIOUXSocket::~GUSISIOUXSocket()
107{
108 if ( !initialized ) return;
109 RemoveConsole();
110}
111ssize_t GUSISIOUXSocket::read(const GUSIScatterer & buffer)
112{
113 if ( !initialized ) Initialize();
114 GUSIStdioFlush();
115 PyMac_OutputSeen();
116 return buffer.SetLength(
117 ReadCharsFromConsole((char *) buffer.Buffer(), (int)buffer.Length()));
118 GUSIContext::Yield(kGUSIPoll);
119}
120ssize_t GUSISIOUXSocket::write(const GUSIGatherer & buffer)
121{
122 ssize_t rv;
123
124 if ( !initialized ) Initialize();
125 PyMac_OutputNotSeen();
126 SIOUXUseWaitNextEvent = false;
127 rv = WriteCharsToConsole((char *) buffer.Buffer(), (int)buffer.Length());
128 GUSIContext::Yield(kGUSIPoll);
129 return rv;
130}
131int GUSISIOUXSocket::ioctl(unsigned int request, va_list)
132{
133 switch (request) {
134 case FIOINTERACTIVE:
135 return 0;
136 default:
137 return GUSISetPosixError(EOPNOTSUPP);
138 }
139}
140int GUSISIOUXSocket::fstat(struct stat * buf)
141{
142 GUSISocket::fstat(buf);
143 buf->st_mode = S_IFCHR | 0666;
144
145 return 0;
146}
147int GUSISIOUXSocket::isatty()
148{
149 return 1;
150}
151static bool input_pending()
152{
153#if !TARGET_API_MAC_CARBON
154 // Jack thinks that completely removing this code is a bit
155 // too much...
156 QHdrPtr eventQueue = LMGetEventQueue();
157 EvQElPtr element = (EvQElPtr)eventQueue->qHead;
158
159 // now, count the number of pending keyDown events.
160 while (element != nil) {
161 if (element->evtQWhat == keyDown || element->evtQWhat == autoKey)
162 return true;
163 element = (EvQElPtr)element->qLink;
164 }
165#endif
166 return false;
167}
168
169bool GUSISIOUXSocket::select(bool * canRead, bool * canWrite, bool *)
170{
171 if ( !initialized ) Initialize();
172 bool cond = false;
173 if (canRead)
174 if (*canRead = input_pending())
175 cond = true;
176 if (canWrite)
177 cond = *canWrite = true;
178
179 return cond;
180}
181GUSISIOUXDevice * GUSISIOUXDevice::sInstance;
182GUSISIOUXDevice * GUSISIOUXDevice::Instance()
183{
184 if (!sInstance)
185 sInstance = new GUSISIOUXDevice();
186 return sInstance;
187}
188bool GUSISIOUXDevice::Want(GUSIFileToken & file)
189{
190 switch (file.WhichRequest()) {
191 case GUSIFileToken::kWillOpen:
192 return file.IsDevice() && (file.StrStdStream(file.Path()) > -1);
193 default:
194 return false;
195 }
196}
197GUSISocket * GUSISIOUXDevice::open(GUSIFileToken &, int)
198{
199 return GUSISIOUXSocket::Instance();
200}
201void GUSISetupConsoleDescriptors()
202{
203 GUSIDescriptorTable * table = GUSIDescriptorTable::Instance();
204 GUSISIOUXSocket * SIOUX = GUSISIOUXSocket::Instance();
205
206 table->InstallSocket(SIOUX);
207 table->InstallSocket(SIOUX);
208 table->InstallSocket(SIOUX);
209}