]> git.sesse.net Git - vlc/blobdiff - modules/services_discovery/xcb_apps.c
ogg: Fix a heap buffer overflow.
[vlc] / modules / services_discovery / xcb_apps.c
index 1ea58bf16d5f0f6fe33e376473b0a41b9c008b95..1db34f5f96257c9328150cae93f521b33462d4bd 100644 (file)
@@ -5,20 +5,20 @@
 /*****************************************************************************
  * Copyright © 2009 Rémi Denis-Courmont
  *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public License
- * as published by the Free Software Foundation; either version 2.1
- * of the License, or (at your option) any later version.
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2.1 of the License, or
+ * (at your option) any later version.
  *
- * This library is distributed in the hope that it will be useful,
+ * This program is distributed in the hope that it will be useful,
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
+ * GNU Lesser General Public License for more details.
  *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
- ****************************************************************************/
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
+ *****************************************************************************/
 
 #ifdef HAVE_CONFIG_H
 # include <config.h>
@@ -30,12 +30,16 @@ typedef xcb_atom_t Atom;
 #include <vlc_common.h>
 #include <vlc_services_discovery.h>
 #include <vlc_dialog.h>
+#include <vlc_charset.h>
 #include <vlc_plugin.h>
+#ifdef HAVE_SEARCH_H
+# include <search.h>
+#endif
 #include <poll.h>
-#include <search.h>
 
 static int  Open (vlc_object_t *);
 static void Close (vlc_object_t *);
+static int vlc_sd_probe_Open (vlc_object_t *);
 
 /*
  * Module descriptor
@@ -48,7 +52,9 @@ vlc_module_begin ()
     set_capability ("services_discovery", 0)
     set_callbacks (Open, Close)
 
-    add_shortcut ("apps")
+    add_shortcut ("apps", "screen")
+
+    VLC_SD_PROBE_SUBMODULE
 vlc_module_end ()
 
 struct services_discovery_sys_t
@@ -56,13 +62,29 @@ struct services_discovery_sys_t
     xcb_connection_t *conn;
     vlc_thread_t      thread;
     xcb_atom_t        net_client_list;
+    xcb_atom_t        net_wm_name;
     xcb_window_t      root_window;
-    void             *nodes;
+    void             *apps;
 };
 
 static void *Run (void *);
-static void Update (services_discovery_t *);
-static void DelItem (void *);
+static void UpdateApps (services_discovery_t *);
+static void DelApp (void *);
+static void AddDesktop(services_discovery_t *);
+
+static int vlc_sd_probe_Open (vlc_object_t *obj)
+{
+    vlc_probe_t *probe = (vlc_probe_t *)obj;
+
+    char *display = var_InheritString (obj, "x11-display");
+    xcb_connection_t *conn = xcb_connect (display, NULL);
+    free (display);
+    if (xcb_connection_has_error (conn))
+        return VLC_PROBE_CONTINUE;
+    xcb_disconnect (conn);
+    return vlc_sd_probe_Add (probe, "xcb_apps{longname=\"Screen capture\"}",
+                             N_("Screen capture"), SD_CAT_DEVICES);
+}
 
 /**
  * Probes and initializes.
@@ -77,7 +99,7 @@ static int Open (vlc_object_t *obj)
     sd->p_sys = p_sys;
 
     /* Connect to X server */
-    char *display = var_CreateGetNonEmptyString (obj, "x11-display");
+    char *display = var_InheritString (obj, "x11-display");
     int snum;
     xcb_connection_t *conn = xcb_connect (display, &snum);
     free (display);
@@ -107,29 +129,40 @@ static int Open (vlc_object_t *obj)
         goto error;
     }
 
+    /* Add a permanent item for the entire desktop */
+    AddDesktop (sd);
+
     p_sys->root_window = scr->root;
     xcb_change_window_attributes (conn, scr->root, XCB_CW_EVENT_MASK,
                                &(uint32_t) { XCB_EVENT_MASK_PROPERTY_CHANGE });
 
     /* TODO: check that _NET_CLIENT_LIST is in _NET_SUPPORTED
      * (and _NET_SUPPORTING_WM_CHECK) */
-    xcb_intern_atom_cookie_t ck;
-    ck = xcb_intern_atom (conn, 1, strlen ("_NET_CLIENT_LIST"),
+    xcb_intern_atom_reply_t *r;
+    xcb_intern_atom_cookie_t ncl, nwn;
+
+    ncl = xcb_intern_atom (conn, 1, strlen ("_NET_CLIENT_LIST"),
                           "_NET_CLIENT_LIST");
-    xcb_intern_atom_reply_t *r = xcb_intern_atom_reply (conn, ck, NULL);
+    nwn = xcb_intern_atom (conn, 0, strlen ("_NET_WM_NAME"), "_NET_WM_NAME");
+
+    r = xcb_intern_atom_reply (conn, ncl, NULL);
     if (r == NULL || r->atom == 0)
     {
-        dialog_Fatal (sd, _("Application list failure"),
-                  _("Your window manager does not support application list."));
-        msg_Err (sd, "application list not support (_NET_CLIENT_LIST absent)");
-        free (r);
-        goto error;
+        dialog_Fatal (sd, _("Screen capture"),
+            _("Your window manager does not provide a list of applications."));
+        msg_Err (sd, "client list not supported (_NET_CLIENT_LIST absent)");
     }
-    p_sys->net_client_list = r->atom;
+    p_sys->net_client_list = r ? r->atom : 0;
     free (r);
+    r = xcb_intern_atom_reply (conn, nwn, NULL);
+    if (r != NULL)
+    {
+        p_sys->net_wm_name = r->atom;
+        free (r);
+    }
 
-    p_sys->nodes = NULL;
-    Update (sd);
+    p_sys->apps = NULL;
+    UpdateApps (sd);
 
     if (vlc_clone (&p_sys->thread, Run, sd, VLC_THREAD_PRIORITY_LOW))
         goto error;
@@ -153,7 +186,7 @@ static void Close (vlc_object_t *obj)
     vlc_cancel (p_sys->thread);
     vlc_join (p_sys->thread, NULL);
     xcb_disconnect (p_sys->conn);
-    tdestroy (p_sys->nodes, DelItem);
+    tdestroy (p_sys->apps, DelApp);
     free (p_sys);
 }
 
