[plt-scheme] Extensibility of MrEd
Matthew Flatt wrote:
> At the Scheme level, there's a `get-eventspace' method on
> `top-level-window<%>', so you should have access to the relevant
> eventspace whenever you have access to a frame's HWND.
>
> Meanwhile, `mred/private/kernel' exports `middle-queue-key'. Its value
> is recognized specially by `queue-callback' when supplied as the
> "boolean" second argument, and it causes a callback to be added with
> the same priority as a GUI event. (Of course, the module
> `mred/private/kernel' is meant to be private to MrEd, but if you have
> enough privileges to load an extension, then it's probably fine also to
> access that module.)
>
Following this advice and also looting the contents of
mred/private/helper, I came up with
(require mred (prefix-in wx: mred/private/kernel)
(define (queue-window-callback w cb)
(parameterize ((current-eventspace (send (send w get-top-level-window)
get-eventspace)))
(queue-callback cb wx:middle-queue-key)))
which seems to work when called like so
(define (foo-callback hwnd x y)
(let ((w0 (assq hwnd *window-set*))) ;; alist of hwnd, canvas% pairs
(unless w0 (error ...))
(let ((w (cdr w0)))
(queue-window-callback w (lambda () (send w on-foo (list '(foo) x
y))))))
#t)
This foo-callback proc is passed as a (_fun _uint _uint _uint -> _bool)
FFI callback to a stub C DLL which does little more than subclass a
canvas with
WNDPROC OldWndProc = 0; // set to the original wndproc of the canvas%
typedef BOOL (*SCHEME_CALLBACK)(HWND, UINT, UINT);
SCHEME_CALLBACK Dispatch = 0; // set via FFI to foo-callback
LRESULT CALLBACK NewWndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM
lParam)
{ if (uMsg == WM_RBUTTONDOWN) // easy enough to catch
{ Dispatch(hwnd, LOWORD(lParam), HIWORD(lParam)); return 0; }
return CallWindowProc(OldWndProc, hwnd, uMsg, wParam, lParam); }
This all works just fine under mred.exe. Continuing with this simple
example, a canvas in my application window is subclassed to catch right
mouse downs, and does some boring stuff when it's dispatched an on-foo
with the coordinates of that right mouse down. No big deal. Run under
the drscheme debugger, however, my program faults frequently in
MrEdDispatchEvent after catching a few right-mouse-downs, the debugger
displaying a lot of suspiciously zeroed registers. You did warn me once
> Beware that there's a bad interaction between PLT Scheme threads and
> Windows: a Scheme-level thread swap cannot be allowed while handling a
> Windows message. The solution is usually to handle a message by just
> queuing a callback in the eventspace, and then return to Windows
> immediately; that works when you don't need to compute any particular
> return value for the message.
>
Am I doing something here that would trigger a thread swap under the
debugger? Perhaps the transition through the callback into Scheme? Or
is my implementation of queue-window-callback toxic?
Thanks,
Ben