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:
parent
6862804a44
commit
a28d5c5c55
12 changed files with 168 additions and 37 deletions
|
@ -308,6 +308,8 @@ endif()
|
|||
|
||||
if(MSVC)
|
||||
set(WINDOWS_SYS_LIBS
|
||||
windowsapp.lib
|
||||
dwmapi.lib
|
||||
Shell32.lib
|
||||
Ole32.lib
|
||||
Advapi32.lib
|
||||
|
|
2
daemon
2
daemon
|
@ -1 +1 @@
|
|||
Subproject commit e4fa5074cac04f7ba5f8e86b4ce371a3af6a0961
|
||||
Subproject commit 9d76cf5cc767e33ab06054bfa40ee45f671002bd
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -117,5 +117,5 @@ private:
|
|||
const QRect getAllScreensBoundingRect();
|
||||
|
||||
// Get the screen number
|
||||
int getScreenNumber() const;
|
||||
int getScreenNumber(int screenId = 0) const;
|
||||
};
|
||||
|
|
|
@ -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})
|
||||
}
|
||||
|
|
|
@ -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: {
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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])
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
|
|
Loading…
Add table
Reference in a new issue