@@ -181,7 +214,7 @@ static void *Run (void *data)
                  const xcb_property_notify_event_t *pn =
                      (xcb_property_notify_event_t *)ev;
                  if (pn->atom == p_sys->net_client_list)
-                     Update (sd);
+                     UpdateApps (sd);
             }
             free (ev);
         }
@@ -190,6 +223,7 @@ static void *Run (void *data)
     return NULL;
 }
 
+/*** Application windows ***/
 struct app
 {
     xcb_window_t          xid; /* must be first for cmpapp */
@@ -197,17 +231,35 @@ struct app
     services_discovery_t *owner;
 };
 
-static struct app *AddItem (services_discovery_t *sd, xcb_window_t xid)
+static struct app *AddApp (services_discovery_t *sd, xcb_window_t xid)
 {
-    char *mrl;
+    services_discovery_sys_t *p_sys = sd->p_sys;
+    char *mrl, *name;
+
     if (asprintf (&mrl, "window://0x%"PRIx8, xid) == -1)
         return NULL;
 
-    input_item_t *item = input_item_NewWithType (VLC_OBJECT (sd), mrl,
-                                                 mrl,
+    xcb_get_property_reply_t *r =
+        xcb_get_property_reply (p_sys->conn,
+            xcb_get_property (p_sys->conn, 0, xid, p_sys->net_wm_name, 0,
+                              0, 1023 /* max size */), NULL);
+    if (r != NULL)
+    {
+        name = strndup (xcb_get_property_value (r),
+                        xcb_get_property_value_length (r));
+        if (name != NULL)
+            EnsureUTF8 (name); /* don't trust third party apps too much ;-) */
+        free (r);
+    }
+    /* TODO: use WM_NAME (Latin-1) for very old apps */
+    else
+        name = NULL;
+
+    input_item_t *item = input_item_NewWithType (mrl, name ? name : mrl,
                                                  0, NULL, 0, -1,
                                                  ITEM_TYPE_CARD /* FIXME */);
     free (mrl);
+    free (name);
     if (item == NULL)
         return NULL;
 
@@ -224,7 +276,7 @@ static struct app *AddItem (services_discovery_t *sd, xcb_window_t xid)
     return app;
 }
 
-static void DelItem (void *data)
+static void DelApp (void *data)
 {
     struct app *app = data;
 
@@ -245,7 +297,7 @@ static int cmpapp (const void *a, const void *b)
     return 0;
 } 
 
-static void Update (services_discovery_t *sd)
+static void UpdateApps (services_discovery_t *sd)
 {
     services_discovery_sys_t *p_sys = sd->p_sys;
     xcb_connection_t *conn = p_sys->conn;
@@ -260,7 +312,7 @@ static void Update (services_discovery_t *sd)
 
     xcb_window_t *ent = xcb_get_property_value (r);
     int n = xcb_get_property_value_length (r) / 4;
-    void *newnodes = NULL, *oldnodes = p_sys->nodes;
+    void *newnodes = NULL, *oldnodes = p_sys->apps;
 
     for (int i = 0; i < n; i++)
     {
@@ -275,18 +327,31 @@ static void Update (services_discovery_t *sd)
         }
         else /* new entry */
         {
-            app = AddItem (sd, id);
+            app = AddApp (sd, id);
             if (app == NULL)
                 continue;
         }
 
         pa = tsearch (app, &newnodes, cmpapp);
         if (pa == NULL /* OOM */ || *pa != app /* buggy window manager */)
-            DelItem (app);
+            DelApp (app);
     }
     free (r);
 
     /* Remove old nodes */
-    tdestroy (oldnodes, DelItem);
-    p_sys->nodes = newnodes;
+    tdestroy (oldnodes, DelApp);
+    p_sys->apps = newnodes;
+}
+
+/*** Whole desktop ***/
+static void AddDesktop(services_discovery_t *sd)
+{
+    input_item_t *item;
+
+    item = input_item_NewWithType ("screen://", _("Desktop"),
+                                   0, NULL, 0, -1, ITEM_TYPE_CARD);
+    if (item == NULL)
+        return;
+
+    services_discovery_AddItem (sd, item, NULL);
 }