ephyr: Move event processing into ephyr.c.

No more extra event structure to translate between hostx.c and
ephyr.c!

Signed-off-by: Eric Anholt <eric@anholt.net>
Reviewed-by: Julien Cristau <jcristau@debian.org>
This commit is contained in:
Eric Anholt 2013-08-18 18:38:29 +02:00
parent 847c856eff
commit 46cf6bf569
3 changed files with 315 additions and 392 deletions

View File

@ -27,6 +27,9 @@
#include <kdrive-config.h>
#endif
#include <xcb/xcb_keysyms.h>
#include <X11/keysym.h>
#include "ephyr.h"
#include "inputstr.h"
@ -799,13 +802,13 @@ ephyrCrossScreen(ScreenPtr pScreen, Bool entering)
{
}
int ephyrCurScreen; /*current event screen */
ScreenPtr ephyrCursorScreen; /* screen containing the cursor */
static void
ephyrWarpCursor(DeviceIntPtr pDev, ScreenPtr pScreen, int x, int y)
{
OsBlockSIGIO();
ephyrCurScreen = pScreen->myNum;
ephyrCursorScreen = pScreen;
miPointerWarpCursor(inputInfo.pointer, pScreen, x, y);
OsReleaseSIGIO();
@ -853,123 +856,324 @@ ephyrExposePairedWindow(int a_remote)
}
#endif /* XF86DRI */
static KdScreenInfo *
screen_from_window(Window w)
{
int i = 0;
for (i = 0; i < screenInfo.numScreens; i++) {
ScreenPtr pScreen = screenInfo.screens[i];
KdPrivScreenPtr kdscrpriv = KdGetScreenPriv(pScreen);
KdScreenInfo *screen = kdscrpriv->screen;
EphyrScrPriv *scrpriv = screen->driver;
if (scrpriv->win == w
|| scrpriv->peer_win == w
|| scrpriv->win_pre_existing == w) {
return screen;
}
}
return NULL;
}
static void
ephyrProcessErrorEvent(xcb_generic_event_t *xev)
{
xcb_generic_error_t *e = (xcb_generic_error_t *)xev;
FatalError("X11 error\n"
"Error code: %hhu\n"
"Sequence number: %hu\n"
"Major code: %hhu\tMinor code: %hu\n"
"Error value: %u\n",
e->error_code,
e->sequence,
e->major_code, e->minor_code,
e->resource_id);
}
static void
ephyrProcessExpose(xcb_generic_event_t *xev)
{
xcb_expose_event_t *expose = (xcb_expose_event_t *)xev;
KdScreenInfo *screen = screen_from_window(expose->window);
EphyrScrPriv *scrpriv = screen->driver;
/* Wait for the last expose event in a series of cliprects
* to actually paint our screen.
*/
if (expose->count != 0)
return;
if (scrpriv) {
hostx_paint_rect(scrpriv->screen, 0, 0, 0, 0,
scrpriv->win_width,
scrpriv->win_height);
} else {
EPHYR_LOG_ERROR("failed to get host screen\n");
#ifdef XF86DRI
/*
* We only receive expose events when the expose event
* have be generated for a drawable that is a host X
* window managed by Xephyr. Host X windows managed by
* Xephyr exists for instance when Xephyr is asked to
* create a GL drawable in a DRI environment.
*/
ephyrExposePairedWindow(expose->window);
#endif /* XF86DRI */
}
}
static void
ephyrProcessMouseMotion(xcb_generic_event_t *xev)
{
xcb_motion_notify_event_t *motion = (xcb_motion_notify_event_t *)xev;
KdScreenInfo *screen = screen_from_window(motion->event);
if (!ephyrMouse ||
!((EphyrPointerPrivate *) ephyrMouse->driverPrivate)->enabled) {
EPHYR_LOG("skipping mouse motion:%d\n", screen->pScreen->myNum);
return;
}
if (ephyrCursorScreen != screen->pScreen) {
EPHYR_LOG("warping mouse cursor. "
"cur_screen%d, motion_screen:%d\n",
ephyrCursorScreen, screen->pScreen->myNum);
ephyrWarpCursor(inputInfo.pointer, screen->pScreen,
motion->event_x, motion->event_y);
}
else {
int x = 0, y = 0;
#ifdef XF86DRI
EphyrWindowPair *pair = NULL;
#endif
EPHYR_LOG("enqueuing mouse motion:%d\n", ephyrCurScreen);
x = motion->event_x;
y = motion->event_y;
EPHYR_LOG("initial (x,y):(%d,%d)\n", x, y);
#ifdef XF86DRI
EPHYR_LOG("is this window peered by a gl drawable ?\n");
if (findWindowPairFromRemote(motion->event, &pair)) {
EPHYR_LOG("yes, it is peered\n");
x += pair->local->drawable.x;
y += pair->local->drawable.y;
}
else {
EPHYR_LOG("no, it is not peered\n");
}
EPHYR_LOG("final (x,y):(%d,%d)\n", x, y);
#endif
KdEnqueuePointerEvent(ephyrMouse, mouseState, x, y, 0);
}
}
static void
ephyrProcessButtonPress(xcb_generic_event_t *xev)
{
xcb_button_press_event_t *button = (xcb_button_press_event_t *)xev;
if (!ephyrMouse ||
!((EphyrPointerPrivate *) ephyrMouse->driverPrivate)->enabled) {
EPHYR_LOG("skipping mouse press:%d\n", ephyrCurScreen);
return;
}
ephyrUpdateModifierState(button->state);
/* This is a bit hacky. will break for button 5 ( defined as 0x10 )
* Check KD_BUTTON defines in kdrive.h
*/
mouseState |= 1 << (button->detail - 1);
EPHYR_LOG("enqueuing mouse press:%d\n", ephyrCurScreen);
KdEnqueuePointerEvent(ephyrMouse, mouseState | KD_MOUSE_DELTA, 0, 0, 0);
}
static void
ephyrProcessButtonRelease(xcb_generic_event_t *xev)
{
xcb_button_press_event_t *button = (xcb_button_press_event_t *)xev;
if (!ephyrMouse ||
!((EphyrPointerPrivate *) ephyrMouse->driverPrivate)->enabled) {
return;
}
ephyrUpdateModifierState(button->state);
mouseState &= ~(1 << (button->detail - 1));
EPHYR_LOG("enqueuing mouse release:%d\n", ephyrCurScreen);
KdEnqueuePointerEvent(ephyrMouse, mouseState | KD_MOUSE_DELTA, 0, 0, 0);
}
static void
ephyrProcessKeyPress(xcb_generic_event_t *xev)
{
xcb_key_press_event_t *key = (xcb_key_press_event_t *)xev;
if (!ephyrKbd ||
!((EphyrKbdPrivate *) ephyrKbd->driverPrivate)->enabled) {
return;
}
ephyrUpdateModifierState(key->state);
KdEnqueueKeyboardEvent(ephyrKbd, key->detail, FALSE);
}
static void
ephyrProcessKeyRelease(xcb_generic_event_t *xev)
{
xcb_connection_t *conn = hostx_get_xcbconn();
xcb_key_release_event_t *key = (xcb_key_release_event_t *)xev;
static xcb_key_symbols_t *keysyms;
static int grabbed_screen = -1;
if (!keysyms)
keysyms = xcb_key_symbols_alloc(conn);
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)) {
KdScreenInfo *screen = screen_from_window(key->event);
EphyrScrPriv *scrpriv = screen->driver;
if (grabbed_screen != -1) {
xcb_ungrab_keyboard(conn, XCB_TIME_CURRENT_TIME);
xcb_ungrab_pointer(conn, XCB_TIME_CURRENT_TIME);
grabbed_screen = -1;
hostx_set_win_title(screen,
"(ctrl+shift grabs mouse and keyboard)");
}
else {
/* Attempt grab */
xcb_grab_keyboard_cookie_t kbgrabc =
xcb_grab_keyboard(conn,
TRUE,
scrpriv->win,
XCB_TIME_CURRENT_TIME,
XCB_GRAB_MODE_ASYNC,
XCB_GRAB_MODE_ASYNC);
xcb_grab_keyboard_reply_t *kbgrabr;
xcb_grab_pointer_cookie_t pgrabc =
xcb_grab_pointer(conn,
TRUE,
scrpriv->win,
0,
XCB_GRAB_MODE_ASYNC,
XCB_GRAB_MODE_ASYNC,
scrpriv->win,
XCB_NONE,
XCB_TIME_CURRENT_TIME);
xcb_grab_pointer_reply_t *pgrabr;
kbgrabr = xcb_grab_keyboard_reply(conn, kbgrabc, NULL);
if (!kbgrabr || kbgrabr->status != XCB_GRAB_STATUS_SUCCESS) {
xcb_discard_reply(conn, pgrabc.sequence);
xcb_ungrab_pointer(conn, XCB_TIME_CURRENT_TIME);
} else {
pgrabr = xcb_grab_pointer_reply(conn, pgrabc, NULL);
if (!pgrabr || pgrabr->status != XCB_GRAB_STATUS_SUCCESS)
{
xcb_ungrab_keyboard(conn,
XCB_TIME_CURRENT_TIME);
} else {
grabbed_screen = scrpriv->mynum;
hostx_set_win_title
(screen,
"(ctrl+shift releases mouse and keyboard)");
}
}
}
}
if (!ephyrKbd ||
!((EphyrKbdPrivate *) ephyrKbd->driverPrivate)->enabled) {
return;
}
/* Still send the release event even if above has happened server
* will get confused with just an up event. Maybe it would be
* better to just block shift+ctrls getting to kdrive all
* together.
*/
ephyrUpdateModifierState(key->state);
KdEnqueueKeyboardEvent(ephyrKbd, key->detail, TRUE);
}
static void
ephyrProcessConfigureNotify(xcb_generic_event_t *xev)
{
xcb_configure_notify_event_t *configure =
(xcb_configure_notify_event_t *)xev;
KdScreenInfo *screen = screen_from_window(configure->window);
EphyrScrPriv *scrpriv = screen->driver;
if (!scrpriv ||
(scrpriv->win_pre_existing == None && !EphyrWantResize)) {
return;
}
#ifdef RANDR
ephyrResizeScreen(screen->pScreen, configure->width, configure->height);
#endif /* RANDR */
}
void
ephyrPoll(void)
{
EphyrHostXEvent ev;
xcb_connection_t *conn = hostx_get_xcbconn();
while (hostx_get_event(&ev)) {
switch (ev.type) {
case EPHYR_EV_MOUSE_MOTION:
if (!ephyrMouse ||
!((EphyrPointerPrivate *) ephyrMouse->driverPrivate)->enabled) {
EPHYR_LOG("skipping mouse motion:%d\n", ephyrCurScreen);
continue;
}
{
if (ev.data.mouse_motion.screen >= 0
&& (ephyrCurScreen != ev.data.mouse_motion.screen)) {
EPHYR_LOG("warping mouse cursor. "
"cur_screen%d, motion_screen:%d\n",
ephyrCurScreen, ev.data.mouse_motion.screen);
if (ev.data.mouse_motion.screen >= 0) {
ephyrWarpCursor
(inputInfo.pointer,
screenInfo.screens[ev.data.mouse_motion.screen],
ev.data.mouse_motion.x, ev.data.mouse_motion.y);
}
}
else {
int x = 0, y = 0;
#ifdef XF86DRI
EphyrWindowPair *pair = NULL;
#endif
EPHYR_LOG("enqueuing mouse motion:%d\n", ephyrCurScreen);
x = ev.data.mouse_motion.x;
y = ev.data.mouse_motion.y;
EPHYR_LOG("initial (x,y):(%d,%d)\n", x, y);
#ifdef XF86DRI
EPHYR_LOG("is this window peered by a gl drawable ?\n");
if (findWindowPairFromRemote(ev.data.mouse_motion.window,
&pair)) {
EPHYR_LOG("yes, it is peered\n");
x += pair->local->drawable.x;
y += pair->local->drawable.y;
}
else {
EPHYR_LOG("no, it is not peered\n");
}
EPHYR_LOG("final (x,y):(%d,%d)\n", x, y);
#endif
KdEnqueuePointerEvent(ephyrMouse, mouseState, x, y, 0);
}
}
break;
case EPHYR_EV_MOUSE_PRESS:
if (!ephyrMouse ||
!((EphyrPointerPrivate *) ephyrMouse->driverPrivate)->enabled) {
EPHYR_LOG("skipping mouse press:%d\n", ephyrCurScreen);
continue;
}
EPHYR_LOG("enqueuing mouse press:%d\n", ephyrCurScreen);
ephyrUpdateModifierState(ev.key_state);
mouseState |= ev.data.mouse_down.button_num;
KdEnqueuePointerEvent(ephyrMouse, mouseState | KD_MOUSE_DELTA, 0, 0,
0);
break;
case EPHYR_EV_MOUSE_RELEASE:
if (!ephyrMouse ||
!((EphyrPointerPrivate *) ephyrMouse->driverPrivate)->enabled)
continue;
ephyrUpdateModifierState(ev.key_state);
mouseState &= ~ev.data.mouse_up.button_num;
EPHYR_LOG("enqueuing mouse release:%d\n", ephyrCurScreen);
KdEnqueuePointerEvent(ephyrMouse, mouseState | KD_MOUSE_DELTA, 0, 0,
0);
break;
case EPHYR_EV_KEY_PRESS:
if (!ephyrKbd ||
!((EphyrKbdPrivate *) ephyrKbd->driverPrivate)->enabled)
continue;
ephyrUpdateModifierState(ev.key_state);
KdEnqueueKeyboardEvent(ephyrKbd, ev.data.key_down.scancode, FALSE);
break;
case EPHYR_EV_KEY_RELEASE:
if (!ephyrKbd ||
!((EphyrKbdPrivate *) ephyrKbd->driverPrivate)->enabled)
continue;
ephyrUpdateModifierState(ev.key_state);
KdEnqueueKeyboardEvent(ephyrKbd, ev.data.key_up.scancode, TRUE);
break;
#ifdef XF86DRI
case EPHYR_EV_EXPOSE:
/*
* We only receive expose events when the expose event have
* be generated for a drawable that is a host X window managed
* by Xephyr. Host X windows managed by Xephyr exists for instance
* when Xephyr is asked to create a GL drawable in a DRI environment.
while (TRUE) {
xcb_generic_event_t *xev = xcb_poll_for_event(conn);
if (!xev) {
/* If our XCB connection has died (for example, our window was
* closed), exit now.
*/
ephyrExposePairedWindow(ev.data.expose.window);
break;
#endif /* XF86DRI */
if (xcb_connection_has_error(conn)) {
CloseWellKnownConnections();
OsCleanup(1);
exit(1);
}
#ifdef RANDR
case EPHYR_EV_CONFIGURE:
ephyrResizeScreen(screenInfo.screens[ev.data.configure.screen],
ev.data.configure.width,
ev.data.configure.height);
break;
#endif /* RANDR */
default:
break;
}
switch (xev->response_type & 0x7f) {
case 0:
ephyrProcessErrorEvent(xev);
break;
case XCB_EXPOSE:
ephyrProcessExpose(xev);
break;
case XCB_MOTION_NOTIFY:
ephyrProcessMouseMotion(xev);
break;
case XCB_KEY_PRESS:
ephyrProcessKeyPress(xev);
break;
case XCB_KEY_RELEASE:
ephyrProcessKeyRelease(xev);
break;
case XCB_BUTTON_PRESS:
ephyrProcessButtonPress(xev);
break;
case XCB_BUTTON_RELEASE:
ephyrProcessButtonRelease(xev);
break;
case XCB_CONFIGURE_NOTIFY:
ephyrProcessConfigureNotify(xev);
break;
}
free(xev);
}
}

