From: Tamas Papp
Subject: threads and X11 problem
Date: 
Message-ID: <87myz48dc9.fsf@pu100877.student.princeton.edu>
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

From: David Lichteblau
Subject: Re: threads and X11 problem
Date: 
Message-ID: <slrnf6vb75.ffm.usenet-2006@babayaga.math.fu-berlin.de>
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". ;-)
From: Tamas Papp
Subject: Re: threads and X11 problem
Date: 
Message-ID: <87ir9s8cvx.fsf@pu100877.student.princeton.edu>
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
From: David Golden
Subject: Re: threads and X11 problem
Date: 
Message-ID: <%8Rbi.20298$j7.374352@news.indigo.ie>
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).
From: David Golden
Subject: Re: threads and X11 problem
Date: 
Message-ID: <N6Tbi.20306$j7.374160@news.indigo.ie>
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]
From: David Golden
Subject: Re: threads and X11 problem
Date: 
Message-ID: <CURbi.20303$j7.374365@news.indigo.ie>
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.





 
From: Tamas Papp
Subject: Re: threads and X11 problem
Date: 
Message-ID: <87ejkf97lk.fsf@pu100877.student.princeton.edu>
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