3937 lines
86 KiB
C++
3937 lines
86 KiB
C++
/*
|
|
* File: mred.cc
|
|
* Purpose: MrEd main file, including a hodge-podge of global stuff
|
|
* Author: Matthew Flatt
|
|
* Created: 1995
|
|
* Copyright: (c) 2004-2007 PLT Scheme Inc.
|
|
* Copyright: (c) 1995-2000, Matthew Flatt
|
|
*/
|
|
|
|
/* wx_xt: */
|
|
#define Uses_XtIntrinsic
|
|
#define Uses_XtIntrinsicP
|
|
#define Uses_XLib
|
|
|
|
#if defined(_MSC_VER) && defined(MZ_PRECISE_GC)
|
|
# include "wx.h"
|
|
#endif
|
|
|
|
/* wx_motif, for wxTimer: */
|
|
#ifdef __GNUG__
|
|
# pragma implementation "wx_timer.h"
|
|
#endif
|
|
|
|
#include "common.h"
|
|
|
|
#include "wx_frame.h"
|
|
#include "wx_utils.h"
|
|
#include "wx_main.h"
|
|
#include "wx_buttn.h"
|
|
#include "wx_messg.h"
|
|
#include "wx_timer.h"
|
|
#include "wx_media.h"
|
|
#include "wx_dialg.h"
|
|
#include "wx_cmdlg.h"
|
|
#include "wx_menu.h"
|
|
#include "wx_dcps.h"
|
|
#include "wx_clipb.h"
|
|
#include "wx_types.h"
|
|
#ifdef wx_mac
|
|
# include "simpledrop.h"
|
|
#endif
|
|
#ifdef wx_msw
|
|
# include "wx_wmgr.h"
|
|
#endif
|
|
#include <ctype.h>
|
|
#include <stdio.h>
|
|
#include <stdarg.h>
|
|
|
|
/* Solaris: getdtablesize sometimes not available */
|
|
#if !defined(USE_ULIMIT) && defined(sun) && defined(__svr4__)
|
|
# define USE_ULIMIT
|
|
#endif
|
|
|
|
#if defined(wx_xt)
|
|
# include <X11/Xlib.h>
|
|
# include <X11/keysymdef.h>
|
|
#endif
|
|
|
|
#ifdef wx_x
|
|
# include <sys/types.h>
|
|
# include <sys/time.h>
|
|
# include <unistd.h>
|
|
# if defined(_IBMR2)
|
|
# include <sys/select.h>
|
|
# endif
|
|
# include <signal.h>
|
|
#endif
|
|
|
|
#ifdef wx_msw
|
|
# ifdef _MSC_VER
|
|
# include <direct.h>
|
|
# else
|
|
# include <dir.h>
|
|
# endif
|
|
#endif
|
|
|
|
#ifdef wx_mac
|
|
# ifndef WX_CARBON
|
|
# include <Events.h>
|
|
# endif
|
|
# ifdef OS_X
|
|
int wx_in_terminal;
|
|
# else
|
|
# define wx_in_terminal 0
|
|
# endif
|
|
#else
|
|
# ifdef wx_msw
|
|
static int wx_in_terminal = 0;
|
|
# else
|
|
# define wx_in_terminal 0
|
|
# endif
|
|
#endif
|
|
|
|
#ifdef OS_X
|
|
extern "C" void _signal_nobind(...);
|
|
#endif
|
|
|
|
#if defined(wx_x) || defined(wx_msw)
|
|
# define ADD_OBJ_DUMP 0
|
|
#else
|
|
# define ADD_OBJ_DUMP 0
|
|
#endif
|
|
|
|
#define INTERRUPT_CHECK_ON 0
|
|
|
|
# include "wxs/wxscheme.h"
|
|
# include "wxs/wxsmred.h"
|
|
# include "wxs/wxs_fram.h"
|
|
# include "wxs/wxs_obj.h"
|
|
|
|
wxFrame *mred_real_main_frame;
|
|
|
|
#if defined(wx_xt) || defined(OS_X)
|
|
# define mred_BREAK_HANDLER
|
|
#endif
|
|
|
|
static Scheme_Thread *user_main_thread;
|
|
|
|
extern void wxMediaIOCheckLSB(void);
|
|
extern void wxMouseEventHandled(void);
|
|
#ifdef wx_xt
|
|
extern int wx_single_instance;
|
|
#endif
|
|
|
|
#include "mred.h"
|
|
|
|
#ifdef MPW_CPLUS
|
|
extern "C" {
|
|
typedef void (*GC_F_PTR)(void *, void *);
|
|
typedef void (*ON_KILL_PTR)(struct Scheme_Thread *p);
|
|
typedef Scheme_Object *(*MK_PTR)(void);
|
|
# if !defined(USE_SENORA_GC) && !defined(MZ_PRECISE_GC)
|
|
typedef void (*IGNORE_PTR)(char *, GC_word);
|
|
# endif
|
|
typedef void (*CONSOLE_PRINTF_PTR)(char *str, ...);
|
|
typedef void (*CONSOLE_OUTPUT_PTR)(char *str, long len);
|
|
typedef void (*EXIT_PTR)(int);
|
|
typedef void (*DW_PRE_PTR)(void *);
|
|
typedef Scheme_Object *(*DW_RUN_PTR)(void *);
|
|
typedef void (*DW_POST_PTR)(void *);
|
|
typedef void (*ON_SUSPEND_PTR)(void);
|
|
}
|
|
# define CAST_SCP (Scheme_Closed_Prim *)
|
|
# define CAST_GCP (GC_F_PTR)
|
|
# define CAST_SCCC (Scheme_Close_Custodian_Client *)
|
|
# define CAST_BLKCHK (Scheme_Ready_Fun)
|
|
# define CAST_WU (Scheme_Needs_Wakeup_Fun)
|
|
# define CAST_TOK (ON_KILL_PTR)
|
|
# define CAST_GS (Scheme_Get_String_Fun)
|
|
# define CAST_IREADY (Scheme_In_Ready_Fun)
|
|
# define CAST_ICLOSE (Scheme_Close_Input_Fun)
|
|
# define CAST_WS (Scheme_Write_String_Fun)
|
|
# define CAST_MK (MK_PTR)
|
|
# define CAST_SLEEP (SLEEP_PROC_PTR)
|
|
# define CAST_IGNORE (IGNORE_PTR)
|
|
# define CAST_PRINTF (CONSOLE_PRINTF_PTR)
|
|
# define CAST_OUTPUT (CONSOLE_OUTPUT_PTR)
|
|
# define CAST_EXIT (EXIT_PTR)
|
|
# define CAST_DW_PRE (DW_PRE_PTR)
|
|
# define CAST_DW_RUN (DW_RUN_PTR)
|
|
# define CAST_DW_POST (DW_POST_PTR)
|
|
# define CAST_SUSPEND (ON_SUSPEND_PTR)
|
|
# define CAST_EXT (Scheme_Custodian_Extractor)
|
|
#else
|
|
# define CAST_SCP /* empty */
|
|
# define CAST_GCP /* empty */
|
|
# define CAST_SCCC /* empty */
|
|
# define CAST_BLKCHK /* empty */
|
|
# define CAST_WU /* empty */
|
|
# define CAST_TOK /* empty */
|
|
# define CAST_GS /* empty */
|
|
# define CAST_IREADY /* empty */
|
|
# define CAST_ICLOSE /* empty */
|
|
# define CAST_WS /* empty */
|
|
# define CAST_MK /* empty */
|
|
# define CAST_SLEEP /* empty */
|
|
# define CAST_IGNORE /* empty */
|
|
# define CAST_PRINTF /* empty */
|
|
# define CAST_OUTPUT /* empty */
|
|
# define CAST_EXIT /* empty */
|
|
# define CAST_DW_PRE /* empty */
|
|
# define CAST_DW_RUN /* empty */
|
|
# define CAST_DW_POST /* empty */
|
|
# define CAST_SUSPEND /* empty */
|
|
# define CAST_EXT /* empty */
|
|
#endif
|
|
|
|
/* Set by mrmain.cxx: */
|
|
/* (The indirection is needed to avoid mutual .dll dependencies.) */
|
|
MrEd_Finish_Cmd_Line_Run_Proc mred_finish_cmd_line_run;
|
|
void mred_set_finish_cmd_line_run(MrEd_Finish_Cmd_Line_Run_Proc p) { mred_finish_cmd_line_run = p; }
|
|
MrEd_Run_From_Cmd_Line_Proc mred_run_from_cmd_line;
|
|
void mred_set_run_from_cmd_line(MrEd_Run_From_Cmd_Line_Proc p) { mred_run_from_cmd_line = p; }
|
|
|
|
#if 0
|
|
/* Force initialization of the garbage collector (currently needed
|
|
only when supporting Irix sprocs) */
|
|
class GCInit {
|
|
public:
|
|
GCInit() {
|
|
GC_INIT();
|
|
}
|
|
};
|
|
static GCInit _gcinit;
|
|
#endif
|
|
|
|
static Scheme_Env *global_env;
|
|
|
|
class MrEdApp: public wxApp
|
|
{
|
|
public:
|
|
Bool initialized;
|
|
int xargc;
|
|
char **xargv;
|
|
|
|
MrEdApp();
|
|
wxFrame *OnInit(void);
|
|
void RealInit(void);
|
|
#ifdef wx_mac
|
|
char *GetDefaultAboutItemName();
|
|
void DoDefaultAboutItem();
|
|
#endif
|
|
int OnExit(void);
|
|
};
|
|
|
|
MrEdApp *TheMrEdApp;
|
|
|
|
static int exit_val = 0;
|
|
|
|
#ifdef LIBGPP_REGEX_HACK
|
|
/* Fixes weirdness with libg++ and the compiler: it tries to
|
|
destroy global regexp objects that were never created. Calling
|
|
the constructor forces the other global values to be initialized. */
|
|
# include <Regex.h>
|
|
#endif
|
|
|
|
/****************************************************************************/
|
|
/* Contexts */
|
|
/****************************************************************************/
|
|
|
|
MrEdContext *mred_contexts;
|
|
static MrEdContext *mred_main_context;
|
|
static MrEdContext *mred_only_context;
|
|
static int only_context_just_once = 0;
|
|
static MrEdContext *user_main_context;
|
|
static MrEdContextFramesRef mred_frames; /* list of all frames (weak link to invisible ones) */
|
|
static Scheme_Hash_Table *timer_contexts;
|
|
int mred_eventspace_param;
|
|
int mred_event_dispatch_param;
|
|
Scheme_Type mred_eventspace_type;
|
|
Scheme_Type mred_nested_wait_type;
|
|
static Scheme_Type mred_eventspace_hop_type;
|
|
static Scheme_Object *def_dispatch;
|
|
int mred_ps_setup_param;
|
|
#ifdef NEED_HET_PARAM
|
|
Scheme_Object *mred_het_key;
|
|
#endif
|
|
|
|
typedef struct Nested_Wait {
|
|
Scheme_Object so;
|
|
Scheme_Object *wait_on;
|
|
} Nested_Wait;
|
|
|
|
typedef struct Context_Custodian_Hop {
|
|
Scheme_Object so;
|
|
MrEdContext *context;
|
|
} Context_Custodian_Hop;
|
|
|
|
#ifdef MZ_PRECISE_GC
|
|
# define WEAKIFY(x) ((MrEdContext *)GC_malloc_weak_box(x, NULL, 0))
|
|
# define WEAKIFIED(x) ((MrEdContext *)GC_weak_box_val(x))
|
|
#else
|
|
# define WEAKIFY(x) x
|
|
# define WEAKIFIED(x) x
|
|
# define HIDE_FROM_XFORM(x) x
|
|
#endif
|
|
|
|
static MrEdContext *check_q_callbacks(int hi, int (*test)(MrEdContext *, MrEdContext *),
|
|
MrEdContext *tdata, int check_only);
|
|
static void remove_q_callbacks(MrEdContext *c);
|
|
|
|
#ifdef MZ_PRECISE_GC
|
|
|
|
START_XFORM_SKIP;
|
|
|
|
static int size_eventspace_val(void *)
|
|
{
|
|
return gcBYTES_TO_WORDS(sizeof(MrEdContext));
|
|
}
|
|
|
|
static int mark_eventspace_val(void *p)
|
|
{
|
|
MrEdContext *c = (MrEdContext *)p;
|
|
|
|
gcMARK_TYPED(Scheme_Thread *, c->handler_running);
|
|
gcMARK_TYPED(MrEdFinalizedContext *, c->finalized);
|
|
|
|
gcMARK_TYPED(wxChildList *, c->topLevelWindowList);
|
|
gcMARK_TYPED(wxStandardSnipClassList *, c->snipClassList);
|
|
gcMARK_TYPED(wxBufferDataClassList *, c->bufferDataClassList);
|
|
gcMARK_TYPED(wxWindow *, c->modal_window);
|
|
gcMARK_TYPED(MrEd_Saved_Modal *, c->modal_stack);
|
|
|
|
gcMARK_TYPED(Scheme_Config *, c->main_config);
|
|
gcMARK_TYPED(Scheme_Thread_Cell_Table *, c->main_cells);
|
|
gcMARK_TYPED(Scheme_Thread_Cell_Table *, c->main_break_cell);
|
|
|
|
gcMARK_TYPED(wxTimer *, c->timer);
|
|
gcMARK_TYPED(wxTimer **, c->timers);
|
|
|
|
gcMARK_TYPED(void *, c->alt_data);
|
|
|
|
gcMARK_TYPED(MrEdContext *, c->next);
|
|
|
|
#ifdef wx_msw
|
|
gcMARK_TYPED(LeaveEvent *, c->queued_leaves);
|
|
#endif
|
|
|
|
gcMARK_TYPED(Context_Custodian_Hop *, c->mr_hop);
|
|
gcMARK_TYPED(Scheme_Custodian_Reference *, c->mref);
|
|
|
|
return gcBYTES_TO_WORDS(sizeof(MrEdContext));
|
|
}
|
|
|
|
static int fixup_eventspace_val(void *p)
|
|
{
|
|
MrEdContext *c = (MrEdContext *)p;
|
|
|
|
gcFIXUP_TYPED(Scheme_Thread *, c->handler_running);
|
|
gcFIXUP_TYPED(MrEdFinalizedContext *, c->finalized);
|
|
|
|
gcFIXUP_TYPED(wxChildList *, c->topLevelWindowList);
|
|
gcFIXUP_TYPED(wxStandardSnipClassList *, c->snipClassList);
|
|
gcFIXUP_TYPED(wxBufferDataClassList *, c->bufferDataClassList);
|
|
gcFIXUP_TYPED(wxWindow *, c->modal_window);
|
|
gcFIXUP_TYPED(MrEd_Saved_Modal *, c->modal_stack);
|
|
|
|
gcFIXUP_TYPED(Scheme_Config *, c->main_config);
|
|
gcFIXUP_TYPED(Scheme_Thread_Cell_Table *, c->main_cells);
|
|
gcFIXUP_TYPED(Scheme_Thread_Cell_Table *, c->main_break_cell);
|
|
|
|
gcFIXUP_TYPED(wxTimer *, c->timer);
|
|
gcFIXUP_TYPED(wxTimer **, c->timers);
|
|
|
|
gcFIXUP_TYPED(void *, c->alt_data);
|
|
|
|
gcFIXUP_TYPED(MrEdContext *, c->next);
|
|
|
|
#ifdef wx_msw
|
|
gcFIXUP_TYPED(LeaveEvent *, c->queued_leaves);
|
|
#endif
|
|
|
|
gcFIXUP_TYPED(Context_Custodian_Hop *, c->mr_hop);
|
|
gcFIXUP_TYPED(Scheme_Custodian_Reference *, c->mref);
|
|
|
|
return gcBYTES_TO_WORDS(sizeof(MrEdContext));
|
|
}
|
|
|
|
static int size_nested_wait_val(void *)
|
|
{
|
|
return gcBYTES_TO_WORDS(sizeof(Nested_Wait));
|
|
}
|
|
|
|
static int mark_nested_wait_val(void *p)
|
|
{
|
|
Nested_Wait *c = (Nested_Wait *)p;
|
|
|
|
gcMARK_TYPED(MrEdContext *, c->wait_on);
|
|
|
|
return gcBYTES_TO_WORDS(sizeof(Nested_Wait));
|
|
}
|
|
|
|
static int fixup_nested_wait_val(void *p)
|
|
{
|
|
Nested_Wait *c = (Nested_Wait *)p;
|
|
|
|
gcFIXUP_TYPED(MrEdContext *, c->wait_on);
|
|
|
|
return gcBYTES_TO_WORDS(sizeof(Nested_Wait));
|
|
}
|
|
|
|
static int size_eventspace_hop_val(void *)
|
|
{
|
|
return gcBYTES_TO_WORDS(sizeof(Context_Custodian_Hop));
|
|
}
|
|
|
|
static int mark_eventspace_hop_val(void *p)
|
|
{
|
|
Context_Custodian_Hop *c = (Context_Custodian_Hop *)p;
|
|
|
|
gcMARK_TYPED(MrEdContext *, c->context);
|
|
|
|
return gcBYTES_TO_WORDS(sizeof(Context_Custodian_Hop));
|
|
}
|
|
|
|
static int fixup_eventspace_hop_val(void *p)
|
|
{
|
|
Context_Custodian_Hop *c = (Context_Custodian_Hop *)p;
|
|
|
|
gcFIXUP_TYPED(MrEdContext *, c->context);
|
|
|
|
return gcBYTES_TO_WORDS(sizeof(Context_Custodian_Hop));
|
|
}
|
|
|
|
END_XFORM_SKIP;
|
|
|
|
#endif
|
|
|
|
MrEdContext *MrEdGetContext(wxObject *w)
|
|
{
|
|
if (w) {
|
|
#if !defined(wx_xt) && !defined(wx_mac)
|
|
if (wxSubType(w->__type, wxTYPE_FRAME)) {
|
|
#endif
|
|
MrEdContext *c;
|
|
c = (MrEdContext *)((wxFrame *)w)->context;
|
|
if (c)
|
|
return c;
|
|
#if !defined(wx_xt) && !defined(wx_mac)
|
|
} else {
|
|
MrEdContext *c;
|
|
c = (MrEdContext *)((wxDialogBox *)w)->context;
|
|
if (c)
|
|
return c;
|
|
}
|
|
#endif
|
|
}
|
|
|
|
if (mred_only_context) {
|
|
if (only_context_just_once) {
|
|
MrEdContext *c = mred_only_context;
|
|
mred_only_context = NULL;
|
|
only_context_just_once = 0;
|
|
return c;
|
|
} else
|
|
return mred_only_context;
|
|
} else
|
|
return (MrEdContext *)scheme_get_param(scheme_current_config(), mred_eventspace_param);
|
|
}
|
|
|
|
void *MrEdGetWindowContext(wxWindow *w)
|
|
{
|
|
while (1) {
|
|
if (wxSubType(w->__type, wxTYPE_FRAME))
|
|
return MrEdGetContext(w);
|
|
#if !defined(wx_xt) && !defined(wx_mac)
|
|
if (wxSubType(w->__type, wxTYPE_DIALOG_BOX))
|
|
return MrEdGetContext(w);
|
|
#endif
|
|
|
|
w = w->GetParent();
|
|
}
|
|
}
|
|
|
|
void *wxGetContextForFrame()
|
|
{
|
|
if (!TheMrEdApp)
|
|
return NULL;
|
|
else
|
|
return (void *)MrEdGetContext();
|
|
}
|
|
|
|
wxChildList *wxGetTopLevelWindowsList(wxObject *w)
|
|
{
|
|
MrEdContext *c;
|
|
c = MrEdGetContext(w);
|
|
|
|
return c->topLevelWindowList;
|
|
}
|
|
|
|
wxWindow *wxGetModalWindow(wxObject *w)
|
|
{
|
|
MrEdContext *c;
|
|
c = MrEdGetContext(w);
|
|
|
|
return c->modal_window;
|
|
}
|
|
|
|
class MrEd_Saved_Modal {
|
|
public:
|
|
wxWindow *win;
|
|
MrEd_Saved_Modal *next;
|
|
};
|
|
|
|
void wxPushModalWindow(wxObject *w, wxWindow *win)
|
|
{
|
|
MrEdContext *c;
|
|
c = MrEdGetContext(w);
|
|
|
|
if (c->modal_window) {
|
|
MrEd_Saved_Modal *save;
|
|
save = new WXGC_PTRS MrEd_Saved_Modal;
|
|
|
|
save->next = c->modal_stack;
|
|
save->win = c->modal_window;
|
|
c->modal_stack = save;
|
|
}
|
|
|
|
c->modal_window = win;
|
|
}
|
|
|
|
void wxPopModalWindow(wxObject *w, wxWindow *win)
|
|
{
|
|
MrEdContext *c;
|
|
MrEd_Saved_Modal *save, *prev;
|
|
c = MrEdGetContext(w);
|
|
|
|
if (c->modal_window == win)
|
|
c->modal_window = NULL;
|
|
|
|
prev = NULL;
|
|
for (save = c->modal_stack; save; save = save->next) {
|
|
if ((save->win == win) || !c->modal_window) {
|
|
if (prev)
|
|
prev->next = save->next;
|
|
else
|
|
c->modal_stack = save->next;
|
|
|
|
if (save->win != win)
|
|
c->modal_window = save->win;
|
|
} else
|
|
prev = save;
|
|
}
|
|
}
|
|
|
|
wxStandardSnipClassList *wxGetTheSnipClassList()
|
|
{
|
|
MrEdContext *c;
|
|
c = MrEdGetContext();
|
|
|
|
return c->snipClassList;
|
|
}
|
|
|
|
wxBufferDataClassList *wxGetTheBufferDataClassList()
|
|
{
|
|
MrEdContext *c;
|
|
c = MrEdGetContext();
|
|
|
|
return c->bufferDataClassList;
|
|
}
|
|
|
|
int wxGetBusyState(void)
|
|
{
|
|
MrEdContext *c;
|
|
c = MrEdGetContext();
|
|
|
|
return c->busyState;
|
|
}
|
|
|
|
void wxSetBusyState(int state)
|
|
{
|
|
MrEdContext *c;
|
|
c = MrEdGetContext();
|
|
|
|
c->busyState = state;
|
|
}
|
|
|
|
extern int MrEdGetDoubleTime(void);
|
|
static int doubleClickThreshold = -1;
|
|
|
|
int wxMrEdGetDoubleTime(void)
|
|
{
|
|
if (doubleClickThreshold < 0) {
|
|
if (!wxGetPreference("doubleClickTime", &doubleClickThreshold)) {
|
|
doubleClickThreshold = MrEdGetDoubleTime();
|
|
}
|
|
}
|
|
|
|
return doubleClickThreshold;
|
|
}
|
|
|
|
#ifdef wx_xt
|
|
/* For widgets: */
|
|
extern "C" {
|
|
int wxGetMultiClickTime(Display *d)
|
|
{
|
|
return wxMrEdGetDoubleTime();
|
|
}
|
|
}
|
|
#endif
|
|
|
|
Bool wxIsPrimEventspace()
|
|
{
|
|
return MrEdGetContext() == mred_main_context;
|
|
}
|
|
|
|
int wxIsUserMainEventspace(Scheme_Object *o)
|
|
{
|
|
return o == (Scheme_Object *)user_main_context;
|
|
}
|
|
|
|
int wxsIsContextShutdown(void *cx)
|
|
{
|
|
MrEdContext *c;
|
|
c = (MrEdContext *)cx;
|
|
|
|
return c->killed;
|
|
}
|
|
|
|
void *wxsCheckEventspace(char *who)
|
|
{
|
|
MrEdContext *c;
|
|
c = (MrEdContext *)wxGetContextForFrame();
|
|
|
|
if (c->killed)
|
|
scheme_signal_error("%s: the current eventspace has been shutdown", who);
|
|
|
|
return (void *)c;
|
|
}
|
|
|
|
static int ps_ready = 0;
|
|
static wxPrintSetupData *orig_ps_setup;
|
|
|
|
wxPrintSetupData *wxGetThePrintSetupData()
|
|
{
|
|
if (ps_ready) {
|
|
Scheme_Object *o;
|
|
o = scheme_get_param(scheme_current_config(), mred_ps_setup_param);
|
|
if (o && SCHEME_TRUEP(o))
|
|
return wxsUnbundlePSSetup(o);
|
|
}
|
|
return orig_ps_setup;
|
|
}
|
|
|
|
void wxSetThePrintSetupData(wxPrintSetupData *d)
|
|
{
|
|
if (ps_ready) {
|
|
Scheme_Object *o;
|
|
o = wxsBundlePSSetup(d);
|
|
scheme_set_param(scheme_current_config(), mred_ps_setup_param, o);
|
|
}
|
|
orig_ps_setup = d;
|
|
}
|
|
|
|
|
|
/* Forward decl: */
|
|
static int MrEdSameContext(MrEdContext *c, MrEdContext *testc);
|
|
|
|
static void destroy_wxObject(wxWindow *w, void *)
|
|
{
|
|
if (w->__gc_external) {
|
|
objscheme_destroy(w, (Scheme_Object *)w->__gc_external);
|
|
((Scheme_Class_Object *)w->__gc_external)->primflag = -2; /* -2 => shutdown */
|
|
w->__gc_external = NULL;
|
|
}
|
|
}
|
|
|
|
static void kill_eventspace(Scheme_Object *ec, void *)
|
|
{
|
|
MrEdContext *c;
|
|
c = WEAKIFIED(((Context_Custodian_Hop *)ec)->context);
|
|
|
|
if (!c)
|
|
return; /* must not have had any frames, timers, etc. */
|
|
|
|
{
|
|
wxClipboardClient *clipOwner;
|
|
clipOwner = wxTheClipboard->GetClipboardClient();
|
|
if (clipOwner && (clipOwner->context == c))
|
|
wxTheClipboard->SetClipboardString("", 0);
|
|
}
|
|
|
|
c->killed = 1;
|
|
|
|
{
|
|
wxChildNode *node, *next;
|
|
for (node = c->topLevelWindowList->First(); node; node = next) {
|
|
wxWindow *w;
|
|
w = (wxWindow *)node->Data();
|
|
next = node->Next();
|
|
if (w) {
|
|
w->ForEach(destroy_wxObject, NULL);
|
|
if (node->IsShown())
|
|
w->Show(FALSE);
|
|
}
|
|
}
|
|
}
|
|
|
|
{
|
|
wxTimer *t;
|
|
while (c->timers) {
|
|
t = c->timers;
|
|
t->Stop();
|
|
}
|
|
}
|
|
|
|
remove_q_callbacks(c);
|
|
}
|
|
|
|
static Scheme_Object *extract_eventspace_from_hop(Scheme_Object *ec)
|
|
{
|
|
return (Scheme_Object *)WEAKIFIED(((Context_Custodian_Hop *)ec)->context);
|
|
}
|
|
|
|
static void CollectingContext(void *cfx, void *)
|
|
{
|
|
wxChildNode *cnode, *next;
|
|
MrEdFinalizedContext *cf;
|
|
cf = (MrEdFinalizedContext *)gcPTR_TO_OBJ(cfx);
|
|
|
|
if (cf->frames->next)
|
|
FRAMES_REF(cf->frames->next)->prev = cf->frames->prev;
|
|
if (cf->frames->prev)
|
|
FRAMES_REF(cf->frames->prev)->next = cf->frames->next;
|
|
else
|
|
mred_frames = cf->frames->next;
|
|
|
|
cf->frames->next = NULL;
|
|
cf->frames->prev = NULL;
|
|
|
|
/* Must explicitly delete frames now because their context
|
|
is going away. (The frame would certainly have been finalized
|
|
later during this set of finalizations, but that would be
|
|
too late.) */
|
|
for (cnode = cf->frames->list->First(); cnode; cnode = next) {
|
|
wxFrame *fr;
|
|
next = cnode->Next();
|
|
fr = (wxFrame *)cnode->Data();
|
|
if (fr) {
|
|
DELETE_OBJ fr;
|
|
}
|
|
}
|
|
|
|
MrEdDestroyContext(cf);
|
|
|
|
DELETE_OBJ cf->frames->list;
|
|
cf->frames = NULL;
|
|
}
|
|
|
|
static MrEdContext *MakeContext(MrEdContext *c)
|
|
{
|
|
MrEdContextFrames *frames;
|
|
Context_Custodian_Hop *mr_hop;
|
|
Scheme_Object *break_cell;
|
|
Scheme_Config *config;
|
|
Scheme_Thread_Cell_Table *cells;
|
|
|
|
scheme_custodian_check_available(NULL, "make-eventspace", "eventspace");
|
|
|
|
if (!c) {
|
|
wxChildList *tlwl;
|
|
wxStandardSnipClassList *scl;
|
|
wxBufferDataClassList *bdcl;
|
|
MrEdFinalizedContext *fc;
|
|
|
|
c = (MrEdContext *)scheme_malloc_tagged(sizeof(MrEdContext));
|
|
c->so.type = mred_eventspace_type;
|
|
|
|
tlwl = new WXGC_PTRS wxChildList();
|
|
c->topLevelWindowList = tlwl;
|
|
scl = wxMakeTheSnipClassList();
|
|
c->snipClassList = scl;
|
|
bdcl = wxMakeTheBufferDataClassList();
|
|
c->bufferDataClassList = bdcl;
|
|
fc = new WXGC_PTRS MrEdFinalizedContext;
|
|
c->finalized = fc;
|
|
}
|
|
|
|
c->ready = 1;
|
|
|
|
c->handler_running = NULL;
|
|
|
|
c->busyState = 0;
|
|
c->killed = 0;
|
|
|
|
frames = new WXGC_PTRS MrEdContextFrames;
|
|
c->finalized->frames = frames;
|
|
frames->next = mred_frames;
|
|
frames->prev = NULL;
|
|
frames->list = c->topLevelWindowList;
|
|
{
|
|
MrEdContextFramesRef r;
|
|
r = MAKE_FRAMES_REF(frames);
|
|
if (mred_frames)
|
|
FRAMES_REF(mred_frames)->prev = r;
|
|
mred_frames = r;
|
|
}
|
|
|
|
c->modal_window = NULL;
|
|
|
|
config = scheme_extend_config(scheme_current_config(),
|
|
mred_eventspace_param,
|
|
(Scheme_Object *)c);
|
|
|
|
c->main_config = config;
|
|
cells = scheme_inherit_cells(NULL);
|
|
c->main_cells = cells;
|
|
break_cell = scheme_current_break_cell();
|
|
c->main_break_cell = break_cell;
|
|
|
|
#ifdef MZ_PRECISE_GC
|
|
/* Override destructor-based finalizer: */
|
|
GC_set_finalizer(gcOBJ_TO_PTR(c->finalized),
|
|
0, 3,
|
|
CollectingContext, NULL,
|
|
NULL, NULL);
|
|
#else
|
|
scheme_register_finalizer(gcOBJ_TO_PTR(c->finalized),
|
|
CAST_GCP CollectingContext, NULL,
|
|
NULL, NULL);
|
|
#endif
|
|
WXGC_IGNORE(c, c->finalized);
|
|
|
|
#ifdef MZ_PRECISE_GC
|
|
mr_hop = (Context_Custodian_Hop *)GC_malloc_one_tagged(sizeof(Context_Custodian_Hop));
|
|
#else
|
|
mr_hop = (Context_Custodian_Hop *)scheme_malloc_atomic(sizeof(Context_Custodian_Hop));
|
|
#endif
|
|
mr_hop->so.type = mred_eventspace_hop_type;
|
|
{
|
|
MrEdContext *ctx;
|
|
ctx = WEAKIFY(c);
|
|
mr_hop->context = ctx;
|
|
}
|
|
c->mr_hop = mr_hop;
|
|
#ifndef MZ_PRECISE_GC
|
|
scheme_weak_reference((void **)(void *)&mr_hop->context);
|
|
#endif
|
|
|
|
{
|
|
Scheme_Custodian_Reference *mr;
|
|
mr = scheme_add_managed(NULL, (Scheme_Object *)mr_hop,
|
|
CAST_SCCC kill_eventspace,
|
|
NULL, 0);
|
|
c->mref = mr;
|
|
}
|
|
|
|
return c;
|
|
}
|
|
|
|
static void ChainContextsList()
|
|
{
|
|
MrEdContextFrames *f;
|
|
MrEdContextFramesRef fr = mred_frames;
|
|
wxChildNode *first;
|
|
|
|
mred_contexts = NULL;
|
|
|
|
while (fr) {
|
|
f = FRAMES_REF(fr);
|
|
first = f->list->First();
|
|
|
|
#if 0
|
|
while (first && !first->IsShown())
|
|
first = first->Next();
|
|
#endif
|
|
|
|
if (first) {
|
|
wxObject *o;
|
|
MrEdContext *c;
|
|
o = first->Data();
|
|
c = MrEdGetContext(o);
|
|
c->next = mred_contexts;
|
|
mred_contexts = c;
|
|
}
|
|
fr = f->next;
|
|
}
|
|
}
|
|
|
|
static void UnchainContextsList()
|
|
{
|
|
while (mred_contexts) {
|
|
MrEdContext *next = mred_contexts->next;
|
|
mred_contexts->next = NULL;
|
|
mred_contexts = next;
|
|
}
|
|
}
|
|
|
|
static wxTimer *GlobalFirstTimer()
|
|
{
|
|
wxTimer *timer = NULL;
|
|
int i;
|
|
for (i = timer_contexts->size; i--; ) {
|
|
if (timer_contexts->vals[i]) {
|
|
MrEdContext *c = (MrEdContext *)timer_contexts->keys[i];
|
|
if (c->ready && c->timers) {
|
|
if (!timer)
|
|
timer = c->timers;
|
|
else if (c->timers->expiration < timer->expiration)
|
|
timer = c->timers;
|
|
}
|
|
}
|
|
}
|
|
return timer;
|
|
}
|
|
|
|
#ifdef wx_xt
|
|
void wxUnhideAllCursors()
|
|
{
|
|
MrEdContextFrames *f;
|
|
MrEdContextFramesRef fr = mred_frames;
|
|
wxChildNode *first;
|
|
int v;
|
|
|
|
if (wxCheckHiddenCursors()) {
|
|
while (fr) {
|
|
f = FRAMES_REF(fr);
|
|
first = f->list->First();
|
|
|
|
if (first) {
|
|
wxObject *o;
|
|
MrEdContext *c;
|
|
o = first->Data();
|
|
c = MrEdGetContext(o);
|
|
v = wxUnhideCursorInFrame(o, c->busyState);
|
|
c->busyState = v;
|
|
}
|
|
fr = f->next;
|
|
}
|
|
}
|
|
}
|
|
#endif
|
|
|
|
Scheme_Object *MrEdMakeEventspace()
|
|
{
|
|
MrEdContext *c;
|
|
|
|
c = MakeContext(NULL);
|
|
|
|
MrEdInitNewContext(c);
|
|
|
|
return (Scheme_Object *)c;
|
|
}
|
|
|
|
Scheme_Object *MrEdEventspaceThread(Scheme_Object *e)
|
|
{
|
|
return (Scheme_Object *)((MrEdContext *)e)->handler_running;
|
|
}
|
|
|
|
Scheme_Object *MrEdGetFrameList(void)
|
|
{
|
|
MrEdContext *c;
|
|
Scheme_Object *l = scheme_null;
|
|
c = MrEdGetContext();
|
|
|
|
if (c) {
|
|
wxChildNode *node;
|
|
for (node = c->topLevelWindowList->First(); node; node = node->Next()) {
|
|
wxObject *o;
|
|
o = node->Data();
|
|
if (node->IsShown()) {
|
|
#ifdef wx_mac
|
|
/* Mac: some frames really represent dialogs. Any modal frame is
|
|
a dialog, so extract its only child. */
|
|
if (((wxFrame *)o)->IsModal()) {
|
|
wxChildNode *node2;
|
|
wxChildList *cl;
|
|
cl = ((wxFrame *)o)->GetChildren();
|
|
node2 = cl->First();
|
|
if (node2)
|
|
o = node2->Data();
|
|
}
|
|
#endif
|
|
l = scheme_make_pair(objscheme_bundle_wxObject(o), l);
|
|
}
|
|
}
|
|
}
|
|
|
|
return l;
|
|
}
|
|
|
|
void *MrEdForEachFrame(ForEachFrameProc fp, void *data)
|
|
{
|
|
MrEdContextFrames *f;
|
|
MrEdContextFramesRef fr = mred_frames;
|
|
wxChildNode *node;
|
|
|
|
while (fr) {
|
|
f = FRAMES_REF(fr);
|
|
node = f->list->First();
|
|
|
|
while (node) {
|
|
if (node->IsShown()) {
|
|
wxObject *o;
|
|
o = node->Data();
|
|
#ifdef wx_mac
|
|
/* Mac: some frames really represent dialogs. Any modal frame is
|
|
a dialog, so extract its only child. */
|
|
if (((wxFrame *)o)->IsModal()) {
|
|
wxChildNode *node2;
|
|
wxChildList *cl;
|
|
cl = ((wxFrame *)o)->GetChildren();
|
|
node2 = cl->First();
|
|
if (node2)
|
|
o = node2->Data();
|
|
}
|
|
#endif
|
|
data = fp(o, data);
|
|
}
|
|
node = node->Next();
|
|
}
|
|
|
|
fr = f->next;
|
|
}
|
|
|
|
return data;
|
|
}
|
|
|
|
static int check_eventspace_inactive(void *_c)
|
|
{
|
|
MrEdContext *c = (MrEdContext *)_c;
|
|
|
|
if (c->nested_avail)
|
|
return 0;
|
|
|
|
/* Any callbacks prepared for this eventspace? */
|
|
if (check_q_callbacks(0, MrEdSameContext, c, 1)
|
|
|| check_q_callbacks(1, MrEdSameContext, c, 1)
|
|
|| check_q_callbacks(2, MrEdSameContext, c, 1))
|
|
return 0;
|
|
|
|
/* Any running timers for the eventspace? */
|
|
if (c->timers)
|
|
return 0;
|
|
|
|
/* Any top-level windows visible in this eventspace */
|
|
{
|
|
MrEdContextFrames *f = c->finalized->frames;
|
|
wxChildNode *node;
|
|
|
|
node = f->list->First();
|
|
|
|
while (node) {
|
|
if (node->IsShown()) {
|
|
return 0;
|
|
}
|
|
node = node->Next();
|
|
}
|
|
}
|
|
|
|
return 1;
|
|
}
|
|
|
|
void mred_wait_eventspace(void)
|
|
{
|
|
MrEdContext *c;
|
|
c = MrEdGetContext();
|
|
if (c && (c->handler_running == scheme_current_thread)) {
|
|
wxDispatchEventsUntilWaitable(check_eventspace_inactive, c, NULL);
|
|
}
|
|
}
|
|
|
|
int mred_current_thread_is_handler(void *ctx)
|
|
{
|
|
if (!ctx)
|
|
ctx = MrEdGetContext();
|
|
|
|
return (((MrEdContext *)ctx)->handler_running == scheme_current_thread);
|
|
}
|
|
|
|
int mred_in_restricted_context()
|
|
{
|
|
#ifdef NEED_HET_PARAM
|
|
/* see wxHiEventTrampoline for info on mred_het_key: */
|
|
Scheme_Object *v;
|
|
if (!scheme_current_thread)
|
|
return 1;
|
|
|
|
if (mred_het_key)
|
|
v = scheme_extract_one_cc_mark(NULL, mred_het_key);
|
|
else
|
|
v = NULL;
|
|
|
|
if (v && SCHEME_BOX_VAL(v))
|
|
return 1;
|
|
#endif
|
|
return 0;
|
|
}
|
|
|
|
/****************************************************************************/
|
|
/* Events */
|
|
/****************************************************************************/
|
|
|
|
static wxTimer *TimerReady(MrEdContext *c)
|
|
{
|
|
wxTimer *timer;
|
|
|
|
if (c) {
|
|
timer = c->timers;
|
|
} else {
|
|
timer = GlobalFirstTimer();
|
|
}
|
|
|
|
if (timer) {
|
|
double now;
|
|
double goal = timer->expiration;
|
|
|
|
now = scheme_get_inexact_milliseconds();
|
|
|
|
return ((now >= goal)
|
|
? timer
|
|
: (wxTimer *)NULL);
|
|
} else
|
|
return NULL;
|
|
}
|
|
|
|
static void DoTimer(wxTimer *timer)
|
|
{
|
|
int once;
|
|
mz_jmp_buf *save, newbuf;
|
|
|
|
if (timer->interval == -1)
|
|
return;
|
|
|
|
once = timer->one_shot;
|
|
timer->one_shot = -1;
|
|
|
|
save = scheme_current_thread->error_buf;
|
|
scheme_current_thread->error_buf = &newbuf;
|
|
if (!scheme_setjmp(newbuf))
|
|
timer->Notify();
|
|
scheme_clear_escape();
|
|
scheme_current_thread->error_buf = save;
|
|
|
|
if (!once && (timer->one_shot == -1) && (timer->interval != -1)
|
|
&& !((MrEdContext *)timer->context)->killed)
|
|
timer->Start(timer->interval, FALSE);
|
|
}
|
|
|
|
static int do_check_for_nested_event(Scheme_Object *cx)
|
|
{
|
|
MrEdContext *c = (MrEdContext *)cx;
|
|
|
|
if (!c->waiting_for_nested)
|
|
return 1;
|
|
|
|
if (c->alternate) {
|
|
if (c->alternate(c->alt_data))
|
|
return 1;
|
|
|
|
return 0;
|
|
} else
|
|
return 0;
|
|
}
|
|
|
|
static int check_for_nested_event(Scheme_Object *cx)
|
|
{
|
|
return do_check_for_nested_event(((Nested_Wait *)cx)->wait_on);
|
|
}
|
|
|
|
static int MrEdSameContext(MrEdContext *c, MrEdContext *testc)
|
|
{
|
|
return (c == testc);
|
|
}
|
|
|
|
static void GoAhead(MrEdContext *c)
|
|
{
|
|
c->ready_to_go = 0;
|
|
|
|
if (c->q_callback) {
|
|
int hi = (c->q_callback - 1);
|
|
c->q_callback = 0;
|
|
(void)check_q_callbacks(hi, MrEdSameContext, c, 0);
|
|
} else if (c->timer) {
|
|
wxTimer *timer;
|
|
timer = c->timer;
|
|
c->timer = NULL;
|
|
DoTimer(timer);
|
|
} else {
|
|
GC_CAN_IGNORE MrEdEvent e;
|
|
mz_jmp_buf *save, newbuf;
|
|
|
|
memcpy(&e, &c->event, sizeof(MrEdEvent));
|
|
|
|
save = scheme_current_thread->error_buf;
|
|
scheme_current_thread->error_buf = &newbuf;
|
|
if (!scheme_setjmp(newbuf))
|
|
MrEdDispatchEvent(&e);
|
|
scheme_clear_escape();
|
|
scheme_current_thread->error_buf = save;
|
|
}
|
|
}
|
|
|
|
static Scheme_Object *def_event_dispatch_handler(int argc, Scheme_Object *argv[])
|
|
{
|
|
MrEdContext *c;
|
|
|
|
c = (MrEdContext *)argv[0];
|
|
if (!SAME_TYPE(SCHEME_TYPE(argv[0]), mred_eventspace_type)
|
|
|| !c->ready_to_go) {
|
|
scheme_wrong_type("default-event-dispatch-handler",
|
|
"eventspace (with ready event)",
|
|
0, argc, argv);
|
|
return NULL;
|
|
}
|
|
|
|
GoAhead(c);
|
|
|
|
return scheme_void;
|
|
}
|
|
|
|
static void DoTheEvent(MrEdContext *c)
|
|
{
|
|
Scheme_Object *p;
|
|
|
|
c->ready_to_go = 1;
|
|
|
|
p = scheme_get_param(scheme_current_config(), mred_event_dispatch_param);
|
|
if (p != def_dispatch) {
|
|
Scheme_Object *a[1];
|
|
mz_jmp_buf *save, newbuf;
|
|
|
|
a[0] = (Scheme_Object *)c;
|
|
|
|
save = scheme_current_thread->error_buf;
|
|
scheme_current_thread->error_buf = &newbuf;
|
|
if (!scheme_setjmp(newbuf))
|
|
scheme_apply_multi(p, 1, a);
|
|
scheme_clear_escape();
|
|
scheme_current_thread->error_buf = save;
|
|
|
|
#if 0
|
|
if (c->ready_to_go)
|
|
printf("Bad dispatcher\n");
|
|
#endif
|
|
}
|
|
|
|
if (c->ready_to_go)
|
|
GoAhead(c);
|
|
}
|
|
|
|
static void reset_nested_wait(MrEdContext *c)
|
|
{
|
|
c->ready = 0;
|
|
c->waiting_for_nested = 0;
|
|
c->alternate = NULL;
|
|
c->alt_data = NULL;
|
|
}
|
|
|
|
static Scheme_Object *MrEdDoNextEvent(MrEdContext *c, wxDispatch_Check_Fun alt, void *altdata, Scheme_Object *alt_wait)
|
|
{
|
|
wxTimer *timer;
|
|
GC_CAN_IGNORE MrEdEvent evt;
|
|
int restricted = 0;
|
|
|
|
#ifdef NEED_HET_PARAM
|
|
/* see wxHiEventTrampoline for info on mred_het_key: */
|
|
if (mred_in_restricted_context())
|
|
restricted = 1;
|
|
#endif
|
|
|
|
if (alt) {
|
|
if (alt(altdata)) {
|
|
/* Do nothing, since alt fired. */
|
|
return scheme_void;
|
|
}
|
|
}
|
|
if (alt_wait) {
|
|
Scheme_Object *a[2], *r;
|
|
a[0] = scheme_make_integer(0);
|
|
a[1] = alt_wait;
|
|
r = scheme_sync_timeout(2, a);
|
|
|
|
if (r) {
|
|
/* Do nothing, since alt fired. */
|
|
return r;
|
|
}
|
|
}
|
|
|
|
if (c->nested_avail) {
|
|
c->nested_avail = 0;
|
|
DoTheEvent(c);
|
|
} else if (check_q_callbacks(2, MrEdSameContext, c, 1)) {
|
|
c->q_callback = 3;
|
|
DoTheEvent(c);
|
|
} else if ((timer = TimerReady(c))) {
|
|
timer->Dequeue();
|
|
c->timer = timer;
|
|
DoTheEvent(c);
|
|
} else if (check_q_callbacks(1, MrEdSameContext, c, 1)) {
|
|
c->q_callback = 2;
|
|
DoTheEvent(c);
|
|
} else if (!restricted && MrEdGetNextEvent(0, 1, &evt, NULL)) {
|
|
memcpy(&c->event, &evt, sizeof(MrEdEvent));
|
|
DoTheEvent(c);
|
|
#ifdef wx_mac
|
|
/* MrEdGetNextEvent might enqueue */
|
|
} else if (check_q_callbacks(1, MrEdSameContext, c, 1)) {
|
|
c->q_callback = 2;
|
|
DoTheEvent(c);
|
|
#endif
|
|
} else if (!restricted && check_q_callbacks(0, MrEdSameContext, c, 1)) {
|
|
c->q_callback = 1;
|
|
DoTheEvent(c);
|
|
} else if (c != mred_main_context) {
|
|
Scheme_Object *result = NULL;
|
|
|
|
c->ready = 1;
|
|
c->waiting_for_nested = 1;
|
|
|
|
c->alternate = alt;
|
|
c->alt_data = altdata;
|
|
|
|
if (alt_wait) {
|
|
Nested_Wait *nw;
|
|
Scheme_Object *a[2], *v = NULL;
|
|
|
|
nw = (Nested_Wait *)scheme_malloc_tagged(sizeof(Nested_Wait));
|
|
nw->so.type = mred_nested_wait_type;
|
|
nw->wait_on = (Scheme_Object *)c;
|
|
|
|
a[0] = alt_wait;
|
|
a[1] = (Scheme_Object *)nw;
|
|
|
|
/* Running arbitrary Scheme code here. */
|
|
BEGIN_ESCAPEABLE(reset_nested_wait, c);
|
|
v = scheme_sync(2, a);
|
|
END_ESCAPEABLE();
|
|
|
|
if (!SAME_OBJ(v, a[1]))
|
|
result = v;
|
|
} else {
|
|
scheme_block_until((Scheme_Ready_Fun)do_check_for_nested_event, NULL,
|
|
(Scheme_Object *)c, 0.0);
|
|
}
|
|
|
|
c->alternate = NULL;
|
|
c->alt_data = NULL;
|
|
|
|
if (c->waiting_for_nested) {
|
|
/* Alternate condition fired. Clear waiting flag. */
|
|
c->ready = 0;
|
|
c->waiting_for_nested = 0;
|
|
if (!result)
|
|
result = scheme_void;
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
void wxDoNextEvent()
|
|
{
|
|
MrEdContext *c;
|
|
c = MrEdGetContext();
|
|
|
|
if (!c->ready_to_go)
|
|
if (c->handler_running == scheme_current_thread)
|
|
MrEdDoNextEvent(c, NULL, NULL, NULL);
|
|
}
|
|
|
|
int MrEdEventReady(MrEdContext *c)
|
|
{
|
|
int restricted = 0;
|
|
|
|
#ifdef NEED_HET_PARAM
|
|
/* see wxHiEventTrampoline for info on mred_het_key: */
|
|
if (mred_in_restricted_context())
|
|
restricted = 1;
|
|
#endif
|
|
|
|
return (c->nested_avail
|
|
|| TimerReady(c)
|
|
|| (!restricted && MrEdGetNextEvent(1, 1, NULL, NULL))
|
|
|| (!restricted && check_q_callbacks(2, MrEdSameContext, c, 1))
|
|
|| check_q_callbacks(1, MrEdSameContext, c, 1)
|
|
|| check_q_callbacks(0, MrEdSameContext, c, 1));
|
|
}
|
|
|
|
int wxEventReady()
|
|
{
|
|
MrEdContext *c;
|
|
c = MrEdGetContext();
|
|
|
|
return (!c->ready_to_go
|
|
&& (c->handler_running == scheme_current_thread)
|
|
&& MrEdEventReady(c));
|
|
}
|
|
|
|
static void WaitForAnEvent_OrDie(MrEdContext *c)
|
|
{
|
|
c->ready = 1;
|
|
c->waiting_for_nested = 1;
|
|
c->alternate = NULL;
|
|
c->alt_data = NULL;
|
|
|
|
/* Suspend the thread. If another event is found for the eventspace, the
|
|
thread will be resumed. */
|
|
c->suspended = 1;
|
|
while (1) {
|
|
scheme_weak_suspend_thread(c->handler_running); /* suspend self */
|
|
|
|
if (c->waiting_for_nested) {
|
|
/* we were resumed for a break signal, or some such: */
|
|
c->suspended = 0;
|
|
c->ready = 0;
|
|
c->waiting_for_nested = 0;
|
|
|
|
scheme_thread_block(0);
|
|
scheme_current_thread->ran_some = 1;
|
|
|
|
/* Go back to sleep: */
|
|
c->ready = 1;
|
|
c->waiting_for_nested = 1;
|
|
c->suspended = 1;
|
|
} else
|
|
break;
|
|
}
|
|
|
|
/* An event has been found. Do it. */
|
|
c->nested_avail = 0;
|
|
DoTheEvent(c);
|
|
|
|
/* Return to loop and look for more events... */
|
|
}
|
|
|
|
static void on_handler_killed(Scheme_Thread *p)
|
|
{
|
|
MrEdContext *c = (MrEdContext *)p->kill_data;
|
|
|
|
p->on_kill = NULL;
|
|
p->kill_data = NULL;
|
|
|
|
/* The thread is forever not ready: */
|
|
c->handler_running = NULL;
|
|
c->ready = 0;
|
|
c->waiting_for_nested = 0;
|
|
c->nested_avail = 0;
|
|
c->q_callback = 0;
|
|
c->timer = NULL;
|
|
c->alternate = NULL;
|
|
c->alt_data = NULL;
|
|
c->ready_to_go = 0;
|
|
}
|
|
|
|
static Scheme_Object *handle_events(void *cx, int, Scheme_Object **)
|
|
{
|
|
MrEdContext *c = (MrEdContext *)cx;
|
|
Scheme_Thread *this_thread;
|
|
mz_jmp_buf newbuf;
|
|
|
|
#if SGC_STD_DEBUGGING
|
|
fprintf(stderr, "new thread\n");
|
|
#endif
|
|
|
|
this_thread = scheme_current_thread;
|
|
if (!this_thread->name) {
|
|
Scheme_Object *tn;
|
|
tn = scheme_intern_symbol("handler");
|
|
this_thread->name = tn;
|
|
}
|
|
c->handler_running = this_thread;
|
|
this_thread->on_kill = CAST_TOK on_handler_killed;
|
|
this_thread->kill_data = c;
|
|
c->suspended = 0;
|
|
c->ready = 0;
|
|
|
|
scheme_current_thread->error_buf = &newbuf;
|
|
if (!scheme_setjmp(newbuf)) {
|
|
if (!TheMrEdApp->initialized)
|
|
TheMrEdApp->RealInit();
|
|
else {
|
|
DoTheEvent(c);
|
|
|
|
while(1) {
|
|
while (MrEdEventReady(c)) {
|
|
MrEdDoNextEvent(c, NULL, NULL, NULL);
|
|
}
|
|
|
|
WaitForAnEvent_OrDie(c);
|
|
}
|
|
}
|
|
}
|
|
|
|
/* We should never get here. */
|
|
#if 0
|
|
c->ready = 1;
|
|
c->handler_running = NULL;
|
|
this_thread->on_kill = NULL;
|
|
this_thread->kill_data = NULL;
|
|
#endif
|
|
|
|
return scheme_void;
|
|
}
|
|
|
|
static int MrEdContextReady(MrEdContext *, MrEdContext *c)
|
|
{
|
|
return ((MrEdContext *)c)->ready;
|
|
}
|
|
|
|
static void event_found(MrEdContext *c)
|
|
{
|
|
if (c->killed)
|
|
return;
|
|
|
|
c->ready = 0;
|
|
|
|
if (c->waiting_for_nested) {
|
|
c->waiting_for_nested = 0;
|
|
c->nested_avail = 1;
|
|
if (c->suspended) {
|
|
c->suspended = 0;
|
|
scheme_weak_resume_thread(c->handler_running);
|
|
}
|
|
} else {
|
|
Scheme_Object *cp, *cust;
|
|
|
|
cp = scheme_make_closed_prim(CAST_SCP handle_events, c);
|
|
cust = scheme_get_thread_param(c->main_config, c->main_cells, MZCONFIG_CUSTODIAN);
|
|
scheme_thread_w_details(cp, c->main_config, c->main_cells, c->main_break_cell, (Scheme_Custodian *)cust, 0);
|
|
}
|
|
}
|
|
|
|
static int try_q_callback(Scheme_Object *do_it, int hi)
|
|
{
|
|
MrEdContext *c;
|
|
|
|
if ((c = check_q_callbacks(hi, MrEdContextReady, NULL, 1))) {
|
|
if (!do_it)
|
|
return 1;
|
|
|
|
if (SCHEME_FALSEP(do_it))
|
|
scheme_current_thread->ran_some = 1;
|
|
|
|
if (c == mred_main_context)
|
|
check_q_callbacks(hi, MrEdSameContext, c, 0);
|
|
else {
|
|
c->q_callback = 1 + hi;
|
|
event_found(c);
|
|
}
|
|
|
|
return 1;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int try_dispatch(Scheme_Object *do_it)
|
|
{
|
|
MrEdContext *c;
|
|
GC_CAN_IGNORE MrEdEvent e;
|
|
wxTimer *timer;
|
|
int got_one;
|
|
|
|
if (try_q_callback(do_it, 2))
|
|
return 1;
|
|
|
|
timer = TimerReady(NULL);
|
|
|
|
if (timer) {
|
|
if (!do_it)
|
|
return 1;
|
|
if (SCHEME_FALSEP(do_it))
|
|
scheme_current_thread->ran_some = 1;
|
|
|
|
c = (MrEdContext *)timer->context;
|
|
|
|
timer->Dequeue();
|
|
|
|
if (c == mred_main_context)
|
|
timer->Notify();
|
|
else {
|
|
c->timer = timer;
|
|
event_found(c);
|
|
}
|
|
|
|
return 1;
|
|
}
|
|
|
|
if (try_q_callback(do_it, 1))
|
|
return 1;
|
|
|
|
ChainContextsList();
|
|
|
|
got_one = MrEdGetNextEvent(!do_it, 0, &e, &c);
|
|
|
|
UnchainContextsList();
|
|
|
|
#ifdef wx_mac
|
|
/* MrEdGetNextEvent might enqueue */
|
|
if (try_q_callback(do_it, 1))
|
|
return 1;
|
|
#endif
|
|
|
|
if (got_one) {
|
|
if (!do_it)
|
|
return 1;
|
|
|
|
if (SCHEME_FALSEP(do_it))
|
|
scheme_current_thread->ran_some = 1;
|
|
|
|
if (c) {
|
|
memcpy(&c->event, &e, sizeof(MrEdEvent));
|
|
event_found(c);
|
|
} else {
|
|
/* Event with unknown context: */
|
|
MrEdDispatchEvent(&e);
|
|
}
|
|
|
|
return 1;
|
|
}
|
|
|
|
if (try_q_callback(do_it, 0))
|
|
return 1;
|
|
|
|
return 0;
|
|
}
|
|
|
|
static void wakeup_on_dispatch(Scheme_Object *, void *fds)
|
|
{
|
|
#ifdef wx_x
|
|
Display *d = XtDisplay(mred_main_context->finalized->toplevel);
|
|
int fd;
|
|
|
|
fd = ConnectionNumber(d);
|
|
|
|
MZ_FD_SET(fd, (fd_set *)fds);
|
|
#endif
|
|
}
|
|
|
|
static int check_initialized(Scheme_Object *)
|
|
{
|
|
return TheMrEdApp->initialized;
|
|
}
|
|
|
|
# define KEEP_GOING wxTheApp->keep_going
|
|
|
|
#if WINDOW_STDIO
|
|
static Scheme_Custodian *main_custodian;
|
|
#endif
|
|
|
|
void wxDoEvents()
|
|
{
|
|
/* When we get here, we are in the main dispatcher thread */
|
|
if (!TheMrEdApp->initialized) {
|
|
MrEdContext *c;
|
|
#if WINDOW_STDIO
|
|
Scheme_Custodian *m, *oldm = NULL;
|
|
Scheme_Config *config = NULL;
|
|
if (!wx_in_terminal) {
|
|
config = scheme_current_config();
|
|
oldm = (Scheme_Custodian *)scheme_get_param(config, MZCONFIG_CUSTODIAN);
|
|
m = scheme_make_custodian(oldm);
|
|
scheme_set_param(config, MZCONFIG_CUSTODIAN, (Scheme_Object *)m);
|
|
wxREGGLOB(main_custodian);
|
|
main_custodian = m;
|
|
}
|
|
#endif
|
|
|
|
/* Create the user's main thread: */
|
|
|
|
c = (MrEdContext *)MrEdMakeEventspace();
|
|
|
|
wxREGGLOB(user_main_context);
|
|
user_main_context = c;
|
|
|
|
{
|
|
Scheme_Object *cp;
|
|
cp = scheme_make_closed_prim(CAST_SCP handle_events, c);
|
|
wxREGGLOB(user_main_thread);
|
|
user_main_thread = (Scheme_Thread *)scheme_thread_w_details(cp,
|
|
c->main_config,
|
|
c->main_cells,
|
|
c->main_break_cell,
|
|
NULL, 0);
|
|
cp = scheme_intern_symbol("mred");
|
|
user_main_thread->name = cp;
|
|
}
|
|
|
|
#if WINDOW_STDIO
|
|
if (!wx_in_terminal)
|
|
scheme_set_param(config, MZCONFIG_CUSTODIAN, (Scheme_Object *)oldm);
|
|
#endif
|
|
|
|
/* Block until the user's main thread is initialized: */
|
|
scheme_block_until(CAST_BLKCHK check_initialized, NULL, NULL, 0.0);
|
|
}
|
|
|
|
if (!try_dispatch(scheme_true)) {
|
|
do {
|
|
scheme_current_thread->block_descriptor = -1;
|
|
scheme_current_thread->blocker = NULL;
|
|
scheme_current_thread->block_check = CAST_BLKCHK try_dispatch;
|
|
scheme_current_thread->block_needs_wakeup = CAST_WU wakeup_on_dispatch;
|
|
|
|
scheme_thread_block(0);
|
|
|
|
scheme_current_thread->block_descriptor = 0;
|
|
/* Sets ran_some if it succeeds: */
|
|
if (try_dispatch(scheme_false))
|
|
break;
|
|
} while (KEEP_GOING);
|
|
}
|
|
}
|
|
|
|
Scheme_Object *wxDispatchEventsUntilWaitable(wxDispatch_Check_Fun f, void *data, Scheme_Object *w)
|
|
{
|
|
MrEdContext *c;
|
|
Scheme_Object *result = scheme_void;
|
|
|
|
c = MrEdGetContext();
|
|
#ifdef wx_mac
|
|
wxMouseEventHandled();
|
|
#endif
|
|
|
|
if (c->ready_to_go
|
|
|| (c->handler_running != scheme_current_thread)) {
|
|
/* This is not the handler thread or an event still hasn't been
|
|
dispatched. Wait. */
|
|
if (w) {
|
|
Scheme_Object *a[1];
|
|
a[0] = w;
|
|
result = scheme_sync(1, a);
|
|
} else {
|
|
scheme_block_until((Scheme_Ready_Fun)f, NULL, (Scheme_Object *)data, 0.0);
|
|
}
|
|
} else {
|
|
/* This is the main thread. Handle events */
|
|
do {
|
|
result = MrEdDoNextEvent(c, f, data, w);
|
|
if (result)
|
|
break;
|
|
} while (1);
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
void wxDispatchEventsUntil(wxDispatch_Check_Fun f, void *data)
|
|
{
|
|
wxDispatchEventsUntilWaitable(f, data, NULL);
|
|
}
|
|
|
|
void wxBlockUntil(wxDispatch_Check_Fun f, void *data)
|
|
{
|
|
scheme_block_until((Scheme_Ready_Fun)f, NULL, (Scheme_Object *)data, 0.0);
|
|
}
|
|
|
|
void wxBlockUntilTimeout(wxDispatch_Check_Fun f, void *data, float timeout)
|
|
{
|
|
scheme_block_until((Scheme_Ready_Fun)f, NULL, (Scheme_Object *)data, timeout);
|
|
}
|
|
|
|
static SLEEP_PROC_PTR mzsleep;
|
|
|
|
static void MrEdSleep(float secs, void *fds)
|
|
{
|
|
double now;
|
|
|
|
#ifdef NEVER_EVER_SLEEP
|
|
return;
|
|
#endif
|
|
|
|
if (!(KEEP_GOING))
|
|
return;
|
|
|
|
now = scheme_get_inexact_milliseconds();
|
|
{
|
|
wxTimer *timer;
|
|
|
|
timer = GlobalFirstTimer();
|
|
|
|
if (timer) {
|
|
double done = timer->expiration;
|
|
double diff = done - now;
|
|
|
|
diff /= 1000;
|
|
if (diff <= 0)
|
|
secs = (float)0.00001;
|
|
else if (!secs || (secs > diff))
|
|
secs = (float)diff;
|
|
}
|
|
}
|
|
|
|
#ifdef wx_msw
|
|
MrEdMSWSleep(secs, fds);
|
|
#else
|
|
# ifdef wx_mac
|
|
MrEdMacSleep(secs, fds, mzsleep);
|
|
# else
|
|
mzsleep(secs, fds);
|
|
# endif
|
|
#endif
|
|
}
|
|
|
|
#ifdef mred_BREAK_HANDLER
|
|
static void user_break_hit(int ignore)
|
|
{
|
|
scheme_break_thread(user_main_thread);
|
|
scheme_signal_received();
|
|
|
|
# ifdef SIGSET_NEEDS_REINSTALL
|
|
MZ_SIGSET(SIGINT, user_break_hit);
|
|
# endif
|
|
# ifdef MZ_PRECISE_GC
|
|
# ifndef GC_STACK_CALLEE_RESTORE
|
|
/* Restore variable stack. */
|
|
GC_variable_stack = (void **)__gc_var_stack__[0];
|
|
# endif
|
|
# endif
|
|
}
|
|
#endif
|
|
|
|
/****************************************************************************/
|
|
/* wxTimer */
|
|
/****************************************************************************/
|
|
|
|
wxTimer::wxTimer(void *ctx)
|
|
#ifdef wx_xt
|
|
: wxObject(WXGC_NO_CLEANUP)
|
|
#endif
|
|
{
|
|
__type = wxTYPE_TIMER;
|
|
|
|
next = prev = NULL;
|
|
|
|
if (!ctx)
|
|
ctx = (void *)MrEdGetContext();
|
|
|
|
context = ctx;
|
|
}
|
|
|
|
wxTimer::~wxTimer(void)
|
|
{
|
|
}
|
|
|
|
void wxTimer::SetContext(void *ctx)
|
|
{
|
|
context = ctx;
|
|
}
|
|
|
|
Bool wxTimer::Start(int millisec, Bool _one_shot)
|
|
{
|
|
double now;
|
|
|
|
if (prev || next || (((MrEdContext *)context)->timers == this))
|
|
return FALSE;
|
|
|
|
if (((MrEdContext *)context)->killed)
|
|
scheme_signal_error("start in timer%%: the current eventspace has been shutdown");
|
|
|
|
interval = millisec;
|
|
if (interval <= 0)
|
|
interval = 1;
|
|
one_shot = !!_one_shot;
|
|
|
|
now = scheme_get_inexact_milliseconds();
|
|
expiration = now + interval;
|
|
|
|
if (((MrEdContext *)context)->timers) {
|
|
wxTimer *t = ((MrEdContext *)context)->timers;
|
|
|
|
while (1) {
|
|
int later;
|
|
|
|
later = (expiration >= t->expiration);
|
|
|
|
if (!later) {
|
|
prev = t->prev;
|
|
t->prev = this;
|
|
next = t;
|
|
if (prev)
|
|
prev->next = this;
|
|
else
|
|
((MrEdContext *)context)->timers = this;
|
|
return TRUE;
|
|
}
|
|
|
|
if (!t->next) {
|
|
t->next = this;
|
|
prev = t;
|
|
|
|
return TRUE;
|
|
}
|
|
t = t->next;
|
|
}
|
|
} else {
|
|
((MrEdContext *)context)->timers = this;
|
|
scheme_hash_set(timer_contexts, (Scheme_Object *)context, scheme_true);
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
void wxTimer::Dequeue(void)
|
|
{
|
|
if (!prev) {
|
|
if (((MrEdContext *)context)->timers == this) {
|
|
((MrEdContext *)context)->timers = next;
|
|
if (!next)
|
|
scheme_hash_set(timer_contexts, (Scheme_Object *)context, NULL);
|
|
}
|
|
}
|
|
|
|
if (prev)
|
|
prev->next = next;
|
|
if (next)
|
|
next->prev = prev;
|
|
|
|
next = prev = NULL;
|
|
}
|
|
|
|
void wxTimer::Stop(void)
|
|
{
|
|
Dequeue();
|
|
|
|
interval = -1;
|
|
}
|
|
|
|
/****************************************************************************/
|
|
/* Callbacks */
|
|
/****************************************************************************/
|
|
|
|
typedef struct Q_Callback {
|
|
/* MZ_PRECISE_GC: allocation relies on this struct as the same as
|
|
array of pointers: */
|
|
MrEdContext *context;
|
|
Scheme_Object *callback;
|
|
struct Q_Callback *prev;
|
|
struct Q_Callback *next;
|
|
} Q_Callback;
|
|
|
|
typedef struct {
|
|
/* Collection relies on this struct as the same as array of
|
|
pointers: */
|
|
Q_Callback *first;
|
|
Q_Callback *last;
|
|
} Q_Callback_Set;
|
|
|
|
static Q_Callback_Set q_callbacks[3];
|
|
|
|
static void insert_q_callback(Q_Callback_Set *cs, Q_Callback *cb)
|
|
{
|
|
/* This can happen under Windows, for example,
|
|
due to an on-paint queue attempt: */
|
|
if (cb->context->killed)
|
|
return;
|
|
|
|
cb->next = NULL;
|
|
cb->prev = cs->last;
|
|
cs->last = cb;
|
|
if (cb->prev)
|
|
cb->prev->next = cb;
|
|
else
|
|
cs->first = cb;
|
|
}
|
|
|
|
static void remove_q_callback(Q_Callback_Set *cs, Q_Callback *cb)
|
|
{
|
|
if (cb->prev)
|
|
cb->prev->next = cb->next;
|
|
else
|
|
cs->first = cb->next;
|
|
if (cb->next)
|
|
cb->next->prev = cb->prev;
|
|
else
|
|
cs->last = cb->prev;
|
|
|
|
cb->next = NULL;
|
|
cb->prev = NULL;
|
|
}
|
|
|
|
static void call_one_callback(Q_Callback * volatile cb)
|
|
{
|
|
mz_jmp_buf *save, newbuf;
|
|
|
|
save = scheme_current_thread->error_buf;
|
|
scheme_current_thread->error_buf = &newbuf;
|
|
if (!scheme_setjmp(newbuf))
|
|
scheme_apply_multi(cb->callback, 0, NULL);
|
|
scheme_clear_escape();
|
|
scheme_current_thread->error_buf = save;
|
|
}
|
|
|
|
static MrEdContext *check_q_callbacks(int hi, int (*test)(MrEdContext *, MrEdContext *),
|
|
MrEdContext *tdata, int check_only)
|
|
{
|
|
Q_Callback_Set *cs = q_callbacks + hi;
|
|
Q_Callback *cb;
|
|
|
|
cb = cs->first;
|
|
while (cb) {
|
|
if (test(tdata, cb->context)) {
|
|
if (check_only)
|
|
return cb->context;
|
|
|
|
remove_q_callback(cs, cb);
|
|
|
|
call_one_callback(cb);
|
|
|
|
return cb->context;
|
|
}
|
|
cb = cb->next;
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
static void remove_q_callbacks(MrEdContext *c)
|
|
{
|
|
Q_Callback_Set *cs;
|
|
Q_Callback *cb, *next;
|
|
int i;
|
|
|
|
for (i = 0; i < 3; i++) {
|
|
cs = q_callbacks + i;
|
|
for (cb = cs->first; cb; cb = next) {
|
|
next = cb->next;
|
|
if (cb->context == c)
|
|
remove_q_callback(cs, cb);
|
|
}
|
|
}
|
|
}
|
|
|
|
Scheme_Object *MrEd_mid_queue_key;
|
|
|
|
void MrEd_add_q_callback(char *who, int argc, Scheme_Object **argv)
|
|
{
|
|
MrEdContext *c;
|
|
Q_Callback_Set *cs;
|
|
Q_Callback *cb;
|
|
int hi;
|
|
|
|
scheme_check_proc_arity(who, 0, 0, argc, argv);
|
|
c = (MrEdContext *)wxsCheckEventspace("queue-callback");
|
|
|
|
if (argc > 1) {
|
|
if (argv[1] == MrEd_mid_queue_key)
|
|
hi = 1;
|
|
else
|
|
hi = (SCHEME_TRUEP(argv[1]) ? 2 : 0);
|
|
} else
|
|
hi = 2;
|
|
|
|
cs = q_callbacks + hi;
|
|
|
|
cb = (Q_Callback*)scheme_malloc(sizeof(Q_Callback));
|
|
cb->context = c;
|
|
cb->callback = argv[0];
|
|
|
|
insert_q_callback(cs, cb);
|
|
}
|
|
|
|
#if defined(wx_msw) || defined(wx_mac)
|
|
|
|
static void MrEdQueueWindowCallback(wxWindow *wx_window, Scheme_Closed_Prim *scp, void *data)
|
|
{
|
|
MrEdContext *c;
|
|
Q_Callback *cb;
|
|
Scheme_Object *p;
|
|
|
|
if (!scheme_current_thread) {
|
|
/* Scheme hasn't started yet, so call directly.
|
|
We might get here for an update to the stdio
|
|
window, for example. */
|
|
scp(data, 0, NULL);
|
|
return;
|
|
}
|
|
|
|
#ifdef wx_mac
|
|
c = MrEdGetContext(wx_window->GetRootFrame());
|
|
#else
|
|
c = MrEdGetContext();
|
|
#endif
|
|
|
|
/* Search for existing queued on-paint: */
|
|
cb = q_callbacks[1].last;
|
|
while (cb) {
|
|
if (cb->context == c) {
|
|
if (SCHEME_CLSD_PRIMP(cb->callback)) {
|
|
Scheme_Closed_Primitive_Proc *prim;
|
|
prim = (Scheme_Closed_Primitive_Proc *)cb->callback;
|
|
if ((prim->data == wx_window)
|
|
&& (prim->prim_val == scp)) {
|
|
/* on-paint already queued */
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
cb = cb->prev;
|
|
}
|
|
|
|
p = scheme_make_closed_prim(scp, data);
|
|
|
|
cb = (Q_Callback*)scheme_malloc(sizeof(Q_Callback));
|
|
cb->context = c;
|
|
cb->callback = p;
|
|
|
|
insert_q_callback(q_callbacks + 1, cb);
|
|
|
|
#ifdef wx_mac
|
|
WakeUpMrEd();
|
|
#endif
|
|
}
|
|
|
|
static Scheme_Object *call_on_paint(void *d, int, Scheme_Object **argv)
|
|
{
|
|
wxWindow *w = (wxWindow *)d;
|
|
#ifdef wx_msw
|
|
w->OnPaint();
|
|
#else
|
|
((wxCanvas *)w)->DoPaint();
|
|
#endif
|
|
return scheme_void;
|
|
}
|
|
|
|
void MrEdQueuePaint(wxWindow *wx_window)
|
|
{
|
|
MrEdQueueWindowCallback(wx_window, CAST_SCP call_on_paint, wx_window);
|
|
}
|
|
|
|
static Scheme_Object *call_close(void *d, int, Scheme_Object **argv)
|
|
{
|
|
wxFrame *w = (wxFrame *)d;
|
|
|
|
if (w->OnClose())
|
|
w->Show(FALSE);
|
|
|
|
return scheme_void;
|
|
}
|
|
|
|
void MrEdQueueClose(wxWindow *wx_window)
|
|
{
|
|
MrEdQueueWindowCallback(wx_window, CAST_SCP call_close, wx_window);
|
|
}
|
|
|
|
static Scheme_Object *call_zoom(void *d, int, Scheme_Object **argv)
|
|
{
|
|
wxFrame *w = (wxFrame *)d;
|
|
|
|
w->Maximize(2);
|
|
|
|
return scheme_void;
|
|
}
|
|
|
|
void MrEdQueueZoom(wxWindow *wx_window)
|
|
{
|
|
MrEdQueueWindowCallback(wx_window, CAST_SCP call_zoom, wx_window);
|
|
}
|
|
|
|
static Scheme_Object *call_toolbar(void *d, int, Scheme_Object **argv)
|
|
{
|
|
wxFrame *w = (wxFrame *)d;
|
|
|
|
w->OnToolbarButton();
|
|
|
|
return scheme_void;
|
|
}
|
|
|
|
void MrEdQueueToolbar(wxWindow *wx_window)
|
|
{
|
|
MrEdQueueWindowCallback(wx_window, CAST_SCP call_toolbar, wx_window);
|
|
}
|
|
|
|
static Scheme_Object *call_on_size(void *d, int, Scheme_Object **argv)
|
|
{
|
|
wxWindow *w = (wxWindow *)d;
|
|
w->OnSize(-1, -1);
|
|
return scheme_void;
|
|
}
|
|
|
|
void MrEdQueueOnSize(wxWindow *wx_window)
|
|
{
|
|
MrEdQueueWindowCallback(wx_window, CAST_SCP call_on_size, wx_window);
|
|
}
|
|
|
|
# ifdef wx_mac
|
|
static Scheme_Object *call_unfocus(void *d, int, Scheme_Object **argv)
|
|
{
|
|
wxFrame *w = (wxFrame *)d;
|
|
w->Unfocus();
|
|
return scheme_void;
|
|
}
|
|
|
|
void MrEdQueueUnfocus(wxWindow *wx_window)
|
|
{
|
|
MrEdQueueWindowCallback(wx_window, CAST_SCP call_unfocus, wx_window);
|
|
}
|
|
|
|
static Scheme_Object *call_drop(void *d, int, Scheme_Object **argv)
|
|
{
|
|
wxWindow *w = (wxWindow *)SCHEME_CAR((Scheme_Object *)d);
|
|
char *s = (char *)SCHEME_CDR((Scheme_Object *)d);
|
|
w->OnDropFile(s);
|
|
return scheme_void;
|
|
}
|
|
|
|
void MrEdQueueDrop(wxWindow *wx_window, char *s)
|
|
{
|
|
MrEdQueueWindowCallback(wx_window, CAST_SCP call_drop,
|
|
scheme_make_pair((Scheme_Object *)wx_window, (Scheme_Object *)s));
|
|
}
|
|
# endif
|
|
|
|
#endif
|
|
|
|
static Scheme_Object *call_being_replaced(void *d, int, Scheme_Object **argv)
|
|
{
|
|
wxClipboardClient *clipOwner = (wxClipboardClient *)d;
|
|
clipOwner->BeingReplaced();
|
|
return scheme_void;
|
|
}
|
|
|
|
void MrEdQueueBeingReplaced(wxClipboardClient *clipOwner)
|
|
{
|
|
Scheme_Object *p;
|
|
MrEdContext *c = (MrEdContext *)clipOwner->context;
|
|
Q_Callback *cb;
|
|
|
|
if (c) {
|
|
clipOwner->context = NULL;
|
|
|
|
p = scheme_make_closed_prim(CAST_SCP call_being_replaced, clipOwner);
|
|
|
|
cb = (Q_Callback*)scheme_malloc(sizeof(Q_Callback));
|
|
cb->context = c;
|
|
cb->callback = p;
|
|
|
|
insert_q_callback(q_callbacks + 1, cb);
|
|
}
|
|
}
|
|
|
|
void MrEdQueueInEventspace(void *context, Scheme_Object *thunk)
|
|
{
|
|
Q_Callback *cb;
|
|
|
|
cb = (Q_Callback*)scheme_malloc(sizeof(Q_Callback));
|
|
cb->context = (MrEdContext *)context;
|
|
cb->callback = thunk;
|
|
|
|
insert_q_callback(q_callbacks + 1, cb);
|
|
}
|
|
|
|
/****************************************************************************/
|
|
/* Redirected Standard I/O */
|
|
/****************************************************************************/
|
|
|
|
#if REDIRECT_STDIO || WINDOW_STDIO || WCONSOLE_STDIO
|
|
static void MrEdSchemeMessages(char *, ...);
|
|
static Scheme_Object *stdin_pipe;
|
|
#endif
|
|
|
|
#if WINDOW_STDIO
|
|
|
|
static int have_stdio = 0;
|
|
static int stdio_kills_prog = 0;
|
|
static Bool RecordInput(void *media, wxEvent *event, void *data);
|
|
static Bool SendBreak(void *media, wxEvent *event, void *data);
|
|
static void break_console_reading_threads();
|
|
static char utf8_leftover[8];
|
|
static int utf8_leftover_count;
|
|
|
|
class IOMediaEdit : public wxMediaEdit
|
|
{
|
|
public:
|
|
Bool CanInsert(long start, long);
|
|
Bool CanDelete(long start, long);
|
|
};
|
|
|
|
class IOFrame : public wxFrame
|
|
{
|
|
public:
|
|
wxMediaCanvas *display;
|
|
wxMediaEdit *media;
|
|
wxMenu *fileMenu;
|
|
Bool hidden, beginEditSeq;
|
|
int endpos;
|
|
|
|
IOFrame();
|
|
void OnSize(int x, int y);
|
|
Bool OnClose(void);
|
|
void OnMenuCommand(long id);
|
|
Bool PreOnChar(wxWindow *, wxKeyEvent *e);
|
|
Bool PreOnEvent(wxWindow *, wxMouseEvent *e);
|
|
void CloseIsQuit(void);
|
|
};
|
|
|
|
IOFrame::IOFrame()
|
|
: wxFrame(NULL, "Standard Output", -1, -1, 600, 400, 0, "stdout")
|
|
{
|
|
wxKeymap *km;
|
|
wxStyle *style;
|
|
wxStyleList *sl;
|
|
wxStyleDelta *sd;
|
|
wxMenuBar *mb;
|
|
wxMenu *m;
|
|
|
|
display = new WXGC_PTRS wxMediaCanvas(this);
|
|
|
|
media = new WXGC_PTRS IOMediaEdit();
|
|
display->SetMedia(media);
|
|
endpos = 0;
|
|
hidden = FALSE;
|
|
|
|
/* Map copy keys: */
|
|
km = media->GetKeymap();
|
|
media->AddBufferFunctions(km);
|
|
media->AddEditorFunctions(km);
|
|
km->AddFunction("send-break", SendBreak, NULL);
|
|
# ifdef wx_msw
|
|
km->MapFunction("c:c", "copy-clipboard");
|
|
km->MapFunction("c:x", "copy-clipboard");
|
|
km->MapFunction("c:v", "paste-clipboard");
|
|
# else
|
|
km->MapFunction("d:c", "copy-clipboard");
|
|
km->MapFunction("d:x", "copy-clipboard");
|
|
km->MapFunction("d:v", "paste-clipboard");
|
|
km->MapFunction("d:.", "send-break");
|
|
# endif
|
|
km->MapFunction("return", "record-input");
|
|
km->AddFunction("record-input", RecordInput, NULL);
|
|
|
|
/* Fixed-width font: */
|
|
sl = media->GetStyleList();
|
|
style = sl->FindNamedStyle("Standard");
|
|
sd = new WXGC_PTRS wxStyleDelta(wxCHANGE_FAMILY, wxMODERN);
|
|
style->SetDelta(sd);
|
|
|
|
#ifdef wx_mac
|
|
OnSize(600, 400);
|
|
#endif
|
|
|
|
#ifdef wx_mac
|
|
# define CLOSE_MENU_ITEM "Close\tCmd+W"
|
|
#else
|
|
# define CLOSE_MENU_ITEM "Close"
|
|
#endif
|
|
|
|
mb = new WXGC_PTRS wxMenuBar();
|
|
SetMenuBar(mb);
|
|
fileMenu = new WXGC_PTRS wxMenu();
|
|
fileMenu->Append(77, CLOSE_MENU_ITEM);
|
|
m = new WXGC_PTRS wxMenu();
|
|
m->Append(79, "&Copy\tCmd+C");
|
|
m->Append(81, "&Paste\tCmd+V");
|
|
m->AppendSeparator();
|
|
m->Append(83, "&Break\tCmd+.");
|
|
mb->Append(fileMenu, "File");
|
|
mb->Append(m, "Edit");
|
|
|
|
have_stdio = 1;
|
|
Show(TRUE);
|
|
|
|
beginEditSeq = 0;
|
|
}
|
|
|
|
void IOFrame::OnSize(int x, int y)
|
|
{
|
|
GetClientSize(&x, &y);
|
|
if (display)
|
|
display->SetSize(0, 0, x, y);
|
|
if (media && (x > 30))
|
|
media->SetMaxWidth((float)(x - 30));
|
|
}
|
|
|
|
Bool IOFrame::OnClose(void)
|
|
{
|
|
hidden = TRUE;
|
|
if (stdio_kills_prog) {
|
|
if (scheme_exit)
|
|
scheme_exit(exit_val);
|
|
#ifdef wx_msw
|
|
mred_clean_up_gdi_objects();
|
|
#endif
|
|
scheme_immediate_exit(exit_val);
|
|
} else {
|
|
break_console_reading_threads();
|
|
have_stdio = 0;
|
|
}
|
|
return TRUE;
|
|
}
|
|
|
|
void IOFrame::OnMenuCommand(long id)
|
|
{
|
|
if (id == 79)
|
|
media->Copy();
|
|
else if (id == 81)
|
|
media->Paste();
|
|
else if (id == 83)
|
|
scheme_break_thread(user_main_thread);
|
|
else if (id == 77)
|
|
if (OnClose())
|
|
Show(FALSE);
|
|
}
|
|
|
|
Bool IOFrame::PreOnChar(wxWindow *, wxKeyEvent *e)
|
|
{
|
|
PreOnEvent(NULL, NULL);
|
|
|
|
#if defined(wx_mac) && WINDOW_STDIO
|
|
if (e->metaDown && e->KeyCode() == (stdio_kills_prog ? 'q' : 'w')) {
|
|
OnMenuCommand(77);
|
|
return TRUE;
|
|
}
|
|
#endif
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
Bool IOFrame::PreOnEvent(wxWindow *, wxMouseEvent *e)
|
|
{
|
|
if (beginEditSeq) {
|
|
beginEditSeq = 0;
|
|
media->EndEditSequence();
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
void IOFrame::CloseIsQuit(void)
|
|
{
|
|
#ifdef wx_mac
|
|
# define QUIT_MENU_ITEM "Quit\tCmd+Q"
|
|
#else
|
|
# define QUIT_MENU_ITEM "E&xit"
|
|
#endif
|
|
fileMenu->Delete(77);
|
|
fileMenu->Append(77, QUIT_MENU_ITEM);
|
|
|
|
media->Insert("\n[Exited]", media->LastPosition());
|
|
if (beginEditSeq) {
|
|
beginEditSeq = 0;
|
|
media->EndEditSequence();
|
|
}
|
|
media->Lock(1);
|
|
}
|
|
|
|
static IOFrame *ioFrame = NULL;
|
|
|
|
Bool IOMediaEdit::CanInsert(long start, long)
|
|
{
|
|
return (start >= ioFrame->endpos);
|
|
}
|
|
|
|
Bool IOMediaEdit::CanDelete(long start, long)
|
|
{
|
|
return (start >= ioFrame->endpos);
|
|
}
|
|
|
|
static Bool RecordInput(void *m, wxEvent *event, void *data)
|
|
{
|
|
char *s;
|
|
long len, start;
|
|
wxMediaEdit *media = ioFrame->media;
|
|
|
|
media->Insert("\n");
|
|
start = media->GetStartPosition();
|
|
len = start - ioFrame->endpos;
|
|
s = media->GetTextUTF8(ioFrame->endpos, start);
|
|
ioFrame->endpos = start;
|
|
|
|
scheme_write_byte_string(s, len, stdin_pipe);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
static Bool SendBreak(void *m, wxEvent *event, void *data)
|
|
{
|
|
scheme_break_thread(user_main_thread);
|
|
return TRUE;
|
|
}
|
|
|
|
#else /* !WINDOW_STDIO */
|
|
|
|
#if WCONSOLE_STDIO
|
|
|
|
static HANDLE console_out;
|
|
|
|
#else /* !WCONSOLE_STDIO */
|
|
|
|
#if REDIRECT_STDIO
|
|
static FILE *mrerr = NULL;
|
|
#else
|
|
#define mrerr stderr
|
|
#endif
|
|
|
|
#endif /* WCONSOLE_STDIO */
|
|
|
|
#endif /* WINDOW_STDIO */
|
|
|
|
#if REDIRECT_STDIO || WINDOW_STDIO || WCONSOLE_STDIO
|
|
static void MrEdSchemeMessages(char *msg, ...)
|
|
{
|
|
GC_CAN_IGNORE va_list args;
|
|
|
|
scheme_start_atomic();
|
|
|
|
#if WINDOW_STDIO
|
|
if (!wx_in_terminal) {
|
|
static int opening = 0;
|
|
if (opening)
|
|
return;
|
|
opening = 1;
|
|
if (!ioFrame) {
|
|
wxREGGLOB(ioFrame);
|
|
if (mred_only_context)
|
|
ioFrame = new WXGC_PTRS IOFrame;
|
|
else {
|
|
/* Set eventspace ... */
|
|
mred_only_context = mred_main_context;
|
|
only_context_just_once = 1;
|
|
ioFrame = new WXGC_PTRS IOFrame;
|
|
mred_only_context = NULL;
|
|
}
|
|
}
|
|
opening = 0;
|
|
if (ioFrame->hidden) {
|
|
ioFrame->hidden = FALSE;
|
|
have_stdio = 1;
|
|
ioFrame->Show(TRUE);
|
|
}
|
|
}
|
|
#endif
|
|
#if WCONSOLE_STDIO
|
|
if (!console_out) {
|
|
AllocConsole();
|
|
console_out = GetStdHandle(STD_OUTPUT_HANDLE);
|
|
}
|
|
#endif
|
|
#if REDIRECT_STDIO
|
|
if (!mrerr)
|
|
mrerr = fopen("mrstderr.txt", "w");
|
|
if (!mrerr) {
|
|
scheme_end_atomic_no_swap();
|
|
return;
|
|
}
|
|
#endif
|
|
|
|
HIDE_FROM_XFORM(va_start(args, msg));
|
|
#if WINDOW_STDIO
|
|
if (wx_in_terminal) {
|
|
vfprintf(stderr, msg, args);
|
|
} else if (!msg) {
|
|
char *s;
|
|
wxchar *us;
|
|
long d, l, ulen, ipos;
|
|
|
|
s = HIDE_FROM_XFORM(va_arg(args, char*));
|
|
d = HIDE_FROM_XFORM(va_arg(args, long));
|
|
l = HIDE_FROM_XFORM(va_arg(args, long));
|
|
|
|
if (!ioFrame->beginEditSeq) {
|
|
ioFrame->media->BeginEditSequence();
|
|
ioFrame->beginEditSeq = 1;
|
|
}
|
|
|
|
if (utf8_leftover_count) {
|
|
char *naya;
|
|
naya = new WXGC_ATOMIC char[l + utf8_leftover_count];
|
|
memcpy(naya, utf8_leftover, utf8_leftover_count);
|
|
memcpy(naya + utf8_leftover_count, s + d, l);
|
|
s = naya;
|
|
d = 0;
|
|
l += utf8_leftover_count;
|
|
}
|
|
|
|
ulen = scheme_utf8_decode_as_prefix((unsigned char *)s, d, l,
|
|
NULL, 0, -1,
|
|
&ipos, 0, '?');
|
|
utf8_leftover_count = (l - (ipos - d));
|
|
memcpy(utf8_leftover, s + ipos, utf8_leftover_count);
|
|
|
|
us = (wxchar *)scheme_malloc_atomic(sizeof(wxchar) * ulen);
|
|
scheme_utf8_decode_as_prefix((unsigned char *)s, d, l,
|
|
us, 0, -1,
|
|
&ipos, 0, '?');
|
|
ioFrame->media->Insert(ulen, us, ioFrame->endpos);
|
|
ioFrame->endpos += ulen;
|
|
|
|
if (ulen != 1 || s[0] == '\n') {
|
|
ioFrame->media->EndEditSequence();
|
|
ioFrame->beginEditSeq = 0;
|
|
}
|
|
} else {
|
|
# define VSP_BUFFER_SIZE 4096
|
|
# ifdef MPW_CPLUS
|
|
/* FIXME: No vsnprintf in MPW. */
|
|
# define vsnprintf(x, y, z, w) vsprintf(x, z, w)
|
|
# endif
|
|
char buffer[VSP_BUFFER_SIZE];
|
|
MSC_IZE(vsnprintf)(buffer, VSP_BUFFER_SIZE, msg, args);
|
|
ioFrame->media->Insert((char *)buffer, ioFrame->endpos);
|
|
ioFrame->endpos += strlen(buffer);
|
|
if (ioFrame->beginEditSeq) {
|
|
ioFrame->media->EndEditSequence();
|
|
ioFrame->beginEditSeq = 0;
|
|
}
|
|
}
|
|
#endif
|
|
#if WCONSOLE_STDIO
|
|
if (!msg) {
|
|
char *s;
|
|
long l;
|
|
DWORD wrote;
|
|
|
|
s = va_arg(args, char*);
|
|
l = va_arg(args, long);
|
|
|
|
WriteConsole(console_out, s, l, &wrote, NULL);
|
|
} else {
|
|
char buffer[2048];
|
|
DWORD wrote;
|
|
vsprintf(buffer, msg, args);
|
|
WriteConsole(console_out, buffer, strlen(buffer), &wrote, NULL);
|
|
}
|
|
#endif
|
|
#if !WINDOW_STDIO && !WCONSOLE_STDIO
|
|
vfprintf(mrerr, msg, args);
|
|
#endif
|
|
|
|
scheme_end_atomic_no_swap();
|
|
|
|
HIDE_FROM_XFORM(va_end(args));
|
|
}
|
|
|
|
static void MrEdSchemeMessagesOutput(char *s, long l)
|
|
{
|
|
if (l)
|
|
MrEdSchemeMessages(NULL, s, 0, l);
|
|
}
|
|
#endif
|
|
|
|
#if REDIRECT_STDIO || WINDOW_STDIO || WCONSOLE_STDIO
|
|
|
|
static Scheme_Object *console_reading;
|
|
|
|
static void add_console_reading()
|
|
{
|
|
if (!console_reading) {
|
|
wxREGGLOB(console_reading);
|
|
console_reading = scheme_null;
|
|
}
|
|
|
|
console_reading = scheme_make_pair((Scheme_Object *)scheme_current_thread,
|
|
console_reading);
|
|
}
|
|
|
|
static void remove_console_reading()
|
|
{
|
|
Scheme_Object *p, *prev = NULL;
|
|
|
|
if (!console_reading)
|
|
return;
|
|
|
|
p = console_reading;
|
|
while (SCHEME_PAIRP(p)) {
|
|
if (SAME_OBJ(SCHEME_CAR(p), (Scheme_Object *)scheme_current_thread)) {
|
|
if (prev)
|
|
SCHEME_CDR(prev) = SCHEME_CDR(p);
|
|
else
|
|
console_reading = SCHEME_CDR(p);
|
|
return;
|
|
}
|
|
prev = p;
|
|
p = SCHEME_CDR(p);
|
|
}
|
|
}
|
|
|
|
static void break_console_reading_threads()
|
|
{
|
|
Scheme_Object *p;
|
|
|
|
if (!console_reading)
|
|
return;
|
|
|
|
for (p = console_reading; SCHEME_PAIRP(p); p = SCHEME_CDR(p)) {
|
|
scheme_break_thread((Scheme_Thread *)SCHEME_CAR(p));
|
|
}
|
|
}
|
|
|
|
static long mrconsole_get_string(Scheme_Input_Port *ip,
|
|
char *buffer, long offset, long size,
|
|
int nonblock, Scheme_Object *unless)
|
|
{
|
|
long result;
|
|
Scheme_Object *pipe = (Scheme_Object *)ip->port_data;
|
|
MrEdSchemeMessages("");
|
|
|
|
add_console_reading();
|
|
result = scheme_get_byte_string("console get-string", pipe, buffer, offset, size, nonblock ? 2 : 0, 0, 0);
|
|
remove_console_reading();
|
|
return result;
|
|
}
|
|
|
|
static int mrconsole_char_ready(Scheme_Input_Port *ip)
|
|
{
|
|
Scheme_Object *pipe = (Scheme_Object *)ip->port_data;
|
|
MrEdSchemeMessages("");
|
|
return scheme_char_ready(pipe);
|
|
}
|
|
|
|
static void mrconsole_close(Scheme_Input_Port *ip)
|
|
{
|
|
Scheme_Object *pipe = (Scheme_Object *)ip->port_data;
|
|
scheme_close_input_port(pipe);
|
|
}
|
|
|
|
static Scheme_Object *MrEdMakeStdIn(void)
|
|
{
|
|
Scheme_Object *readp;
|
|
Scheme_Input_Port *ip;
|
|
|
|
wxREGGLOB(stdin_pipe);
|
|
|
|
scheme_pipe(&readp, &stdin_pipe);
|
|
|
|
ip = scheme_make_input_port(scheme_make_port_type("mred-console-input-port"),
|
|
readp,
|
|
scheme_intern_symbol("mred-console"),
|
|
CAST_GS mrconsole_get_string,
|
|
NULL,
|
|
scheme_progress_evt_via_get,
|
|
scheme_peeked_read_via_get,
|
|
CAST_IREADY mrconsole_char_ready,
|
|
CAST_ICLOSE mrconsole_close,
|
|
NULL,
|
|
0);
|
|
|
|
return (Scheme_Object *)ip;
|
|
}
|
|
|
|
static long stdout_write(Scheme_Output_Port*, const char *s, long d, long l,
|
|
int rarely_block, int enable_break)
|
|
{
|
|
#if WINDOW_STDIO || WCONSOLE_STDIO
|
|
if (l)
|
|
MrEdSchemeMessages(NULL, s, d, l);
|
|
#else
|
|
static FILE *out = NULL;
|
|
|
|
if (!out)
|
|
out = fopen("mrstdout.txt", "w");
|
|
|
|
if (out)
|
|
fwrite(s + d, l, 1, out);
|
|
#endif
|
|
return l;
|
|
}
|
|
|
|
static Scheme_Object *MrEdMakeStdOut(void)
|
|
{
|
|
Scheme_Object *outtype;
|
|
|
|
outtype = scheme_make_port_type("stdout");
|
|
|
|
return (Scheme_Object *)scheme_make_output_port(outtype, NULL,
|
|
scheme_intern_symbol("mred-console"),
|
|
scheme_write_evt_via_write,
|
|
CAST_WS stdout_write,
|
|
NULL, NULL, NULL, NULL, NULL, 0);
|
|
}
|
|
|
|
static long stderr_write(Scheme_Output_Port*, const char *s, long d, long l,
|
|
int rarely_block, int enable_break)
|
|
{
|
|
#if WINDOW_STDIO || WCONSOLE_STDIO
|
|
if (l)
|
|
MrEdSchemeMessages(NULL, s, d, l);
|
|
#else
|
|
if (!mrerr)
|
|
mrerr = fopen("mrstderr.txt", "w");
|
|
|
|
if (mrerr)
|
|
fwrite(s + d, l, 1, mrerr);
|
|
#endif
|
|
return l;
|
|
}
|
|
|
|
static Scheme_Object *MrEdMakeStdErr(void)
|
|
{
|
|
Scheme_Object *errtype;
|
|
|
|
errtype = scheme_make_port_type("stderr");
|
|
|
|
return (Scheme_Object *)scheme_make_output_port(errtype, NULL,
|
|
scheme_intern_symbol("mred-console"),
|
|
scheme_write_evt_via_write,
|
|
CAST_WS stderr_write,
|
|
NULL, NULL, NULL, NULL, NULL, 0);
|
|
}
|
|
#endif
|
|
|
|
void wxmeError(const char *e)
|
|
{
|
|
scheme_signal_error("%s", e);
|
|
}
|
|
|
|
/****************************************************************************/
|
|
/* Debugging */
|
|
/****************************************************************************/
|
|
|
|
#if ADD_OBJ_DUMP
|
|
extern int wx_object_count;
|
|
|
|
# ifndef USE_SENORA_GC
|
|
extern "C" GC_PTR GC_changing_list_start, GC_changing_list_current;
|
|
# else
|
|
# define GC_word int
|
|
# endif
|
|
extern "C" GC_word GC_dl_entries;
|
|
extern "C" GC_word GC_fo_entries;
|
|
|
|
Scheme_Object *OBJDump(int, Scheme_Object *[])
|
|
{
|
|
# if REDIRECT_STDIO || WINDOW_STDIO || WCONSOLE
|
|
# define PRINT_IT MrEdSchemeMessages
|
|
# else
|
|
# define PRINT_IT scheme_console_printf
|
|
# endif
|
|
int c;
|
|
|
|
PRINT_IT("Objects: %d\n", wx_object_count);
|
|
# ifndef USE_SENORA_GC
|
|
PRINT_IT("Memory: %d\n", GC_get_heap_size());
|
|
# endif
|
|
PRINT_IT("FO: %d\n", GC_fo_entries);
|
|
PRINT_IT("DL: %d\n", GC_dl_entries);
|
|
# ifndef USE_SENORA_GC
|
|
PRINT_IT("Changing: %d\n",
|
|
(long)GC_changing_list_current - (long)GC_changing_list_start);
|
|
# endif
|
|
|
|
Scheme_Thread *p;
|
|
for (c = 0, p = scheme_first_thread; p; p = p->next)
|
|
c++;
|
|
|
|
PRINT_IT("Threads: %d\n", c);
|
|
|
|
return scheme_make_integer(wx_object_count);
|
|
}
|
|
#endif
|
|
|
|
#ifdef SGC_STD_DEBUGGING
|
|
extern "C" {
|
|
extern void (*scheme_external_dump_info)(void);
|
|
extern void (*scheme_external_dump_arg)(Scheme_Object *);
|
|
extern char *(*scheme_external_dump_type)(void *);
|
|
};
|
|
extern void GC_cpp_for_each(void (*f)(void *, int, void *), void *data);
|
|
extern int GC_is_wx_object(void *v);
|
|
|
|
#define NUM_OBJ_KIND (wxTYPE_SNIP_CLASS_LIST + 1)
|
|
static int cpp_count[NUM_OBJ_KIND], cpp_sch_count[NUM_OBJ_KIND], cpp_size[NUM_OBJ_KIND];
|
|
static int cpp_actual_count[NUM_OBJ_KIND], cpp_actual_size[NUM_OBJ_KIND];
|
|
static unsigned long cpp_lo[NUM_OBJ_KIND], cpp_hi[NUM_OBJ_KIND];
|
|
|
|
static int trace_path_type;
|
|
|
|
#if SGC_STD_DEBUGGING
|
|
# define USE_WXOBJECT_TRACE_COUNTER
|
|
#endif
|
|
|
|
#ifdef USE_WXOBJECT_TRACE_COUNTER
|
|
|
|
void wxTraceCount(void *o, int size)
|
|
{
|
|
wxObject *obj = (wxObject *)o;
|
|
int type = obj->__type;
|
|
|
|
if ((type >= 0) && (type < NUM_OBJ_KIND)) {
|
|
cpp_actual_count[type]++;
|
|
cpp_actual_size[type] += size;
|
|
|
|
unsigned long s = (unsigned long)o;
|
|
if (!cpp_lo[type] || (s < cpp_lo[type]))
|
|
cpp_lo[type] = s;
|
|
if (!cpp_hi[type] || (s > cpp_hi[type]))
|
|
cpp_hi[type] = s;
|
|
}
|
|
}
|
|
|
|
void wxTracePath(void *o, unsigned long src, void *pd)
|
|
{
|
|
if (trace_path_type > 0) {
|
|
wxObject *obj = (wxObject *)o;
|
|
int type = obj->__type;
|
|
|
|
if (type == trace_path_type)
|
|
GC_store_path(o, src, pd);
|
|
}
|
|
}
|
|
|
|
void wxTraceInit(void)
|
|
{
|
|
int i;
|
|
|
|
for (i = 0; i < NUM_OBJ_KIND; i++) {
|
|
cpp_actual_count[i] = cpp_actual_size[i] = 0;
|
|
cpp_lo[i] = cpp_hi[i] = 0;
|
|
}
|
|
}
|
|
|
|
void wxTraceDone(void)
|
|
{
|
|
/* nothing */
|
|
}
|
|
|
|
void wxObjectFinalize(void *o)
|
|
{
|
|
#if 0
|
|
/* Not every gc instance is a wxObject instance, now: */
|
|
if (((wxObject *)o)->__type != -1) {
|
|
# if 0
|
|
/* New non-cleanup flag makes this incorrect: */
|
|
fprintf(stderr, "ERROR: free wxObject had non-deleted type value!");
|
|
# else
|
|
((wxObject *)o)->__type = -1;
|
|
# endif
|
|
}
|
|
#endif
|
|
}
|
|
|
|
static void set_trace_arg(Scheme_Object *a)
|
|
{
|
|
trace_path_type = -1;
|
|
if (a && SCHEME_SYMBOLP(a)) {
|
|
char *s = SCHEME_SYM_VAL(a);
|
|
int i;
|
|
|
|
for (i = 0; i < NUM_OBJ_KIND; i++) {
|
|
char *tn = wxGetTypeName(i);
|
|
if (tn && !strcmp(tn, s)) {
|
|
trace_path_type = i;
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
static char *object_type_name(void *v)
|
|
{
|
|
if (GC_is_wx_object(v)) {
|
|
int t = ((wxObject *)v)->__type;
|
|
if ((t >= 0) && (t < NUM_OBJ_KIND)) {
|
|
char *c;
|
|
c = wxGetTypeName(t);
|
|
if (c) {
|
|
if (wxSubType(t, wxTYPE_WINDOW)) {
|
|
char *lbl;
|
|
lbl = ((wxWindow *)v)->GetLabel();
|
|
if (!lbl)
|
|
lbl = ((wxWindow *)v)->GetTitle();
|
|
if (!lbl)
|
|
lbl = ((wxWindow *)v)->GetName();
|
|
|
|
if (lbl) {
|
|
int l1, l2;
|
|
char *r;
|
|
l1 = strlen(c);
|
|
l2 = strlen(lbl);
|
|
r = new WXGC_ATOMIC char[l1+l2+2];
|
|
memcpy(r, c, l1);
|
|
r[l1] = '=';
|
|
memcpy(r + l1 + 1, lbl, l2 + 1);
|
|
|
|
return r;
|
|
}
|
|
}
|
|
return c;
|
|
} else
|
|
return "wxUNKNOWN";
|
|
} else
|
|
return "wxBAD";
|
|
} else
|
|
return "";
|
|
}
|
|
|
|
#endif
|
|
|
|
static void count_obj(void *o, int s, void *)
|
|
{
|
|
wxObject *obj = (wxObject *)o;
|
|
int type = obj->__type;
|
|
|
|
if ((type >= 0) && (type < NUM_OBJ_KIND)) {
|
|
cpp_count[type]++;
|
|
if (obj->__gc_external)
|
|
cpp_sch_count[type]++;
|
|
#ifdef MEMORY_USE_METHOD
|
|
cpp_size[type] += s + (obj->MemoryUse());
|
|
#endif
|
|
}
|
|
}
|
|
|
|
static void dump_cpp_info()
|
|
{
|
|
int i, total_count = 0, total_size = 0, total_actual_size = 0;
|
|
|
|
for (i = 0; i < NUM_OBJ_KIND; i++)
|
|
cpp_count[i] = cpp_sch_count[i] = cpp_size[i] = 0;
|
|
|
|
GC_cpp_for_each(count_obj, NULL);
|
|
|
|
scheme_console_printf("\nBegin wxWindows\n");
|
|
|
|
for (i = 0; i < NUM_OBJ_KIND; i++) {
|
|
if (cpp_count[i] || cpp_actual_count[i]) {
|
|
char buffer[50];
|
|
char *name = wxGetTypeName(i);
|
|
|
|
if (!name) {
|
|
sprintf(buffer, "#%d", i);
|
|
name = buffer;
|
|
}
|
|
|
|
scheme_console_printf("%30.30s %4ld %5ld %10ld %10ld %8lx - %8lx\n",
|
|
name,
|
|
cpp_sch_count[i],
|
|
cpp_count[i],
|
|
cpp_size[i],
|
|
cpp_actual_size[i],
|
|
cpp_lo[i],
|
|
cpp_hi[i]);
|
|
#ifdef USE_WXOBJECT_TRACE_COUNTER
|
|
if (cpp_count[i] != cpp_actual_count[i])
|
|
scheme_console_printf("%30.30s actual count: %10ld\n",
|
|
"", cpp_actual_count[i]);
|
|
#endif
|
|
total_count += cpp_count[i];
|
|
total_size += cpp_size[i];
|
|
total_actual_size += cpp_actual_size[i];
|
|
}
|
|
}
|
|
|
|
scheme_console_printf("%30.30s %10ld %10ld %10ld\n",
|
|
"total", total_count, total_size, total_actual_size);
|
|
|
|
scheme_console_printf("End wxWindows\n");
|
|
|
|
#if ADD_OBJ_DUMP
|
|
scheme_console_printf("\n");
|
|
OBJDump(0, NULL);
|
|
#endif
|
|
}
|
|
|
|
#endif
|
|
|
|
/****************************************************************************/
|
|
/* AIX DANGER signal */
|
|
/****************************************************************************/
|
|
|
|
#if defined(_IBMR2)
|
|
#define DANGER_ALARM
|
|
#endif
|
|
|
|
#ifdef DANGER_ALARM
|
|
|
|
static int danger_signal_received = 0;
|
|
static wxDialogBox *dangerFrame = NULL;
|
|
|
|
class DangerThreadTimer : public wxTimer
|
|
{
|
|
public:
|
|
void Notify(void);
|
|
};
|
|
|
|
void DismissDanger(wxObject &o, wxEvent &e)
|
|
{
|
|
dangerFrame->Show(FALSE);
|
|
dangerFrame = NULL;
|
|
danger_signal_received = 0;
|
|
}
|
|
|
|
void DangerThreadTimer::Notify(void)
|
|
{
|
|
if (danger_signal_received) {
|
|
if (!dangerFrame) {
|
|
wxREGGLOB(dangerFrame);
|
|
dangerFrame = new WXGC_PTRS wxDialogBox((wxWindow *)NULL, "Danger", FALSE, 0, 0, 300, 200);
|
|
|
|
(void) new WXGC_PTRS wxMessage(dangerFrame, "Warning: Paging space is low.");
|
|
|
|
dangerFrame->NewLine();
|
|
|
|
wxButton *b = new WXGC_PTRS wxButton(dangerFrame, (wxFunction)DismissDanger, "Ok");
|
|
|
|
dangerFrame->Fit();
|
|
b->Centre(wxHORIZONTAL);
|
|
|
|
dangerFrame->Centre(wxBOTH);
|
|
dangerFrame->Show(TRUE);
|
|
}
|
|
}
|
|
}
|
|
|
|
#endif
|
|
|
|
/****************************************************************************/
|
|
/* Application */
|
|
/****************************************************************************/
|
|
|
|
MrEdApp::MrEdApp()
|
|
{
|
|
#ifndef wx_xt
|
|
if (!wx_class)
|
|
wx_class = "mred";
|
|
#endif
|
|
}
|
|
|
|
extern "C" {
|
|
MZ_EXTERN void (*GC_out_of_memory)(void);
|
|
};
|
|
|
|
static void MrEdOutOfMemory(void)
|
|
{
|
|
#ifdef wx_mac
|
|
Alert(101, NULL);
|
|
ExitToShell();
|
|
#else
|
|
#ifdef wx_x
|
|
printf("mred: out of memory\n");
|
|
#endif
|
|
_exit(-1);
|
|
#endif
|
|
}
|
|
|
|
void *wxOutOfMemory()
|
|
{
|
|
MrEdOutOfMemory();
|
|
return NULL;
|
|
}
|
|
|
|
extern "C" {
|
|
typedef void (*OOM_ptr)(void);
|
|
}
|
|
|
|
static OOM_ptr mr_save_oom;
|
|
static mz_jmp_buf oom_buf;
|
|
|
|
static void not_so_much_memory(void)
|
|
{
|
|
scheme_longjmp(oom_buf, 1);
|
|
}
|
|
|
|
void *wxMallocAtomicIfPossible(size_t s)
|
|
{
|
|
void *v;
|
|
|
|
if (s < 5000)
|
|
return scheme_malloc_atomic(s);
|
|
|
|
mr_save_oom = GC_out_of_memory;
|
|
if (!scheme_setjmp(oom_buf)) {
|
|
GC_out_of_memory = (OOM_ptr)not_so_much_memory;
|
|
v = scheme_malloc_atomic(s);
|
|
} else {
|
|
v = NULL;
|
|
}
|
|
GC_out_of_memory = mr_save_oom;
|
|
|
|
return v;
|
|
}
|
|
|
|
static const char *CallSchemeExpand(const char *filename, const char *who, int to_write)
|
|
{
|
|
char *s;
|
|
|
|
s = scheme_expand_filename((char *)filename, strlen(filename),
|
|
who, 0,
|
|
(to_write
|
|
? SCHEME_GUARD_FILE_WRITE
|
|
: SCHEME_GUARD_FILE_READ));
|
|
|
|
return s ? s : filename;
|
|
}
|
|
|
|
#if !defined(USE_SENORA_GC) && !defined(MZ_PRECISE_GC)
|
|
static void MrEdIgnoreWarnings(char *, GC_word)
|
|
{
|
|
}
|
|
#endif
|
|
|
|
void wxDoMainLoop()
|
|
{
|
|
TheMrEdApp->MainLoop();
|
|
}
|
|
|
|
static Scheme_Env *setup_basic_env()
|
|
{
|
|
wxREGGLOB(global_env);
|
|
global_env = scheme_basic_env();
|
|
|
|
scheme_no_dumps("the graphics library is running");
|
|
|
|
scheme_set_banner(BANNER);
|
|
|
|
wxmeExpandFilename = CallSchemeExpand;
|
|
|
|
#ifdef DANGER_ALARM
|
|
{
|
|
DangerThreadTimer *t = new WXGC_PTRS DangerThreadTimer();
|
|
t->Start(10000);
|
|
}
|
|
#endif
|
|
|
|
scheme_add_evt(mred_eventspace_type,
|
|
(Scheme_Ready_Fun)check_eventspace_inactive,
|
|
NULL,
|
|
NULL, 0);
|
|
scheme_add_evt(mred_nested_wait_type,
|
|
CAST_BLKCHK check_for_nested_event,
|
|
NULL,
|
|
NULL, 0);
|
|
|
|
scheme_add_custodian_extractor(mred_eventspace_hop_type,
|
|
CAST_EXT extract_eventspace_from_hop);
|
|
|
|
wxsScheme_setup(global_env);
|
|
|
|
scheme_set_param(scheme_current_config(), mred_eventspace_param, (Scheme_Object *)mred_main_context);
|
|
|
|
wxREGGLOB(def_dispatch);
|
|
def_dispatch = scheme_make_prim_w_arity(CAST_SP def_event_dispatch_handler,
|
|
"default-event-dispatch-handler",
|
|
1, 1);
|
|
scheme_set_param(scheme_current_config(), mred_event_dispatch_param, def_dispatch);
|
|
|
|
/* Make sure ps-setup is installed in the parameterization */
|
|
ps_ready = 1;
|
|
/* wxSetThePrintSetupData(wxGetThePrintSetupData()); */
|
|
|
|
MakeContext(mred_main_context);
|
|
|
|
mred_only_context = NULL;
|
|
|
|
/* This handler_running pointer gets reset later. Do
|
|
we really need to set it now? */
|
|
mred_main_context->handler_running = scheme_current_thread;
|
|
|
|
mzsleep = scheme_sleep;
|
|
scheme_sleep = CAST_SLEEP MrEdSleep;
|
|
|
|
#if ADD_OBJ_DUMP
|
|
scheme_add_global("dump-object-stats",
|
|
scheme_make_prim(OBJDump), global_env);
|
|
#endif
|
|
|
|
return global_env;
|
|
}
|
|
|
|
wxFrame *MrEdApp::OnInit(void)
|
|
{
|
|
MrEdContext *mmc;
|
|
|
|
initialized = 0;
|
|
|
|
#ifdef wx_mac
|
|
{
|
|
TSMDocumentID doc;
|
|
OSType itfs[1];
|
|
itfs[0] = kUnicodeDocumentInterfaceType;
|
|
NewTSMDocument(1, itfs, &doc, 0);
|
|
UseInputWindow(NULL, TRUE);
|
|
ActivateTSMDocument(doc);
|
|
}
|
|
#endif
|
|
|
|
wxREGGLOB(mred_frames);
|
|
wxREGGLOB(timer_contexts);
|
|
timer_contexts = scheme_make_hash_table(SCHEME_hash_ptr);
|
|
|
|
#ifdef LIBGPP_REGEX_HACK
|
|
new WXGC_PTRS Regex("a", 0);
|
|
#endif
|
|
|
|
#if REDIRECT_STDIO || WINDOW_STDIO || WCONSOLE_STDIO
|
|
if (!wx_in_terminal) {
|
|
scheme_make_stdin = CAST_MK MrEdMakeStdIn;
|
|
scheme_make_stdout = CAST_MK MrEdMakeStdOut;
|
|
scheme_make_stderr = CAST_MK MrEdMakeStdErr;
|
|
}
|
|
#endif
|
|
|
|
#if !defined(USE_SENORA_GC) && !defined(MZ_PRECISE_GC)
|
|
GC_set_warn_proc(CAST_IGNORE MrEdIgnoreWarnings);
|
|
#endif
|
|
#if 0
|
|
/* Used to be set for the sake of Mac OS Classic. Now,
|
|
setting GC_out_of_memory for 3m means that it's ok
|
|
to fail when a limit is reached. We don't want that. */
|
|
GC_out_of_memory = (OOM_ptr)MrEdOutOfMemory;
|
|
#endif
|
|
|
|
#ifdef SGC_STD_DEBUGGING
|
|
scheme_external_dump_info = dump_cpp_info;
|
|
# ifdef USE_WXOBJECT_TRACE_COUNTER
|
|
scheme_external_dump_type = object_type_name;
|
|
scheme_external_dump_arg = set_trace_arg;
|
|
# endif
|
|
#endif
|
|
|
|
#if REDIRECT_STDIO || WINDOW_STDIO || WCONSOLE_STDIO
|
|
scheme_console_printf = CAST_PRINTF MrEdSchemeMessages;
|
|
if (!wx_in_terminal) {
|
|
scheme_console_output = CAST_OUTPUT MrEdSchemeMessagesOutput;
|
|
}
|
|
#endif
|
|
|
|
mred_eventspace_param = scheme_new_param();
|
|
mred_event_dispatch_param = scheme_new_param();
|
|
mred_ps_setup_param = scheme_new_param();
|
|
|
|
wxInitSnips(); /* and snip classes */
|
|
|
|
mred_eventspace_type = scheme_make_type("<eventspace>");
|
|
mred_nested_wait_type = scheme_make_type("<eventspace-nested-wait>");
|
|
mred_eventspace_hop_type = scheme_make_type("<internal:eventspace-hop>");
|
|
#ifdef MZ_PRECISE_GC
|
|
GC_register_traversers(mred_eventspace_type,
|
|
size_eventspace_val,
|
|
mark_eventspace_val,
|
|
fixup_eventspace_val,
|
|
1, 0);
|
|
GC_register_traversers(mred_nested_wait_type,
|
|
size_nested_wait_val,
|
|
mark_nested_wait_val,
|
|
fixup_nested_wait_val,
|
|
1, 0);
|
|
GC_register_traversers(mred_eventspace_hop_type,
|
|
size_eventspace_hop_val,
|
|
mark_eventspace_hop_val,
|
|
fixup_eventspace_hop_val,
|
|
1, 0);
|
|
#endif
|
|
|
|
#ifdef NEED_HET_PARAM
|
|
wxREGGLOB(mred_het_key);
|
|
mred_het_key = scheme_make_symbol("het"); /* uninterned */
|
|
#endif
|
|
|
|
#ifdef MZ_PRECISE_GC
|
|
mmc = (MrEdContext *)GC_malloc_one_tagged(sizeof(MrEdContext));
|
|
#else
|
|
mmc = new WXGC_PTRS MrEdContext;
|
|
#endif
|
|
mmc->so.type = mred_eventspace_type;
|
|
wxREGGLOB(mred_main_context);
|
|
mred_main_context = mmc;
|
|
{
|
|
wxChildList *cl;
|
|
cl = new WXGC_PTRS wxChildList();
|
|
mmc->topLevelWindowList = cl;
|
|
}
|
|
{
|
|
wxStandardSnipClassList *scl;
|
|
scl = wxMakeTheSnipClassList();
|
|
mmc->snipClassList = scl;
|
|
}
|
|
{
|
|
wxBufferDataClassList *dcl;
|
|
dcl = wxMakeTheBufferDataClassList();
|
|
mmc->bufferDataClassList = dcl;
|
|
}
|
|
{
|
|
MrEdFinalizedContext *fc;
|
|
fc = new WXGC_PTRS MrEdFinalizedContext;
|
|
mmc->finalized = fc;
|
|
}
|
|
|
|
wxREGGLOB(mred_only_context);
|
|
mred_only_context = mred_main_context;
|
|
|
|
MrEdInitFirstContext(mred_main_context);
|
|
|
|
/* Just in case wxWindows needs an initial frame: */
|
|
/* (Windows needs it for the clipboard.) */
|
|
wxREGGLOB(mred_real_main_frame);
|
|
mred_real_main_frame = new WXGC_PTRS wxFrame(NULL, "MrEd");
|
|
#ifdef wx_msw
|
|
TheMrEdApp->wx_frame = mred_real_main_frame;
|
|
#endif
|
|
|
|
wxInitMedia();
|
|
|
|
wxscheme_early_gl_init();
|
|
|
|
#ifdef mred_BREAK_HANDLER
|
|
# ifdef OS_X
|
|
_signal_nobind(SIGINT, user_break_hit);
|
|
# else
|
|
MZ_SIGSET(SIGINT, user_break_hit);
|
|
# endif
|
|
#endif
|
|
|
|
mred_run_from_cmd_line(argc, argv, setup_basic_env);
|
|
|
|
#if WINDOW_STDIO
|
|
if (!wx_in_terminal) {
|
|
/* The only reason we get here is that a command-line error or
|
|
-h occured. In either case, stick around for the sake of the
|
|
console. */
|
|
setup_basic_env();
|
|
TheMrEdApp->initialized = 1;
|
|
stdio_kills_prog = 1;
|
|
if (ioFrame)
|
|
ioFrame->CloseIsQuit();
|
|
wxTheApp->MainLoop();
|
|
}
|
|
#endif
|
|
|
|
return NULL;
|
|
}
|
|
|
|
#if WINDOW_STDIO
|
|
static void MrEdExit(int v)
|
|
{
|
|
if (have_stdio) {
|
|
stdio_kills_prog = 1;
|
|
if (ioFrame)
|
|
ioFrame->CloseIsQuit();
|
|
scheme_close_managed(main_custodian);
|
|
return;
|
|
}
|
|
|
|
#ifdef wx_msw
|
|
mred_clean_up_gdi_objects();
|
|
#endif
|
|
scheme_immediate_exit(v);
|
|
}
|
|
#endif
|
|
|
|
static void on_main_killed(Scheme_Thread *p)
|
|
{
|
|
on_handler_killed(p);
|
|
|
|
if (scheme_exit)
|
|
scheme_exit(exit_val);
|
|
else {
|
|
#ifdef wx_msw
|
|
mred_clean_up_gdi_objects();
|
|
#endif
|
|
scheme_immediate_exit(exit_val);
|
|
}
|
|
}
|
|
|
|
void MrEdApp::RealInit(void)
|
|
{
|
|
initialized = 1;
|
|
|
|
wxMediaIOCheckLSB(/* scheme_console_printf */);
|
|
|
|
scheme_current_thread->on_kill = CAST_TOK on_main_killed;
|
|
#if WINDOW_STDIO
|
|
if (!wx_in_terminal)
|
|
scheme_exit = CAST_EXIT MrEdExit;
|
|
#endif
|
|
|
|
#ifdef wx_xt
|
|
if (wx_single_instance) {
|
|
exit_val = wxCheckSingleInstance(global_env);
|
|
}
|
|
#endif
|
|
|
|
if (!exit_val)
|
|
exit_val = mred_finish_cmd_line_run();
|
|
|
|
scheme_kill_thread(scheme_current_thread);
|
|
}
|
|
|
|
#ifdef wx_mac
|
|
char *wx_original_argv_zero;
|
|
static char *about_label;
|
|
extern "C" char *scheme_get_exec_path();
|
|
char *MrEdApp::GetDefaultAboutItemName()
|
|
{
|
|
# ifdef OS_X
|
|
if (!about_label) {
|
|
char *p;
|
|
int i, len;
|
|
|
|
p = wx_original_argv_zero;
|
|
len = strlen(p);
|
|
for (i = len - 1; i; i--) {
|
|
if (p[i] == '/') {
|
|
i++;
|
|
break;
|
|
}
|
|
}
|
|
|
|
wxREGGLOB(about_label);
|
|
about_label = new WXGC_ATOMIC char[len - i + 20];
|
|
sprintf(about_label, "About %s...", p + i);
|
|
}
|
|
|
|
return about_label;
|
|
# else
|
|
return "About...";
|
|
# endif
|
|
}
|
|
|
|
void MrEdApp::DoDefaultAboutItem()
|
|
{
|
|
DialogPtr dial;
|
|
short hit;
|
|
CGrafPtr port;
|
|
GDHandle device;
|
|
|
|
dial = GetNewDialog(129, NULL, (WindowRef)-1);
|
|
GetGWorld(&port,&device);
|
|
|
|
SetGWorld(GetDialogPort(dial),GetGDevice());
|
|
|
|
TextFont(kFontIDGeneva);
|
|
TextSize(10);
|
|
SetGWorld(port,device);
|
|
|
|
ModalDialog(NULL, &hit);
|
|
|
|
DisposeDialog(dial);
|
|
}
|
|
|
|
#ifdef OS_X
|
|
extern int scheme_mac_path_to_spec(const char *filename, FSSpec *spec);
|
|
#endif
|
|
|
|
int wxGetOriginalAppFSSpec(FSSpec *spec)
|
|
{
|
|
char *s = wx_original_argv_zero;
|
|
|
|
#ifdef OS_X
|
|
/* Need the folder of the exe, three levels up: */
|
|
{
|
|
char *p;
|
|
int i, len, c = 0;
|
|
|
|
p = s;
|
|
len = strlen(s);
|
|
for (i = len - 1; i; i--) {
|
|
if (p[i] == '/') {
|
|
c++;
|
|
if (c == 3) {
|
|
i++;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (i) {
|
|
char *s2;
|
|
s2 = new WXGC_ATOMIC char[i + 1];
|
|
memcpy(s2, s, i);
|
|
s2[i] = 0;
|
|
s = s2;
|
|
}
|
|
}
|
|
#endif
|
|
|
|
return scheme_mac_path_to_spec(s, spec);
|
|
}
|
|
|
|
#endif
|
|
|
|
int MrEdApp::OnExit(void)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
void wxCreateApp(void)
|
|
{
|
|
if (!TheMrEdApp) {
|
|
#ifdef wx_mac
|
|
wxmac_reg_globs();
|
|
#endif
|
|
#ifdef wx_msw
|
|
{
|
|
HANDLE h;
|
|
h = GetStdHandle(STD_OUTPUT_HANDLE);
|
|
if (h && (h != INVALID_HANDLE_VALUE)
|
|
&& (GetFileType(h) != FILE_TYPE_UNKNOWN)) {
|
|
wx_in_terminal = 1;
|
|
}
|
|
}
|
|
#endif
|
|
|
|
wxREGGLOB(orig_ps_setup);
|
|
wxREGGLOB(q_callbacks);
|
|
|
|
wxREGGLOB(TheMrEdApp);
|
|
TheMrEdApp = new WXGC_PTRS MrEdApp;
|
|
}
|
|
}
|
|
|
|
/****************************************************************************/
|
|
/* wxFlushDisplay */
|
|
/****************************************************************************/
|
|
|
|
void wxFlushDisplay(void)
|
|
{
|
|
#ifdef wx_x
|
|
Display *d;
|
|
|
|
d = XtDisplay(wxAPP_TOPLEVEL);
|
|
|
|
XFlush(d);
|
|
XSync(d, FALSE);
|
|
XFlush(d);
|
|
XSync(d, FALSE);
|
|
#endif
|
|
#ifdef wx_mac
|
|
wxFlushMacDisplay();
|
|
#endif
|
|
}
|
|
|
|
#ifdef DEFINE_DUMMY_PURE_VIRTUAL
|
|
/* Weird hack to avoid linking to libg++ */
|
|
extern "C" {
|
|
void __pure_virtual(void) { }
|
|
}
|
|
#endif
|
|
|
|
/****************************************************************************/
|
|
/* wxHiEventTrampoline */
|
|
/****************************************************************************/
|
|
|
|
#ifdef NEED_HET_PARAM
|
|
|
|
/* In certain Windows and Mac OS modes (e.g., to implement scrolling),
|
|
we run Scheme code atomically to avoid copying part of the stack
|
|
that belongs to the system. We run arbitrary code, however, the
|
|
code does not run to completion. Instead, we suspend the
|
|
continuation after a while, and then try to continue on the next OS
|
|
stop point (e.g., an WM_XSCROLL message). Hopefully, a timer
|
|
ensures that a suspended continuation gets to continue soon when
|
|
nothing else is going on. During this special mode, other messages
|
|
that can call into Scheme are ignored (e.g., WM_ACTIVATE). After
|
|
the OS mode ends (e.g., the scroller returns), any pending
|
|
continuation is finished, but in non-atomic mode, and things are
|
|
generally back to normal.
|
|
|
|
The call process is
|
|
wxHiEventTrampoline(f, data)
|
|
-> f(data) in ht mode
|
|
-> ... mred_het_run_some(g, data2) \
|
|
-> Scheme code, may finish or may not | maybe loop
|
|
het->in_progress inicates whether done /
|
|
-> continue scheme if not finished
|
|
|
|
In this process, it's the call stack between f(data)
|
|
and the call to mred_het_run_some() that won't be copied
|
|
in or out until f(data) returns.
|
|
|
|
Nesting wxHiEventTrampoline() calls should be safe, but it won't
|
|
achieve the goal, which is to limit the amount of work done before
|
|
returning (because the inner wxHiEventTrampoline will have to run
|
|
to completion). */
|
|
|
|
static unsigned long get_deeper_base();
|
|
|
|
int wxHiEventTrampoline(int (*_wha_f)(void *), void *wha_data)
|
|
{
|
|
HiEventTramp *het;
|
|
HiEventTrampProc wha_f = (HiEventTrampProc)_wha_f;
|
|
Scheme_Cont_Frame_Data cframe;
|
|
Scheme_Object *bx;
|
|
|
|
het = new WXGC_PTRS HiEventTramp;
|
|
|
|
bx = scheme_make_raw_pair((Scheme_Object *)het, NULL);
|
|
|
|
scheme_push_continuation_frame(&cframe);
|
|
scheme_set_cont_mark(mred_het_key, bx);
|
|
|
|
het->progress_cont = scheme_new_jmpupbuf_holder();
|
|
|
|
scheme_init_jmpup_buf(&het->progress_cont->buf);
|
|
|
|
scheme_start_atomic();
|
|
het->val = wha_f(wha_data);
|
|
|
|
if (het->timer_on) {
|
|
het->timer_on = 0;
|
|
# ifdef wx_msw
|
|
KillTimer(NULL, het->timer_id);
|
|
# endif
|
|
}
|
|
|
|
if (het->in_progress) {
|
|
/* We have leftover work; jump and finish it (non-atomically).
|
|
But don't swap until we've jumped back in, because the jump-in
|
|
point might be trying to suspend the thread (and that should
|
|
complete before any swap). */
|
|
scheme_end_atomic_no_swap();
|
|
SCHEME_CAR(bx) = NULL;
|
|
het->in_progress = 0;
|
|
het->progress_is_resumed = 1;
|
|
if (!scheme_setjmp(het->progress_base)) {
|
|
#ifdef MZ_PRECISE_GC
|
|
het->fixup_var_stack_chain = &__gc_var_stack__;
|
|
#endif
|
|
scheme_longjmpup(&het->progress_cont->buf);
|
|
}
|
|
} else {
|
|
scheme_end_atomic();
|
|
}
|
|
|
|
scheme_pop_continuation_frame(&cframe);
|
|
|
|
het->old_param = NULL;
|
|
het->progress_cont = NULL;
|
|
het->do_data = NULL;
|
|
|
|
return het->val;
|
|
}
|
|
|
|
static void suspend_het_progress(void)
|
|
{
|
|
HiEventTramp * volatile het;
|
|
double msecs;
|
|
|
|
{
|
|
Scheme_Object *v;
|
|
v = scheme_extract_one_cc_mark(NULL, mred_het_key);
|
|
het = (HiEventTramp *)SCHEME_CAR(v);
|
|
}
|
|
|
|
msecs = scheme_get_inexact_milliseconds();
|
|
if (msecs < het->continue_until)
|
|
return;
|
|
|
|
scheme_on_atomic_timeout = NULL;
|
|
|
|
het->yielding = 0;
|
|
het->in_progress = 1;
|
|
if (scheme_setjmpup(&het->progress_cont->buf, (void*)het->progress_cont, het->progress_base_addr)) {
|
|
/* we're back */
|
|
scheme_reset_jmpup_buf(&het->progress_cont->buf);
|
|
het->yielding = 0;
|
|
#ifdef MZ_PRECISE_GC
|
|
/* Base addr points to the last valid gc_var_stack address.
|
|
Fixup that link to skip over the part of the stack we're
|
|
not using right now. */
|
|
((void **)het->progress_base_addr)[0] = het->fixup_var_stack_chain;
|
|
((void **)het->progress_base_addr)[1] = NULL;
|
|
#endif
|
|
} else {
|
|
/* we're leaving */
|
|
scheme_longjmp(het->progress_base, 1);
|
|
}
|
|
}
|
|
|
|
#define HET_RUN_MSECS 200
|
|
|
|
static void het_run_new(HiEventTramp * volatile het)
|
|
{
|
|
double msecs;
|
|
|
|
/* We're willing to start new work that is specific to this thread */
|
|
het->progress_is_resumed = 0;
|
|
|
|
msecs = scheme_get_inexact_milliseconds();
|
|
het->continue_until = msecs + HET_RUN_MSECS;
|
|
|
|
if (!scheme_setjmp(het->progress_base)) {
|
|
scheme_start_atomic();
|
|
scheme_on_atomic_timeout = CAST_SUSPEND suspend_het_progress;
|
|
/* Due to het param, yield work will be restricted: */
|
|
het->yielding = 1;
|
|
if (het->do_f) {
|
|
HiEventTrampProc do_f = het->do_f;
|
|
do_f(het->do_data);
|
|
} else
|
|
wxYield();
|
|
het->yielding = 0;
|
|
}
|
|
|
|
if (het->progress_is_resumed) {
|
|
/* we've already returned once; jump out to new progress base */
|
|
scheme_longjmp(het->progress_base, 1);
|
|
} else {
|
|
scheme_on_atomic_timeout = NULL;
|
|
scheme_end_atomic_no_swap();
|
|
}
|
|
}
|
|
|
|
static void het_do_run_new(HiEventTramp * volatile het, int *iteration)
|
|
{
|
|
/* This function just makes room on the stack, eventually calling
|
|
het_run_new(). */
|
|
int new_iter[32];
|
|
|
|
if (iteration[0] == 3) {
|
|
#ifdef MZ_PRECISE_GC
|
|
het->progress_base_addr = (void *)&__gc_var_stack__;
|
|
#else
|
|
het->progress_base_addr = (void *)new_iter;
|
|
#endif
|
|
het_run_new(het);
|
|
} else {
|
|
new_iter[0] = iteration[0] + 1;
|
|
het_do_run_new(het, new_iter);
|
|
}
|
|
}
|
|
|
|
int mred_het_run_some(HiEventTrampProc do_f, void *do_data)
|
|
{
|
|
HiEventTramp * volatile het;
|
|
int more = 0;
|
|
|
|
{
|
|
Scheme_Object *v;
|
|
v = scheme_extract_one_cc_mark(NULL, mred_het_key);
|
|
if (v)
|
|
het = (HiEventTramp *)SCHEME_CAR(v);
|
|
else
|
|
het = NULL;
|
|
}
|
|
|
|
if (het) {
|
|
if (het->in_progress) {
|
|
/* We have work in progress. */
|
|
if ((unsigned long)het->progress_base_addr < get_deeper_base()) {
|
|
/* We have stack space to resume the old work: */
|
|
double msecs;
|
|
het->in_progress = 0;
|
|
het->progress_is_resumed = 1;
|
|
msecs = scheme_get_inexact_milliseconds();
|
|
het->continue_until = msecs + HET_RUN_MSECS;
|
|
scheme_start_atomic();
|
|
scheme_on_atomic_timeout = CAST_SUSPEND suspend_het_progress;
|
|
if (!scheme_setjmp(het->progress_base)) {
|
|
#ifdef MZ_PRECISE_GC
|
|
het->fixup_var_stack_chain = &__gc_var_stack__;
|
|
#endif
|
|
scheme_longjmpup(&het->progress_cont->buf);
|
|
} else {
|
|
scheme_on_atomic_timeout = NULL;
|
|
scheme_end_atomic_no_swap();
|
|
}
|
|
}
|
|
} else {
|
|
int iter[1];
|
|
iter[0] = 0;
|
|
het->do_f = do_f;
|
|
het->do_data = do_data;
|
|
het_do_run_new(het, iter);
|
|
}
|
|
|
|
more = het->in_progress;
|
|
}
|
|
|
|
return more;
|
|
}
|
|
|
|
// Disable warning for returning address of local variable.
|
|
#ifdef _MSC_VER
|
|
#pragma warning (disable:4172)
|
|
#endif
|
|
|
|
static unsigned long get_deeper_base()
|
|
{
|
|
long here;
|
|
return (unsigned long)&here;
|
|
}
|
|
|
|
// re-enable warning
|
|
#ifdef _MSC_VER
|
|
#pragma warning (default:4172)
|
|
#endif
|
|
|
|
#endif
|
|
|
|
/****************************************************************************/
|
|
/* AE-like support */
|
|
/****************************************************************************/
|
|
|
|
static void wxDo(Scheme_Object *proc, int argc, Scheme_Object **argv)
|
|
{
|
|
mz_jmp_buf * volatile save, newbuf;
|
|
volatile int block_descriptor;
|
|
|
|
if (!proc) {
|
|
/* Oops --- too early. */
|
|
return;
|
|
}
|
|
|
|
/* wxDo might be called when MrEd is sleeping (i.e.,
|
|
blocked on WNE in OS X). Since we're hijacking the
|
|
thread, save an restore block information. */
|
|
block_descriptor = scheme_current_thread->block_descriptor;
|
|
scheme_current_thread->block_descriptor = 0;
|
|
|
|
scheme_start_atomic();
|
|
|
|
save = scheme_current_thread->error_buf;
|
|
scheme_current_thread->error_buf = &newbuf;
|
|
|
|
if (scheme_setjmp(newbuf)) {
|
|
scheme_clear_escape();
|
|
} else {
|
|
scheme_apply(proc, argc, argv);
|
|
}
|
|
|
|
scheme_current_thread->error_buf = save;
|
|
scheme_current_thread->block_descriptor = block_descriptor;
|
|
|
|
scheme_end_atomic_no_swap();
|
|
}
|
|
|
|
void wxDrop_Runtime(char **argv, int argc)
|
|
{
|
|
int i;
|
|
|
|
for (i = 0; i < argc; i++) {
|
|
Scheme_Object *p[1];
|
|
#ifdef wx_xt
|
|
p[0] = scheme_char_string_to_path(scheme_make_utf8_string(argv[i]));
|
|
#else
|
|
p[0] = scheme_make_path(argv[i]);
|
|
#endif
|
|
wxDo(wxs_app_file_proc, 1, p);
|
|
}
|
|
}
|
|
|
|
#if defined(wx_mac) || defined(wx_msw)
|
|
void wxDrop_Quit()
|
|
{
|
|
#if WINDOW_STDIO
|
|
if (ioFrame) {
|
|
if (ioFrame->OnClose())
|
|
ioFrame->Show(FALSE);
|
|
}
|
|
#endif
|
|
|
|
wxDo(wxs_app_quit_proc, 0, NULL);
|
|
}
|
|
#endif
|
|
|
|
#ifdef wx_mac
|
|
void wxDo_About()
|
|
{
|
|
wxDo(wxs_app_about_proc, 0, NULL);
|
|
}
|
|
|
|
void wxDo_Pref()
|
|
{
|
|
if (!SCHEME_FALSEP(wxs_app_pref_proc))
|
|
wxDo(wxs_app_pref_proc, 0, NULL);
|
|
}
|
|
|
|
int wxCan_Do_Pref()
|
|
{
|
|
return SCHEME_TRUEP(wxs_app_pref_proc);
|
|
}
|
|
#endif
|