fix to work on python <= 2.1
[python/dscho.git] / Mac / Python / pyGUSISIOUX.cp
blob4e63ebe616e13c2261cc9db6f77a476e3b2525ae
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
21 #include <LowMem.h>
23 #include <fcntl.h>
24 #include <sys/stat.h>
25 #include <sys/ioctl.h>
26 #include <errno.h>
27 #include <console.h>
29 #include "Python.h"
30 #include "macglue.h"
31 extern Boolean SIOUXUseWaitNextEvent;
33 static PyReadHandler sInConsole = 0L;
34 static PyWriteHandler sOutConsole = 0L;
35 static PyWriteHandler sErrConsole = 0L;
37 inline bool hasCustomConsole(void) { return sInConsole != 0L; }
39 class GUSISIOUXSocket : public GUSISocket {
40 public:
41         ~GUSISIOUXSocket();
42         
43         
44 ssize_t read(const GUSIScatterer & buffer);
45 ssize_t write(const GUSIGatherer & buffer);
46 virtual int     ioctl(unsigned int request, va_list arg);
47 virtual int     fstat(struct stat * buf);
48 virtual int     isatty();
49 bool select(bool * canRead, bool * canWrite, bool *);
51         static GUSISIOUXSocket *        Instance(int fd);
52 private:        
53         GUSISIOUXSocket(int fd);
54         static bool initialized;
55         static void Initialize();
56         int fFd;
58 class GUSISIOUXDevice : public GUSIDevice {
59 public:
60         static GUSISIOUXDevice *        Instance();
62         
63 virtual bool Want(GUSIFileToken & file);
64 virtual GUSISocket * open(GUSIFileToken &, int flags);
65 private:
66         GUSISIOUXDevice()                                                               {}
67         
68         static GUSISIOUXDevice *        sInstance;
71 GUSISIOUXSocket * GUSISIOUXSocket::Instance(int fd)
73         return new GUSISIOUXSocket(fd);
75 // This declaration lies about the return type
76 extern "C" void SIOUXHandleOneEvent(EventRecord *userevent);
78 bool GUSISIOUXSocket::initialized = false;
80 GUSISIOUXSocket::GUSISIOUXSocket(int fd) : fFd(fd) 
82         if (!hasCustomConsole()) {
83                 if (!PyMac_GetDelayConsoleFlag() && !initialized)
84                         Initialize();
85                 /* Tell the upper layers there's no unseen output */
86                 PyMac_OutputSeen();
87         }
90 void
91 GUSISIOUXSocket::Initialize()
93         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         }
107 GUSISIOUXSocket::~GUSISIOUXSocket()
109         if ( !initialized || hasCustomConsole() )
110                 return;
111         
112         initialized = false;
113         RemoveConsole();
115 ssize_t GUSISIOUXSocket::read(const GUSIScatterer & buffer)
117         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         
126         if ( !initialized ) Initialize();
127         GUSIStdioFlush();
128         PyMac_OutputSeen();
129         PyMac_RaiseConsoleWindow();
130         return buffer.SetLength(
131                 ReadCharsFromConsole((char *) buffer.Buffer(), (int)buffer.Length()));
132         GUSIContext::Yield(kGUSIPoll);
134 ssize_t GUSISIOUXSocket::write(const GUSIGatherer & buffer)
136         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         
146         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;
155 int GUSISIOUXSocket::ioctl(unsigned int request, va_list)
157         switch (request)        {
158         case FIOINTERACTIVE:
159                 return 0;
160         default:
161                 return GUSISetPosixError(EOPNOTSUPP);
162         }
164 int     GUSISIOUXSocket::fstat(struct stat * buf)
166         GUSISocket::fstat(buf);
167         buf->st_mode =  S_IFCHR | 0666;
168         
169         return 0;
171 int GUSISIOUXSocket::isatty()
173         return 1;
175 static bool input_pending()
177         return false;
180 bool GUSISIOUXSocket::select(bool * canRead, bool * canWrite, bool *)
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;
192 GUSISIOUXDevice * GUSISIOUXDevice::sInstance;
193 GUSISIOUXDevice * GUSISIOUXDevice::Instance()
195         if (!sInstance)
196                 sInstance = new GUSISIOUXDevice();
197         return sInstance;
199 bool GUSISIOUXDevice::Want(GUSIFileToken & file)
201         switch (file.WhichRequest()) {
202         case GUSIFileToken::kWillOpen:
203                 return file.IsDevice() && (file.StrStdStream(file.Path()) > -1);
204         default:
205                 return false;
206         }
208 GUSISocket * GUSISIOUXDevice::open(GUSIFileToken &, int)
210         return GUSISIOUXSocket::Instance(1);
212 void GUSISetupConsoleDescriptors()
214         GUSIDescriptorTable * table = GUSIDescriptorTable::Instance();
215         
216         table->InstallSocket(GUSISIOUXSocket::Instance(0));
217         table->InstallSocket(GUSISIOUXSocket::Instance(1));
218         table->InstallSocket(GUSISIOUXSocket::Instance(2));
221 void PyMac_SetConsoleHandler(PyReadHandler stdinH, PyWriteHandler stdoutH, PyWriteHandler stderrH)
223         if(stdinH && stdoutH && stderrH)
224         {
225                 sInConsole = stdinH;
226                 sOutConsole = stdoutH;
227                 sErrConsole = stderrH;
228         }
231 long PyMac_DummyReadHandler(char *buffer, long n)
233         return 0;
236 long PyMac_DummyWriteHandler(char *buffer, long n)
238         return 0;