From e1d85b2db06b839e69c6203144aa8718eb99a348 Mon Sep 17 00:00:00 2001 From: Aline Gondim Santos <aline.gondimsantos@savoirfairelinux.com> Date: Tue, 10 Jan 2023 15:52:36 -0300 Subject: [PATCH] window sharing: track window name change If a window changes its name, we should share the parent process windows. This can happen with chrome, visual studio code and file explorer for example. + Fixes non opening SelectScreen window when Jami language changes. Change-Id: Ib16992dde08e6a9fa191c9fb1cbc4efd304efe6d --- daemon | 2 +- src/app/avadapter.cpp | 9 ++-- src/app/avadapter.h | 4 +- src/app/mainview/components/CallActionBar.qml | 28 +++++------ src/app/mainview/components/SelectScreen.qml | 8 +-- src/libclient/api/callmodel.h | 3 +- src/libclient/avmodel.cpp | 4 +- src/libclient/callmodel.cpp | 50 +++++++++++++++++-- src/libclient/qtwrapper/conversions_wrap.hpp | 2 +- src/libclient/qtwrapper/videomanager_wrap.h | 2 +- 10 files changed, 79 insertions(+), 33 deletions(-) diff --git a/daemon b/daemon index eb9c52cee..3382b2436 160000 --- a/daemon +++ b/daemon @@ -1 +1 @@ -Subproject commit eb9c52cee45660f68334adb32a23d6f743d6bcf4 +Subproject commit 3382b2436017d7044e343dcc1e9190595f2bcc8b diff --git a/src/app/avadapter.cpp b/src/app/avadapter.cpp index 80a02a172..23df74a82 100644 --- a/src/app/avadapter.cpp +++ b/src/app/avadapter.cpp @@ -233,9 +233,9 @@ AvAdapter::shareScreenArea(unsigned x, unsigned y, unsigned width, unsigned heig } void -AvAdapter::shareWindow(const QString& windowId) +AvAdapter::shareWindow(const QString& windowProcessId, const QString& windowId) { - auto resource = lrcInstance_->getCurrentCallModel()->getDisplay(windowId); + auto resource = lrcInstance_->getCurrentCallModel()->getDisplay(windowProcessId, windowId); auto callId = lrcInstance_->getCurrentCallId(); muteCamera_ = !isCapturing(); @@ -243,9 +243,8 @@ AvAdapter::shareWindow(const QString& windowId) ->addMedia(callId, resource, lrc::api::CallModel::MediaRequestType::SCREENSHARING); } -#pragma optimize("", off) QString -AvAdapter::getSharingResource(int screenId = -2, const QString& windowId = "") +AvAdapter::getSharingResource(int screenId, const QString& windowProcessId, const QString& windowId) { if (screenId == -1) { const auto arrangementRect = getAllScreensBoundingRect(); @@ -276,7 +275,7 @@ AvAdapter::getSharingResource(int screenId = -2, const QString& windowId = "") rect.height() * screen->devicePixelRatio()); } else if (!windowId.isEmpty()) { - return lrcInstance_->getCurrentCallModel()->getDisplay(windowId); + return lrcInstance_->getCurrentCallModel()->getDisplay(windowProcessId, windowId); } return ""; diff --git a/src/app/avadapter.h b/src/app/avadapter.h index abd011296..6472a3d18 100644 --- a/src/app/avadapter.h +++ b/src/app/avadapter.h @@ -86,10 +86,10 @@ protected: Q_INVOKABLE void shareScreenArea(unsigned x, unsigned y, unsigned width, unsigned height); // Select window to display. - Q_INVOKABLE void shareWindow(const QString& windowId); + Q_INVOKABLE void shareWindow(const QString& windowProcessId, const QString& windowId); // Returns the screensharing resource - Q_INVOKABLE QString getSharingResource(int screenId, const QString& key); + Q_INVOKABLE QString getSharingResource(int screenId = -2, const QString& windowProcessId = "", const QString& key = ""); Q_INVOKABLE void getListWindows(); diff --git a/src/app/mainview/components/CallActionBar.qml b/src/app/mainview/components/CallActionBar.qml index 3f9ed4d59..1ffec3e1c 100644 --- a/src/app/mainview/components/CallActionBar.qml +++ b/src/app/mainview/components/CallActionBar.qml @@ -117,21 +117,21 @@ Control { property int popupMode: CallActionBar.ActionPopupMode.ListElement property var listModel: ListModel { id: shareModel - - Component.onCompleted: { - shareModel.append({"Name": JamiStrings.shareScreen, - "IconSource": JamiResources.laptop_black_24dp_svg}) - if (Qt.platform.os.toString() !== "osx") { - shareModel.append({"Name": JamiStrings.shareWindow, - "IconSource" : JamiResources.window_black_24dp_svg}) - } - if (Qt.platform.os.toString() !== "windows") { // temporarily disable for windows - shareModel.append({"Name": JamiStrings.shareScreenArea, - "IconSource" : JamiResources.share_area_black_24dp_svg}) - } - shareModel.append({"Name": JamiStrings.shareFile, - "IconSource" : JamiResources.file_black_24dp_svg}) + } + onTriggered: { + shareModel.clear() + shareModel.append({"Name": JamiStrings.shareScreen, + "IconSource": JamiResources.laptop_black_24dp_svg}) + if (Qt.platform.os.toString() !== "osx") { + shareModel.append({"Name": JamiStrings.shareWindow, + "IconSource" : JamiResources.window_black_24dp_svg}) + } + if (Qt.platform.os.toString() !== "windows") { // temporarily disable for windows + shareModel.append({"Name": JamiStrings.shareScreenArea, + "IconSource" : JamiResources.share_area_black_24dp_svg}) } + shareModel.append({"Name": JamiStrings.shareFile, + "IconSource" : JamiResources.file_black_24dp_svg}) } function accept(index) { switch(shareModel.get(index).Name) { diff --git a/src/app/mainview/components/SelectScreen.qml b/src/app/mainview/components/SelectScreen.qml index 6488e3276..dcd35feaa 100644 --- a/src/app/mainview/components/SelectScreen.qml +++ b/src/app/mainview/components/SelectScreen.qml @@ -167,7 +167,7 @@ Window { } Component.onCompleted: { if (visible) { - const rId = AvAdapter.getSharingResource(index, "") + const rId = AvAdapter.getSharingResource(index) if (rId !== "") { rendererId = VideoDevices.startDevice(rId) } @@ -237,7 +237,7 @@ Window { } Component.onCompleted: { if (visible) { - const rId = AvAdapter.getSharingResource(-1, "") + const rId = AvAdapter.getSharingResource(-1) if (rId !== "") { rendererId = VideoDevices.startDevice(rId) } @@ -315,7 +315,7 @@ Window { } Component.onCompleted: { if (visible) { - const rId = AvAdapter.getSharingResource(-2, AvAdapter.windowsIds[index - Qt.application.screens.length]) + const rId = AvAdapter.getSharingResource(-2, AvAdapter.windowsIds[index - Qt.application.screens.length], AvAdapter.windowsNames[index - Qt.application.screens.length]) if (rId !== "") { rendererId = VideoDevices.startDevice(rId) } @@ -376,7 +376,7 @@ Window { if (selectedScreenNumber < Qt.application.screens.length) AvAdapter.shareEntireScreen(selectedScreenNumber) else { - AvAdapter.shareWindow(AvAdapter.windowsIds[selectedScreenNumber - Qt.application.screens.length]) + AvAdapter.shareWindow(AvAdapter.windowsIds[selectedScreenNumber - Qt.application.screens.length], AvAdapter.windowsNames[selectedScreenNumber - Qt.application.screens.length]) } } root.close() diff --git a/src/libclient/api/callmodel.h b/src/libclient/api/callmodel.h index 282c300e8..f6fa50ad5 100644 --- a/src/libclient/api/callmodel.h +++ b/src/libclient/api/callmodel.h @@ -386,9 +386,10 @@ public: QString getDisplay(int idx, int x, int y, int w, int h); /** * Get the current window resource string + * @param windowProcessId * @param windowId */ - QString getDisplay(const QString& windowId); + QString getDisplay(const QString& windowProcessId, const QString& windowId); void emplaceConversationConference(const QString& callId); diff --git a/src/libclient/avmodel.cpp b/src/libclient/avmodel.cpp index a33dec1b2..3ddd4ec00 100644 --- a/src/libclient/avmodel.cpp +++ b/src/libclient/avmodel.cpp @@ -618,7 +618,9 @@ CbEnumAltTab(HWND hwnd, LPARAM lParam) if (keys.indexOf(name) > 0) { return FALSE; } else { - windowList->insert(name, name); + DWORD processId; + GetWindowThreadProcessId(hwnd, &processId); + windowList->insert(name, QVariant::fromValue(processId)); } return TRUE; diff --git a/src/libclient/callmodel.cpp b/src/libclient/callmodel.cpp index 0c425dfe8..9ef31038f 100644 --- a/src/libclient/callmodel.cpp +++ b/src/libclient/callmodel.cpp @@ -55,6 +55,11 @@ #include <random> #include <map> +#ifdef WIN32 +#define NOMINMAX +#include "Windows.h" +#endif + using namespace libjami::Media; constexpr static const char HARDWARE_ACCELERATION[] = "HARDWARE_ACCELERATION"; @@ -942,8 +947,35 @@ CallModel::getDisplay(int idx, int x, int y, int w, int h) .arg(h); } + + +#ifdef WIN32 +BOOL CALLBACK +EnumWindowsProcMy(HWND hwnd, LPARAM lParam) +{ + std::pair<DWORD, QString>* dataPair = reinterpret_cast<std::pair<DWORD, QString>*>( + lParam); + DWORD lpdwProcessId; + if (auto parent = GetWindow(hwnd, GW_OWNER)) + GetWindowThreadProcessId(parent, &lpdwProcessId); + else + GetWindowThreadProcessId(hwnd, &lpdwProcessId); + int len = GetWindowTextLength(hwnd) + 1; + std::vector<wchar_t> buf(len); + GetWindowText(hwnd, &buf[0], len); + + if (lpdwProcessId == dataPair->first) { + if (!IsWindowVisible(hwnd)) + return TRUE; + dataPair->second = QString::fromStdWString(&buf[0]); + return FALSE; + } + return TRUE; +} +#endif + QString -CallModel::getDisplay(const QString& windowId) +CallModel::getDisplay(const QString& windowProcessId, const QString& windowId) { QString sep = libjami::Media::VideoProtocolPrefix::SEPARATOR; QString ret{}; @@ -951,13 +983,25 @@ CallModel::getDisplay(const QString& windowId) ret = QString("%1%2:+0,0 window-id:%3") .arg(libjami::Media::VideoProtocolPrefix::DISPLAY) .arg(sep) - .arg(windowId); + .arg(windowProcessId); #endif #ifdef WIN32 + // If window changed the name we must look for the parent process window + QString newWindowId = windowId; + auto hwnd = FindWindow(NULL, windowId.toStdWString().c_str()); + if (!hwnd) { + std::pair<DWORD, QString> idName(windowProcessId.toInt(), {}); + LPARAM lParam = reinterpret_cast<LPARAM>(&idName); + EnumWindows(EnumWindowsProcMy, lParam); + if (!idName.second.isEmpty()) { + newWindowId = idName.second; + } + } + ret = QString("%1%2:+0,0 window-id:title=%3") .arg(libjami::Media::VideoProtocolPrefix::DISPLAY) .arg(sep) - .arg(windowId); + .arg(newWindowId); #endif return ret; } diff --git a/src/libclient/qtwrapper/conversions_wrap.hpp b/src/libclient/qtwrapper/conversions_wrap.hpp index 9e9dd1fb3..e814e5427 100644 --- a/src/libclient/qtwrapper/conversions_wrap.hpp +++ b/src/libclient/qtwrapper/conversions_wrap.hpp @@ -68,7 +68,7 @@ convertMap(const std::map<std::string, std::string>& m) { MapStringString temp; for (const auto& [key, value] : m) { - temp[QString(key.c_str())] = QString(value.c_str()); + temp[QString(key.c_str())] = QString::fromLatin1(QByteArray::fromStdString(value)); } return temp; } diff --git a/src/libclient/qtwrapper/videomanager_wrap.h b/src/libclient/qtwrapper/videomanager_wrap.h index 4a2b68f4c..f93a85c21 100644 --- a/src/libclient/qtwrapper/videomanager_wrap.h +++ b/src/libclient/qtwrapper/videomanager_wrap.h @@ -126,7 +126,7 @@ public Q_SLOTS: // METHODS QString openVideoInput(const QString& resource) { #ifdef ENABLE_VIDEO - return QByteArray::fromStdString(libjami::openVideoInput(resource.toLatin1().toStdString())); + return QString::fromLatin1(QByteArray::fromStdString(libjami::openVideoInput(resource.toStdString()))); #endif } -- GitLab