Xephyr: use xcb for event handling
v2: Rebase on indentation changes, squash in a simpler variant of the later event compression patch, fix server hang or segfault on window close by reimplementing the x_io_error_handler in the new XCB event loop (anholt). Reviewed-by: Mikhail Gusarov <dottedmag@dottedmag.net> (v1) Signed-off-by: Julien Cristau <jcristau@debian.org> Signed-off-by: Eric Anholt <eric@anholt.net>
This commit is contained in:
parent
ff26845252
commit
3ea75a59d5
|
@ -942,24 +942,39 @@ host_screen_from_window(Window w)
|
||||||
int
|
int
|
||||||
hostx_get_event(EphyrHostXEvent * ev)
|
hostx_get_event(EphyrHostXEvent * ev)
|
||||||
{
|
{
|
||||||
XEvent xev;
|
xcb_generic_event_t *xev;
|
||||||
static int grabbed_screen = -1;
|
static int grabbed_screen = -1;
|
||||||
static xcb_key_symbols_t *keysyms;
|
static xcb_key_symbols_t *keysyms;
|
||||||
|
|
||||||
if (!keysyms)
|
if (!keysyms)
|
||||||
keysyms = xcb_key_symbols_alloc(HostX.conn);
|
keysyms = xcb_key_symbols_alloc(HostX.conn);
|
||||||
|
|
||||||
if (XPending(HostX.dpy)) {
|
xev = xcb_poll_for_event(HostX.conn);
|
||||||
XNextEvent(HostX.dpy, &xev);
|
if (!xev) {
|
||||||
|
/* If our XCB connection has died (for example, our window was
|
||||||
|
* closed), exit now.
|
||||||
|
*/
|
||||||
|
if (xcb_connection_has_error(HostX.conn)) {
|
||||||
|
CloseWellKnownConnections();
|
||||||
|
OsCleanup(1);
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
switch (xev.type) {
|
return 0;
|
||||||
case Expose:
|
}
|
||||||
/* Not so great event compression, but works ok */
|
|
||||||
while (XCheckTypedWindowEvent(HostX.dpy, xev.xexpose.window,
|
switch (xev->response_type & 0x7f) {
|
||||||
Expose, &xev));
|
case XCB_EXPOSE: {
|
||||||
{
|
xcb_expose_event_t *expose = (xcb_expose_event_t *)xev;
|
||||||
struct EphyrHostScreen *host_screen =
|
struct EphyrHostScreen *host_screen =
|
||||||
host_screen_from_window(xev.xexpose.window);
|
host_screen_from_window(expose->window);
|
||||||
|
|
||||||
|
/* Wait for the last expose event in a series of cliprects
|
||||||
|
* to actually paint our screen.
|
||||||
|
*/
|
||||||
|
if (expose->count != 0)
|
||||||
|
break;
|
||||||
|
|
||||||
if (host_screen) {
|
if (host_screen) {
|
||||||
hostx_paint_rect(host_screen->info, 0, 0, 0, 0,
|
hostx_paint_rect(host_screen->info, 0, 0, 0, 0,
|
||||||
host_screen->win_width,
|
host_screen->win_width,
|
||||||
|
@ -968,55 +983,66 @@ hostx_get_event(EphyrHostXEvent * ev)
|
||||||
else {
|
else {
|
||||||
EPHYR_LOG_ERROR("failed to get host screen\n");
|
EPHYR_LOG_ERROR("failed to get host screen\n");
|
||||||
ev->type = EPHYR_EV_EXPOSE;
|
ev->type = EPHYR_EV_EXPOSE;
|
||||||
ev->data.expose.window = xev.xexpose.window;
|
ev->data.expose.window = expose->window;
|
||||||
|
free(xev);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
return 0;
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
case MotionNotify:
|
case XCB_MOTION_NOTIFY: {
|
||||||
{
|
xcb_motion_notify_event_t *motion = (xcb_motion_notify_event_t *)xev;
|
||||||
struct EphyrHostScreen *host_screen =
|
struct EphyrHostScreen *host_screen =
|
||||||
host_screen_from_window(xev.xmotion.window);
|
host_screen_from_window(motion->event);
|
||||||
|
|
||||||
ev->type = EPHYR_EV_MOUSE_MOTION;
|
ev->type = EPHYR_EV_MOUSE_MOTION;
|
||||||
ev->data.mouse_motion.x = xev.xmotion.x;
|
ev->data.mouse_motion.x = motion->event_x;
|
||||||
ev->data.mouse_motion.y = xev.xmotion.y;
|
ev->data.mouse_motion.y = motion->event_y;
|
||||||
ev->data.mouse_motion.window = xev.xmotion.window;
|
ev->data.mouse_motion.window = motion->event;
|
||||||
ev->data.mouse_motion.screen =
|
ev->data.mouse_motion.screen =
|
||||||
(host_screen ? host_screen->mynum : -1);
|
(host_screen ? host_screen->mynum : -1);
|
||||||
}
|
free(xev);
|
||||||
return 1;
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
case ButtonPress:
|
case XCB_BUTTON_PRESS: {
|
||||||
|
xcb_button_press_event_t *button = (xcb_button_press_event_t *)xev;
|
||||||
ev->type = EPHYR_EV_MOUSE_PRESS;
|
ev->type = EPHYR_EV_MOUSE_PRESS;
|
||||||
ev->key_state = xev.xkey.state;
|
ev->key_state = button->state;
|
||||||
/*
|
/*
|
||||||
* This is a bit hacky. will break for button 5 ( defined as 0x10 )
|
* This is a bit hacky. will break for button 5 ( defined as 0x10 )
|
||||||
* Check KD_BUTTON defines in kdrive.h
|
* Check KD_BUTTON defines in kdrive.h
|
||||||
*/
|
*/
|
||||||
ev->data.mouse_down.button_num = 1 << (xev.xbutton.button - 1);
|
ev->data.mouse_down.button_num = 1 << (button->detail - 1);
|
||||||
return 1;
|
free(xev);
|
||||||
|
|
||||||
case ButtonRelease:
|
|
||||||
ev->type = EPHYR_EV_MOUSE_RELEASE;
|
|
||||||
ev->key_state = xev.xkey.state;
|
|
||||||
ev->data.mouse_up.button_num = 1 << (xev.xbutton.button - 1);
|
|
||||||
return 1;
|
|
||||||
|
|
||||||
case KeyPress:
|
|
||||||
{
|
|
||||||
ev->type = EPHYR_EV_KEY_PRESS;
|
|
||||||
ev->key_state = xev.xkey.state;
|
|
||||||
ev->data.key_down.scancode = xev.xkey.keycode;
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
case KeyRelease:
|
|
||||||
if ((xcb_key_symbols_get_keysym(keysyms,xev.xkey.keycode, 0) == XK_Shift_L
|
case XCB_BUTTON_RELEASE: {
|
||||||
|| xcb_key_symbols_get_keysym(keysyms,xev.xkey.keycode, 0) == XK_Shift_R)
|
xcb_button_release_event_t *button = (xcb_button_release_event_t *)xev;
|
||||||
&& (xev.xkey.state & XCB_MOD_MASK_CONTROL)) {
|
ev->type = EPHYR_EV_MOUSE_RELEASE;
|
||||||
|
ev->key_state = button->state;
|
||||||
|
ev->data.mouse_up.button_num = 1 << (button->detail-1);
|
||||||
|
free(xev);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
case XCB_KEY_PRESS: {
|
||||||
|
xcb_key_press_event_t *key = (xcb_key_press_event_t *)xev;
|
||||||
|
ev->type = EPHYR_EV_KEY_PRESS;
|
||||||
|
ev->key_state = key->state;
|
||||||
|
ev->data.key_down.scancode = key->detail;
|
||||||
|
free(xev);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
case XCB_KEY_RELEASE: {
|
||||||
|
xcb_key_release_event_t *key = (xcb_key_release_event_t *)xev;
|
||||||
|
if ((xcb_key_symbols_get_keysym(keysyms, key->detail, 0) == XK_Shift_L
|
||||||
|
|| xcb_key_symbols_get_keysym(keysyms, key->detail, 0) == XK_Shift_R)
|
||||||
|
&& (key->state & XCB_MOD_MASK_CONTROL)) {
|
||||||
struct EphyrHostScreen *host_screen =
|
struct EphyrHostScreen *host_screen =
|
||||||
host_screen_from_window(xev.xexpose.window);
|
host_screen_from_window(key->event);
|
||||||
|
|
||||||
if (grabbed_screen != -1) {
|
if (grabbed_screen != -1) {
|
||||||
xcb_ungrab_keyboard(HostX.conn, XCB_TIME_CURRENT_TIME);
|
xcb_ungrab_keyboard(HostX.conn, XCB_TIME_CURRENT_TIME);
|
||||||
|
@ -1072,31 +1098,31 @@ hostx_get_event(EphyrHostXEvent * ev)
|
||||||
* kdrive all togeather.
|
* kdrive all togeather.
|
||||||
*/
|
*/
|
||||||
ev->type = EPHYR_EV_KEY_RELEASE;
|
ev->type = EPHYR_EV_KEY_RELEASE;
|
||||||
ev->key_state = xev.xkey.state;
|
ev->key_state = key->state;
|
||||||
ev->data.key_up.scancode = xev.xkey.keycode;
|
ev->data.key_up.scancode = key->detail;
|
||||||
return 1;
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
case ConfigureNotify:
|
case ConfigureNotify:
|
||||||
{
|
{
|
||||||
struct EphyrHostScreen *host_screen;
|
struct EphyrHostScreen *host_screen;
|
||||||
|
xcb_configure_notify_event_t *configure =
|
||||||
|
(xcb_configure_notify_event_t *)xev;
|
||||||
|
|
||||||
/* event compression as for Expose events, cause
|
host_screen = host_screen_from_window(configure->window);
|
||||||
* we don't want to resize the framebuffer for
|
|
||||||
* every single change */
|
|
||||||
while (XCheckTypedWindowEvent(HostX.dpy, xev.xconfigure.window,
|
|
||||||
ConfigureNotify, &xev));
|
|
||||||
host_screen = host_screen_from_window(xev.xconfigure.window);
|
|
||||||
|
|
||||||
if (!host_screen ||
|
if (!host_screen ||
|
||||||
(host_screen->win_pre_existing == None && !EphyrWantResize)) {
|
(host_screen->win_pre_existing == None && !EphyrWantResize)) {
|
||||||
|
free(xev);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
ev->type = EPHYR_EV_CONFIGURE;
|
ev->type = EPHYR_EV_CONFIGURE;
|
||||||
ev->data.configure.width = xev.xconfigure.width;
|
ev->data.configure.width = configure->width;
|
||||||
ev->data.configure.height = xev.xconfigure.height;
|
ev->data.configure.height = configure->height;
|
||||||
ev->data.configure.window = xev.xconfigure.window;
|
ev->data.configure.window = configure->window;
|
||||||
ev->data.configure.screen = host_screen->mynum;
|
ev->data.configure.screen = host_screen->mynum;
|
||||||
|
free(xev);
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
@ -1104,7 +1130,7 @@ hostx_get_event(EphyrHostXEvent * ev)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
free(xev);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue