1
0
Fork 0
mirror of https://git.jami.net/savoirfairelinux/jami-client-qt.git synced 2025-04-21 21:52:03 +02:00

windows: enable window sharing

GitLab: https://git.jami.net/savoirfairelinux/jami-project/-/issues/1294
GitLab: #481
Change-Id: Iafdb542d37f9a1d59b35d83ba779c1c2f2f0ca0f
This commit is contained in:
Aline Gondim Santos 2022-09-02 09:31:55 -03:00
parent 6862804a44
commit a28d5c5c55
12 changed files with 168 additions and 37 deletions

View file

@ -308,6 +308,8 @@ endif()
if(MSVC) if(MSVC)
set(WINDOWS_SYS_LIBS set(WINDOWS_SYS_LIBS
windowsapp.lib
dwmapi.lib
Shell32.lib Shell32.lib
Ole32.lib Ole32.lib
Advapi32.lib Advapi32.lib

2
daemon

@ -1 +1 @@
Subproject commit e4fa5074cac04f7ba5f8e86b4ce371a3af6a0961 Subproject commit 9d76cf5cc767e33ab06054bfa40ee45f671002bd

View file

@ -92,9 +92,15 @@ AvAdapter::shareEntireScreen(int screenNumber)
if (!screen) if (!screen)
return; return;
QRect rect = screen->geometry(); QRect rect = screen->geometry();
#ifdef WIN32
rect.moveRight(rect.right() - rect.left() + 1);
rect.moveLeft(0);
rect.moveBottom(rect.bottom() - rect.top() + 1);
rect.moveTop(0);
#endif
auto resource = lrcInstance_->getCurrentCallModel() auto resource = lrcInstance_->getCurrentCallModel()
->getDisplay(getScreenNumber(), ->getDisplay(getScreenNumber(screenNumber),
rect.x(), rect.x(),
rect.y(), rect.y(),
rect.width() * screen->devicePixelRatio(), rect.width() * screen->devicePixelRatio(),
@ -229,6 +235,7 @@ AvAdapter::shareWindow(const QString& windowId)
->addMedia(callId, resource, lrc::api::CallModel::MediaRequestType::SCREENSHARING); ->addMedia(callId, resource, lrc::api::CallModel::MediaRequestType::SCREENSHARING);
} }
#pragma optimize("", off)
QString QString
AvAdapter::getSharingResource(int screenId = -2, const QString& windowId = "") AvAdapter::getSharingResource(int screenId = -2, const QString& windowId = "")
{ {
@ -246,7 +253,14 @@ AvAdapter::getSharingResource(int screenId = -2, const QString& windowId = "")
return ""; return "";
QRect rect = screen->geometry(); QRect rect = screen->geometry();
return lrcInstance_->getCurrentCallModel()->getDisplay(getScreenNumber(), #ifdef WIN32
rect.moveRight(rect.right() - rect.left() + 1);
rect.moveLeft(0);
rect.moveBottom(rect.bottom() - rect.top() + 1);
rect.moveTop(0);
#endif
return lrcInstance_->getCurrentCallModel()->getDisplay(screenId,
rect.x(), rect.x(),
rect.y(), rect.y(),
rect.width() rect.width()
@ -375,7 +389,7 @@ AvAdapter::hasCamera() const
} }
int int
AvAdapter::getScreenNumber() const AvAdapter::getScreenNumber(int screenId) const
{ {
int display = 0; int display = 0;
@ -389,6 +403,10 @@ AvAdapter::getScreenNumber() const
display = list.at(0).toInt(); display = list.at(0).toInt();
} }
} }
#else
#ifdef WIN32
display = screenId;
#endif
#endif #endif
return display; return display;
} }

View file

@ -117,5 +117,5 @@ private:
const QRect getAllScreensBoundingRect(); const QRect getAllScreensBoundingRect();
// Get the screen number // Get the screen number
int getScreenNumber() const; int getScreenNumber(int screenId = 0) const;
}; };

View file

