2 * Copyright (c) 2010,2012 GraÅžvydas Ignotas
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the organization nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 * ARE DISCLAIMED. IN NO EVENT SHALL COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
22 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
23 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
24 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
25 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32 #include <X11/Xutil.h>
33 #include <X11/XKBlib.h>
34 #include <X11/XF86keysym.h>
36 #include <sys/types.h>
41 #include <sys/ioctl.h>
50 #define PFX "op_runfbapp: "
52 static struct termios g_kbd_termios_saved;
53 static int g_kbdfd = -1;
55 static pid_t g_child_pid;
56 static pthread_cond_t g_start_cond = PTHREAD_COND_INITIALIZER;
57 static pthread_mutex_t g_start_mutex = PTHREAD_MUTEX_INITIALIZER;
59 static void signal_main_thread(void)
61 pthread_mutex_lock(&g_start_mutex);
62 pthread_cond_signal(&g_start_cond);
63 pthread_mutex_unlock(&g_start_mutex);
66 static Cursor transparent_cursor(Display *display, Window win)
73 memset(&dummy, 0, sizeof(dummy));
74 pix = XCreateBitmapFromData(display, win, &d, 1, 1);
75 cursor = XCreatePixmapCursor(display, pix, pix,
76 &dummy, &dummy, 0, 0);
77 XFreePixmap(display, pix);
81 static void x11h_wait_vmstate(Display *display)
83 Atom wm_state = XInternAtom(display, "WM_STATE", False);
87 for (i = 0; i < 20; i++) {
88 while (XPending(display)) {
89 XNextEvent(display, &evt);
90 if (evt.type == PropertyNotify && evt.xproperty.atom == wm_state)
96 fprintf(stderr, "timeout waiting for wm_state change\n");
99 static struct omapfb_plane_info desktop_pi, app_pi[2];
100 static struct fb_var_screeninfo desktop_si, app_si[2];
101 static int desktop_saved;
103 static int save_fb_state(int index, struct omapfb_plane_info *pi,
104 struct fb_var_screeninfo *si)
111 snprintf(buf, sizeof(buf), "/dev/fb%d", index);
112 fd = open(buf, O_RDWR);
114 fprintf(stderr, PFX);
119 ret = ioctl(fd, OMAPFB_QUERY_PLANE, pi);
121 perror(PFX "QUERY_PLANE");
125 ret = ioctl(fd, FBIOGET_VSCREENINFO, si);
127 perror(PFX "FBIOGET_VSCREENINFO");
138 static int load_fb_state(int index, struct omapfb_plane_info *pi,
139 struct fb_var_screeninfo *si)
141 struct omapfb_plane_info tmp_pi;
147 snprintf(buf, sizeof(buf), "/dev/fb%d", index);
148 fd = open(buf, O_RDWR);
150 fprintf(stderr, PFX);
155 // resolution can sometimes only be restored if position is right,
156 // so it's a bit more tricky..
157 ret = ioctl(fd, OMAPFB_QUERY_PLANE, &tmp_pi);
159 perror(PFX "QUERY_PLANE");
166 ret = ioctl(fd, OMAPFB_SETUP_PLANE, &tmp_pi);
168 perror(PFX "SETUP_PLANE");
172 ret = ioctl(fd, FBIOPUT_VSCREENINFO, si);
174 perror(PFX "FBIOPUT_VSCREENINFO");
178 ret = ioctl(fd, OMAPFB_SETUP_PLANE, pi);
180 perror(PFX "SETUP_PLANE(2)");
191 // prepare OMAP layers for desktop
192 static int minimize_omap_layers(void)
194 struct omapfb_plane_info pi_set;
199 if (!desktop_saved) {
200 fprintf(stderr, PFX "desktop not saved\n");
204 for (i = 0; i < 2; i++) {
205 ret = save_fb_state(i, &app_pi[i], &app_si[i]);
207 fprintf(stderr, PFX "layer %d state save failed\n", i);
212 retval = 0; // no restoring needed
214 if (memcmp(&app_pi[0], &desktop_pi, sizeof(desktop_pi)) != 0) {
215 ret = load_fb_state(0, &desktop_pi, &desktop_si);
217 fprintf(stderr, PFX "desktop restore failed\n");
218 // but continue, I guess?
223 if (app_pi[1].enabled) {
227 fd = open("/dev/fb1", O_RDWR);
228 ret = ioctl(fd, OMAPFB_SETUP_PLANE, &pi_set);
230 perror(PFX "SETUP_PLANE");
241 static void restore_omap_layers(void)
245 for (i = 0; i < 2; i++) {
246 ret = load_fb_state(i, &app_pi[i], &app_si[i]);
248 fprintf(stderr, PFX "layer %d state load failed\n", i);
249 // .. but try to continue ..
254 static int x11h_minimize(Display *display, Window window)
256 XSetWindowAttributes attributes;
257 int screen = DefaultScreen(display);
258 int display_width, display_height;
262 XWithdrawWindow(display, window, screen);
264 attributes.override_redirect = False;
265 XChangeWindowAttributes(display, window,
266 CWOverrideRedirect, &attributes);
268 wm_hints.flags = StateHint;
269 wm_hints.initial_state = IconicState;
270 XSetWMHints(display, window, &wm_hints);
272 XMapWindow(display, window);
274 while (XNextEvent(display, &evt) == 0)
276 // printf("m event %d\n", evt.type);
287 XWithdrawWindow(display, window, screen);
289 // must wait for some magic vmstate property change before setting override_redirect
290 x11h_wait_vmstate(display);
292 attributes.override_redirect = True;
293 XChangeWindowAttributes(display, window,
294 CWOverrideRedirect, &attributes);
296 // fixup window after resize on override_redirect loss
297 display_width = DisplayWidth(display, screen);
298 display_height = DisplayHeight(display, screen);
299 XMoveResizeWindow(display, window, 0, 0, display_width, display_height);
301 XMapWindow(display, window);
302 XGrabKeyboard(display, window, False, GrabModeAsync, GrabModeAsync, CurrentTime);
303 XkbSetDetectableAutoRepeat(display, 1, NULL);
305 // we don't know when event dispatch will be called, so sync now
306 XSync(display, False);
311 static void *x11_handler(void *arg)
313 unsigned int display_width, display_height;
314 XSetWindowAttributes attributes;
315 const char *window_title = arg;
322 display = XOpenDisplay(NULL);
325 fprintf(stderr, PFX "(not hiding X): Can't open display: %s\n",
327 signal_main_thread();
332 screen = DefaultScreen(display);
334 display_width = DisplayWidth(display, screen);
335 display_height = DisplayHeight(display, screen);
337 win = XCreateSimpleWindow(display,
338 RootWindow(display, screen),
339 0, 0, display_width, display_height, 0,
340 BlackPixel(display, screen),
341 BlackPixel(display, screen));
343 attributes.override_redirect = True;
344 attributes.cursor = transparent_cursor(display, win);
345 XChangeWindowAttributes(display, win, CWOverrideRedirect | CWCursor, &attributes);
347 XStoreName(display, win, window_title);
348 XSelectInput(display, win, ExposureMask | FocusChangeMask
349 | KeyPressMask | KeyReleaseMask | PropertyChangeMask);
350 XMapWindow(display, win);
351 XGrabKeyboard(display, win, False, GrabModeAsync, GrabModeAsync, CurrentTime);
352 XkbSetDetectableAutoRepeat(display, 1, NULL);
353 XSync(display, False);
357 XNextEvent(display, &evt);
361 signal_main_thread();
362 while (XCheckTypedEvent(display, Expose, &evt))
367 if (XLookupKeysym(&evt.xkey, 0) == XF86XK_MenuKB
368 && g_child_pid != 0) {
369 kill(g_child_pid, SIGSTOP);
371 ret = minimize_omap_layers();
375 x11h_minimize(display, win);
378 restore_omap_layers();
383 kill(g_child_pid, SIGCONT);
392 static void hidecon_start(void)
394 struct termios kbd_termios;
397 g_kbdfd = open("/dev/tty", O_RDWR);
399 perror(PFX "open /dev/tty");
403 if (ioctl(g_kbdfd, KDGETMODE, &mode) == -1) {
404 perror(PFX "(not hiding FB): KDGETMODE");
408 if (tcgetattr(g_kbdfd, &kbd_termios) == -1) {
409 perror(PFX "tcgetattr");
413 g_kbd_termios_saved = kbd_termios;
414 kbd_termios.c_lflag &= ~(ICANON | ECHO); // | ISIG);
415 kbd_termios.c_iflag &= ~(ISTRIP | IGNCR | ICRNL | INLCR | IXOFF | IXON);
416 kbd_termios.c_cc[VMIN] = 0;
417 kbd_termios.c_cc[VTIME] = 0;
419 if (tcsetattr(g_kbdfd, TCSAFLUSH, &kbd_termios) == -1) {
420 perror(PFX "tcsetattr");
424 if (ioctl(g_kbdfd, KDSETMODE, KD_GRAPHICS) == -1) {
425 perror(PFX "KDSETMODE KD_GRAPHICS");
426 tcsetattr(g_kbdfd, TCSAFLUSH, &g_kbd_termios_saved);
437 static void hidecon_end(void)
442 if (ioctl(g_kbdfd, KDSETMODE, KD_TEXT) == -1)
443 perror(PFX "KDSETMODE KD_TEXT");
445 if (tcsetattr(g_kbdfd, TCSAFLUSH, &g_kbd_termios_saved) == -1)
446 perror(PFX "tcsetattr");
452 static void do_exec(char * const argv[])
465 execvp(argv[0], argv);
466 perror(PFX "execvp");
472 ret = waitpid(pid, &status, 0);
474 perror(PFX "waitpid");
477 int main(int argc, char *argv[])
484 printf("usage:\n%s <app> [arg]..\n", argv[0]);
488 pthread_mutex_lock(&g_start_mutex);
490 name = strrchr(argv[1], '/');
496 ret = pthread_create(&tid, NULL, x11_handler, name);
498 fprintf(stderr, PFX "pthread_create: %d\n", ret);
503 // assume desktop is in good state..
504 ret = save_fb_state(0, &desktop_pi, &desktop_si);
508 fprintf(stderr, PFX "initial desktop state save failed\n");
510 pthread_cond_wait(&g_start_cond, &g_start_mutex);
511 pthread_mutex_unlock(&g_start_mutex);
521 /* XXX: maybe stop the X thread nicely? */