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
#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
unsigned char tabwarn;
unsigned char nosite;
unsigned char nonavservice;
+ unsigned char delayconsole;
} PyMac_PrefRecord;
#endif
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:
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')
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):
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()
{
#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"
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 */
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
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);
{
return PyMac_GetPythonDir();
}
+
+int
+PyMac_GetDelayConsoleFlag()
+{
+ return (int)PyMac_options.delayconsole;
+}
\ No newline at end of file
--- /dev/null
+/*
+** 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 <LowMem.h>
+
+#include <fcntl.h>
+#include <sys/stat.h>
+#include <sys/ioctl.h>
+#include <errno.h>
+#include <console.h>
+
+#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);
+}
byte newStandardExceptions = 0, oldStandardExceptions = 1;
byte sitePython = 0, noSitePython = 1;
byte navService = 0, noNavService = 1;
+ byte noDelayConsole = 0, delayConsole = 1;
};
type 'TMPL' {
"Old standard exceptions", 'DBYT',
"No site-python support", 'DBYT',
"No NavServices in macfs", 'DBYT',
+ "Delay console window", 'DBYT',
}
};
newStandardExceptions,
sitePython,
navService,
+ noDelayConsole,
};
/* The sys.path initializer */