]> git.sesse.net Git - vlc/commitdiff
xcb: support for WM_DELETE_WINDOW(WM_PROTOCOLS)
authorErwan Tulou <erwan10@videolan.org>
Fri, 28 Jan 2011 12:03:29 +0000 (13:03 +0100)
committerErwan Tulou <erwan10@videolan.org>
Fri, 28 Jan 2011 18:18:56 +0000 (19:18 +0100)
When the default window provider is used (dummy, rc, ... interfaces),
rather decide what to do when the user closes the video window than let
the WM blindly destroy it. Till now, this led to an error message, input
dying and the playlist being stopped. For -I dummy, it also meant leaving
vlc hanging since no interface could then be used to stop vlc.

Action taken is to stop vlc, but feel free to change/improve/make it
more configurable if need be.

modules/video_output/xcb/window.c

index 0fdd2bcac434baf95cd04fd5ed143dac547ab7fe..833c68daf570854053d7b769b2eca0ca977f6fe8 100644 (file)
@@ -37,6 +37,7 @@ typedef xcb_atom_t Atom;
 #include <vlc_common.h>
 #include <vlc_plugin.h>
 #include <vlc_vout_window.h>
+#include <vlc_interface.h>
 
 #include "xcb_vlc.h"
 
@@ -99,6 +100,8 @@ struct vout_window_sys_t
     vlc_thread_t thread;
 
     xcb_window_t root;
+    xcb_atom_t wm_protocols;
+    xcb_atom_t wm_delete_window;
     xcb_atom_t wm_state;
     xcb_atom_t wm_state_above;
     xcb_atom_t wm_state_below;
@@ -140,6 +143,18 @@ void set_wm_hints (xcb_connection_t *conn, xcb_window_t window)
                          XA_WM_HINTS, 32, 8, wm_hints);
 }
 
+static inline
+void set_wm_protocols (vout_window_t *wnd, xcb_connection_t *conn,
+                       xcb_window_t window)
+{
+    const xcb_atom_t wm_protocols[1] = {
+        wnd->sys->wm_delete_window,
+    };
+    xcb_change_property (conn, XCB_PROP_MODE_REPLACE, window,
+                         wnd->sys->wm_protocols, XA_ATOM,
+                         32, 1, wm_protocols);
+}
+
 /** Set the Window ICCCM client machine property */
 static inline
 void set_hostname_prop (xcb_connection_t *conn, xcb_window_t window)
@@ -188,9 +203,12 @@ xcb_atom_t get_atom (xcb_connection_t *conn, xcb_intern_atom_cookie_t ck)
 static void CacheAtoms (vout_window_sys_t *p_sys)
 {
     xcb_connection_t *conn = p_sys->conn;
-    xcb_intern_atom_cookie_t wm_state_ck, wm_state_above_ck,
+    xcb_intern_atom_cookie_t wm_protocols_ck, wm_delete_window_ck,
+                             wm_state_ck, wm_state_above_ck,
                              wm_state_below_ck, wm_state_fs_ck;
 
+    wm_protocols_ck = intern_string (conn, "WM_PROTOCOLS");
+    wm_delete_window_ck = intern_string (conn, "WM_DELETE_WINDOW");
     wm_state_ck = intern_string (conn, "_NET_WM_STATE");
     wm_state_above_ck = intern_string (conn, "_NET_WM_STATE_ABOVE");
     wm_state_below_ck = intern_string (conn, "_NET_WM_STATE_BELOW");
@@ -202,6 +220,8 @@ static void CacheAtoms (vout_window_sys_t *p_sys)
                                              "_MB_CURRENT_APP_WINDOW");
 #endif
 
+    p_sys->wm_protocols = get_atom (conn, wm_protocols_ck);
+    p_sys->wm_delete_window = get_atom (conn, wm_delete_window_ck);
     p_sys->wm_state = get_atom (conn, wm_state_ck);
     p_sys->wm_state_above = get_atom (conn, wm_state_above_ck);
     p_sys->wm_state_below = get_atom (conn, wm_state_below_ck);
@@ -334,6 +354,10 @@ static int Open (vout_window_t *wnd, const vout_window_cfg_t *cfg)
 
     /* Cache any EWMH atom we may need later */
     CacheAtoms (p_sys);
+
+    /* tell the WM which protocols we support */
+    set_wm_protocols (wnd, conn, window );
+
 #ifdef MATCHBOX_HACK
     if (p_sys->mb_current_app_window)
     {
@@ -394,6 +418,24 @@ static void Close (vout_window_t *wnd)
 }
 
 
+static int ProcessClientMessage (vout_window_t *wnd, xcb_generic_event_t *ev)
+{
+    if ((ev->response_type & 0x7f) != XCB_CLIENT_MESSAGE)
+        return -1;
+
+    xcb_client_message_event_t* evt = (xcb_client_message_event_t*)ev;
+    if (evt->type == wnd->sys->wm_protocols
+     && evt->data.data32[0] == wnd->sys->wm_delete_window)
+    {
+        msg_Dbg (wnd, "WM_DELETE_WINDOW received from the Window Manager");
+        libvlc_Quit (wnd->p_libvlc);
+    }
+    else
+        msg_Dbg (wnd, "unhandled client message");
+    return 0;
+}
+
+
 /** Background thread for X11 events handling */
 static void *Thread (void *data)
 {
@@ -415,6 +457,8 @@ static void *Thread (void *data)
         int canc = vlc_savecancel ();
         while ((ev = xcb_poll_for_event (conn)) != NULL)
         {
+            if (ProcessClientMessage (wnd, ev) == 0)
+                continue;
             if (ProcessKeyEvent (p_sys->keys, ev) == 0)
                 continue;
 #ifdef MATCHBOX_HACK