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)
set(WINDOWS_SYS_LIBS
windowsapp.lib
dwmapi.lib
Shell32.lib
Ole32.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)
return;
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()
->getDisplay(getScreenNumber(),
->getDisplay(getScreenNumber(screenNumber),
rect.x(),
rect.y(),
rect.width() * screen->devicePixelRatio(),
@ -229,6 +235,7 @@ 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 = "")
{
@ -246,7 +253,14 @@ AvAdapter::getSharingResource(int screenId = -2, const QString& windowId = "")
return "";
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.y(),
rect.width()
@ -375,7 +389,7 @@ AvAdapter::hasCamera() const
}
int
AvAdapter::getScreenNumber() const
AvAdapter::getScreenNumber(int screenId) const
{
int display = 0;
@ -389,6 +403,10 @@ AvAdapter::getScreenNumber() const
display = list.at(0).toInt();
}
}
#else
#ifdef WIN32
display = screenId;
#endif
#endif
return display;
}

View file

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

View file

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

View file

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

View file

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

View file

@ -65,7 +65,9 @@ Window {
return screens.length
}
onActiveChanged: {
onVisibleChanged: {
if (!visible)
return
if (!active) {
selectedScreenNumber = -1
selectAllScreens = false
@ -161,10 +163,8 @@ Window {
width: screenItem.width - 50
Component.onDestruction: {
if (rendererId !== "" && rendererId !== currentPreview) {
VideoDevices.stopDevice(rendererId)
}
}
Component.onCompleted: {
if (visible) {
const rId = AvAdapter.getSharingResource(index, "")
@ -209,7 +209,7 @@ Window {
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 {
id: screenNameAll
@ -233,10 +233,8 @@ Window {
width: screenSelectionRectAll.width - 50
Component.onDestruction: {
if (rendererId !== "" && rendererId !== currentPreview) {
VideoDevices.stopDevice(rendererId)
}
}
Component.onCompleted: {
if (visible) {
const rId = AvAdapter.getSharingResource(-1, "")
@ -313,10 +311,8 @@ Window {
width: screenItem2.width - 50
Component.onDestruction: {
if (rendererId !== "" && rendererId !== currentPreview) {
VideoDevices.stopDevice(rendererId)
}
}
Component.onCompleted: {
if (visible) {
const rId = AvAdapter.getSharingResource(-2, AvAdapter.windowsIds[index - Qt.application.screens.length])

View file

@ -53,6 +53,11 @@
#if defined(Q_OS_UNIX) && !defined(__APPLE__)
#include <xcb/xcb.h>
#endif
#ifdef WIN32
#include "Windows.h"
#include <tchar.h>
#include <dwmapi.h>
#endif
namespace lrc {
@ -540,6 +545,71 @@ AVModel::stopPreview(const QString& 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__)
static xcb_atom_t
getAtom(xcb_connection_t* c, const std::string& atomName)
@ -630,10 +700,19 @@ AVModel::getListWindows() const
}
}
}
return ret;
#else
return ret;
#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

View file

@ -928,10 +928,20 @@ QString
CallModel::getDisplay(const QString& windowId)
{
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(sep)
.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,

View file

@ -30,15 +30,17 @@ VideoManagerInterface::VideoManagerInterface()
int width,
int height,
bool isMixer) {
Q_EMIT decodingStarted(QString(id.c_str()),
QString(shmPath.c_str()),
Q_EMIT decodingStarted(QString::fromLatin1(QByteArray::fromStdString(id)),
QString::fromLatin1(QByteArray::fromStdString(shmPath)),
width,
height,
isMixer);
}),
exportable_callback<VideoSignal::DecodingStopped>(
[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
}

View file

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