Skip to content

Commit

Permalink
Handle windows closing gracefully under X11 (#42)
Browse files Browse the repository at this point in the history
Request and process WM_DELETE_WINDOW events, so that clicking on the "close"
button is equivalent to calling `Graphics.close_graph`.  Subsequent graphical
operations will raise the `Graphic_failure` exception instead of killing
the program on an I/O error.

In passing, use `XPending` + `XNextEvent` instead of `XCheckMaskEvent(-1)`,
as the latter ignores client events such as WM_DELETE_WINDOW.

Co-authored-by: David Allsopp <[email protected]>
  • Loading branch information
xavierleroy and dra27 authored Jan 5, 2023
1 parent 97f6696 commit 77572a4
Show file tree
Hide file tree
Showing 3 changed files with 23 additions and 4 deletions.
15 changes: 12 additions & 3 deletions src/unix/events.c
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,12 @@ void caml_gr_handle_event(XEvent * event)
caml_gr_enqueue_event(event->type, event->xmotion.x, event->xmotion.y,
BUTTON_STATE(event->xmotion.state), 0);
break;

case ClientMessage:
if ((Atom) event->xclient.data.l[0] == caml_wm_delete_window) {
caml_gr_close_graph();
}
break;
}
}

Expand All @@ -165,8 +171,10 @@ static value caml_gr_wait_event_poll(void)
unsigned int i;

/* Process pending X events before polling */
while (XCheckMaskEvent(caml_gr_display, -1 /*all events*/, &grevent)) {
while (XPending(caml_gr_display)) {
XNextEvent(caml_gr_display, &grevent);
caml_gr_handle_event(&grevent);
caml_gr_check_open();
}
/* Poll the mouse state */
if (XQueryPointer(caml_gr_display, caml_gr_window.win,
Expand Down Expand Up @@ -232,8 +240,9 @@ static value caml_gr_wait_event_blocking(long mask)
/* Replenish our event queue from that of X11 */
caml_gr_ignore_sigio = True;
while (1) {
if (XCheckMaskEvent(caml_gr_display, -1 /*all events*/, &event)) {
if (XPending(caml_gr_display)) {
/* One event available: add it to our queue */
XNextEvent(caml_gr_display, &event);
caml_gr_handle_event(&event);
/* See if we now have a matching event */
res = caml_gr_wait_event_in_queue(mask);
Expand All @@ -245,8 +254,8 @@ static value caml_gr_wait_event_blocking(long mask)
caml_enter_blocking_section();
select(FD_SETSIZE, &readfds, NULL, NULL, NULL);
caml_leave_blocking_section();
caml_gr_check_open(); /* in case another thread closed the display */
}
caml_gr_check_open(); /* in case the display was closed in the meantime */
}
caml_gr_ignore_sigio = False;

Expand Down
2 changes: 2 additions & 0 deletions src/unix/libgraph.h
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ extern int caml_gr_color; /* Current *CAML* drawing color (can be -1) */
extern XFontStruct * caml_gr_font; /* Current font */
extern long caml_gr_selected_events; /* Events we are interested in */
extern Bool caml_gr_ignore_sigio; /* Whether to consume events on sigio */
extern Atom caml_wm_delete_window; /* "WM_DELETE_WINDOW" atom */

extern Bool caml_gr_direct_rgb;
extern int caml_gr_byte_order;
Expand Down Expand Up @@ -87,3 +88,4 @@ extern void caml_gr_handle_event(XEvent *e);
extern void caml_gr_init_color_cache(void);
extern void caml_gr_init_direct_rgb_to_pixel(void);
extern value caml_gr_id_of_window( Window w );
extern value caml_gr_close_graph(void);
10 changes: 9 additions & 1 deletion src/unix/open.c
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ long caml_gr_selected_events;
Bool caml_gr_ignore_sigio = False;
static Bool caml_gr_initialized = False;
static char * window_name = NULL;
Atom caml_wm_delete_window;

static int caml_gr_error_handler(Display *display, XErrorEvent *error);
static int caml_gr_ioerror_handler(Display *display);
Expand Down Expand Up @@ -121,6 +122,12 @@ value caml_gr_open_graph(value arg)
/* What not use XSetWMProperties? */
XSetStandardProperties(caml_gr_display, caml_gr_window.win, p, p,
None, NULL, 0, &hints);
/* Handle "please delete window" requests from window manager */
caml_wm_delete_window =
XInternAtom(caml_gr_display, "WM_DELETE_WINDOW", False);
XSetWMProtocols(caml_gr_display, caml_gr_window.win,
&caml_wm_delete_window, 1);

caml_gr_window.gc = XCreateGC(caml_gr_display, caml_gr_window.win, 0, NULL);
XSetBackground(caml_gr_display, caml_gr_window.gc, caml_gr_background);
XSetForeground(caml_gr_display, caml_gr_window.gc, caml_gr_black);
Expand Down Expand Up @@ -353,7 +360,8 @@ value caml_gr_sigio_handler(void)
XEvent grevent;

if (caml_gr_initialized && !caml_gr_ignore_sigio) {
while (XCheckMaskEvent(caml_gr_display, -1 /*all events*/, &grevent)) {
while (XPending(caml_gr_display)) {
XNextEvent(caml_gr_display, &grevent);
caml_gr_handle_event(&grevent);
}
}
Expand Down

0 comments on commit 77572a4

Please sign in to comment.