From 9cd21769ec7851e62c7feff9cd67868a4f356b52 Mon Sep 17 00:00:00 2001 From: Grazvydas Ignotas Date: Mon, 9 Apr 2012 22:38:58 +0300 Subject: [PATCH] op_runfbapp: minimize on pnd btn press --- op_runfbapp.c | 117 +++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 110 insertions(+), 7 deletions(-) diff --git a/op_runfbapp.c b/op_runfbapp.c index da0a1c8..2226827 100644 --- a/op_runfbapp.c +++ b/op_runfbapp.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010, Gražvydas Ignotas + * Copyright (c) 2010,2012 Gražvydas Ignotas * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -30,6 +30,8 @@ #include #include #include +#include +#include #include #include @@ -38,6 +40,7 @@ #include #include #include +#include #include #define PFX "op_runfbapp: " @@ -45,6 +48,7 @@ static struct termios g_kbd_termios_saved; static int g_kbdfd = -1; static int g_have_x; +static pid_t g_child_pid; static pthread_cond_t g_start_cond = PTHREAD_COND_INITIALIZER; static pthread_mutex_t g_start_mutex = PTHREAD_MUTEX_INITIALIZER; @@ -70,12 +74,88 @@ static Cursor transparent_cursor(Display *display, Window win) return cursor; } +static void x11h_wait_vmstate(Display *display) +{ + Atom wm_state = XInternAtom(display, "WM_STATE", False); + XEvent evt; + int i; + + for (i = 0; i < 20; i++) { + while (XPending(display)) { + XNextEvent(display, &evt); + if (evt.type == PropertyNotify && evt.xproperty.atom == wm_state) + return; + } + usleep(200000); + } + + fprintf(stderr, "timeout waiting for wm_state change\n"); +} + +static int x11h_minimize(Display *display, Window window) +{ + XSetWindowAttributes attributes; + int screen = DefaultScreen(display); + int display_width, display_height; + XWMHints wm_hints; + XEvent evt; + + XWithdrawWindow(display, window, screen); + + attributes.override_redirect = False; + XChangeWindowAttributes(display, window, + CWOverrideRedirect, &attributes); + + wm_hints.flags = StateHint; + wm_hints.initial_state = IconicState; + XSetWMHints(display, window, &wm_hints); + + XMapWindow(display, window); + + while (XNextEvent(display, &evt) == 0) + { + // printf("m event %d\n", evt.type); + switch (evt.type) + { + case FocusIn: + goto out; + default: + break; + } + } + +out: + XWithdrawWindow(display, window, screen); + + // must wait for some magic vmstate property change before setting override_redirect + x11h_wait_vmstate(display); + + attributes.override_redirect = True; + XChangeWindowAttributes(display, window, + CWOverrideRedirect, &attributes); + + // fixup window after resize on override_redirect loss + display_width = DisplayWidth(display, screen); + display_height = DisplayHeight(display, screen); + XMoveResizeWindow(display, window, 0, 0, display_width, display_height); + + XMapWindow(display, window); + XGrabKeyboard(display, window, False, GrabModeAsync, GrabModeAsync, CurrentTime); + XkbSetDetectableAutoRepeat(display, 1, NULL); + + // we don't know when event dispatch will be called, so sync now + XSync(display, False); + + return 0; +} + static void *x11_handler(void *arg) { unsigned int display_width, display_height; XSetWindowAttributes attributes; + const char *window_title = arg; Window win; - XEvent report; + XEvent evt; Display *display; int screen; @@ -104,19 +184,33 @@ static void *x11_handler(void *arg) attributes.cursor = transparent_cursor(display, win); XChangeWindowAttributes(display, win, CWOverrideRedirect | CWCursor, &attributes); - XSelectInput(display, win, ExposureMask); + XStoreName(display, win, window_title); + XSelectInput(display, win, ExposureMask | FocusChangeMask + | KeyPressMask | KeyReleaseMask | PropertyChangeMask); XMapWindow(display, win); XGrabKeyboard(display, win, False, GrabModeAsync, GrabModeAsync, CurrentTime); + XkbSetDetectableAutoRepeat(display, 1, NULL); XSync(display, False); while (1) { - XNextEvent(display, &report); + XNextEvent(display, &evt); - if (report.type == Expose) { + switch (evt.type) { + case Expose: signal_main_thread(); - while (XCheckTypedEvent(display, Expose, &report)) + while (XCheckTypedEvent(display, Expose, &evt)) ; + break; + + case KeyPress: + if (XLookupKeysym(&evt.xkey, 0) == XF86XK_MenuKB + && g_child_pid != 0) { + kill(g_child_pid, SIGSTOP); + x11h_minimize(display, win); + kill(g_child_pid, SIGCONT); + } + break; } } @@ -201,6 +295,8 @@ static void do_exec(char * const argv[]) exit(1); } + g_child_pid = pid; + ret = waitpid(pid, &status, 0); if (ret < 0) perror(PFX "waitpid"); @@ -209,6 +305,7 @@ static void do_exec(char * const argv[]) int main(int argc, char *argv[]) { pthread_t tid; + char *name; int ret; if (argc < 2) { @@ -218,7 +315,13 @@ int main(int argc, char *argv[]) pthread_mutex_lock(&g_start_mutex); - ret = pthread_create(&tid, NULL, x11_handler, NULL); + name = strrchr(argv[1], '/'); + if (name == NULL) + name = argv[1]; + else + name++; + + ret = pthread_create(&tid, NULL, x11_handler, name); if (ret != 0) { fprintf(stderr, PFX "pthread_create: %d\n", ret); return 1; -- 2.39.5