XCB window hoykeys support
authorRémi Denis-Courmont <rdenis@simphalempin.com>
Thu, 5 Feb 2009 19:23:57 +0000 (21:23 +0200)
committerRémi Denis-Courmont <rdenis@simphalempin.com>
Thu, 5 Feb 2009 19:23:57 +0000 (21:23 +0200)
It kinda suck to have to duplicate this though. Qt4 embedded X video
exhibits the same problem. One ugly "fix" could involve the video
output listening for the parent window event - not sure if this would
work. Another option would be to now create a window in the video
output at all, but then we loose reparenting (useless?). In either
cases, handling of hotkeys in fullscreen mode would seem problematic,
unless we handle fullscreen via the window provider too
(control request?).

modules/video_output/Modules.am
modules/video_output/xcb/window.c

index 5f68727..e8209b6 100644 (file)
@@ -42,11 +42,13 @@ libxcb_plugin_la_LIBADD = $(AM_LIBADD) \
        $(XCB_AUX_LIBS) $(XCB_IMAGE_LIBS) $(XCB_KEYSYMS_LIBS)
 libxcb_plugin_la_DEPENDENCIES =
 
-libxcb_window_plugin_la_SOURCES = xcb/window.c
+libxcb_window_plugin_la_SOURCES = xcb/window.c xcb/keys.c
 libxcb_window_plugin_la_CFLAGS = $(AM_CFLAGS) \
-       $(XCB_CFLAGS) $(XCB_AUX_CFLAGS)
+       $(XCB_CFLAGS) \
+       $(XCB_AUX_CFLAGS) $(XCB_KEYSYMS_CFLAGS)
 libxcb_window_plugin_la_LIBADD = $(AM_LIBADD) \
-       $(XCB_LIBS) $(XCB_AUX_LIBS)
+       $(XCB_LIBS) \
+       $(XCB_AUX_LIBS) $(XCB_KEYSYMS_LIBS)
 libxcb_window_plugin_la_DEPENDENCIES =
 
 EXTRA_LTLIBRARIES += libxcb_plugin.la libxcb_window_plugin.la
index 50cef9e..f31690a 100644 (file)
@@ -26,6 +26,7 @@
 
 #include <stdarg.h>
 #include <assert.h>
+#include <poll.h>
 
 #include <xcb/xcb.h>
 #include <xcb/xcb_aux.h>
@@ -34,6 +35,8 @@
 #include <vlc_plugin.h>
 #include <vlc_window.h>
 
+#include "xcb_vlc.h"
+
 #define DISPLAY_TEXT N_("X11 display")
 #define DISPLAY_LONGTEXT N_( \
     "X11 hardware display to use. By default VLC will " \
@@ -58,6 +61,14 @@ vlc_module_begin ()
 vlc_module_end ()
 
 static int Control (vout_window_t *, int, va_list ap);
+static void *Thread (void *);
+
+struct vout_window_sys_t
+{
+    xcb_connection_t *conn;
+    key_handler_t *keys;
+    vlc_thread_t thread;
+};
 
 /**
  * Create an X11 window.
@@ -65,9 +76,13 @@ static int Control (vout_window_t *, int, va_list ap);
 static int Open (vlc_object_t *obj)
 {
     vout_window_t *wnd = (vout_window_t *)obj;
+    vout_window_sys_t *p_sys = malloc (sizeof (*p_sys));
     xcb_generic_error_t *err;
     xcb_void_cookie_t ck;
 
+    if (p_sys == NULL)
+        return VLC_ENOMEM;
+
     /* Connect to X */
     char *display = var_CreateGetNonEmptyString (wnd, "x11-display");
     int snum;
@@ -79,10 +94,12 @@ static int Open (vlc_object_t *obj)
 
     /* Create window */
     xcb_screen_t *scr = xcb_aux_get_screen (conn, snum);
-    const uint32_t mask = XCB_CW_BACK_PIXEL;
-    uint32_t values[1] = {
+    const uint32_t mask = XCB_CW_BACK_PIXEL | XCB_CW_EVENT_MASK;
+    uint32_t values[2] = {
         /* XCB_CW_BACK_PIXEL */
         scr->black_pixel,
+        /* XCB_CW_EVENT_MASK */
+        XCB_EVENT_MASK_KEY_PRESS,
     };
 
     xcb_window_t window = xcb_generate_id (conn);
@@ -97,17 +114,26 @@ static int Open (vlc_object_t *obj)
         goto error;
     }
 
+    wnd->handle.xid = window;
+    wnd->p_sys = p_sys;
+    wnd->control = Control;
+
+    p_sys->conn = conn;
+    p_sys->keys = CreateKeyHandler (obj, conn);
+
+    if ((p_sys->keys != NULL)
+     && vlc_clone (&p_sys->thread, Thread, wnd, VLC_THREAD_PRIORITY_LOW))
+        DestroyKeyHandler (p_sys->keys);
+
     /* Make sure the window is ready */
     xcb_map_window (conn, window);
     xcb_flush (conn);
 
-    wnd->handle.xid = window;
-    wnd->p_sys = conn;
-    wnd->control = Control;
     return VLC_SUCCESS;
 
 error:
     xcb_disconnect (conn);
+    free (p_sys);
     return VLC_EGENERIC;
 }
 
@@ -118,12 +144,56 @@ error:
 static void Close (vlc_object_t *obj)
 {
     vout_window_t *wnd = (vout_window_t *)obj;
-    xcb_connection_t *conn = wnd->p_sys;
+    vout_window_sys_t *p_sys = wnd->p_sys;
+    xcb_connection_t *conn = p_sys->conn;
     xcb_window_t window = wnd->handle.xid;
 
+    if (p_sys->keys)
+    {
+        vlc_cancel (p_sys->thread);
+        vlc_join (p_sys->thread, NULL);
+        DestroyKeyHandler (p_sys->keys);
+    }
     xcb_unmap_window (conn, window);
     xcb_destroy_window (conn, window);
     xcb_disconnect (conn);
+    free (p_sys);
+}
+
+
+static void *Thread (void *data)
+{
+    vout_window_t *wnd = data;
+    vout_window_sys_t *p_sys = wnd->p_sys;
+    xcb_connection_t *conn = p_sys->conn;
+
+    int fd = xcb_get_file_descriptor (conn);
+    if (fd == -1)
+        return NULL;
+
+    for (;;)
+    {
+        xcb_generic_event_t *ev;
+        struct pollfd ufd = { .fd = fd, .events = POLLIN, };
+
+        poll (&ufd, 1, -1);
+
+        int canc = vlc_savecancel ();
+        while ((ev = xcb_poll_for_event (conn)) != NULL)
+        {
+            if (ProcessKeyEvent (p_sys->keys, ev) == 0)
+                continue;
+            free (ev);
+        }
+        vlc_restorecancel (canc);
+
+        if (xcb_connection_has_error (conn))
+        {
+            msg_Err (wnd, "X server failure");
+            break;
+        }
+    }
+    return NULL;
 }