[vlc-devel] commit: XCB screen capture discovery plugin ( Rémi Denis-Courmont )

git version control git at videolan.org
Sun Nov 1 11:09:20 CET 2009


vlc | branch: master | Rémi Denis-Courmont <remi at remlab.net> | Sun Nov  1 12:06:44 2009 +0200| [4ce1f5d968c0f4358dc9fb6d6e3ee850328454a4] | committer: Rémi Denis-Courmont 

XCB screen capture discovery plugin

TODO:
 - use application names for input items
 - add an item for the whole desktop,
 - add items for XRandR outputs.

> http://git.videolan.org/gitweb.cgi/vlc.git/?a=commit;h=4ce1f5d968c0f4358dc9fb6d6e3ee850328454a4
---

 configure.ac                          |    1 +
 modules/services_discovery/Modules.am |   12 ++
 modules/services_discovery/xcb_apps.c |  292 +++++++++++++++++++++++++++++++++
 3 files changed, 305 insertions(+), 0 deletions(-)

diff --git a/configure.ac b/configure.ac
index 28a9baa..94da05a 100644
--- a/configure.ac
+++ b/configure.ac
@@ -3658,6 +3658,7 @@ AS_IF([test "${enable_xcb}" != "no"], [
   PKG_CHECK_MODULES(XCB_SHM, [xcb-shm])
   VLC_ADD_PLUGIN([xcb_x11])
   VLC_ADD_PLUGIN([xcb_screen])
+  VLC_ADD_PLUGIN([xcb_apps])
   VLC_SET_CFLAGS_WERROR([xcb_screen], [-Wno-error=uninitialized]) # some gcc report a warning which doesn't reveal an error
 
   AS_IF([test "${enable_xvideo}" != "no"], [
diff --git a/modules/services_discovery/Modules.am b/modules/services_discovery/Modules.am
index 71d27a5..45302d1 100644
--- a/modules/services_discovery/Modules.am
+++ b/modules/services_discovery/Modules.am
@@ -7,3 +7,15 @@ SOURCES_podcast = podcast.c
 SOURCES_mtp = mtp.c
 SOURCES_mediadirs = mediadirs.c
 SOURCES_udev = udev.c
+
+libxcb_apps_plugin_la_SOURCES = xcb_apps.c
+libxcb_apps_plugin_la_CFLAGS = $(AM_CFLAGS) \
+	$(XCB_CFLAGS)
+libxcb_apps_plugin_la_LIBADD = $(AM_LIBADD) \
+	$(XCB_LIBS)
+libxcb_apps_plugin_la_DEPENDENCIES =
+
+EXTRA_LTLIBRARIES += \
+	libxcb_apps_plugin.la
+libvlc_LTLIBRARIES += \
+	$(LTLIBxcb_apps)
diff --git a/modules/services_discovery/xcb_apps.c b/modules/services_discovery/xcb_apps.c
new file mode 100644
index 0000000..1ea58bf
--- /dev/null
+++ b/modules/services_discovery/xcb_apps.c
@@ -0,0 +1,292 @@
+/**
+ * @file xcb_apps.c
+ * @brief List of application windows XCB module for VLC media player
+ */
+/*****************************************************************************
+ * 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 library 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.
+ *
+ * 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
+ ****************************************************************************/
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+#include <stdarg.h>
+#include <xcb/xcb.h>
+typedef xcb_atom_t Atom;
+#include <X11/Xatom.h> /* XA_WINDOW */
+#include <vlc_common.h>
+#include <vlc_services_discovery.h>
+#include <vlc_dialog.h>
+#include <vlc_plugin.h>
+#include <poll.h>
+#include <search.h>
+
+static int  Open (vlc_object_t *);
+static void Close (vlc_object_t *);
+
+/*
+ * Module descriptor
+ */
+vlc_module_begin ()
+    set_shortname (N_("Screen capture"))
+    set_description (N_("Screen capture"))
+    set_category (CAT_PLAYLIST)
+    set_subcategory (SUBCAT_PLAYLIST_SD)
+    set_capability ("services_discovery", 0)
+    set_callbacks (Open, Close)
+
+    add_shortcut ("apps")
+vlc_module_end ()
+
+struct services_discovery_sys_t
+{
+    xcb_connection_t *conn;
+    vlc_thread_t      thread;
+    xcb_atom_t        net_client_list;
+    xcb_window_t      root_window;
+    void             *nodes;
+};
+
+static void *Run (void *);
+static void Update (services_discovery_t *);
+static void DelItem (void *);
+
+/**
+ * Probes and initializes.
+ */
+static int Open (vlc_object_t *obj)
+{
+    services_discovery_t *sd = (services_discovery_t *)obj;
+    services_discovery_sys_t *p_sys = malloc (sizeof (*p_sys));
+
+    if (p_sys == NULL)
+        return VLC_ENOMEM;
+    sd->p_sys = p_sys;
+
+    /* Connect to X server */
+    char *display = var_CreateGetNonEmptyString (obj, "x11-display");
+    int snum;
+    xcb_connection_t *conn = xcb_connect (display, &snum);
+    free (display);
+    if (xcb_connection_has_error (conn))
+    {
+        free (p_sys);
+        return VLC_EGENERIC;
+    }
+    p_sys->conn = conn;
+
+    /* Find configured screen */
+    const xcb_setup_t *setup = xcb_get_setup (conn);
+    const xcb_screen_t *scr = NULL;
+    for (xcb_screen_iterator_t i = xcb_setup_roots_iterator (setup);
+         i.rem > 0; xcb_screen_next (&i))
+    {
+        if (snum == 0)
+        {
+            scr = i.data;
+            break;
+        }
+        snum--;
+    }
+    if (scr == NULL)
+    {
+        msg_Err (obj, "bad X11 screen number");
+        goto error;
+    }
+
+    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"),
+                          "_NET_CLIENT_LIST");
+    xcb_intern_atom_reply_t *r = xcb_intern_atom_reply (conn, ck, 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;
+    }
+    p_sys->net_client_list = r->atom;
+    free (r);
+
+    p_sys->nodes = NULL;
+    Update (sd);
+
+    if (vlc_clone (&p_sys->thread, Run, sd, VLC_THREAD_PRIORITY_LOW))
+        goto error;
+    return VLC_SUCCESS;
+
+error:
+    xcb_disconnect (p_sys->conn);
+    free (p_sys);
+    return VLC_EGENERIC;
+}
+
+
+/**
+ * Releases resources
+ */
+static void Close (vlc_object_t *obj)
+{
+    services_discovery_t *sd = (services_discovery_t *)obj;
+    services_discovery_sys_t *p_sys = sd->p_sys;
+
+    vlc_cancel (p_sys->thread);
+    vlc_join (p_sys->thread, NULL);
+    xcb_disconnect (p_sys->conn);
+    tdestroy (p_sys->nodes, DelItem);
+    free (p_sys);
+}
+
+static void *Run (void *data)
+{
+    services_discovery_t *sd = data;
+    services_discovery_sys_t *p_sys = sd->p_sys;
+    xcb_connection_t *conn = p_sys->conn;
+    int fd = xcb_get_file_descriptor (conn);
+    if (fd == -1)
+        return NULL;
+
+    while (!xcb_connection_has_error (conn))
+    {
+        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 ((ev->response_type & 0x7F) == XCB_PROPERTY_NOTIFY)
+            {
+                 const xcb_property_notify_event_t *pn =
+                     (xcb_property_notify_event_t *)ev;
+                 if (pn->atom == p_sys->net_client_list)
+                     Update (sd);
+            }
+            free (ev);
+        }
+        vlc_restorecancel (canc);
+    }
+    return NULL;
+}
+
+struct app
+{
+    xcb_window_t          xid; /* must be first for cmpapp */
+    input_item_t         *item;
+    services_discovery_t *owner;
+};
+
+static struct app *AddItem (services_discovery_t *sd, xcb_window_t xid)
+{
+    char *mrl;
+    if (asprintf (&mrl, "window://0x%"PRIx8, xid) == -1)
+        return NULL;
+
+    input_item_t *item = input_item_NewWithType (VLC_OBJECT (sd), mrl,
+                                                 mrl,
+                                                 0, NULL, 0, -1,
+                                                 ITEM_TYPE_CARD /* FIXME */);
+    free (mrl);
+    if (item == NULL)
+        return NULL;
+
+    struct app *app = malloc (sizeof (*app));
+    if (app == NULL)
+    {
+        vlc_gc_decref (item);
+        return NULL;
+    }
+    app->xid = xid;
+    app->item = item;
+    app->owner = sd;
+    services_discovery_AddItem (sd, item, _("Applications"));
+    return app;
+}
+
+static void DelItem (void *data)
+{
+    struct app *app = data;
+
+    services_discovery_RemoveItem (app->owner, app->item);
+    vlc_gc_decref (app->item);
+    free (app);
+}
+
+static int cmpapp (const void *a, const void *b)
+{
+    xcb_window_t wa = *(xcb_window_t *)a;
+    xcb_window_t wb = *(xcb_window_t *)b;
+
+    if (wa > wb)
+        return 1;
+    if (wa < wb)
+        return -1;
+    return 0;
+} 
+
+static void Update (services_discovery_t *sd)
+{
+    services_discovery_sys_t *p_sys = sd->p_sys;
+    xcb_connection_t *conn = p_sys->conn;
+
+    xcb_get_property_reply_t *r =
+        xcb_get_property_reply (conn,
+            xcb_get_property (conn, false, p_sys->root_window,
+                              p_sys->net_client_list, XA_WINDOW, 0, 1024),
+            NULL);
+    if (r == NULL)
+        return; /* FIXME: remove all entries */
+
+    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;
+
+    for (int i = 0; i < n; i++)
+    {
+        xcb_window_t id = *(ent++);
+        struct app *app;
+
+        struct app **pa = tfind (&id, &oldnodes, cmpapp);
+        if (pa != NULL) /* existing entry */
+        {
+            app = *pa;
+            tdelete (app, &oldnodes, cmpapp);
+        }
+        else /* new entry */
+        {
+            app = AddItem (sd, id);
+            if (app == NULL)
+                continue;
+        }
+
+        pa = tsearch (app, &newnodes, cmpapp);
+        if (pa == NULL /* OOM */ || *pa != app /* buggy window manager */)
+            DelItem (app);
+    }
+    free (r);
+
+    /* Remove old nodes */
+    tdestroy (oldnodes, DelItem);
+    p_sys->nodes = newnodes;
+}




More information about the vlc-devel mailing list