From a805c8556900f3abca95c6b6536a9c267f8135fc Mon Sep 17 00:00:00 2001 From: notaz Date: Sun, 8 Jan 2012 19:23:52 +0200 Subject: [PATCH] frontend: add minimize support --- frontend/linux/xenv.c | 161 +++++++++++++++++++++++++++++++++++++--- frontend/linux/xenv.h | 3 +- frontend/main.c | 3 + frontend/main.h | 1 + frontend/menu.c | 3 + frontend/plat.h | 1 + frontend/plat_dummy.c | 4 + frontend/plat_omap.c | 9 ++- frontend/plat_pandora.c | 1 + frontend/plat_pollux.c | 4 + maemo/hildon.c | 4 + 11 files changed, 180 insertions(+), 14 deletions(-) diff --git a/frontend/linux/xenv.c b/frontend/linux/xenv.c index 3de7628e..f54e57d2 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): @@ -38,6 +38,7 @@ struct xstuff { Display *display; + Window window; FPTR(XCreateBitmapFromData); FPTR(XCreatePixmapCursor); FPTR(XFreePixmap); @@ -50,11 +51,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,7 +81,7 @@ static Cursor transparent_cursor(struct xstuff *xf, Display *display, Window win return cursor; } -static int x11h_init(void) +static int x11h_init(const char *window_title) { unsigned int display_width, display_height; Display *display; @@ -102,11 +109,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 +145,25 @@ 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); + g_xstuff.pXStoreName(display, win, window_title); + g_xstuff.pXSelectInput(display, win, + ExposureMask | FocusChangeMask | KeyPressMask | KeyReleaseMask | PropertyChangeMask); 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); @@ -169,6 +185,8 @@ static int x11h_update(int *is_down) case Expose: while (g_xstuff.pXCheckTypedEvent(g_xstuff.display, Expose, &evt)) ; + default: + // printf("event %d\n", evt.type); break; case KeyPress: @@ -185,6 +203,86 @@ static int x11h_update(int *is_down) return NoSymbol; } +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); + } + + printf("timeout waiting for wm_state change\n"); +} + +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); + + 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; + } + } + +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; static int g_kbdfd = -1; @@ -249,11 +347,11 @@ static void tty_end(void) g_kbdfd = -1; } -int xenv_init(void) +int xenv_init(const char *window_title) { int ret; - ret = x11h_init(); + ret = x11h_init(window_title); if (ret == 0) return 0; @@ -274,8 +372,47 @@ int xenv_update(int *is_down) return -1; } +/* blocking minimize until user maximazes again */ +int xenv_minimize(void) +{ + int ret, dummy; + + if (g_xstuff.display) { + xenv_update(&dummy); + ret = x11h_minimize(); + xenv_update(&dummy); + 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 diff --git a/frontend/linux/xenv.h b/frontend/linux/xenv.h index 948381e5..1afad9da 100644 --- a/frontend/linux/xenv.h +++ b/frontend/linux/xenv.h @@ -1,5 +1,6 @@ -int xenv_init(void); +int xenv_init(const char *window_title); int xenv_update(int *is_down); +int xenv_minimize(void); void xenv_finish(void); diff --git a/frontend/main.c b/frontend/main.c index 7b3aac53..d7f23ed4 100644 --- a/frontend/main.c +++ b/frontend/main.c @@ -250,6 +250,9 @@ void do_emu_action(void) case SACTION_VOLUME_DOWN: plat_step_volume(emu_action == SACTION_VOLUME_UP); return; + case SACTION_MINIMIZE: + plat_minimize(); + return; default: return; } diff --git a/frontend/main.h b/frontend/main.h index bc6c2673..22a42f6e 100644 --- a/frontend/main.h +++ b/frontend/main.h @@ -60,6 +60,7 @@ enum sched_action { SACTION_SCREENSHOT, SACTION_VOLUME_UP, SACTION_VOLUME_DOWN, + SACTION_MINIMIZE, SACTION_GUN_TRIGGER = 16, SACTION_GUN_A, SACTION_GUN_B, diff --git a/frontend/menu.c b/frontend/menu.c index c6a52ded..1e647189 100644 --- a/frontend/menu.c +++ b/frontend/menu.c @@ -756,6 +756,9 @@ me_bind_action emuctrl_actions[] = { "Toggle Frameskip ", 1 << SACTION_TOGGLE_FSKIP }, { "Take Screenshot ", 1 << SACTION_SCREENSHOT }, { "Enter Menu ", 1 << SACTION_ENTER_MENU }, +#ifdef __ARM_ARCH_7A__ /* XXX */ + { "Minimize ", 1 << SACTION_MINIMIZE }, +#endif { "Gun Trigger ", 1 << SACTION_GUN_TRIGGER }, { "Gun A button ", 1 << SACTION_GUN_A }, { "Gun B button ", 1 << SACTION_GUN_B }, diff --git a/frontend/plat.h b/frontend/plat.h index 185ee98c..6a22035f 100644 --- a/frontend/plat.h +++ b/frontend/plat.h @@ -1,3 +1,4 @@ +void plat_minimize(void); void *plat_prepare_screenshot(int *w, int *h, int *bpp); void plat_step_volume(int is_up); int plat_cpu_clock_get(void); diff --git a/frontend/plat_dummy.c b/frontend/plat_dummy.c index e768946a..7929015c 100644 --- a/frontend/plat_dummy.c +++ b/frontend/plat_dummy.c @@ -71,3 +71,7 @@ void plat_step_volume(int is_up) void plat_trigger_vibrate(void) { } + +void plat_minimize(void) +{ +} diff --git a/frontend/plat_omap.c b/frontend/plat_omap.c index b529cfab..62f198b5 100644 --- a/frontend/plat_omap.c +++ b/frontend/plat_omap.c @@ -121,6 +121,13 @@ void plat_video_menu_leave(void) fprintf(stderr, "warning: vout_fbdev_resize failed\n"); } +void plat_minimize(void) +{ + omap_enable_layer(0); + xenv_minimize(); + omap_enable_layer(1); +} + void plat_step_volume(int is_up) { } @@ -158,7 +165,7 @@ void plat_init(void) exit(1); } - xenv_init(); + xenv_init("PCSX-ReARMed"); w = h = 0; main_fb = vout_fbdev_init(main_fb_name, &w, &h, 16, 2); diff --git a/frontend/plat_pandora.c b/frontend/plat_pandora.c index d869d245..1c079243 100644 --- a/frontend/plat_pandora.c +++ b/frontend/plat_pandora.c @@ -53,6 +53,7 @@ struct in_default_bind in_evdev_defbinds[] = { { KEY_RIGHTCTRL, IN_BINDTYPE_PLAYER12, DKEY_R1 }, { KEY_Q, IN_BINDTYPE_PLAYER12, DKEY_L2 }, { KEY_P, IN_BINDTYPE_PLAYER12, DKEY_R2 }, + { KEY_TAB, IN_BINDTYPE_EMU, SACTION_MINIMIZE }, { KEY_SPACE, IN_BINDTYPE_EMU, SACTION_ENTER_MENU }, { KEY_1, IN_BINDTYPE_EMU, SACTION_SAVE_STATE }, { KEY_2, IN_BINDTYPE_EMU, SACTION_LOAD_STATE }, diff --git a/frontend/plat_pollux.c b/frontend/plat_pollux.c index af91066f..af5b81a8 100644 --- a/frontend/plat_pollux.c +++ b/frontend/plat_pollux.c @@ -262,6 +262,10 @@ void *plat_prepare_screenshot(int *w, int *h, int *bpp) return pl_vout_buf; } +void plat_minimize(void) +{ +} + static void pl_vout_set_raw_vram(void *vram) { int i; diff --git a/maemo/hildon.c b/maemo/hildon.c index a5f151ec..03999096 100644 --- a/maemo/hildon.c +++ b/maemo/hildon.c @@ -265,3 +265,7 @@ void plat_step_volume(int is_up) void plat_trigger_vibrate(void) { } + +void plat_minimize(void) +{ +} -- 2.39.5