From 2b3ad824c8031e58134b3f79b91e4c9db8c6b791 Mon Sep 17 00:00:00 2001 From: agsantos <aline.gondimsantos@savoirfairelinux.com> Date: Mon, 29 Nov 2021 14:57:33 -0500 Subject: [PATCH] x11: get windows name and ids GitLab: https://git.jami.net/savoirfairelinux/jami-project/-/issues/1294 Change-Id: Icf117d50b9ad3e6cf0d329252be371c3a856e96b --- src/api/avmodel.h | 10 ++++- src/api/newcallmodel.h | 7 +++ src/avmodel.cpp | 99 ++++++++++++++++++++++++++++++++++++++++++ src/newcallmodel.cpp | 10 +++++ 4 files changed, 124 insertions(+), 2 deletions(-) diff --git a/src/api/avmodel.h b/src/api/avmodel.h index 51945f41..321066ce 100644 --- a/src/api/avmodel.h +++ b/src/api/avmodel.h @@ -253,18 +253,24 @@ public: * @throw std::out_of_range if not found */ const video::Renderer& getRenderer(const QString& id) const; + /** + * Get the list of available windows ids + * X11: a id is of the form 0x0000000 + * @return map with windows names and ids + */ + const QVariantMap getListWindows() const; /** * set to true to receive AVFrames from render */ void useAVFrame(bool useAVFrame); /** * set current using device - * @ param device name + * @param device name */ Q_INVOKABLE void setCurrentVideoCaptureDevice(const QString& currentVideoCaptureDevice); /** * set current using device - * @ return current using device name + * @return current using device name */ Q_INVOKABLE QString getCurrentVideoCaptureDevice() const; /** diff --git a/src/api/newcallmodel.h b/src/api/newcallmodel.h index 2a70620c..456705b4 100644 --- a/src/api/newcallmodel.h +++ b/src/api/newcallmodel.h @@ -345,6 +345,7 @@ public: video::RenderedDevice getCurrentRenderedDevice(const QString& call_id) const; /** + * @deprecated * Render a file to the call id specified * @param uri the path of the file * @param callId @@ -369,6 +370,12 @@ public: */ QString getDisplay(int idx, int x, int y, int w, int h); /** + * Get the current window resource string + * @param windowId + */ + QString getDisplay(const QString& windowId); + /** + * @deprecated * Render the current display to the call id specified * @param idx of the display * @param x top left of the area diff --git a/src/avmodel.cpp b/src/avmodel.cpp index 653bc370..f9864e8c 100644 --- a/src/avmodel.cpp +++ b/src/avmodel.cpp @@ -46,6 +46,10 @@ #include "dbus/videomanager.h" #include "authority/storagehelper.h" +#if defined(Q_OS_UNIX) && !defined(__APPLE__) +#include <xcb/xcb.h> +#endif + namespace lrc { using namespace api; @@ -540,6 +544,101 @@ AVModel::getRenderer(const QString& id) const return *pimpl_->renderers_[id]; } +#if defined(Q_OS_UNIX) && !defined(__APPLE__) +static xcb_atom_t +getAtom(xcb_connection_t* c, const std::string& atomName) +{ + xcb_intern_atom_cookie_t atom_cookie = xcb_intern_atom(c, 0, atomName.size(), atomName.c_str()); + if (auto* rep = xcb_intern_atom_reply(c, atom_cookie, nullptr)) { + xcb_atom_t atom = rep->atom; + free(rep); + return atom; + } + return {}; +} +#endif + +const QVariantMap +AVModel::getListWindows() const +{ + QMap<QString, QVariant> ret {}; + +#if defined(Q_OS_UNIX) && !defined(__APPLE__) + std::unique_ptr<xcb_connection_t, void (*)(xcb_connection_t*)> c(xcb_connect(nullptr, nullptr), + [](xcb_connection_t* ptr) { + xcb_disconnect(ptr); + }); + + if (xcb_connection_has_error(c.get())) { + qDebug() << "xcb connection has error"; + return ret; + } + + auto atomNetClient = getAtom(c.get(), "_NET_CLIENT_LIST"); + auto atomWMVisibleName = getAtom(c.get(), "_NET_WM_NAME"); + if (!atomNetClient || !atomWMVisibleName) + return ret; + + auto* screen = xcb_setup_roots_iterator(xcb_get_setup(c.get())).data; + + xcb_get_property_cookie_t propCookieList = xcb_get_property(c.get(), + 0, + screen->root, + atomNetClient, + XCB_GET_PROPERTY_TYPE_ANY, + 0, + 100); + + using propertyPtr + = std::unique_ptr<xcb_get_property_reply_t, void (*)(xcb_get_property_reply_t*)>; + + xcb_generic_error_t* e; + propertyPtr replyPropList(xcb_get_property_reply(c.get(), propCookieList, &e), + [](auto* ptr) { free(ptr); }); + if (e) { + qDebug() << "Error: " << e->error_code; + free(e); + } + if (replyPropList.get()) { + int valueLegth = xcb_get_property_value_length(replyPropList.get()); + if (valueLegth) { + auto* win = static_cast<xcb_window_t*>(xcb_get_property_value(replyPropList.get())); + for (int i = 0; i < valueLegth / 4; i++) { + xcb_get_property_cookie_t prop_cookie = xcb_get_property(c.get(), + 0, + win[i], + atomWMVisibleName, + XCB_GET_PROPERTY_TYPE_ANY, + 0, + 1000); + propertyPtr replyProp {xcb_get_property_reply(c.get(), prop_cookie, &e), + [](auto* ptr) { + free(ptr); + }}; + if (e) { + qDebug() << "Error: " << e->error_code; + free(e); + } + if (replyProp.get()) { + int valueLegth2 = xcb_get_property_value_length(replyProp.get()); + if (valueLegth2) { + auto name = QString::fromUtf8( + reinterpret_cast<char*>(xcb_get_property_value(replyProp.get()))); + name.truncate(valueLegth2); + if (ret.find(name) != ret.end()) + name += QString(" - 0x%1").arg(win[i], 0, 16); + ret.insert(name, QVariant(QString("0x%1").arg(win[i], 0, 16))); + } + } + } + } + } + return ret; +#else + return ret; +#endif +} + void AVModel::setCurrentVideoCaptureDevice(const QString& currentVideoCaptureDevice) { diff --git a/src/newcallmodel.cpp b/src/newcallmodel.cpp index 8b36a672..6bcd9d5f 100644 --- a/src/newcallmodel.cpp +++ b/src/newcallmodel.cpp @@ -838,6 +838,16 @@ NewCallModel::getDisplay(int idx, int x, int y, int w, int h) .arg(h); } +QString +NewCallModel::getDisplay(const QString& windowId) +{ + QString sep = DRing::Media::VideoProtocolPrefix::SEPARATOR; + return QString("%1%2:+0,0 window-id:%3") + .arg(DRing::Media::VideoProtocolPrefix::DISPLAY) + .arg(sep) + .arg(windowId); +} + void NewCallModel::setDisplay(int idx, int x, int y, int w, int h, const QString& callId) { -- GitLab