X-Git-Url: https://notaz.gp2x.de/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=frontend%2Flinux%2Fxenv.c;h=40bf92c91d5bfcdeb2673c11181fae527fda9b2c;hb=2c843d964027089a747453afc0b07d0eac5835d9;hp=3de7628e4c602f6b0a059e9924e1096d9bbd289d;hpb=0b49a8f782ef178d5aa22f189e275cfbc43967f3;p=pcsx_rearmed.git diff --git a/frontend/linux/xenv.c b/frontend/linux/xenv.c index 3de7628e..40bf92c9 100644 --- a/frontend/linux/xenv.c +++ b/frontend/linux/xenv.c @@ -1,5 +1,5 @@ /* - * (C) Gražvydas "notaz" Ignotas, 2009-2011 + * (C) Gražvydas "notaz" Ignotas, 2009-2012 * * This work is licensed under the terms of any of these licenses * (at your option): @@ -25,6 +25,8 @@ #include #include +#include "xenv.h" + #define PFX "xenv: " #define FPTR(f) typeof(f) * p##f @@ -38,6 +40,7 @@ struct xstuff { Display *display; + Window window; FPTR(XCreateBitmapFromData); FPTR(XCreatePixmapCursor); FPTR(XFreePixmap); @@ -50,11 +53,17 @@ struct xstuff { FPTR(XMapWindow); FPTR(XNextEvent); FPTR(XCheckTypedEvent); - FPTR(XUnmapWindow); + FPTR(XWithdrawWindow); FPTR(XGrabKeyboard); FPTR(XPending); FPTR(XLookupKeysym); FPTR(XkbSetDetectableAutoRepeat); + FPTR(XStoreName); + FPTR(XIconifyWindow); + FPTR(XMoveResizeWindow); + FPTR(XInternAtom); + FPTR(XSetWMHints); + FPTR(XSync); }; static struct xstuff g_xstuff; @@ -74,13 +83,14 @@ static Cursor transparent_cursor(struct xstuff *xf, Display *display, Window win return cursor; } -static int x11h_init(void) +static int x11h_init(int *xenv_flags, const char *window_title) { unsigned int display_width, display_height; Display *display; XSetWindowAttributes attributes; Window win; Visual *visual; + long evt_mask; void *x11lib; int screen; @@ -102,11 +112,17 @@ static int x11h_init(void) FPTR_LINK(g_xstuff, x11lib, XMapWindow); FPTR_LINK(g_xstuff, x11lib, XNextEvent); FPTR_LINK(g_xstuff, x11lib, XCheckTypedEvent); - FPTR_LINK(g_xstuff, x11lib, XUnmapWindow); + FPTR_LINK(g_xstuff, x11lib, XWithdrawWindow); FPTR_LINK(g_xstuff, x11lib, XGrabKeyboard); FPTR_LINK(g_xstuff, x11lib, XPending); FPTR_LINK(g_xstuff, x11lib, XLookupKeysym); FPTR_LINK(g_xstuff, x11lib, XkbSetDetectableAutoRepeat); + FPTR_LINK(g_xstuff, x11lib, XStoreName); + FPTR_LINK(g_xstuff, x11lib, XIconifyWindow); + FPTR_LINK(g_xstuff, x11lib, XMoveResizeWindow); + FPTR_LINK(g_xstuff, x11lib, XInternAtom); + FPTR_LINK(g_xstuff, x11lib, XSetWMHints); + FPTR_LINK(g_xstuff, x11lib, XSync); //XInitThreads(); @@ -132,22 +148,30 @@ static int x11h_init(void) display_height = DisplayHeight(display, screen); printf(PFX "display is %dx%d\n", display_width, display_height); - win = g_xstuff.pXCreateSimpleWindow(display, - RootWindow(display, screen), - 0, 0, display_width, display_height, 0, - BlackPixel(display, screen), - BlackPixel(display, screen)); + g_xstuff.window = win = g_xstuff.pXCreateSimpleWindow(display, + RootWindow(display, screen), 0, 0, display_width, display_height, + 0, BlackPixel(display, screen), BlackPixel(display, screen)); attributes.override_redirect = True; attributes.cursor = transparent_cursor(&g_xstuff, display, win); g_xstuff.pXChangeWindowAttributes(display, win, CWOverrideRedirect | CWCursor, &attributes); - g_xstuff.pXSelectInput(display, win, ExposureMask | FocusChangeMask | KeyPressMask | KeyReleaseMask); + if (window_title != NULL) + g_xstuff.pXStoreName(display, win, window_title); + evt_mask = ExposureMask | FocusChangeMask | PropertyChangeMask; + if (xenv_flags && (*xenv_flags & XENV_CAP_KEYS)) + evt_mask |= KeyPressMask | KeyReleaseMask; + if (xenv_flags && (*xenv_flags & XENV_CAP_MOUSE)) + evt_mask |= ButtonPressMask | ButtonReleaseMask | PointerMotionMask; + g_xstuff.pXSelectInput(display, win, evt_mask); g_xstuff.pXMapWindow(display, win); g_xstuff.pXGrabKeyboard(display, win, False, GrabModeAsync, GrabModeAsync, CurrentTime); g_xstuff.pXkbSetDetectableAutoRepeat(display, 1, NULL); // XSetIOErrorHandler + // we don't know when event dispatch will be called, so sync now + g_xstuff.pXSync(display, False); + return 0; fail2: dlclose(x11lib); @@ -157,32 +181,134 @@ fail: return -1; } -static int x11h_update(int *is_down) +static void x11h_update(int (*key_cb)(void *cb_arg, int kc, int is_pressed), + int (*mouseb_cb)(void *cb_arg, int x, int y, int button, int is_pressed), + int (*mousem_cb)(void *cb_arg, int x, int y), + void *cb_arg) { XEvent evt; + int keysym; while (g_xstuff.pXPending(g_xstuff.display)) { g_xstuff.pXNextEvent(g_xstuff.display, &evt); switch (evt.type) { - case Expose: - while (g_xstuff.pXCheckTypedEvent(g_xstuff.display, Expose, &evt)) - ; - break; + case Expose: + while (g_xstuff.pXCheckTypedEvent(g_xstuff.display, Expose, &evt)) + ; + break; + + case KeyPress: + keysym = g_xstuff.pXLookupKeysym(&evt.xkey, 0); + if (key_cb != NULL) + key_cb(cb_arg, keysym, 1); + break; + + case KeyRelease: + keysym = g_xstuff.pXLookupKeysym(&evt.xkey, 0); + if (key_cb != NULL) + key_cb(cb_arg, keysym, 0); + break; + + case ButtonPress: + if (mouseb_cb != NULL) + mouseb_cb(cb_arg, evt.xbutton.x, evt.xbutton.y, + evt.xbutton.button, 1); + break; + + case ButtonRelease: + if (mouseb_cb != NULL) + mouseb_cb(cb_arg, evt.xbutton.x, evt.xbutton.y, + evt.xbutton.button, 0); + break; + + case MotionNotify: + if (mousem_cb != NULL) + mousem_cb(cb_arg, evt.xmotion.x, evt.xmotion.y); + break; + } + } +} + +static void x11h_wait_vmstate(void) +{ + Atom wm_state = g_xstuff.pXInternAtom(g_xstuff.display, "WM_STATE", False); + XEvent evt; + int i; + + usleep(20000); + + for (i = 0; i < 20; i++) { + while (g_xstuff.pXPending(g_xstuff.display)) { + g_xstuff.pXNextEvent(g_xstuff.display, &evt); + // printf("w event %d\n", evt.type); + if (evt.type == PropertyNotify && evt.xproperty.atom == wm_state) + return; + } + usleep(200000); + } + + fprintf(stderr, PFX "timeout waiting for wm_state change\n"); +} - case KeyPress: - *is_down = 1; - return g_xstuff.pXLookupKeysym(&evt.xkey, 0); +static int x11h_minimize(void) +{ + XSetWindowAttributes attributes; + Display *display = g_xstuff.display; + Window window = g_xstuff.window; + int screen = DefaultScreen(g_xstuff.display); + int display_width, display_height; + XWMHints wm_hints; + XEvent evt; + + g_xstuff.pXWithdrawWindow(display, window, screen); - case KeyRelease: - *is_down = 0; - return g_xstuff.pXLookupKeysym(&evt.xkey, 0); - // printf("press %d\n", evt.xkey.keycode); + attributes.override_redirect = False; + g_xstuff.pXChangeWindowAttributes(display, window, + CWOverrideRedirect, &attributes); + + wm_hints.flags = StateHint; + wm_hints.initial_state = IconicState; + g_xstuff.pXSetWMHints(display, window, &wm_hints); + + g_xstuff.pXMapWindow(display, window); + + while (g_xstuff.pXNextEvent(display, &evt) == 0) + { + // printf("m event %d\n", evt.type); + switch (evt.type) + { + case FocusIn: + goto out; + default: + break; } } - return NoSymbol; +out: + g_xstuff.pXWithdrawWindow(display, window, screen); + + // must wait for some magic vmstate property change before setting override_redirect + x11h_wait_vmstate(); + + attributes.override_redirect = True; + g_xstuff.pXChangeWindowAttributes(display, window, + CWOverrideRedirect, &attributes); + + // fixup window after resize on override_redirect loss + display_width = DisplayWidth(display, screen); + display_height = DisplayHeight(display, screen); + g_xstuff.pXMoveResizeWindow(display, window, 0, 0, display_width, display_height); + + g_xstuff.pXMapWindow(display, window); + g_xstuff.pXGrabKeyboard(display, window, False, GrabModeAsync, GrabModeAsync, CurrentTime); + g_xstuff.pXkbSetDetectableAutoRepeat(display, 1, NULL); + + // we don't know when event dispatch will be called, so sync now + g_xstuff.pXSync(display, False); + + return 0; } static struct termios g_kbd_termios_saved; @@ -249,33 +375,81 @@ static void tty_end(void) g_kbdfd = -1; } -int xenv_init(void) +int xenv_init(int *xenv_flags, const char *window_title) { int ret; - ret = x11h_init(); + ret = x11h_init(xenv_flags, window_title); if (ret == 0) - return 0; + goto out; + if (xenv_flags != NULL) + *xenv_flags &= ~(XENV_CAP_KEYS | XENV_CAP_MOUSE); /* TODO? */ ret = tty_init(); if (ret == 0) - return 0; + goto out; fprintf(stderr, PFX "error: both x11h_init and tty_init failed\n"); - return -1; + ret = -1; +out: + return ret; } -int xenv_update(int *is_down) +int xenv_update(int (*key_cb)(void *cb_arg, int kc, int is_pressed), + int (*mouseb_cb)(void *cb_arg, int x, int y, int button, int is_pressed), + int (*mousem_cb)(void *cb_arg, int x, int y), + void *cb_arg) { - if (g_xstuff.display) - return x11h_update(is_down); + if (g_xstuff.display) { + x11h_update(key_cb, mouseb_cb, mousem_cb, cb_arg); + return 0; + } // TODO: read tty? return -1; } +/* blocking minimize until user maximizes again */ +int xenv_minimize(void) +{ + int ret; + + if (g_xstuff.display) { + xenv_update(NULL, NULL, NULL, NULL); + ret = x11h_minimize(); + xenv_update(NULL, NULL, NULL, NULL); + return ret; + } + + return -1; +} + void xenv_finish(void) { // TODO: cleanup X? tty_end(); } + +#if 0 +int main() +{ + int i, r, d; + + xenv_init("just a test"); + + for (i = 0; i < 5; i++) { + while ((r = xenv_update(&d)) > 0) + printf("%d %x %d\n", d, r, r); + sleep(1); + + if (i == 1) + xenv_minimize(); + printf("ll %d\n", i); + } + + printf("xenv_finish..\n"); + xenv_finish(); + + return 0; +} +#endif