From 8a38714ba05a3734f812bb1bbebdc527732a22bc Mon Sep 17 00:00:00 2001 From: Jack Jansen Date: Sun, 11 Feb 2001 01:08:04 +0000 Subject: [PATCH] Bit the bullet and added a private GUSISIOUX for Python. This makes the delayconsole and keepopen code neater. Also tells Sioux to behave better with events, and handles cmd-. during print better. The pythonpreferences have also changed due to this. --- Mac/Include/macglue.h | 2 + Mac/Include/pythonresources.h | 3 +- Mac/Lib/pythonprefs.py | 23 ++-- Mac/Python/macglue.c | 19 ++++ Mac/Python/macmain.c | 42 +++++-- Mac/Python/pyGUSISIOUX.cp | 209 ++++++++++++++++++++++++++++++++++ Mac/Resources/pythonpath.r | 3 + 7 files changed, 274 insertions(+), 27 deletions(-) create mode 100644 Mac/Python/pyGUSISIOUX.cp diff --git a/Mac/Include/macglue.h b/Mac/Include/macglue.h index 372871e288d..fa61709c89a 100644 --- a/Mac/Include/macglue.h +++ b/Mac/Include/macglue.h @@ -130,6 +130,8 @@ int PyMac_setfiletype(char *, long, long); /* Set file creator and type */ void PyMac_Exit(int); void PyMac_InitApplication(void); void PyMac_OutputSeen(void); +void PyMac_OutputNotSeen(void); +int PyMac_GetDelayConsoleFlag(void); #ifdef USE_MAC_APPLET_SUPPORT void PyMac_InitApplet(void); #endif diff --git a/Mac/Include/pythonresources.h b/Mac/Include/pythonresources.h index 9bb899833a7..29026a88c40 100644 --- a/Mac/Include/pythonresources.h +++ b/Mac/Include/pythonresources.h @@ -137,7 +137,7 @@ OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. #define PYTHONOPTIONS_ID 228 #define PYTHONOPTIONSOVERRIDE_ID 229 -#define POPT_VERSION_CURRENT 6 /* Current version number */ +#define POPT_VERSION_CURRENT 7 /* Current version number */ #define POPT_KEEPCONSOLE_NEVER 0 #define POPT_KEEPCONSOLE_OUTPUT 1 #define POPT_KEEPCONSOLE_ERROR 2 @@ -158,6 +158,7 @@ typedef struct PyMac_PrefRecord { unsigned char tabwarn; unsigned char nosite; unsigned char nonavservice; + unsigned char delayconsole; } PyMac_PrefRecord; #endif diff --git a/Mac/Lib/pythonprefs.py b/Mac/Lib/pythonprefs.py index 81d095f3f67..0ae3e36915b 100644 --- a/Mac/Lib/pythonprefs.py +++ b/Mac/Lib/pythonprefs.py @@ -16,14 +16,14 @@ OVERRIDE_POPT_ID = 229 OVERRIDE_GUSI_ID = 10241 # version -CUR_VERSION=6 +CUR_VERSION=7 preffilename = PstringLoader(AnyResLoader('STR ', resname=PREFNAME_NAME)).load() pref_fss = preferencefile(preffilename, 'Pyth', 'pref') class PoptLoader(VersionLoader): def __init__(self, loader): - VersionLoader.__init__(self, "bbbbbbbbbbbbb", loader) + VersionLoader.__init__(self, "bbbbbbbbbbbbbb", loader) def versioncheck(self, data): if data[0] == CUR_VERSION: @@ -44,16 +44,11 @@ class GusiLoader: tp = self.data[0:4] cr = self.data[4:8] flags = ord(self.data[9]) - delay = ((flags & 0x20) == 0x20) - return cr, tp, delay + return cr, tp - def save(self, (cr, tp, delay)): + def save(self, (cr, tp)): flags = ord(self.data[9]) - if delay: - flags = flags | 0x20 - else: - flags = flags & ~0x20 - newdata = tp + cr + self.data[8] + chr(flags) + self.data[10:] + newdata = tp + cr + self.data[8:] self.loader.save(newdata) popt_default_default = NullLoader(chr(CUR_VERSION) + 8*'\0') @@ -85,23 +80,23 @@ class PythonOptions: diralias = self.dir.load() dirfss, dummy = macfs.RawAlias(diralias).Resolve() dict['dir'] = dirfss - dict['creator'], dict['type'], dict['delayconsole'] = self.gusi.load() + dict['creator'], dict['type'] = self.gusi.load() flags = self.popt.load() dict['version'], dict['inspect'], dict['verbose'], dict['optimize'], \ dict['unbuffered'], dict['debugging'], dummy, dict['keep_console'], \ dict['nointopt'], dict['noargs'], dict['tabwarn'], \ - dict['nosite'], dict['nonavservice'] = flags + dict['nosite'], dict['nonavservice'], dict['delayconsole'] = flags return dict def save(self, dict): self.path.save(dict['path']) diralias = macfs.FSSpec(dict['dir']).NewAlias().data self.dir.save(diralias) - self.gusi.save((dict['creator'], dict['type'], dict['delayconsole'])) + self.gusi.save((dict['creator'], dict['type'])) flags = dict['version'], dict['inspect'], dict['verbose'], dict['optimize'], \ dict['unbuffered'], dict['debugging'], 0, dict['keep_console'], \ dict['nointopt'], dict['noargs'], dict['tabwarn'], \ - dict['nosite'], dict['nonavservice'] + dict['nosite'], dict['nonavservice'], dict['delayconsole'] self.popt.save(flags) def AppletOptions(file): diff --git a/Mac/Python/macglue.c b/Mac/Python/macglue.c index ade635ed9b4..63214217205 100644 --- a/Mac/Python/macglue.c +++ b/Mac/Python/macglue.c @@ -539,6 +539,25 @@ PyErr_CheckSignals() return 0; } +#if 0 +/* +** This routine is called if we know that an external library yielded +** to background tasks, so we shouldn't count that time in our computation +** of how much CPU we used. +** This happens with SIOUX, and the routine is called from our modified +** GUSISIOUX. +*/ +void +PyMac_LibraryDidYield(int howlong) +{ + unsigned long maxnextcheck = (unsigned long)LMGetTicks() + schedparams.check_interval; + + schedparams.next_check = schedparams.next_check + howlong; + if (schedparams.next_check > maxnextcheck ) + schedparams.next_check = maxnextcheck; +} +#endif + int PyOS_InterruptOccurred() { diff --git a/Mac/Python/macmain.c b/Mac/Python/macmain.c index 8dfbdaf1574..09d86486d26 100644 --- a/Mac/Python/macmain.c +++ b/Mac/Python/macmain.c @@ -53,9 +53,9 @@ extern int ccommand(char ***); #ifdef USE_MAC_SHARED_LIBRARY extern PyMac_AddLibResources(void); #endif -#ifdef USE_GUSI -#include "GUSISIOUX.h" -#endif +//#ifdef USE_GUSI +//#include "GUSISIOUX.h" +//#endif #define STARTUP "PythonStartup" @@ -71,6 +71,14 @@ short PyMac_AppRefNum; /* RefNum of application resource fork */ static char **orig_argv; static int orig_argc; +/* A flag which remembers whether the user has acknowledged all the console +** output (by typing something) +*/ +#define STATE_UNKNOWN 0 +#define STATE_LASTREAD 1 +#define STATE_LASTWRITE 2 +int console_output_state = STATE_UNKNOWN; + PyMac_PrefRecord PyMac_options; static void Py_Main(int, char **); /* Forward */ @@ -544,11 +552,19 @@ Py_Main(argc, argv) void PyMac_OutputSeen() { -#ifdef GUSISIOUX_STATE_UNKNOWN - gusisioux_state = GUSISIOUX_STATE_LASTREAD; -#endif + console_output_state = STATE_LASTREAD; } +/* +** Set the "unseen output" flag +*/ +void +PyMac_OutputNotSeen() +{ + console_output_state = STATE_LASTWRITE; +} + + /* ** Terminate application */ @@ -569,15 +585,11 @@ PyMac_Exit(status) keep = 0; break; case POPT_KEEPCONSOLE_OUTPUT: -#ifdef GUSISIOUX_STATE_UNKNOWN - if (gusisioux_state == GUSISIOUX_STATE_LASTWRITE || - gusisioux_state == GUSISIOUX_STATE_UNKNOWN ) + if (console_output_state == STATE_LASTWRITE || + console_output_state == STATE_UNKNOWN ) keep = 1; else keep = 0; -#else - keep = 1; -#endif break; case POPT_KEEPCONSOLE_ERROR: keep = (status != 0); @@ -636,3 +648,9 @@ Py_GetExecPrefix() { return PyMac_GetPythonDir(); } + +int +PyMac_GetDelayConsoleFlag() +{ + return (int)PyMac_options.delayconsole; +} \ No newline at end of file diff --git a/Mac/Python/pyGUSISIOUX.cp b/Mac/Python/pyGUSISIOUX.cp new file mode 100644 index 00000000000..795e10e0e47 --- /dev/null +++ b/Mac/Python/pyGUSISIOUX.cp @@ -0,0 +1,209 @@ +/* +** Modified version of GUSISIOUX.cp especially for Python. +** Changes (by Jack): +** - Optionally delay the console window until something is written to it. +** - Tell the upper layers whether the last command was a read or a write. +** - Tell SIOUX not to use WaitNextEvent (both Python and SIOUX trying to be +** nice to background apps means we're yielding almost 100% of the time). +** - Make sure signals are processed when returning from read/write. +*/ +#define GUSI_SOURCE +#include "GUSIInternal.h" +#include "GUSISIOUX.h" +#include "GUSIDevice.h" +#include "GUSIDescriptor.h" +#include "GUSIBasics.h" +#include "GUSIDiag.h" +//#ifndef WITHOUT_JACK_MODS +//#include "GUSIConfig.h" +//#endif + +#include + +#include +#include +#include +#include +#include + +#include "Python.h" +#include "macglue.h" +extern Boolean SIOUXUseWaitNextEvent; + +class GUSISIOUXSocket : public GUSISocket { +public: + ~GUSISIOUXSocket(); + + +ssize_t read(const GUSIScatterer & buffer); +ssize_t write(const GUSIGatherer & buffer); +virtual int ioctl(unsigned int request, va_list arg); +virtual int fstat(struct stat * buf); +virtual int isatty(); +bool select(bool * canRead, bool * canWrite, bool *); + + static GUSISIOUXSocket * Instance(); +private: + static GUSISIOUXSocket * sInstance; + + GUSISIOUXSocket(); + bool initialized; + void Initialize(); + bool fDelayConsole; +}; +class GUSISIOUXDevice : public GUSIDevice { +public: + static GUSISIOUXDevice * Instance(); + + +virtual bool Want(GUSIFileToken & file); +virtual GUSISocket * open(GUSIFileToken &, int flags); +private: + GUSISIOUXDevice() {} + + static GUSISIOUXDevice * sInstance; +}; +GUSISIOUXSocket * GUSISIOUXSocket::sInstance; + +GUSISIOUXSocket * GUSISIOUXSocket::Instance() +{ + if (!sInstance) + if (sInstance = new GUSISIOUXSocket) + sInstance->AddReference(); + + return sInstance; +} +// This declaration lies about the return type +extern "C" void SIOUXHandleOneEvent(EventRecord *userevent); + +GUSISIOUXSocket::GUSISIOUXSocket() +{ + if (PyMac_GetDelayConsoleFlag()) + fDelayConsole = true; + else + fDelayConsole = false; + if ( fDelayConsole ) + initialized = 0; + else + Initialize(); + /* Tell the upper layers there's no unseen output */ + PyMac_OutputSeen(); +} + +void +GUSISIOUXSocket::Initialize() +{ + initialized = 1; + InstallConsole(0); + GUSISetHook(GUSI_EventHook+nullEvent, (GUSIHook)SIOUXHandleOneEvent); + GUSISetHook(GUSI_EventHook+mouseDown, (GUSIHook)SIOUXHandleOneEvent); + GUSISetHook(GUSI_EventHook+mouseUp, (GUSIHook)SIOUXHandleOneEvent); + GUSISetHook(GUSI_EventHook+updateEvt, (GUSIHook)SIOUXHandleOneEvent); + GUSISetHook(GUSI_EventHook+diskEvt, (GUSIHook)SIOUXHandleOneEvent); + GUSISetHook(GUSI_EventHook+activateEvt, (GUSIHook)SIOUXHandleOneEvent); + GUSISetHook(GUSI_EventHook+osEvt, (GUSIHook)SIOUXHandleOneEvent); +} +GUSISIOUXSocket::~GUSISIOUXSocket() +{ + if ( !initialized ) return; + RemoveConsole(); +} +ssize_t GUSISIOUXSocket::read(const GUSIScatterer & buffer) +{ + if ( !initialized ) Initialize(); + GUSIStdioFlush(); + PyMac_OutputSeen(); + return buffer.SetLength( + ReadCharsFromConsole((char *) buffer.Buffer(), (int)buffer.Length())); + GUSIContext::Yield(kGUSIPoll); +} +ssize_t GUSISIOUXSocket::write(const GUSIGatherer & buffer) +{ + ssize_t rv; + + if ( !initialized ) Initialize(); + PyMac_OutputNotSeen(); + SIOUXUseWaitNextEvent = false; + rv = WriteCharsToConsole((char *) buffer.Buffer(), (int)buffer.Length()); + GUSIContext::Yield(kGUSIPoll); + return rv; +} +int GUSISIOUXSocket::ioctl(unsigned int request, va_list) +{ + switch (request) { + case FIOINTERACTIVE: + return 0; + default: + return GUSISetPosixError(EOPNOTSUPP); + } +} +int GUSISIOUXSocket::fstat(struct stat * buf) +{ + GUSISocket::fstat(buf); + buf->st_mode = S_IFCHR | 0666; + + return 0; +} +int GUSISIOUXSocket::isatty() +{ + return 1; +} +static bool input_pending() +{ +#if !TARGET_API_MAC_CARBON + // Jack thinks that completely removing this code is a bit + // too much... + QHdrPtr eventQueue = LMGetEventQueue(); + EvQElPtr element = (EvQElPtr)eventQueue->qHead; + + // now, count the number of pending keyDown events. + while (element != nil) { + if (element->evtQWhat == keyDown || element->evtQWhat == autoKey) + return true; + element = (EvQElPtr)element->qLink; + } +#endif + return false; +} + +bool GUSISIOUXSocket::select(bool * canRead, bool * canWrite, bool *) +{ + if ( !initialized ) Initialize(); + bool cond = false; + if (canRead) + if (*canRead = input_pending()) + cond = true; + if (canWrite) + cond = *canWrite = true; + + return cond; +} +GUSISIOUXDevice * GUSISIOUXDevice::sInstance; +GUSISIOUXDevice * GUSISIOUXDevice::Instance() +{ + if (!sInstance) + sInstance = new GUSISIOUXDevice(); + return sInstance; +} +bool GUSISIOUXDevice::Want(GUSIFileToken & file) +{ + switch (file.WhichRequest()) { + case GUSIFileToken::kWillOpen: + return file.IsDevice() && (file.StrStdStream(file.Path()) > -1); + default: + return false; + } +} +GUSISocket * GUSISIOUXDevice::open(GUSIFileToken &, int) +{ + return GUSISIOUXSocket::Instance(); +} +void GUSISetupConsoleDescriptors() +{ + GUSIDescriptorTable * table = GUSIDescriptorTable::Instance(); + GUSISIOUXSocket * SIOUX = GUSISIOUXSocket::Instance(); + + table->InstallSocket(SIOUX); + table->InstallSocket(SIOUX); + table->InstallSocket(SIOUX); +} diff --git a/Mac/Resources/pythonpath.r b/Mac/Resources/pythonpath.r index 2739b19aed8..b127d9f9e05 100644 --- a/Mac/Resources/pythonpath.r +++ b/Mac/Resources/pythonpath.r @@ -25,6 +25,7 @@ type 'Popt' { byte newStandardExceptions = 0, oldStandardExceptions = 1; byte sitePython = 0, noSitePython = 1; byte navService = 0, noNavService = 1; + byte noDelayConsole = 0, delayConsole = 1; }; type 'TMPL' { @@ -53,6 +54,7 @@ resource 'TMPL' (PYTHONOPTIONS_ID, "Popt") { "Old standard exceptions", 'DBYT', "No site-python support", 'DBYT', "No NavServices in macfs", 'DBYT', + "Delay console window", 'DBYT', } }; @@ -72,6 +74,7 @@ resource 'Popt' (PYTHONOPTIONS_ID, "Options") { newStandardExceptions, sitePython, navService, + noDelayConsole, }; /* The sys.path initializer */