Hi,
I am trying to create an X11 window from Lisp in a thread. The idea
is that once it is created, a pointer to a structure with the window
information is returned, and the X11 event loop runs in the
background. But something strange happens: the when the window will
only get the events when it comes into focus. I already asked on the
X11 mailing list, but they couldn't help, so I thought it might be
something I am not aware of with SBCL's threads.
From Lisp, I call
(defun create-window (&optional (display-name ":0"))
"Create an X11 window in a thread, return a pointer to its structure."
(let ((wd)
(wd-pointer (cffi:foreign-alloc :pointer)))
;; we will detect changes with null-pointer-p
(setf (cffi:mem-ref wd-pointer :pointer) (cffi:null-pointer))
;; start and save thread
(setf wd
(sb-thread:make-thread
(lambda ()
(create_window display-name wd-pointer)
;; when done, set wd to nil
(setf wd nil))))
;; wait for thread to fill pointer
(do ()
((not (cffi:null-pointer-p (cffi:mem-ref wd-pointer :pointer)))))
(setf wd (cffi:mem-ref wd-pointer :pointer))
(cffi:foreign-free wd-pointer)
wd))
(defparameter *wd* (create-window))
;; switch from new window back to the one with the REPL
(close_window *wd*)
;; window is not destroyed until you switch to it and do something
The C code looks like this (the whole self-contained code is available
from http://www.princeton.edu/~tpapp/test.tar.gz):
typedef struct {
Display *display;
Window window;
} window_data;
/***************************************************************************
* create_window -- create window, save it in wd_pointer, start event loop *
***************************************************************************/
int
create_window(char *display_name,
window_data **wd_pointer)
{
Window root; /* root window */
Visual *visual; /* visual */
int depth; /* depth */
XEvent ev; /* event */
int screen; /* screen */
GC gc;
Atom prots[1];
window_data *wd = malloc( sizeof(window_data) ); /* allocate window_data */
/* open display, get screen, root, visual, and depth */
wd->display = XOpenDisplay(display_name);
screen = DefaultScreen(wd->display);
root = RootWindow(wd->display, screen);
visual = DefaultVisual(wd->display, screen);
depth = DefaultDepth(wd->display, screen);
wd->window = XCreateSimpleWindow(wd->display, root, 0, 0, 100, 100, 0, 0,
WhitePixel (wd->display, screen));
/* graphics context */
gc = XCreateGC(wd->display, wd->window, 0, 0);
/* select events, map window */
XSelectInput( wd->display, wd->window,
ExposureMask | StructureNotifyMask | KeyPressMask | KeyReleaseMask |
SubstructureNotifyMask );
/* handle window closing */
prots[0] = XInternAtom(wd->display, "WM_DELETE_WINDOW", 0);
XSetWMProtocols(wd->display, wd->window, prots, 1);
XMapWindow(wd->display, wd->window); /* map window */
*wd_pointer = wd; /* set pointers before we start loop */
/* main loop */
for (;;) {
XNextEvent(wd->display, &ev);
switch (ev.type) {
case Expose:
if (ev.xexpose.count > 0)
break;
/* do nothing */
break;
case DestroyNotify:
case ClientMessage:
/* cleanup & close */
XDestroyWindow( wd->display, wd->window );
XCloseDisplay( wd->display );
return(0);
default:
break;
}
}
}
void close_window(window_data *wd)
{
XEvent ev;
ev.type = DestroyNotify;
XSendEvent(wd->display, wd->window, 0, 0, &ev);
}
Any suggestions would be appreciated.
Thanks,
Tamas
On 2007-06-13, Tamas Papp <······@gmail.com> wrote:
> (do ()
> ((not (cffi:null-pointer-p (cffi:mem-ref wd-pointer :pointer)))))
Although this "works", it is not quite what I meant when I said
"condition variable". ;-)
David Lichteblau <···········@lichteblau.com> writes:
> On 2007-06-13, Tamas Papp <······@gmail.com> wrote:
>> (do ()
>> ((not (cffi:null-pointer-p (cffi:mem-ref wd-pointer :pointer)))))
>
> Although this "works", it is not quite what I meant when I said
> "condition variable". ;-)
Thanks, I mean to clean up this code when I resolve the more
fundamental problems (such as the one I mentioned in this thread).
Tamas
Tamas Papp wrote:
> Hi,
>
> I am trying to create an X11 window from Lisp in a thread. The idea
> is that once it is created, a pointer to a structure with the window
> information is returned, and the X11 event loop runs in the
> background. But something strange happens: the when the window will
> only get the events when it comes into focus. I already asked on the
> X11 mailing list, but they couldn't help, so I thought it might be
> something I am not aware of with SBCL's threads.>
Just curious, and not directly helpful - is there a reason for
not using CLX? I'm just worried you're going through the trouble of
an FFI binding to use X11 graphics, when a mature lisp X11 binding
exists that doesn't need FFI (since X11 is actually a wire protocol).
David Golden wrote:
> Just curious, and not directly helpful - is there a reason for
> not using CLX?
[Never mind, I see your earlier postings re your cairo2 project now]
Tamas Papp wrote:
> void close_window(window_data *wd)
> {
> XEvent ev;
> ev.type = DestroyNotify;
> XSendEvent(wd->display, wd->window, 0, 0, &ev);
> }
>
> Any suggestions would be appreciated.
>
Anyhow, if you are committed to doing things this (odd) way, then I
think you very probably want to XSync(display, false) after your
XSendEvent() in close_window().
I haven't tested whether that's the actual problem, but give it a
go, I don't quite see how it could work without it.
David Golden <············@oceanfree.net> writes:
> Anyhow, if you are committed to doing things this (odd) way, then I
> think you very probably want to XSync(display, false) after your
> XSendEvent() in close_window().
>
> I haven't tested whether that's the actual problem, but give it a
> go, I don't quite see how it could work without it.
David,
Thanks for the suggestion -- it actually does solve some of my
problems. And it turns out that it is at least a workaround for the
rest: when writing on a pixmap with Cairo, XDamage creates
DamageNotify events but does not flush the queue. Once I learn how to
make it do that, I will release another version of cl-cairo2, now with
X11 support.
Thanks again,
Tamas