blob: f26216b83ae5a0b8a4411ce472164c45c1b980b6 [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);
Jack Jansen15f1c082001-04-25 22:07:27 +0000105 PyMac_InitMenuBar();
Jack Jansen8a387142001-02-11 01:08:04 +0000106}
107GUSISIOUXSocket::~GUSISIOUXSocket()
108{
109 if ( !initialized ) return;
110 RemoveConsole();
111}
112ssize_t GUSISIOUXSocket::read(const GUSIScatterer & buffer)
113{
114 if ( !initialized ) Initialize();
115 GUSIStdioFlush();
116 PyMac_OutputSeen();
Jack Jansen15f1c082001-04-25 22:07:27 +0000117 PyMac_RaiseConsoleWindow();
Jack Jansen8a387142001-02-11 01:08:04 +0000118 return buffer.SetLength(
119 ReadCharsFromConsole((char *) buffer.Buffer(), (int)buffer.Length()));
120 GUSIContext::Yield(kGUSIPoll);
121}
122ssize_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}
133int 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}
142int GUSISIOUXSocket::fstat(struct stat * buf)
143{
144 GUSISocket::fstat(buf);
145 buf->st_mode = S_IFCHR | 0666;
146
147 return 0;
148}
149int GUSISIOUXSocket::isatty()
150{
151 return 1;
152}
153static 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
171bool 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}
183GUSISIOUXDevice * GUSISIOUXDevice::sInstance;
184GUSISIOUXDevice * GUSISIOUXDevice::Instance()
185{
186 if (!sInstance)
187 sInstance = new GUSISIOUXDevice();
188 return sInstance;
189}
190bool 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}
199GUSISocket * GUSISIOUXDevice::open(GUSIFileToken &, int)
200{
201 return GUSISIOUXSocket::Instance();
202}
203void 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}