@ -121,12 +121,14 @@ Control {
Component.onCompleted: { Component.onCompleted: {
shareModel.append({"Name": JamiStrings.shareScreen, shareModel.append({"Name": JamiStrings.shareScreen,
"IconSource": JamiResources.laptop_black_24dp_svg}) "IconSource": JamiResources.laptop_black_24dp_svg})
if (Qt.platform.os == "linux") { if (Qt.platform.os.toString() !== "osx") {
shareModel.append({"Name": JamiStrings.shareWindow, shareModel.append({"Name": JamiStrings.shareWindow,
"IconSource" : JamiResources.window_black_24dp_svg}) "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.shareScreenArea,
"IconSource" : JamiResources.share_area_black_24dp_svg})
shareModel.append({"Name": JamiStrings.shareFile, shareModel.append({"Name": JamiStrings.shareFile,
"IconSource" : JamiResources.file_black_24dp_svg}) "IconSource" : JamiResources.file_black_24dp_svg})
} }

View file

@ -130,8 +130,7 @@ ContextMenuAutoLoader {
GeneralMenuItem { GeneralMenuItem {
id: shareWindow id: shareWindow
canTrigger: Qt.platform.os === "linux" canTrigger: CurrentAccount.videoEnabled_Video
&& CurrentAccount.videoEnabled_Video
&& AvAdapter.currentRenderingDeviceType !== Video.DeviceType.DISPLAY && AvAdapter.currentRenderingDeviceType !== Video.DeviceType.DISPLAY
&& !CurrentCall.isSIP && !CurrentCall.isSIP
itemName: JamiStrings.shareWindow itemName: JamiStrings.shareWindow
@ -150,6 +149,7 @@ ContextMenuAutoLoader {
canTrigger: CurrentAccount.videoEnabled_Video canTrigger: CurrentAccount.videoEnabled_Video
&& AvAdapter.currentRenderingDeviceType !== Video.DeviceType.DISPLAY && AvAdapter.currentRenderingDeviceType !== Video.DeviceType.DISPLAY
&& !CurrentCall.isSIP && !CurrentCall.isSIP
&& Qt.platform.os.toString() !== "windows" // temporarily disable for windows
itemName: JamiStrings.shareScreenArea itemName: JamiStrings.shareScreenArea
iconSource: JamiResources.share_area_black_24dp_svg iconSource: JamiResources.share_area_black_24dp_svg
onClicked: { onClicked: {

View file

@ -32,18 +32,40 @@ Window {
id: screenRubberBandWindow id: screenRubberBandWindow
function setAllScreensGeo() { function setAllScreensGeo() {
var width = 0, height = 0 var width = 0, height = 0, x = 0, y = 0
var screens = Qt.application.screens var screens = Qt.application.screens
for (var i = 0; i < screens.length; ++i) { for (var i = 0; i < screens.length; ++i) {
width += screens[i].width var screenWidth = screens[i].width * screens[i].devicePixelRatio
if (height < screens[i].height) var screenHeight = screens[i].height * screens[i].devicePixelRatio
height = screens[i].height
if (screens[i].virtualX >= x + width)
width += screenWidth
else if (screens[i].virtualX + screenWidth <= x)
width += screenWidth
else if (screens[i].virtualX < x && screens[i].virtualX + screenWidth > x)
width += (x - screens[i].virtualX) * screens[i].devicePixelRatio
else if (screens[i].virtualX > x && screens[i].virtualX + screenWidth > x + width)
width += (screens[i].virtualX + screenWidth - x - width) * screens[i].devicePixelRatio
if (screens[i].virtualY >= y + height)
height += screenHeight
else if (screens[i].virtualY + screenHeight <= y)
height += screenHeight
else if (screens[i].virtualY < y && screens[i].virtualY + screenHeight > y)
height += (y - screens[i].virtualY) * screens[i].devicePixelRatio
else if (screens[i].virtualY > y && screens[i].virtualY + screenHeight > y + height)
height += (screens[i].virtualY + screenWidth - y - height) * screens[i].devicePixelRatio
if (screens[i].virtualY < y)
y = screens[i].virtualY
if (screens[i].virtualX < x)
x = screens[i].virtualX
} }
screenRubberBandWindow.width = width screenRubberBandWindow.width = width
screenRubberBandWindow.height = height screenRubberBandWindow.height = height
screenRubberBandWindow.x = 0 screenRubberBandWindow.x = x
screenRubberBandWindow.y = 0 screenRubberBandWindow.y = y
} }
flags: Qt.FramelessWindowHint | Qt.WindowStaysOnTopHint | Qt.WA_TranslucentBackground flags: Qt.FramelessWindowHint | Qt.WindowStaysOnTopHint | Qt.WA_TranslucentBackground

View file

@ -65,7 +65,9 @@ Window {
return screens.length return screens.length
} }
onActiveChanged: { onVisibleChanged: {
if (!visible)
return
if (!active) { if (!active) {
selectedScreenNumber = -1 selectedScreenNumber = -1
selectAllScreens = false selectAllScreens = false
@ -161,9 +163,7 @@ Window {
width: screenItem.width - 50 width: screenItem.width - 50
Component.onDestruction: { Component.onDestruction: {
if (rendererId !== "" && rendererId !== currentPreview) { VideoDevices.stopDevice(rendererId)
VideoDevices.stopDevice(rendererId)
}
} }
Component.onCompleted: { Component.onCompleted: {
if (visible) { if (visible) {
@ -209,7 +209,7 @@ Window {
border.color: selectAllScreens ? JamiTheme.screenSelectionBorderColor : JamiTheme.tabbarBorderColor border.color: selectAllScreens ? JamiTheme.screenSelectionBorderColor : JamiTheme.tabbarBorderColor
visible: !root.window && Qt.application.screens.length > 1 visible: !root.window && Qt.application.screens.length > 1 && Qt.platform.os.toString() !== "windows"
Text { Text {
id: screenNameAll id: screenNameAll
@ -233,9 +233,7 @@ Window {
width: screenSelectionRectAll.width - 50 width: screenSelectionRectAll.width - 50
Component.onDestruction: { Component.onDestruction: {
if (rendererId !== "" && rendererId !== currentPreview) { VideoDevices.stopDevice(rendererId)
VideoDevices.stopDevice(rendererId)
}
} }
Component.onCompleted: { Component.onCompleted: {
if (visible) { if (visible) {
@ -313,9 +311,7 @@ Window {
width: screenItem2.width - 50 width: screenItem2.width - 50
Component.onDestruction: { Component.onDestruction: {
if (rendererId !== "" && rendererId !== currentPreview) { VideoDevices.stopDevice(rendererId)
VideoDevices.stopDevice(rendererId)
}
} }
Component.onCompleted: { Component.onCompleted: {
if (visible) { if (visible) {

View file

@ -53,6 +53,11 @@
#if defined(Q_OS_UNIX) && !defined(__APPLE__) #if defined(Q_OS_UNIX) && !defined(__APPLE__)
#include <xcb/xcb.h> #include <xcb/xcb.h>
#endif #endif
#ifdef WIN32
#include "Windows.h"
#include <tchar.h>
#include <dwmapi.h>
#endif
namespace lrc { namespace lrc {
@ -540,6 +545,71 @@ AVModel::stopPreview(const QString& resource)
VideoManager::instance().closeVideoInput(resource); VideoManager::instance().closeVideoInput(resource);
} }
#ifdef WIN32
BOOL
IsAltTabWindow(HWND hwnd)
{
LONG style = GetWindowLong(hwnd, GWL_STYLE);
if (!((style & WS_DISABLED) != WS_DISABLED)) {
return false;
}
DWORD cloaked = FALSE;
HRESULT hrTemp = DwmGetWindowAttribute(hwnd, DWMWA_CLOAKED, &cloaked, sizeof(cloaked));
if (SUCCEEDED(hrTemp) && cloaked == DWM_CLOAKED_SHELL) {
return false;
}
// Start at the root owner
HWND hwndWalk = GetAncestor(hwnd, GA_ROOTOWNER);
// See if we are the last active visible popup
HWND hwndTry;
while ((hwndTry = GetLastActivePopup(hwndWalk)) != hwndTry) {
if (IsWindowVisible(hwndTry))
break;
hwndWalk = hwndTry;
}
return hwndWalk == hwnd;
}
BOOL CALLBACK
CbEnumAltTab(HWND hwnd, LPARAM lParam)
{
// Do not show invisible windows
if (!IsWindowVisible(hwnd))
return TRUE;
// Alt-tab test as described by Raymond Chen
if (!IsAltTabWindow(hwnd))
return TRUE;
const size_t MAX_WINDOW_NAME = 256;
TCHAR windowName[MAX_WINDOW_NAME];
if (hwnd == GetShellWindow())
return TRUE;
else
GetWindowText(hwnd, windowName, MAX_WINDOW_NAME);
// Do not show windows that has no caption
if (0 == windowName[0])
return TRUE;
std::wstring msg = std::wstring(windowName);
auto name = QString::fromStdWString(msg);
QMap<QString, QVariant>* windowList = reinterpret_cast<QMap<QString, QVariant>*>(lParam);
auto keys = windowList->keys();
if (keys.indexOf(name) > 0) {
return FALSE;
} else {
windowList->insert(name, name);
}
return TRUE;
}
#endif
#if defined(Q_OS_UNIX) && !defined(__APPLE__) #if defined(Q_OS_UNIX) && !defined(__APPLE__)
static xcb_atom_t static xcb_atom_t
getAtom(xcb_connection_t* c, const std::string& atomName) getAtom(xcb_connection_t* c, const std::string& atomName)
@ -630,10 +700,19 @@ AVModel::getListWindows() const
} }
} }
} }
return ret;
#else
return ret;
#endif #endif
#ifdef WIN32
try {
auto newWindow = true;
LPARAM lParam = reinterpret_cast<LPARAM>(&ret);
while (newWindow) {
newWindow = EnumWindows(CbEnumAltTab, lParam);
}
auto finishedloop = true;
} catch (...) {
}
#endif
return ret;
} }
void void

View file

@ -928,10 +928,20 @@ QString
CallModel::getDisplay(const QString& windowId) CallModel::getDisplay(const QString& windowId)
{ {
QString sep = libjami::Media::VideoProtocolPrefix::SEPARATOR; QString sep = libjami::Media::VideoProtocolPrefix::SEPARATOR;
return QString("%1%2:+0,0 window-id:%3") QString ret{};
#if (defined(Q_OS_UNIX) && !defined(__APPLE__))
ret = QString("%1%2:+0,0 window-id:%3")
.arg(libjami::Media::VideoProtocolPrefix::DISPLAY) .arg(libjami::Media::VideoProtocolPrefix::DISPLAY)
.arg(sep) .arg(sep)
.arg(windowId); .arg(windowId);
#endif
#ifdef WIN32
ret = QString("%1%2:+0,0 window-id:title=%3")
.arg(libjami::Media::VideoProtocolPrefix::DISPLAY)
.arg(sep)
.arg(windowId);
#endif
return ret;
} }
CallModelPimpl::CallModelPimpl(const CallModel& linked, CallModelPimpl::CallModelPimpl(const CallModel& linked,

View file

@ -30,15 +30,17 @@ VideoManagerInterface::VideoManagerInterface()
int width, int width,
int height, int height,
bool isMixer) { bool isMixer) {
Q_EMIT decodingStarted(QString(id.c_str()), Q_EMIT decodingStarted(QString::fromLatin1(QByteArray::fromStdString(id)),
QString(shmPath.c_str()), QString::fromLatin1(QByteArray::fromStdString(shmPath)),
width, width,
height, height,
isMixer); isMixer);
}), }),
exportable_callback<VideoSignal::DecodingStopped>( exportable_callback<VideoSignal::DecodingStopped>(
[this](const std::string& id, const std::string& shmPath, bool isMixer) { [this](const std::string& id, const std::string& shmPath, bool isMixer) {
Q_EMIT decodingStopped(QString(id.c_str()), QString(shmPath.c_str()), isMixer); Q_EMIT decodingStopped(QString::fromLatin1(QByteArray::fromStdString(id)),
QString::fromLatin1(QByteArray::fromStdString(shmPath)),
isMixer);
})}; })};
#endif #endif
} }

View file

@ -126,7 +126,7 @@ public Q_SLOTS: // METHODS
QString openVideoInput(const QString& resource) QString openVideoInput(const QString& resource)
{ {
#ifdef ENABLE_VIDEO #ifdef ENABLE_VIDEO
return libjami::openVideoInput(resource.toLatin1().toStdString()).c_str(); return QByteArray::fromStdString(libjami::openVideoInput(resource.toLatin1().toStdString()));
#endif #endif
} }
@ -150,7 +150,7 @@ public Q_SLOTS: // METHODS
bool registerSinkTarget(const QString& sinkID, const libjami::SinkTarget& target) bool registerSinkTarget(const QString& sinkID, const libjami::SinkTarget& target)
{ {
#ifdef ENABLE_VIDEO #ifdef ENABLE_VIDEO
return libjami::registerSinkTarget(sinkID.toStdString(), target); return libjami::registerSinkTarget(sinkID.toLatin1().toStdString(), target);
#else #else
Q_UNUSED(sinkID) Q_UNUSED(sinkID)
Q_UNUSED(target) Q_UNUSED(target)