View File

@ -853,231 +853,6 @@ hostx_load_keymap(void)
ephyrKeySyms.maxKeyCode = max_keycode;
}
static KdScreenInfo *
screen_from_window(Window w)
{
int index = 0;
for (index = 0; index < HostX.n_screens; index++) {
EphyrScrPriv *scrpriv = HostX.screens[index]->driver;
if (scrpriv->win == w
|| scrpriv->peer_win == w
|| scrpriv->win_pre_existing == w) {
return HostX.screens[index];
}
}
return NULL;
}
int
hostx_get_event(EphyrHostXEvent * ev)
{
xcb_generic_event_t *xev;
static int grabbed_screen = -1;
static xcb_key_symbols_t *keysyms;
if (!keysyms)
keysyms = xcb_key_symbols_alloc(HostX.conn);
xev = xcb_poll_for_event(HostX.conn);
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);
}
return 0;
}
switch (xev->response_type & 0x7f) {
case 0: { /* error */
xcb_generic_error_t *e = (xcb_generic_error_t *)xev;
fprintf(stderr, "X11 error\n"
"Error code: %hhu\n"
"Sequence number: %hu\n"
"Major code: %hhu\tMinor code: %hu\n"
"Error value: %u\n",
e->error_code,
e->sequence,
e->major_code, e->minor_code,
e->resource_id);
free(xev);
exit(1);
}
case XCB_EXPOSE: {
xcb_expose_event_t *expose = (xcb_expose_event_t *)xev;
KdScreenInfo *screen = screen_from_window(expose->window);
EphyrScrPriv *scrpriv = screen->driver;
/* Wait for the last expose event in a series of cliprects
* to actually paint our screen.
*/
if (expose->count != 0)
break;
if (scrpriv) {
hostx_paint_rect(screen, 0, 0, 0, 0,
scrpriv->win_width,
scrpriv->win_height);
}
else {
EPHYR_LOG_ERROR("failed to get host screen\n");
ev->type = EPHYR_EV_EXPOSE;
ev->data.expose.window = expose->window;
free(xev);
return 1;
}
return 0;
}
case XCB_MOTION_NOTIFY: {
xcb_motion_notify_event_t *motion = (xcb_motion_notify_event_t *)xev;
KdScreenInfo *screen = screen_from_window(motion->event);
EphyrScrPriv *scrpriv = screen->driver;
ev->type = EPHYR_EV_MOUSE_MOTION;
ev->data.mouse_motion.x = motion->event_x;
ev->data.mouse_motion.y = motion->event_y;
ev->data.mouse_motion.window = motion->event;
ev->data.mouse_motion.screen = scrpriv ? scrpriv->mynum : -1;
free(xev);
return 1;
}
case XCB_BUTTON_PRESS: {
xcb_button_press_event_t *button = (xcb_button_press_event_t *)xev;
ev->type = EPHYR_EV_MOUSE_PRESS;
ev->key_state = button->state;
/*
* This is a bit hacky. will break for button 5 ( defined as 0x10 )
* Check KD_BUTTON defines in kdrive.h
*/
ev->data.mouse_down.button_num = 1 << (button->detail - 1);
free(xev);
return 1;
}
case XCB_BUTTON_RELEASE: {
xcb_button_release_event_t *button = (xcb_button_release_event_t *)xev;
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)) {
KdScreenInfo *screen = screen_from_window(key->event);
EphyrScrPriv *scrpriv = screen->driver;
if (grabbed_screen != -1) {
xcb_ungrab_keyboard(HostX.conn, XCB_TIME_CURRENT_TIME);
xcb_ungrab_pointer(HostX.conn, XCB_TIME_CURRENT_TIME);
grabbed_screen = -1;
hostx_set_win_title(screen,
"(ctrl+shift grabs mouse and keyboard)");
}
else {
/* Attempt grab */
xcb_grab_keyboard_cookie_t kbgrabc =
xcb_grab_keyboard(HostX.conn,
TRUE,
scrpriv->win,
XCB_TIME_CURRENT_TIME,
XCB_GRAB_MODE_ASYNC,
XCB_GRAB_MODE_ASYNC);
xcb_grab_keyboard_reply_t *kbgrabr;
xcb_grab_pointer_cookie_t pgrabc =
xcb_grab_pointer(HostX.conn,
TRUE,
scrpriv->win,
0,
XCB_GRAB_MODE_ASYNC,
XCB_GRAB_MODE_ASYNC,
scrpriv->win,
XCB_NONE,
XCB_TIME_CURRENT_TIME);
xcb_grab_pointer_reply_t *pgrabr;
kbgrabr = xcb_grab_keyboard_reply(HostX.conn, kbgrabc, NULL);
if (!kbgrabr || kbgrabr->status != XCB_GRAB_STATUS_SUCCESS) {
xcb_discard_reply(HostX.conn, pgrabc.sequence);
xcb_ungrab_pointer(HostX.conn, XCB_TIME_CURRENT_TIME);
} else {
pgrabr = xcb_grab_pointer_reply(HostX.conn, pgrabc, NULL);
if (!pgrabr || pgrabr->status != XCB_GRAB_STATUS_SUCCESS)
{
xcb_ungrab_keyboard(HostX.conn,
XCB_TIME_CURRENT_TIME);
} else {
grabbed_screen = scrpriv->mynum;
hostx_set_win_title
(screen,
"(ctrl+shift releases mouse and keyboard)");
}
}
}
}
/* Still send the release event even if above has happened
* server will get confused with just an up event.
* Maybe it would be better to just block shift+ctrls getting to
* kdrive all togeather.
*/
ev->type = EPHYR_EV_KEY_RELEASE;
ev->key_state = key->state;
ev->data.key_up.scancode = key->detail;
return 1;
}
case ConfigureNotify:
{
xcb_configure_notify_event_t *configure =
(xcb_configure_notify_event_t *)xev;
KdScreenInfo *screen = screen_from_window(configure->window);
EphyrScrPriv *scrpriv = screen->driver;
if (!scrpriv ||
(scrpriv->win_pre_existing == None && !EphyrWantResize)) {
free(xev);
return 0;
}
ev->type = EPHYR_EV_CONFIGURE;
ev->data.configure.width = configure->width;
ev->data.configure.height = configure->height;
ev->data.configure.window = configure->window;
ev->data.configure.screen = scrpriv->mynum;
free(xev);
return 1;
}
default:
break;
}
free(xev);
return 0;
}
xcb_connection_t *
hostx_get_xcbconn(void)
{

View File

@ -41,65 +41,12 @@
#endif
typedef struct EphyrHostXVars EphyrHostXVars;
typedef struct EphyrHostXEvent EphyrHostXEvent;
typedef enum EphyrHostXEventType {
EPHYR_EV_MOUSE_MOTION,
EPHYR_EV_MOUSE_PRESS,
EPHYR_EV_MOUSE_RELEASE,
EPHYR_EV_KEY_PRESS,
EPHYR_EV_KEY_RELEASE,
EPHYR_EV_EXPOSE,
EPHYR_EV_CONFIGURE,
} EphyrHostXEventType;
typedef struct {
int minKeyCode;
int maxKeyCode;
} EphyrKeySyms;
struct EphyrHostXEvent {
EphyrHostXEventType type;
union {
struct mouse_motion {
int x;
int y;
int screen;
int window;
} mouse_motion;
struct mouse_down {
int button_num;
} mouse_down;
struct mouse_up {
int button_num;
} mouse_up;
struct key_up {
int scancode;
} key_up;
struct key_down {
int scancode;
} key_down;
struct expose {
int window;
} expose;
struct configure {
int width;
int height;
int screen;
int window;
} configure;
} data;
int key_state;
};
typedef struct {
VisualID visualid;
int screen;
@ -199,9 +146,6 @@ hostx_paint_rect(KdScreenInfo *screen,
void
hostx_load_keymap(void);
int
hostx_get_event(EphyrHostXEvent * ev);
xcb_connection_t *
hostx_get_xcbconn(void);