/*
- * 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
#include <pthread.h>
#include <X11/Xlib.h>
#include <X11/Xutil.h>
+#include <X11/XKBlib.h>
+#include <X11/XF86keysym.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include <termios.h>
+#include <signal.h>
#include <linux/kd.h>
#define PFX "op_runfbapp: "
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;
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;
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;
}
}
exit(1);
}
+ g_child_pid = pid;
+
ret = waitpid(pid, &status, 0);
if (ret < 0)
perror(PFX "waitpid");
int main(int argc, char *argv[])
{
pthread_t tid;
+ char *name;
int ret;
if (argc < 2) {
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;