mirror of
https://gitlab.linphone.org/BC/public/linphone-desktop.git
synced 2026-01-17 03:18:07 +00:00
Screensharing + Mac ARM64 + Linux build
This commit is contained in:
parent
231d42db1c
commit
99f752390b
55 changed files with 2452 additions and 74 deletions
|
|
@ -57,7 +57,7 @@ endif()
|
|||
set(CMAKE_INSTALL_PREFIX "${APPLICATION_OUTPUT_DIR}")
|
||||
|
||||
if( APPLE )
|
||||
set(LINPHONEAPP_MACOS_ARCHS "x86_64" CACHE STRING "MacOS architectures to build: comma-separated list of values in [arm64, x86_64]")
|
||||
set(LINPHONEAPP_MACOS_ARCHS "arm64" CACHE STRING "MacOS architectures to build: comma-separated list of values in [arm64, x86_64]")
|
||||
set(LINPHONESDK_BUILD_TYPE "Default")#Using Mac will remove all SDK targets.
|
||||
set(ENABLE_FAT_BINARY "ON") # Disable XCFrameworks as it is not supported.
|
||||
|
||||
|
|
@ -149,6 +149,7 @@ add_option(OPTION_LIST ENABLE_QT_KEYCHAIN "Build QtKeychain to manage VFS from S
|
|||
add_option(OPTION_LIST ENABLE_QRCODE "Enable QRCode support" OFF)#Experimental
|
||||
add_option(OPTION_LIST ENABLE_RELATIVE_PREFIX "Set Internal packages relative to the binary" ON)
|
||||
add_option(OPTION_LIST ENABLE_SANITIZER "Enable sanitizer." OFF)
|
||||
add_option(OPTION_LIST ENABLE_SCREENSHARING "Enable screen sharing." ON)
|
||||
add_option(OPTION_LIST ENABLE_STRICT "Build with strict compilator flags e.g. -Wall -Werror" OFF)
|
||||
add_option(OPTION_LIST ENABLE_TESTS "Build with testing binaries of SDK" OFF)
|
||||
add_option(OPTION_LIST ENABLE_TESTS_COMPONENTS "Build libbctoolbox-tester" OFF)
|
||||
|
|
|
|||
|
|
@ -27,6 +27,14 @@ endif()
|
|||
find_package(Qt6 REQUIRED COMPONENTS Core)
|
||||
find_package(Qt6 REQUIRED COMPONENTS ${QT_PACKAGES})
|
||||
|
||||
if(NOT WIN32)
|
||||
find_package(X11)
|
||||
endif()
|
||||
|
||||
if(X11_FOUND)
|
||||
list(APPEND APP_TARGETS X11::X11)
|
||||
endif()
|
||||
|
||||
################################################################
|
||||
# CONFIGS
|
||||
################################################################
|
||||
|
|
@ -132,6 +140,15 @@ if(MSVC)
|
|||
set_target_properties(${TARGET_NAME} PROPERTIES PDB_NAME "${EXECUTABLE_NAME}_app")
|
||||
endif()
|
||||
|
||||
if(WIN32)
|
||||
if(ENABLE_SCREENSHARING)
|
||||
target_link_libraries(${TARGET_NAME} PUBLIC Dwmapi)
|
||||
endif()
|
||||
elseif (APPLE)
|
||||
target_link_libraries(${TARGET_NAME} PUBLIC "-framework Cocoa" "-framework IOKit" "-framework AVFoundation" "-framework ScreenCaptureKit")
|
||||
endif()
|
||||
|
||||
|
||||
foreach(T ${APP_TARGETS})
|
||||
target_include_directories(${TARGET_NAME} SYSTEM PUBLIC $<TARGET_PROPERTY:${T},INTERFACE_INCLUDE_DIRECTORIES>)
|
||||
target_link_libraries(${TARGET_NAME} PUBLIC ${T})
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
set(APPLICATION_DESCRIPTION "A libre SIP client")
|
||||
set(APPLICATION_ID "com.belledonnecommunications.linphone")
|
||||
set(APPLICATION_ID "com.belledonnecommunications.linphone60")
|
||||
set(APPLICATION_NAME Linphone60)
|
||||
set(APPLICATION_URL "https://www.linphone.org")
|
||||
set(APPLICATION_VENDOR "Belledonne Communications")
|
||||
|
|
|
|||
|
|
@ -33,6 +33,7 @@
|
|||
#cmakedefine EXECUTABLE_NAME "${EXECUTABLE_NAME}"
|
||||
#cmakedefine MSPLUGINS_DIR "${MSPLUGINS_DIR}"
|
||||
#cmakedefine ENABLE_APP_WEBVIEW "${ENABLE_APP_WEBVIEW}"
|
||||
#cmakedefine ENABLE_SCREENSHARING "${ENABLE_SCREENSHARING}"
|
||||
#cmakedefine QTKEYCHAIN_TARGET_NAME ${QTKEYCHAIN_TARGET_NAME}
|
||||
#cmakedefine PDF_ENABLED
|
||||
|
||||
|
|
|
|||
|
|
@ -57,18 +57,23 @@
|
|||
#include "core/participant/ParticipantProxy.hpp"
|
||||
#include "core/phone-number/PhoneNumber.hpp"
|
||||
#include "core/phone-number/PhoneNumberProxy.hpp"
|
||||
#include "core/screen/ScreenList.hpp"
|
||||
#include "core/screen/ScreenProxy.hpp"
|
||||
#include "core/search/MagicSearchProxy.hpp"
|
||||
#include "core/setting/SettingsCore.hpp"
|
||||
#include "core/singleapplication/singleapplication.h"
|
||||
#include "core/timezone/TimeZone.hpp"
|
||||
#include "core/timezone/TimeZoneProxy.hpp"
|
||||
#include "core/variant/VariantList.hpp"
|
||||
#include "core/videoSource/VideoSourceDescriptorGui.hpp"
|
||||
#include "model/object/VariantObject.hpp"
|
||||
#include "tool/Constants.hpp"
|
||||
#include "tool/EnumsToString.hpp"
|
||||
#include "tool/Utils.hpp"
|
||||
#include "tool/native/DesktopTools.hpp"
|
||||
#include "tool/providers/AvatarProvider.hpp"
|
||||
#include "tool/providers/ImageProvider.hpp"
|
||||
#include "tool/providers/ScreenProvider.hpp"
|
||||
#include "tool/thread/Thread.hpp"
|
||||
|
||||
DEFINE_ABSTRACT_OBJECT(App)
|
||||
|
|
@ -158,6 +163,9 @@ void App::init() {
|
|||
initCppInterfaces();
|
||||
mEngine->addImageProvider(ImageProvider::ProviderId, new ImageProvider());
|
||||
mEngine->addImageProvider(AvatarProvider::ProviderId, new AvatarProvider());
|
||||
mEngine->addImageProvider(ScreenProvider::ProviderId, new ScreenProvider());
|
||||
mEngine->addImageProvider(WindowProvider::ProviderId, new WindowProvider());
|
||||
mEngine->addImageProvider(WindowIconProvider::ProviderId, new WindowIconProvider());
|
||||
|
||||
// Enable notifications.
|
||||
mNotifier = new Notifier(mEngine);
|
||||
|
|
@ -254,6 +262,13 @@ void App::initCppInterfaces() {
|
|||
qmlRegisterType<ParticipantDeviceGui>(Constants::MainQmlUri, 1, 0, "ParticipantDeviceGui");
|
||||
qmlRegisterType<ParticipantDeviceProxy>(Constants::MainQmlUri, 1, 0, "ParticipantDeviceProxy");
|
||||
|
||||
qmlRegisterUncreatableType<ScreenList>(Constants::MainQmlUri, 1, 0, "ScreenList", QLatin1String("Uncreatable"));
|
||||
qmlRegisterType<ScreenProxy>(Constants::MainQmlUri, 1, 0, "ScreenProxy");
|
||||
|
||||
qmlRegisterUncreatableType<VideoSourceDescriptorCore>(Constants::MainQmlUri, 1, 0, "VideoSourceDescriptorCore",
|
||||
QLatin1String("Uncreatable"));
|
||||
qmlRegisterType<VideoSourceDescriptorGui>(Constants::MainQmlUri, 1, 0, "VideoSourceDescriptorGui");
|
||||
|
||||
LinphoneEnums::registerMetaTypes();
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -56,6 +56,12 @@ list(APPEND _LINPHONEAPP_SOURCES
|
|||
core/participant/ParticipantDeviceProxy.cpp
|
||||
core/participant/ParticipantList.cpp
|
||||
core/participant/ParticipantProxy.cpp
|
||||
|
||||
core/screen/ScreenList.cpp
|
||||
core/screen/ScreenProxy.cpp
|
||||
|
||||
core/videoSource/VideoSourceDescriptorCore.cpp
|
||||
core/videoSource/VideoSourceDescriptorGui.cpp
|
||||
)
|
||||
|
||||
## Single Application
|
||||
|
|
|
|||
|
|
@ -102,6 +102,8 @@ CallCore::CallCore(const std::shared_ptr<linphone::Call> &call) : QObject(nullpt
|
|||
mMicrophoneVolume = call->getRecordVolume();
|
||||
mRecordable = mState == LinphoneEnums::CallState::StreamsRunning;
|
||||
mConferenceVideoLayout = mCallModel->getConferenceVideoLayout();
|
||||
auto videoSource = call->getVideoSource();
|
||||
mVideoSourceDescriptor = VideoSourceDescriptorCore::create(videoSource ? videoSource->clone() : nullptr);
|
||||
}
|
||||
|
||||
CallCore::~CallCore() {
|
||||
|
|
@ -299,6 +301,17 @@ void CallCore::setSelf(QSharedPointer<CallCore> me) {
|
|||
&CallCore::lSetConferenceVideoLayout, [this](LinphoneEnums::ConferenceLayout layout) {
|
||||
mCallModelConnection->invokeToModel([this, layout]() { mCallModel->changeConferenceVideoLayout(layout); });
|
||||
});
|
||||
mCallModelConnection->makeConnectToCore(
|
||||
&CallCore::lSetVideoSourceDescriptor, [this](VideoSourceDescriptorGui *gui) {
|
||||
mCallModelConnection->invokeToModel(
|
||||
[this, model = gui->getCore()->getModel()]() { mCallModel->setVideoSourceDescriptorModel(model); });
|
||||
});
|
||||
|
||||
mCallModelConnection->makeConnectToModel(&CallModel::videoDescriptorChanged, [this]() {
|
||||
auto videoSource = mCallModel->getMonitor()->getVideoSource();
|
||||
auto core = VideoSourceDescriptorCore::create(videoSource ? videoSource->clone() : nullptr);
|
||||
mCallModelConnection->invokeToCore([this, core]() { setVideoSourceDescriptor(core); });
|
||||
});
|
||||
}
|
||||
|
||||
QString CallCore::getPeerAddress() const {
|
||||
|
|
@ -568,6 +581,17 @@ LinphoneEnums::ConferenceLayout CallCore::getConferenceVideoLayout() const {
|
|||
return mConferenceVideoLayout;
|
||||
}
|
||||
|
||||
VideoSourceDescriptorGui *CallCore::getVideoSourceDescriptorGui() const {
|
||||
return new VideoSourceDescriptorGui(mVideoSourceDescriptor);
|
||||
}
|
||||
|
||||
void CallCore::setVideoSourceDescriptor(QSharedPointer<VideoSourceDescriptorCore> core) {
|
||||
if (mVideoSourceDescriptor != core) {
|
||||
mVideoSourceDescriptor = core;
|
||||
emit videoSourceDescriptorChanged();
|
||||
}
|
||||
}
|
||||
|
||||
void CallCore::setConferenceVideoLayout(LinphoneEnums::ConferenceLayout layout) {
|
||||
mustBeInMainThread(log().arg(Q_FUNC_INFO));
|
||||
if (mConferenceVideoLayout != layout) {
|
||||
|
|
|
|||
|
|
@ -23,6 +23,7 @@
|
|||
|
||||
#include "core/conference/ConferenceCore.hpp"
|
||||
#include "core/conference/ConferenceGui.hpp"
|
||||
#include "core/videoSource/VideoSourceDescriptorGui.hpp"
|
||||
#include "model/call/CallModel.hpp"
|
||||
#include "tool/LinphoneEnums.hpp"
|
||||
#include "tool/thread/SafeConnection.hpp"
|
||||
|
|
@ -66,6 +67,9 @@ class CallCore : public QObject, public AbstractObject {
|
|||
Q_PROPERTY(LinphoneEnums::ConferenceLayout conferenceVideoLayout READ getConferenceVideoLayout WRITE
|
||||
lSetConferenceVideoLayout NOTIFY conferenceVideoLayoutChanged)
|
||||
|
||||
Q_PROPERTY(VideoSourceDescriptorGui *videoSourceDescriptor READ getVideoSourceDescriptorGui WRITE
|
||||
lSetVideoSourceDescriptor NOTIFY videoSourceDescriptorChanged)
|
||||
|
||||
public:
|
||||
// Should be call from model Thread. Will be automatically in App thread after initialization
|
||||
static QSharedPointer<CallCore> create(const std::shared_ptr<linphone::Call> &call);
|
||||
|
|
@ -149,8 +153,10 @@ public:
|
|||
LinphoneEnums::ConferenceLayout getConferenceVideoLayout() const;
|
||||
void setConferenceVideoLayout(LinphoneEnums::ConferenceLayout layout);
|
||||
|
||||
std::shared_ptr<CallModel> getModel() const;
|
||||
VideoSourceDescriptorGui *getVideoSourceDescriptorGui() const;
|
||||
void setVideoSourceDescriptor(QSharedPointer<VideoSourceDescriptorCore> core);
|
||||
|
||||
std::shared_ptr<CallModel> getModel() const;
|
||||
signals:
|
||||
void statusChanged(LinphoneEnums::CallStatus status);
|
||||
void stateChanged(LinphoneEnums::CallState state);
|
||||
|
|
@ -174,6 +180,7 @@ signals:
|
|||
void microphoneVolumeGainChanged();
|
||||
void conferenceChanged();
|
||||
void conferenceVideoLayoutChanged();
|
||||
void videoSourceDescriptorChanged();
|
||||
|
||||
// Linphone commands
|
||||
void lAccept(bool withVideo); // Accept an incoming call
|
||||
|
|
@ -194,6 +201,7 @@ signals:
|
|||
void lSetInputAudioDevice(QString id);
|
||||
void lSetOutputAudioDevice(QString id);
|
||||
void lSetConferenceVideoLayout(LinphoneEnums::ConferenceLayout layout);
|
||||
void lSetVideoSourceDescriptor(VideoSourceDescriptorGui *gui);
|
||||
|
||||
/* TODO
|
||||
Q_INVOKABLE void acceptWithVideo();
|
||||
|
|
@ -216,6 +224,7 @@ signals:
|
|||
private:
|
||||
std::shared_ptr<CallModel> mCallModel;
|
||||
QSharedPointer<ConferenceCore> mConference;
|
||||
QSharedPointer<VideoSourceDescriptorCore> mVideoSourceDescriptor;
|
||||
LinphoneEnums::CallStatus mStatus;
|
||||
LinphoneEnums::CallState mState;
|
||||
LinphoneEnums::CallState mTransferState;
|
||||
|
|
|
|||
|
|
@ -39,6 +39,8 @@ ConferenceCore::ConferenceCore(const std::shared_ptr<linphone::Conference> &conf
|
|||
mConferenceModel = ConferenceModel::create(conference);
|
||||
mSubject = Utils::coreStringToAppString(conference->getSubject());
|
||||
mParticipantDeviceCount = conference->getParticipantDeviceList().size();
|
||||
mIsLocalScreenSharing = mConferenceModel->isLocalScreenSharing();
|
||||
mIsScreenSharingEnabled = mConferenceModel->isScreenSharingEnabled();
|
||||
auto me = conference->getMe();
|
||||
if (me) {
|
||||
mMe = ParticipantCore::create(me);
|
||||
|
|
@ -57,27 +59,27 @@ void ConferenceCore::setSelf(QSharedPointer<ConferenceCore> me) {
|
|||
[this](const std::shared_ptr<linphone::ParticipantDevice> &participantDevice) {
|
||||
auto device = ParticipantDeviceCore::create(participantDevice);
|
||||
mConferenceModelConnection->invokeToCore([this, device]() { setActiveSpeaker(device); });
|
||||
});
|
||||
mConferenceModelConnection->makeConnectToModel(&ConferenceModel::participantDeviceAdded, [this]() {
|
||||
int count = mConferenceModel->getParticipantDeviceCount();
|
||||
mConferenceModelConnection->invokeToCore([this, count]() { setParticipantDeviceCount(count); });
|
||||
});
|
||||
mConferenceModelConnection->makeConnectToModel(&ConferenceModel::participantDeviceRemoved, [this]() {
|
||||
int count = mConferenceModel->getParticipantDeviceCount();
|
||||
mConferenceModelConnection->invokeToCore([this, count]() { setParticipantDeviceCount(count); });
|
||||
});
|
||||
mConferenceModelConnection->makeConnectToModel(&ConferenceModel::participantAdded, [this]() {
|
||||
int count = mConferenceModel->getParticipantDeviceCount();
|
||||
mConferenceModelConnection->invokeToCore([this, count]() { setParticipantDeviceCount(count); });
|
||||
});
|
||||
mConferenceModelConnection->makeConnectToModel(&ConferenceModel::participantRemoved, [this]() {
|
||||
int count = mConferenceModel->getParticipantDeviceCount();
|
||||
mConferenceModelConnection->invokeToCore([this, count]() { setParticipantDeviceCount(count); });
|
||||
});
|
||||
});
|
||||
|
||||
mConferenceModelConnection->makeConnectToModel(&ConferenceModel::participantDeviceStateChanged, [this]() {
|
||||
int count = mConferenceModel->getParticipantDeviceCount();
|
||||
mConferenceModelConnection->invokeToCore([this, count]() { setParticipantDeviceCount(count); });
|
||||
});
|
||||
|
||||
mConferenceModelConnection->makeConnectToModel(&ConferenceModel::participantDeviceCountChanged, [this](int count) {
|
||||
mConferenceModelConnection->invokeToCore([this, count]() { setParticipantDeviceCount(count); });
|
||||
});
|
||||
mConferenceModelConnection->makeConnectToModel(&ConferenceModel::isLocalScreenSharingChanged, [this]() {
|
||||
auto state = mConferenceModel->isLocalScreenSharing();
|
||||
mConferenceModelConnection->invokeToCore([this, state]() { setIsLocalScreenSharing(state); });
|
||||
});
|
||||
mConferenceModelConnection->makeConnectToModel(&ConferenceModel::isScreenSharingEnabledChanged, [this]() {
|
||||
auto state = mConferenceModel->isScreenSharingEnabled();
|
||||
mConferenceModelConnection->invokeToCore([this, state]() { setIsScreenSharingEnabled(state); });
|
||||
});
|
||||
mConferenceModelConnection->makeConnectToCore(&ConferenceCore::lToggleScreenSharing, [this]() {
|
||||
mConferenceModelConnection->invokeToModel([this]() { mConferenceModel->toggleScreenSharing(); });
|
||||
});
|
||||
}
|
||||
|
||||
bool ConferenceCore::updateLocalParticipant() { // true if changed
|
||||
|
|
@ -117,6 +119,22 @@ void ConferenceCore::setIsReady(bool state) {
|
|||
}
|
||||
}
|
||||
|
||||
void ConferenceCore::setIsLocalScreenSharing(bool state) {
|
||||
mustBeInMainThread(log().arg(Q_FUNC_INFO));
|
||||
if (mIsLocalScreenSharing != state) {
|
||||
mIsLocalScreenSharing = state;
|
||||
emit isLocalScreenSharingChanged();
|
||||
}
|
||||
}
|
||||
|
||||
void ConferenceCore::setIsScreenSharingEnabled(bool state) {
|
||||
mustBeInMainThread(log().arg(Q_FUNC_INFO));
|
||||
if (mIsScreenSharingEnabled != state) {
|
||||
mIsScreenSharingEnabled = state;
|
||||
emit isScreenSharingEnabledChanged();
|
||||
}
|
||||
}
|
||||
|
||||
std::shared_ptr<ConferenceModel> ConferenceCore::getModel() const {
|
||||
return mConferenceModel;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -40,7 +40,12 @@ public:
|
|||
// Q_PROPERTY(ParticipantDeviceList *participantDevices READ getParticipantDeviceList CONSTANT)
|
||||
// Q_PROPERTY(ParticipantModel* localParticipant READ getLocalParticipant NOTIFY localParticipantChanged)
|
||||
Q_PROPERTY(bool isReady MEMBER mIsReady WRITE setIsReady NOTIFY isReadyChanged)
|
||||
|
||||
Q_PROPERTY(QString subject MEMBER mSubject CONSTANT)
|
||||
Q_PROPERTY(bool isLocalScreenSharing MEMBER mIsLocalScreenSharing WRITE setIsLocalScreenSharing NOTIFY
|
||||
isLocalScreenSharingChanged)
|
||||
Q_PROPERTY(bool isScreenSharingEnabled MEMBER mIsScreenSharingEnabled WRITE setIsScreenSharingEnabled NOTIFY
|
||||
isScreenSharingEnabledChanged)
|
||||
Q_PROPERTY(int participantDeviceCount READ getParticipantDeviceCount NOTIFY participantDeviceCountChanged)
|
||||
Q_PROPERTY(ParticipantDeviceGui *activeSpeaker READ getActiveSpeakerGui NOTIFY activeSpeakerChanged)
|
||||
Q_PROPERTY(ParticipantGui *me READ getMeGui)
|
||||
|
|
@ -66,15 +71,22 @@ public:
|
|||
|
||||
void setIsReady(bool state);
|
||||
|
||||
void setIsLocalScreenSharing(bool state);
|
||||
void setIsScreenSharingEnabled(bool state);
|
||||
|
||||
std::shared_ptr<ConferenceModel> getModel() const;
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
signals:
|
||||
void isReadyChanged();
|
||||
void isLocalScreenSharingChanged();
|
||||
void isScreenSharingEnabledChanged();
|
||||
void participantDeviceCountChanged();
|
||||
void activeSpeakerChanged();
|
||||
|
||||
void lToggleScreenSharing();
|
||||
|
||||
private:
|
||||
QSharedPointer<SafeConnection<ConferenceCore, ConferenceModel>> mConferenceModelConnection;
|
||||
std::shared_ptr<ConferenceModel> mConferenceModel;
|
||||
|
|
@ -83,6 +95,8 @@ private:
|
|||
int mParticipantDeviceCount = 0;
|
||||
|
||||
bool mIsReady = false;
|
||||
bool mIsLocalScreenSharing = false;
|
||||
bool mIsScreenSharingEnabled = false;
|
||||
QString mSubject;
|
||||
QDateTime mStartDate = QDateTime::currentDateTime();
|
||||
|
||||
|
|
|
|||
76
Linphone/core/screen/ScreenList.cpp
Normal file
76
Linphone/core/screen/ScreenList.cpp
Normal file
|
|
@ -0,0 +1,76 @@
|
|||
/*
|
||||
* Copyright (c) 2010-2024 Belledonne Communications SARL.
|
||||
*
|
||||
* This file is part of linphone-desktop
|
||||
* (see https://www.linphone.org).
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "ScreenList.hpp"
|
||||
#include <QGuiApplication>
|
||||
#include <QPixmap>
|
||||
#include <QScreen>
|
||||
#include <QWindow>
|
||||
|
||||
#include "tool/native/DesktopTools.hpp"
|
||||
|
||||
ScreenList::ScreenList(QObject *parent) : AbstractListProxy(parent) {
|
||||
connect(this, &ScreenList::modeChanged, this, &ScreenList::update);
|
||||
}
|
||||
|
||||
ScreenList::~ScreenList() {
|
||||
}
|
||||
|
||||
ScreenList::Mode ScreenList::getMode() const {
|
||||
return mMode;
|
||||
}
|
||||
|
||||
void ScreenList::setMode(ScreenList::Mode data) {
|
||||
if (mMode != data) {
|
||||
mMode = data;
|
||||
emit modeChanged();
|
||||
}
|
||||
}
|
||||
|
||||
void ScreenList::update() {
|
||||
beginResetModel();
|
||||
mList.clear();
|
||||
if (mMode == WINDOWS) {
|
||||
auto list = DesktopTools::getWindows();
|
||||
qDebug() << list;
|
||||
for (auto l : list)
|
||||
mList << l;
|
||||
} else {
|
||||
auto list = QGuiApplication::screens();
|
||||
for (auto l : list) {
|
||||
QVariantMap w;
|
||||
w["name"] = l->name();
|
||||
w["screenIndex"] = mList.size();
|
||||
mList << w;
|
||||
}
|
||||
}
|
||||
|
||||
endResetModel();
|
||||
}
|
||||
|
||||
QVariant ScreenList::data(const QModelIndex &index, int role) const {
|
||||
int row = index.row();
|
||||
if (!index.isValid() || row < 0 || row >= mList.count()) return QVariant();
|
||||
if (role == Qt::DisplayRole) {
|
||||
QVariantMap data = mList[row];
|
||||
return data;
|
||||
}
|
||||
return QVariant();
|
||||
}
|
||||
51
Linphone/core/screen/ScreenList.hpp
Normal file
51
Linphone/core/screen/ScreenList.hpp
Normal file
|
|
@ -0,0 +1,51 @@
|
|||
/*
|
||||
* Copyright (c) 2010-2024 Belledonne Communications SARL.
|
||||
*
|
||||
* This file is part of linphone-desktop
|
||||
* (see https://www.linphone.org).
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef SCREEN_LIST_H_
|
||||
#define SCREEN_LIST_H_
|
||||
|
||||
#include "core/proxy/AbstractListProxy.hpp"
|
||||
|
||||
#include <QScreen>
|
||||
|
||||
class ScreenList : public AbstractListProxy<QVariantMap> {
|
||||
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
enum Mode { SCREENS = 0, WINDOWS = 1 };
|
||||
Q_ENUM(Mode)
|
||||
|
||||
ScreenList(QObject *parent = Q_NULLPTR);
|
||||
virtual ~ScreenList();
|
||||
|
||||
ScreenList::Mode getMode() const;
|
||||
void setMode(ScreenList::Mode);
|
||||
|
||||
void update();
|
||||
|
||||
Mode mMode = WINDOWS;
|
||||
|
||||
virtual QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
|
||||
signals:
|
||||
void modeChanged();
|
||||
};
|
||||
|
||||
#endif
|
||||
41
Linphone/core/screen/ScreenProxy.cpp
Normal file
41
Linphone/core/screen/ScreenProxy.cpp
Normal file
|
|
@ -0,0 +1,41 @@
|
|||
/*
|
||||
* Copyright (c) 2010-2024 Belledonne Communications SARL.
|
||||
*
|
||||
* This file is part of linphone-desktop
|
||||
* (see https://www.linphone.org).
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <QQuickWindow>
|
||||
|
||||
#include "ScreenList.hpp"
|
||||
#include "ScreenProxy.hpp"
|
||||
// =============================================================================
|
||||
|
||||
ScreenProxy::ScreenProxy(QObject *parent) : SortFilterProxy(parent) {
|
||||
setSourceModel(new ScreenList(this));
|
||||
sort(0);
|
||||
}
|
||||
ScreenList::Mode ScreenProxy::getMode() const {
|
||||
return dynamic_cast<ScreenList *>(sourceModel())->getMode();
|
||||
}
|
||||
|
||||
void ScreenProxy::setMode(ScreenList::Mode data) {
|
||||
dynamic_cast<ScreenList *>(sourceModel())->setMode(data);
|
||||
}
|
||||
|
||||
void ScreenProxy::update() {
|
||||
dynamic_cast<ScreenList *>(sourceModel())->update();
|
||||
}
|
||||
46
Linphone/core/screen/ScreenProxy.hpp
Normal file
46
Linphone/core/screen/ScreenProxy.hpp
Normal file
|
|
@ -0,0 +1,46 @@
|
|||
/*
|
||||
* Copyright (c) 2010-2024 Belledonne Communications SARL.
|
||||
*
|
||||
* This file is part of linphone-desktop
|
||||
* (see https://www.linphone.org).
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef SCREEN_PROXY_H_
|
||||
#define SCREEN_PROXY_H_
|
||||
|
||||
#include "ScreenList.hpp"
|
||||
#include "core/proxy/SortFilterProxy.hpp"
|
||||
// =============================================================================
|
||||
|
||||
class QWindow;
|
||||
|
||||
class ScreenProxy : public SortFilterProxy {
|
||||
class ScreenModelFilter;
|
||||
|
||||
Q_OBJECT
|
||||
Q_PROPERTY(ScreenList::Mode mode READ getMode WRITE setMode NOTIFY modeChanged)
|
||||
public:
|
||||
ScreenProxy(QObject *parent = Q_NULLPTR);
|
||||
|
||||
ScreenList::Mode getMode() const;
|
||||
void setMode(ScreenList::Mode);
|
||||
|
||||
Q_INVOKABLE void update();
|
||||
signals:
|
||||
void modeChanged();
|
||||
};
|
||||
|
||||
#endif
|
||||
99
Linphone/core/videoSource/VideoSourceDescriptorCore.cpp
Normal file
99
Linphone/core/videoSource/VideoSourceDescriptorCore.cpp
Normal file
|
|
@ -0,0 +1,99 @@
|
|||
/*
|
||||
* Copyright (c) 2021 Belledonne Communications SARL.
|
||||
*
|
||||
* This file is part of linphone-desktop
|
||||
* (see https://www.linphone.org).
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "VideoSourceDescriptorCore.hpp"
|
||||
#include "core/App.hpp"
|
||||
#include "tool/Utils.hpp"
|
||||
#include "tool/thread/SafeConnection.hpp"
|
||||
|
||||
// =============================================================================
|
||||
|
||||
DEFINE_ABSTRACT_OBJECT(VideoSourceDescriptorCore)
|
||||
|
||||
QSharedPointer<VideoSourceDescriptorCore>
|
||||
VideoSourceDescriptorCore::create(const std::shared_ptr<linphone::VideoSourceDescriptor> &desc) {
|
||||
auto sharedPointer =
|
||||
QSharedPointer<VideoSourceDescriptorCore>(new VideoSourceDescriptorCore(desc), &QObject::deleteLater);
|
||||
sharedPointer->setSelf(sharedPointer);
|
||||
sharedPointer->moveToThread(App::getInstance()->thread());
|
||||
return sharedPointer;
|
||||
}
|
||||
|
||||
VideoSourceDescriptorCore::VideoSourceDescriptorCore(const std::shared_ptr<linphone::VideoSourceDescriptor> &desc) {
|
||||
App::getInstance()->mEngine->setObjectOwnership(this, QQmlEngine::CppOwnership);
|
||||
mustBeInLinphoneThread(getClassName());
|
||||
mVideoDescModel = Utils::makeQObject_ptr<VideoSourceDescriptorModel>(desc);
|
||||
mScreenIndex = mVideoDescModel->getScreenSharingIndex();
|
||||
mWindowId = mVideoDescModel->getWindowId();
|
||||
}
|
||||
|
||||
VideoSourceDescriptorCore::~VideoSourceDescriptorCore() {
|
||||
}
|
||||
|
||||
void VideoSourceDescriptorCore::setSelf(QSharedPointer<VideoSourceDescriptorCore> me) {
|
||||
mVideoDescModelConnection = QSharedPointer<SafeConnection<VideoSourceDescriptorCore, VideoSourceDescriptorModel>>(
|
||||
new SafeConnection<VideoSourceDescriptorCore, VideoSourceDescriptorModel>(me, mVideoDescModel),
|
||||
&QObject::deleteLater);
|
||||
mVideoDescModelConnection->makeConnectToCore(&VideoSourceDescriptorCore::lSetWindowId, [this](quint64 id) {
|
||||
mVideoDescModelConnection->invokeToModel([this, id]() { mVideoDescModel->setScreenSharingWindow((void *)id); });
|
||||
});
|
||||
mVideoDescModelConnection->makeConnectToCore(&VideoSourceDescriptorCore::lSetScreenIndex, [this](int index) {
|
||||
mVideoDescModelConnection->invokeToModel([this, index]() { mVideoDescModel->setScreenSharingDisplay(index); });
|
||||
});
|
||||
|
||||
mVideoDescModelConnection->makeConnectToModel(&VideoSourceDescriptorModel::videoDescriptorChanged, [this]() {
|
||||
auto id = mVideoDescModel->getWindowId();
|
||||
auto index = mVideoDescModel->getScreenSharingIndex();
|
||||
mVideoDescModelConnection->invokeToCore([this, id, index]() {
|
||||
setWindowId(id);
|
||||
setScreenSharingDisplay(index);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
quint64 VideoSourceDescriptorCore::getWindowId() const {
|
||||
return mWindowId;
|
||||
}
|
||||
|
||||
void VideoSourceDescriptorCore::setWindowId(quint64 id) {
|
||||
mustBeInMainThread(log().arg(Q_FUNC_INFO));
|
||||
if (mWindowId != id) {
|
||||
mWindowId = id;
|
||||
if (mWindowId != 0 && mScreenIndex >= 0) setScreenSharingDisplay(-1);
|
||||
emit windowIdChanged();
|
||||
}
|
||||
}
|
||||
|
||||
int VideoSourceDescriptorCore::getScreenSharingIndex() const {
|
||||
return mScreenIndex;
|
||||
}
|
||||
|
||||
void VideoSourceDescriptorCore::setScreenSharingDisplay(int data) {
|
||||
mustBeInMainThread(log().arg(Q_FUNC_INFO));
|
||||
if (mScreenIndex != data) {
|
||||
mScreenIndex = data;
|
||||
if (mScreenIndex >= 0 && mWindowId != 0) setWindowId(0);
|
||||
emit screenIndexChanged();
|
||||
}
|
||||
}
|
||||
|
||||
std::shared_ptr<VideoSourceDescriptorModel> VideoSourceDescriptorCore::getModel() {
|
||||
return mVideoDescModel;
|
||||
}
|
||||
72
Linphone/core/videoSource/VideoSourceDescriptorCore.hpp
Normal file
72
Linphone/core/videoSource/VideoSourceDescriptorCore.hpp
Normal file
|
|
@ -0,0 +1,72 @@
|
|||
/*
|
||||
* Copyright (c) 2021 Belledonne Communications SARL.
|
||||
*
|
||||
* This file is part of linphone-desktop
|
||||
* (see https://www.linphone.org).
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef VIDEO_SOURCE_DESCRIPTOR_CORE_H_
|
||||
#define VIDEO_SOURCE_DESCRIPTOR_CORE_H_
|
||||
|
||||
#include <linphone++/linphone.hh>
|
||||
// =============================================================================
|
||||
#include <QDateTime>
|
||||
#include <QObject>
|
||||
#include <QSharedPointer>
|
||||
#include <QString>
|
||||
|
||||
#include "tool/LinphoneEnums.hpp"
|
||||
#include "tool/thread/SafeConnection.hpp"
|
||||
|
||||
#include "model/videoSource/VideoSourceDescriptorModel.hpp"
|
||||
|
||||
class VideoSourceDescriptorCore : public QObject, public AbstractObject {
|
||||
Q_OBJECT
|
||||
|
||||
Q_PROPERTY(int screenSharingIndex READ getScreenSharingIndex WRITE lSetScreenIndex NOTIFY screenIndexChanged)
|
||||
Q_PROPERTY(quint64 windowId READ getWindowId WRITE lSetWindowId NOTIFY windowIdChanged)
|
||||
public:
|
||||
static QSharedPointer<VideoSourceDescriptorCore>
|
||||
create(const std::shared_ptr<linphone::VideoSourceDescriptor> &desc);
|
||||
VideoSourceDescriptorCore(const std::shared_ptr<linphone::VideoSourceDescriptor> &desc);
|
||||
virtual ~VideoSourceDescriptorCore();
|
||||
void setSelf(QSharedPointer<VideoSourceDescriptorCore> me);
|
||||
|
||||
int getScreenSharingIndex() const;
|
||||
void setScreenSharingDisplay(int index);
|
||||
|
||||
quint64 getWindowId() const;
|
||||
void setWindowId(quint64 id);
|
||||
|
||||
std::shared_ptr<VideoSourceDescriptorModel> getModel();
|
||||
|
||||
signals:
|
||||
void videoDescriptorChanged();
|
||||
void windowIdChanged();
|
||||
void screenIndexChanged();
|
||||
|
||||
void lSetWindowId(quint64 windowId);
|
||||
void lSetScreenIndex(int index);
|
||||
|
||||
private:
|
||||
int mScreenIndex = 0;
|
||||
quint64 mWindowId = 0;
|
||||
std::shared_ptr<VideoSourceDescriptorModel> mVideoDescModel;
|
||||
QSharedPointer<SafeConnection<VideoSourceDescriptorCore, VideoSourceDescriptorModel>> mVideoDescModelConnection;
|
||||
DECLARE_ABSTRACT_OBJECT
|
||||
};
|
||||
Q_DECLARE_METATYPE(VideoSourceDescriptorCore *)
|
||||
#endif
|
||||
38
Linphone/core/videoSource/VideoSourceDescriptorGui.cpp
Normal file
38
Linphone/core/videoSource/VideoSourceDescriptorGui.cpp
Normal file
|
|
@ -0,0 +1,38 @@
|
|||
/*
|
||||
* Copyright (c) 2010-2024 Belledonne Communications SARL.
|
||||
*
|
||||
* This file is part of linphone-desktop
|
||||
* (see https://www.linphone.org).
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "VideoSourceDescriptorGui.hpp"
|
||||
#include "core/App.hpp"
|
||||
|
||||
DEFINE_ABSTRACT_OBJECT(VideoSourceDescriptorGui)
|
||||
|
||||
VideoSourceDescriptorGui::VideoSourceDescriptorGui(QSharedPointer<VideoSourceDescriptorCore> core) {
|
||||
App::getInstance()->mEngine->setObjectOwnership(this, QQmlEngine::JavaScriptOwnership);
|
||||
mCore = core;
|
||||
if (isInLinphoneThread()) moveToThread(App::getInstance()->thread());
|
||||
}
|
||||
|
||||
VideoSourceDescriptorGui::~VideoSourceDescriptorGui() {
|
||||
mustBeInMainThread("~" + getClassName());
|
||||
}
|
||||
|
||||
VideoSourceDescriptorCore *VideoSourceDescriptorGui::getCore() const {
|
||||
return mCore.get();
|
||||
}
|
||||
41
Linphone/core/videoSource/VideoSourceDescriptorGui.hpp
Normal file
41
Linphone/core/videoSource/VideoSourceDescriptorGui.hpp
Normal file
|
|
@ -0,0 +1,41 @@
|
|||
/*
|
||||
* Copyright (c) 2010-2024 Belledonne Communications SARL.
|
||||
*
|
||||
* This file is part of linphone-desktop
|
||||
* (see https://www.linphone.org).
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef VIDEO_SOURCE_DESCRIPTOR_GUI_H_
|
||||
#define VIDEO_SOURCE_DESCRIPTOR_GUI_H_
|
||||
|
||||
#include "VideoSourceDescriptorCore.hpp"
|
||||
#include <QObject>
|
||||
#include <QSharedPointer>
|
||||
|
||||
class VideoSourceDescriptorGui : public QObject, public AbstractObject {
|
||||
Q_OBJECT
|
||||
|
||||
Q_PROPERTY(VideoSourceDescriptorCore *core READ getCore CONSTANT)
|
||||
|
||||
public:
|
||||
VideoSourceDescriptorGui(QSharedPointer<VideoSourceDescriptorCore> core);
|
||||
~VideoSourceDescriptorGui();
|
||||
VideoSourceDescriptorCore *getCore() const;
|
||||
QSharedPointer<VideoSourceDescriptorCore> mCore;
|
||||
DECLARE_ABSTRACT_OBJECT
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
@ -30,6 +30,8 @@ list(APPEND _LINPHONEAPP_SOURCES
|
|||
model/setting/SettingsModel.cpp
|
||||
|
||||
model/tool/ToolModel.cpp
|
||||
|
||||
model/videoSource/VideoSourceDescriptorModel.cpp
|
||||
)
|
||||
|
||||
set(_LINPHONEAPP_SOURCES ${_LINPHONEAPP_SOURCES} PARENT_SCOPE)
|
||||
|
|
|
|||
|
|
@ -330,6 +330,32 @@ void CallModel::updateConferenceVideoLayout() {
|
|||
}
|
||||
}
|
||||
|
||||
void CallModel::setVideoSource(std::shared_ptr<linphone::VideoSourceDescriptor> videoDesc) {
|
||||
mMonitor->setVideoSource(videoDesc);
|
||||
|
||||
emit videoDescriptorChanged();
|
||||
}
|
||||
|
||||
LinphoneEnums::VideoSourceScreenSharingType CallModel::getVideoSourceType() const {
|
||||
auto videoSource = mMonitor->getVideoSource();
|
||||
return LinphoneEnums::fromLinphone(videoSource ? videoSource->getScreenSharingType()
|
||||
: linphone::VideoSourceScreenSharingType::Display);
|
||||
}
|
||||
int CallModel::getScreenSharingIndex() const {
|
||||
auto videoSource = mMonitor->getVideoSource();
|
||||
if (videoSource && videoSource->getScreenSharingType() == linphone::VideoSourceScreenSharingType::Display) {
|
||||
void *t = videoSource->getScreenSharing();
|
||||
return *(int *)(&t);
|
||||
} else return -1;
|
||||
}
|
||||
|
||||
void CallModel::setVideoSourceDescriptorModel(std::shared_ptr<VideoSourceDescriptorModel> model) {
|
||||
if (model) setVideoSource(model->mDesc);
|
||||
else {
|
||||
setVideoSource(nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
void CallModel::onDtmfReceived(const std::shared_ptr<linphone::Call> &call, int dtmf) {
|
||||
emit dtmfReceived(call, dtmf);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -22,6 +22,7 @@
|
|||
#define CALL_MODEL_H_
|
||||
|
||||
#include "model/listener/Listener.hpp"
|
||||
#include "model/videoSource/VideoSourceDescriptorModel.hpp"
|
||||
#include "tool/AbstractObject.hpp"
|
||||
#include "tool/LinphoneEnums.hpp"
|
||||
|
||||
|
|
@ -72,6 +73,11 @@ public:
|
|||
void changeConferenceVideoLayout(LinphoneEnums::ConferenceLayout layout); // Make a call request
|
||||
void updateConferenceVideoLayout(); // Called from call state changed ater the new layout has been set.
|
||||
|
||||
void setVideoSource(std::shared_ptr<linphone::VideoSourceDescriptor> videoDesc);
|
||||
LinphoneEnums::VideoSourceScreenSharingType getVideoSourceType() const;
|
||||
int getScreenSharingIndex() const;
|
||||
void setVideoSourceDescriptorModel(std::shared_ptr<VideoSourceDescriptorModel> model = nullptr);
|
||||
|
||||
static void activateLocalVideo(std::shared_ptr<linphone::CallParams> ¶ms,
|
||||
const std::shared_ptr<const linphone::CallParams> ¤tParams,
|
||||
bool enable);
|
||||
|
|
@ -92,6 +98,7 @@ signals:
|
|||
void outputAudioDeviceChanged(const std::string &id);
|
||||
void conferenceChanged();
|
||||
void conferenceVideoLayoutChanged(LinphoneEnums::ConferenceLayout layout);
|
||||
void videoDescriptorChanged();
|
||||
|
||||
private:
|
||||
QTimer mDurationTimer;
|
||||
|
|
|
|||
|
|
@ -24,6 +24,7 @@
|
|||
|
||||
#include "core/path/Paths.hpp"
|
||||
#include "model/core/CoreModel.hpp"
|
||||
#include "model/tool/ToolModel.hpp"
|
||||
#include "tool/Utils.hpp"
|
||||
|
||||
DEFINE_ABSTRACT_OBJECT(ConferenceModel)
|
||||
|
|
@ -38,6 +39,8 @@ ConferenceModel::ConferenceModel(const std::shared_ptr<linphone::Conference> &co
|
|||
: ::Listener<linphone::Conference, linphone::ConferenceListener>(conference, parent) {
|
||||
mustBeInLinphoneThread(getClassName());
|
||||
lDebug() << "[ConferenceModel] new" << this << conference.get();
|
||||
connect(this, &ConferenceModel::isScreenSharingEnabledChanged, this,
|
||||
&ConferenceModel::onIsScreenSharingEnabledChanged);
|
||||
}
|
||||
|
||||
ConferenceModel::~ConferenceModel() {
|
||||
|
|
@ -132,6 +135,32 @@ std::shared_ptr<const linphone::AudioDevice> ConferenceModel::getOutputAudioDevi
|
|||
return mMonitor->getOutputAudioDevice();
|
||||
}
|
||||
|
||||
void ConferenceModel::toggleScreenSharing() {
|
||||
mustBeInLinphoneThread(log().arg(Q_FUNC_INFO));
|
||||
auto device = mMonitor->getScreenSharingParticipantDevice();
|
||||
|
||||
if (!device || ToolModel::isLocal(mMonitor, device)) {
|
||||
bool enable = !device;
|
||||
auto params = CoreModel::getInstance()->getCore()->createCallParams(mMonitor->getCall());
|
||||
params->enableScreenSharing(enable);
|
||||
if (enable) {
|
||||
params->setConferenceVideoLayout(linphone::Conference::Layout::ActiveSpeaker);
|
||||
params->enableVideo(true);
|
||||
}
|
||||
if (params->isValid()) mMonitor->getCall()->update(params);
|
||||
else lCritical() << log().arg("Cannot toggle screen sharing because parameters are invalid");
|
||||
}
|
||||
}
|
||||
|
||||
bool ConferenceModel::isLocalScreenSharing() const {
|
||||
auto device = mMonitor->getScreenSharingParticipantDevice();
|
||||
return device && ToolModel::isLocal(mMonitor, device);
|
||||
}
|
||||
|
||||
bool ConferenceModel::isScreenSharingEnabled() const {
|
||||
return mMonitor && mMonitor->getScreenSharingParticipant();
|
||||
}
|
||||
|
||||
void ConferenceModel::onActiveSpeakerParticipantDevice(
|
||||
const std::shared_ptr<linphone::Conference> &conference,
|
||||
const std::shared_ptr<const linphone::ParticipantDevice> &participantDevice) {
|
||||
|
|
@ -143,10 +172,12 @@ void ConferenceModel::onActiveSpeakerParticipantDevice(
|
|||
void ConferenceModel::onParticipantAdded(const std::shared_ptr<linphone::Conference> &conference,
|
||||
const std::shared_ptr<linphone::Participant> &participant) {
|
||||
emit participantAdded(participant);
|
||||
emit participantDeviceCountChanged(getParticipantDeviceCount());
|
||||
}
|
||||
void ConferenceModel::onParticipantRemoved(const std::shared_ptr<linphone::Conference> &conference,
|
||||
const std::shared_ptr<const linphone::Participant> &participant) {
|
||||
emit participantRemoved(participant);
|
||||
emit participantDeviceCountChanged(getParticipantDeviceCount());
|
||||
}
|
||||
void ConferenceModel::onParticipantDeviceAdded(const std::shared_ptr<linphone::Conference> &conference,
|
||||
const std::shared_ptr<linphone::ParticipantDevice> &participantDevice) {
|
||||
|
|
@ -156,6 +187,7 @@ void ConferenceModel::onParticipantDeviceAdded(const std::shared_ptr<linphone::C
|
|||
for (auto d : conference->getMe()->getDevices())
|
||||
lDebug() << "\t--> " << d->getAddress()->asString().c_str();
|
||||
emit participantDeviceAdded(participantDevice);
|
||||
emit participantDeviceCountChanged(getParticipantDeviceCount());
|
||||
}
|
||||
void ConferenceModel::onParticipantDeviceRemoved(
|
||||
const std::shared_ptr<linphone::Conference> &conference,
|
||||
|
|
@ -163,7 +195,9 @@ void ConferenceModel::onParticipantDeviceRemoved(
|
|||
lDebug() << "onParticipantDeviceRemoved: " << participantDevice->getAddress()->asString().c_str() << " isInConf?["
|
||||
<< participantDevice->isInConference() << "]";
|
||||
lDebug() << "Me devices : " << conference->getMe()->getDevices().size();
|
||||
if (participantDevice->screenSharingEnabled()) emit isScreenSharingEnabledChanged(false);
|
||||
emit participantDeviceRemoved(participantDevice);
|
||||
emit participantDeviceCountChanged(getParticipantDeviceCount());
|
||||
}
|
||||
void ConferenceModel::onParticipantDeviceStateChanged(const std::shared_ptr<linphone::Conference> &conference,
|
||||
const std::shared_ptr<const linphone::ParticipantDevice> &device,
|
||||
|
|
@ -201,9 +235,28 @@ void ConferenceModel::onParticipantDeviceIsSpeakingChanged(
|
|||
// ". Speaking:" << isSpeaking;
|
||||
emit participantDeviceIsSpeakingChanged(participantDevice, isSpeaking);
|
||||
}
|
||||
|
||||
void ConferenceModel::onParticipantDeviceScreenSharingChanged(
|
||||
const std::shared_ptr<linphone::Conference> &conference,
|
||||
const std::shared_ptr<const linphone::ParticipantDevice> &device,
|
||||
bool enabled) {
|
||||
qDebug() << "onParticipantDeviceScreenSharingChanged: " << device->getAddress()->asString().c_str()
|
||||
<< ". Enabled:" << enabled;
|
||||
emit participantDeviceScreenSharingChanged(device, enabled);
|
||||
if (ToolModel::isLocal(mMonitor, device)) {
|
||||
emit isLocalScreenSharingChanged(enabled);
|
||||
}
|
||||
emit isScreenSharingEnabledChanged(enabled);
|
||||
}
|
||||
|
||||
void ConferenceModel::onStateChanged(const std::shared_ptr<linphone::Conference> &conference,
|
||||
linphone::Conference::State newState) {
|
||||
lDebug() << "onStateChanged:" << (int)newState;
|
||||
if (newState == linphone::Conference::State::Created) {
|
||||
emit participantDeviceCountChanged(mMonitor->getParticipantDeviceList().size());
|
||||
if (mMonitor->getScreenSharingParticipant()) emit isScreenSharingEnabledChanged(true);
|
||||
}
|
||||
// updateLocalParticipant();
|
||||
emit conferenceStateChanged(newState);
|
||||
}
|
||||
void ConferenceModel::onSubjectChanged(const std::shared_ptr<linphone::Conference> &conference,
|
||||
|
|
@ -215,3 +268,12 @@ void ConferenceModel::onAudioDeviceChanged(const std::shared_ptr<linphone::Confe
|
|||
const std::shared_ptr<const linphone::AudioDevice> &audioDevice) {
|
||||
lDebug() << "onAudioDeviceChanged is not yet implemented.";
|
||||
}
|
||||
|
||||
void ConferenceModel::onIsScreenSharingEnabledChanged() {
|
||||
auto call = mMonitor->getCall();
|
||||
std::shared_ptr<linphone::CallParams> params = CoreModel::getInstance()->getCore()->createCallParams(call);
|
||||
if (params->getConferenceVideoLayout() == linphone::Conference::Layout::Grid && params->videoEnabled()) {
|
||||
params->setConferenceVideoLayout(linphone::Conference::Layout::ActiveSpeaker);
|
||||
}
|
||||
call->update(params);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -49,6 +49,10 @@ public:
|
|||
void setOutputAudioDevice(const std::shared_ptr<linphone::AudioDevice> &id);
|
||||
std::shared_ptr<const linphone::AudioDevice> getOutputAudioDevice() const;
|
||||
|
||||
void toggleScreenSharing();
|
||||
bool isLocalScreenSharing() const;
|
||||
bool isScreenSharingEnabled() const;
|
||||
|
||||
void setPaused(bool paused);
|
||||
|
||||
void removeParticipant(const std::shared_ptr<linphone::Participant> &p);
|
||||
|
|
@ -57,6 +61,8 @@ public:
|
|||
|
||||
int getParticipantDeviceCount() const;
|
||||
|
||||
void onIsScreenSharingEnabledChanged();
|
||||
|
||||
signals:
|
||||
void microphoneMutedChanged(bool isMuted);
|
||||
void speakerMutedChanged(bool isMuted);
|
||||
|
|
@ -70,6 +76,9 @@ signals:
|
|||
void microphoneVolumeGainChanged(float volume);
|
||||
void inputAudioDeviceChanged(const std::string &id);
|
||||
void outputAudioDeviceChanged(const std::string &id);
|
||||
void isLocalScreenSharingChanged(bool enabled);
|
||||
void isScreenSharingEnabledChanged(bool enabled);
|
||||
void participantDeviceCountChanged(int count);
|
||||
|
||||
private:
|
||||
// LINPHONE LISTENERS
|
||||
|
|
@ -102,12 +111,16 @@ private:
|
|||
onParticipantDeviceIsSpeakingChanged(const std::shared_ptr<linphone::Conference> &conference,
|
||||
const std::shared_ptr<const linphone::ParticipantDevice> &participantDevice,
|
||||
bool isSpeaking) override;
|
||||
virtual void
|
||||
onParticipantDeviceScreenSharingChanged(const std::shared_ptr<linphone::Conference> &conference,
|
||||
const std::shared_ptr<const linphone::ParticipantDevice> &device,
|
||||
bool enabled) override;
|
||||
virtual void onStateChanged(const std::shared_ptr<linphone::Conference> &conference,
|
||||
linphone::Conference::State newState) override;
|
||||
virtual void onSubjectChanged(const std::shared_ptr<linphone::Conference> &conference,
|
||||
const std::string &subject) override;
|
||||
virtual void onAudioDeviceChanged(const std::shared_ptr<linphone::Conference> &conference,
|
||||
const std::shared_ptr<const linphone::AudioDevice> &audioDevice) override;
|
||||
const std::shared_ptr<const linphone::AudioDevice> &audioDevice) override;
|
||||
|
||||
signals:
|
||||
void activeSpeakerParticipantDevice(const std::shared_ptr<linphone::ParticipantDevice> &participantDevice);
|
||||
|
|
@ -125,6 +138,8 @@ signals:
|
|||
const std::shared_ptr<const linphone::ParticipantDevice> &participantDevice);
|
||||
void participantDeviceIsSpeakingChanged(const std::shared_ptr<const linphone::ParticipantDevice> &participantDevice,
|
||||
bool isSpeaking);
|
||||
void participantDeviceScreenSharingChanged(const std::shared_ptr<const linphone::ParticipantDevice> &device,
|
||||
bool enabled);
|
||||
void conferenceStateChanged(linphone::Conference::State newState);
|
||||
void subjectChanged(const std::string &subject);
|
||||
|
||||
|
|
|
|||
82
Linphone/model/videoSource/VideoSourceDescriptorModel.cpp
Normal file
82
Linphone/model/videoSource/VideoSourceDescriptorModel.cpp
Normal file
|
|
@ -0,0 +1,82 @@
|
|||
/*
|
||||
* Copyright (c) 2021 Belledonne Communications SARL.
|
||||
*
|
||||
* This file is part of linphone-desktop
|
||||
* (see https://www.linphone.org).
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "VideoSourceDescriptorModel.hpp"
|
||||
#include "tool/native/DesktopTools.hpp"
|
||||
// =============================================================================
|
||||
|
||||
DEFINE_ABSTRACT_OBJECT(VideoSourceDescriptorModel)
|
||||
|
||||
VideoSourceDescriptorModel::VideoSourceDescriptorModel() {
|
||||
}
|
||||
VideoSourceDescriptorModel::VideoSourceDescriptorModel(std::shared_ptr<linphone::VideoSourceDescriptor> desc) {
|
||||
mDesc = desc;
|
||||
if (mDesc && mDesc->getScreenSharingType() == linphone::VideoSourceScreenSharingType::Display)
|
||||
mScreenIndex = DesktopTools::getDisplayIndex(mDesc->getScreenSharing());
|
||||
}
|
||||
|
||||
void VideoSourceDescriptorModel::setScreenSharingDisplay(int index) {
|
||||
if (!mDesc) mDesc = linphone::Factory::get()->createVideoSourceDescriptor();
|
||||
mScreenIndex = index;
|
||||
mDesc->setScreenSharing(linphone::VideoSourceScreenSharingType::Display, DesktopTools::getDisplay(index));
|
||||
emit videoDescriptorChanged();
|
||||
}
|
||||
|
||||
void VideoSourceDescriptorModel::setScreenSharingWindow(void *window) { // Get data from DesktopTools.
|
||||
if (!mDesc) mDesc = linphone::Factory::get()->createVideoSourceDescriptor();
|
||||
else if (getVideoSourceType() == LinphoneEnums::VideoSourceScreenSharingTypeWindow && window == getScreenSharing())
|
||||
return;
|
||||
mDesc->setScreenSharing(linphone::VideoSourceScreenSharingType::Window, window);
|
||||
emit videoDescriptorChanged();
|
||||
}
|
||||
|
||||
void *VideoSourceDescriptorModel::getScreenSharing() const {
|
||||
if (!mDesc) return nullptr;
|
||||
else return mDesc->getScreenSharing();
|
||||
}
|
||||
|
||||
quint64 VideoSourceDescriptorModel::getWindowId() const {
|
||||
if (!mDesc) return 0;
|
||||
else {
|
||||
void *temp = mDesc->getScreenSharing();
|
||||
return *(quint64 *)&temp;
|
||||
}
|
||||
}
|
||||
|
||||
void VideoSourceDescriptorModel::setWindowId(quint64 id) {
|
||||
if (getWindowId() != id) {
|
||||
setScreenSharingWindow((void *)id);
|
||||
}
|
||||
}
|
||||
|
||||
bool VideoSourceDescriptorModel::isScreenSharing() const {
|
||||
return mDesc && mDesc->getType() == linphone::VideoSourceType::ScreenSharing;
|
||||
}
|
||||
|
||||
LinphoneEnums::VideoSourceScreenSharingType VideoSourceDescriptorModel::getVideoSourceType() const {
|
||||
return mDesc ? LinphoneEnums::fromLinphone(mDesc->getScreenSharingType())
|
||||
: LinphoneEnums::VideoSourceScreenSharingType::VideoSourceScreenSharingTypeDisplay;
|
||||
}
|
||||
|
||||
int VideoSourceDescriptorModel::getScreenSharingIndex() const {
|
||||
if (mDesc && mDesc->getScreenSharingType() == linphone::VideoSourceScreenSharingType::Display) {
|
||||
return mScreenIndex;
|
||||
} else return -1;
|
||||
}
|
||||
58
Linphone/model/videoSource/VideoSourceDescriptorModel.hpp
Normal file
58
Linphone/model/videoSource/VideoSourceDescriptorModel.hpp
Normal file
|
|
@ -0,0 +1,58 @@
|
|||
/*
|
||||
* Copyright (c) 2021 Belledonne Communications SARL.
|
||||
*
|
||||
* This file is part of linphone-desktop
|
||||
* (see https://www.linphone.org).
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef VIDEO_SOURCE_DESCRIPTOR_MODEL_H_
|
||||
#define VIDEO_SOURCE_DESCRIPTOR_MODEL_H_
|
||||
|
||||
// =============================================================================
|
||||
#include "tool/AbstractObject.hpp"
|
||||
#include "tool/LinphoneEnums.hpp"
|
||||
|
||||
#include <QObject>
|
||||
#include <QTimer>
|
||||
#include <linphone++/linphone.hh>
|
||||
|
||||
class VideoSourceDescriptorModel : public QObject, public AbstractObject {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
VideoSourceDescriptorModel();
|
||||
VideoSourceDescriptorModel(std::shared_ptr<linphone::VideoSourceDescriptor> desc);
|
||||
void setScreenSharingDisplay(int index);
|
||||
void setScreenSharingWindow(void *window); // Get data from DesktopTools.
|
||||
void *getScreenSharing() const;
|
||||
|
||||
quint64 getWindowId() const;
|
||||
void setWindowId(quint64 id);
|
||||
|
||||
bool isScreenSharing() const;
|
||||
LinphoneEnums::VideoSourceScreenSharingType getVideoSourceType() const;
|
||||
int getScreenSharingIndex() const;
|
||||
|
||||
std::shared_ptr<linphone::VideoSourceDescriptor> mDesc;
|
||||
int mScreenIndex = -1;
|
||||
|
||||
signals:
|
||||
void videoDescriptorChanged();
|
||||
|
||||
private:
|
||||
DECLARE_ABSTRACT_OBJECT
|
||||
};
|
||||
#endif
|
||||
|
|
@ -9,8 +9,30 @@ list(APPEND _LINPHONEAPP_SOURCES
|
|||
tool/thread/Thread.cpp
|
||||
tool/providers/AvatarProvider.cpp
|
||||
tool/providers/ImageProvider.cpp
|
||||
tool/providers/ScreenProvider.cpp
|
||||
|
||||
tool/native/DesktopTools.hpp
|
||||
)
|
||||
|
||||
if (APPLE)
|
||||
list(APPEND _LINPHONEAPP_SOURCES
|
||||
tool/native/DesktopToolsMacOs.cpp
|
||||
tool/native/DesktopToolsMacOsNative.mm
|
||||
tool/native/screen-saver/ScreenSaverMacOs.m
|
||||
tool/native/state-process/StateProcessMacOs.mm
|
||||
)
|
||||
elseif (WIN32)
|
||||
list(APPEND _LINPHONEAPP_SOURCES
|
||||
tool/native/DesktopToolsWindows.cpp
|
||||
)
|
||||
else ()
|
||||
list(APPEND _LINPHONEAPP_SOURCES
|
||||
tool/native/DesktopToolsLinux.cpp
|
||||
tool/native/screen-saver/ScreenSaverDBus.cpp
|
||||
tool/native/screen-saver/ScreenSaverXdg.cpp
|
||||
)
|
||||
endif ()
|
||||
|
||||
set(_LINPHONEAPP_SOURCES ${_LINPHONEAPP_SOURCES} PARENT_SCOPE)
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -42,6 +42,7 @@ void LinphoneEnums::registerMetaTypes() {
|
|||
qRegisterMetaType<LinphoneEnums::RegistrationState>();
|
||||
qRegisterMetaType<LinphoneEnums::TunnelMode>();
|
||||
qRegisterMetaType<LinphoneEnums::TransportType>();
|
||||
qRegisterMetaType<LinphoneEnums::VideoSourceScreenSharingType>();
|
||||
qmlRegisterUncreatableMetaObject(LinphoneEnums::staticMetaObject, Constants::MainQmlUri, 1, 0, "LinphoneEnums",
|
||||
"Only enums");
|
||||
}
|
||||
|
|
@ -275,3 +276,12 @@ void LinphoneEnums::fromString(const QString &transportType, LinphoneEnums::Tran
|
|||
else if (transportType.toUpper() == QLatin1String("TLS")) *transport = TransportType::Tls;
|
||||
else *transport = TransportType::Dtls;
|
||||
}
|
||||
|
||||
linphone::VideoSourceScreenSharingType
|
||||
LinphoneEnums::toLinphone(const LinphoneEnums::VideoSourceScreenSharingType &type) {
|
||||
return static_cast<linphone::VideoSourceScreenSharingType>(type);
|
||||
}
|
||||
LinphoneEnums::VideoSourceScreenSharingType
|
||||
LinphoneEnums::fromLinphone(const linphone::VideoSourceScreenSharingType &type) {
|
||||
return static_cast<LinphoneEnums::VideoSourceScreenSharingType>(type);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -308,6 +308,17 @@ Q_ENUM_NS(TransportType)
|
|||
|
||||
linphone::TransportType toLinphone(const LinphoneEnums::TransportType &type);
|
||||
LinphoneEnums::TransportType fromLinphone(const linphone::TransportType &type);
|
||||
|
||||
enum VideoSourceScreenSharingType {
|
||||
VideoSourceScreenSharingTypeArea = int(linphone::VideoSourceScreenSharingType::Area),
|
||||
VideoSourceScreenSharingTypeDisplay = int(linphone::VideoSourceScreenSharingType::Display),
|
||||
VideoSourceScreenSharingTypeWindow = int(linphone::VideoSourceScreenSharingType::Window)
|
||||
};
|
||||
Q_ENUM_NS(VideoSourceScreenSharingType)
|
||||
|
||||
linphone::VideoSourceScreenSharingType toLinphone(const LinphoneEnums::VideoSourceScreenSharingType &type);
|
||||
LinphoneEnums::VideoSourceScreenSharingType fromLinphone(const linphone::VideoSourceScreenSharingType &type);
|
||||
|
||||
QString toString(const LinphoneEnums::TransportType &type);
|
||||
void fromString(const QString &transportType, LinphoneEnums::TransportType *transport);
|
||||
} // namespace LinphoneEnums
|
||||
|
|
|
|||
36
Linphone/tool/native/DesktopTools.hpp
Normal file
36
Linphone/tool/native/DesktopTools.hpp
Normal file
|
|
@ -0,0 +1,36 @@
|
|||
/*
|
||||
* Copyright (c) 2010-2020 Belledonne Communications SARL.
|
||||
*
|
||||
* This file is part of linphone-desktop
|
||||
* (see https://www.linphone.org).
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef DESKTOP_TOOLS_H_
|
||||
#define DESKTOP_TOOLS_H_
|
||||
|
||||
#include <QtGlobal>
|
||||
|
||||
#ifdef Q_OS_LINUX
|
||||
#include "DesktopToolsLinux.hpp"
|
||||
#elif defined(Q_OS_WIN)
|
||||
#include "DesktopToolsWindows.hpp"
|
||||
#else
|
||||
#include "DesktopToolsMacOs.hpp"
|
||||
#endif // ifdef Q_OS_LINUX
|
||||
|
||||
// =============================================================================
|
||||
|
||||
#endif // DESKTOP_TOOLS_H_
|
||||
265
Linphone/tool/native/DesktopToolsLinux.cpp
Normal file
265
Linphone/tool/native/DesktopToolsLinux.cpp
Normal file
|
|
@ -0,0 +1,265 @@
|
|||
/*
|
||||
* Copyright (c) 2010-2020 Belledonne Communications SARL.
|
||||
*
|
||||
* This file is part of linphone-desktop
|
||||
* (see https://www.linphone.org).
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "DesktopToolsLinux.hpp"
|
||||
#include "config.h"
|
||||
|
||||
#include <QDebug>
|
||||
#include <QPixmap>
|
||||
#include <QRect>
|
||||
#include <QThread>
|
||||
#include <X11/Xlib.h>
|
||||
#include <X11/Xutil.h>
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <X11/cursorfont.h>
|
||||
|
||||
// =============================================================================
|
||||
|
||||
DesktopTools::~DesktopTools() {
|
||||
setScreenSaverStatus(true);
|
||||
}
|
||||
|
||||
bool DesktopTools::getScreenSaverStatus() const {
|
||||
return mScreenSaverStatus;
|
||||
}
|
||||
|
||||
void DesktopTools::setScreenSaverStatus(bool status) {
|
||||
screenSaverDBus.setScreenSaverStatus(status);
|
||||
screenSaverXdg.setScreenSaverStatus(status);
|
||||
|
||||
bool newStatus = screenSaverDBus.getScreenSaverStatus() || screenSaverXdg.getScreenSaverStatus();
|
||||
if (newStatus != mScreenSaverStatus) {
|
||||
mScreenSaverStatus = newStatus;
|
||||
emit screenSaverStatusChanged(mScreenSaverStatus);
|
||||
}
|
||||
}
|
||||
|
||||
#define ACTIVE_WINDOWS "_NET_CLIENT_LIST"
|
||||
QList<QVariantMap> DesktopTools::getWindows() {
|
||||
#ifdef ENABLE_SCREENSHARING
|
||||
QList<QVariantMap> windowsMaps;
|
||||
const char *displayStr = getenv("DISPLAY");
|
||||
if (displayStr == NULL) displayStr = ":0";
|
||||
Display *display = XOpenDisplay(displayStr);
|
||||
if (display == NULL) {
|
||||
qCritical() << "Can't open X display!";
|
||||
return windowsMaps;
|
||||
}
|
||||
|
||||
auto screen = DefaultScreen(display);
|
||||
auto rootWindow = RootWindow(display, screen);
|
||||
|
||||
// Algo 1
|
||||
Atom actualType;
|
||||
int format;
|
||||
unsigned long numItems;
|
||||
unsigned long bytesAfter;
|
||||
unsigned char *data = nullptr;
|
||||
Window *list;
|
||||
char *windowName;
|
||||
Atom atom = XInternAtom(display, ACTIVE_WINDOWS, true);
|
||||
int status = XGetWindowProperty(display, rootWindow, atom, 0L, (~0L), false, AnyPropertyType, &actualType, &format,
|
||||
&numItems, &bytesAfter, &data);
|
||||
list = (Window *)data;
|
||||
if (status >= Success && numItems) {
|
||||
for (size_t i = 0; i < numItems; ++i) {
|
||||
status = XFetchName(display, list[i], &windowName);
|
||||
if (status >= Success) {
|
||||
QVariantMap windowMap;
|
||||
windowMap["name"] = QString(windowName);
|
||||
windowMap["windowId"] = (quint64)list[i];
|
||||
windowsMaps << windowMap;
|
||||
XFree(windowName);
|
||||
}
|
||||
}
|
||||
}
|
||||
XFree(data);
|
||||
|
||||
/* //Algo2
|
||||
Window root_return;
|
||||
Window parent_return;
|
||||
Window *children_return;
|
||||
unsigned int nchildren_return;
|
||||
|
||||
XQueryTree(display, rootWindow, &root_return, &parent_return, &children_return, &nchildren_return);
|
||||
for (size_t i = 0; i < nchildren_return; ++i) {
|
||||
XWindowAttributes attributes;
|
||||
XGetWindowAttributes(display, children_return[i], &attributes);
|
||||
// XTextProperty name;
|
||||
// XGetWMName(display, children_return[i], &name);
|
||||
char *name;
|
||||
XFetchName(display, children_return[i], &name);
|
||||
if (attributes.c_class == InputOutput && attributes.map_state == IsViewable) {
|
||||
qDebug() << name << attributes.depth << attributes.root;
|
||||
QVariantMap windowMap;
|
||||
windowMap["name"] = QString(name);
|
||||
windowMap["windowId"] = (quint64)children_return[i];
|
||||
windowsMaps << windowMap;
|
||||
}
|
||||
XFree(name);
|
||||
}
|
||||
|
||||
if (children_return) XFree(children_return);
|
||||
qDebug() << "Found " << nchildren_return << "Windows";
|
||||
*/
|
||||
|
||||
return windowsMaps;
|
||||
#else
|
||||
return QList<QVariantMap>();
|
||||
#endif
|
||||
}
|
||||
|
||||
QImage DesktopTools::takeScreenshot(void *window) {
|
||||
#ifdef ENABLE_SCREENSHARING
|
||||
Display *display = XOpenDisplay(NULL);
|
||||
Window rootWindow = (Window)window;
|
||||
XWindowAttributes attributes;
|
||||
XGetWindowAttributes(display, rootWindow, &attributes);
|
||||
|
||||
int width = attributes.width;
|
||||
int height = attributes.height;
|
||||
|
||||
XColor colors;
|
||||
XImage *image;
|
||||
QImage screenshot(width, height, QImage::Format_RGB32);
|
||||
unsigned long red_mask;
|
||||
unsigned long green_mask;
|
||||
unsigned long blue_mask;
|
||||
|
||||
image = XGetImage(display, rootWindow, 0, 0, width, height, AllPlanes, ZPixmap);
|
||||
if (!image) return QImage();
|
||||
red_mask = image->red_mask;
|
||||
green_mask = image->green_mask;
|
||||
blue_mask = image->blue_mask;
|
||||
|
||||
for (int i = 0; i < height; ++i) {
|
||||
for (int j = 0; j < width; ++j) {
|
||||
colors.pixel = XGetPixel(image, j, i);
|
||||
screenshot.setPixel(
|
||||
j, i,
|
||||
qRgb((colors.pixel & red_mask) >> 16, (colors.pixel & green_mask) >> 8, colors.pixel & blue_mask));
|
||||
}
|
||||
}
|
||||
|
||||
XFree(image);
|
||||
|
||||
return screenshot;
|
||||
#else
|
||||
Q_UNUSED(window)
|
||||
return QImage();
|
||||
#endif
|
||||
}
|
||||
|
||||
QImage DesktopTools::getWindowIcon(void *window) {
|
||||
#ifdef ENABLE_SCREENSHARING
|
||||
Window rootWindow = (Window)window;
|
||||
|
||||
QList<QVariantMap> windowsMaps;
|
||||
const char *displayStr = getenv("DISPLAY");
|
||||
if (displayStr == NULL) displayStr = ":0";
|
||||
Display *display = XOpenDisplay(displayStr);
|
||||
if (display == NULL) {
|
||||
qCritical() << "Can't open X display!";
|
||||
return QImage();
|
||||
}
|
||||
|
||||
auto screen = DefaultScreen(display);
|
||||
|
||||
// Algo 1
|
||||
Atom actualType;
|
||||
int format;
|
||||
unsigned long numItems;
|
||||
unsigned long bytesAfter;
|
||||
unsigned char *data = nullptr;
|
||||
Window *list;
|
||||
char *windowName;
|
||||
Atom atom = XInternAtom(display, "_NET_WM_ICON", true);
|
||||
int status = XGetWindowProperty(display, rootWindow, atom, 0L, 1, 0, AnyPropertyType, &actualType, &format,
|
||||
&numItems, &bytesAfter, &data);
|
||||
if (!data) return QImage();
|
||||
int width = *(int *)data;
|
||||
XFree(data);
|
||||
XGetWindowProperty(display, rootWindow, atom, 1, 1, 0, AnyPropertyType, &actualType, &format, &numItems,
|
||||
&bytesAfter, &data);
|
||||
if (!data) return QImage();
|
||||
int height = *(int *)data;
|
||||
XFree(data);
|
||||
int size = width * height;
|
||||
XGetWindowProperty(display, rootWindow, atom, 2, size, 0, AnyPropertyType, &actualType, &format, &numItems,
|
||||
&bytesAfter, &data);
|
||||
if (!data) return QImage();
|
||||
QImage icon(width, height, QImage::Format_ARGB32);
|
||||
|
||||
unsigned int *imgData = new unsigned int[size];
|
||||
unsigned long *ul = (unsigned long *)data;
|
||||
for (int i = 0; i < numItems; ++i) {
|
||||
imgData[i] = (unsigned int)ul[i];
|
||||
}
|
||||
unsigned char *argb = (unsigned char *)imgData;
|
||||
// qDebug() << bytesAfter << " / " << numItems << height << "x" << width << " == " << height * width << " : "
|
||||
// << height * width * 4;
|
||||
for (int y = 0; y < height; y++) {
|
||||
for (int x = 0; x < width; x++) {
|
||||
unsigned char a = argb[3];
|
||||
unsigned char r = argb[2] * a / 255;
|
||||
unsigned char g = argb[1] * a / 255;
|
||||
unsigned char b = argb[0] * a / 255;
|
||||
icon.setPixel(x, y, qRgba(r, g, b, a));
|
||||
argb += 4;
|
||||
}
|
||||
}
|
||||
XFree(data);
|
||||
delete[] imgData;
|
||||
return icon;
|
||||
#else
|
||||
Q_UNUSED(window)
|
||||
return QImage();
|
||||
#endif
|
||||
}
|
||||
|
||||
uintptr_t DesktopTools::getDisplayIndex(void *screenSharing) {
|
||||
Q_UNUSED(screenSharing)
|
||||
#ifdef ENABLE_SCREENSHARING
|
||||
return *(uintptr_t *)(&screenSharing);
|
||||
#else
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
QRect DesktopTools::getWindowGeometry(void *screenSharing) {
|
||||
Q_UNUSED(screenSharing)
|
||||
#ifdef ENABLE_SCREENSHARING
|
||||
const char *displayStr = getenv("DISPLAY");
|
||||
if (displayStr == NULL) displayStr = ":0";
|
||||
Display *display = XOpenDisplay(displayStr);
|
||||
if (display == NULL) {
|
||||
qCritical() << "Can't open X display!";
|
||||
return QRect();
|
||||
}
|
||||
Window windowId = (Window)screenSharing;
|
||||
XWindowAttributes attributes;
|
||||
XGetWindowAttributes(display, windowId, &attributes);
|
||||
return QRect(attributes.x, attributes.y, attributes.width, attributes.height);
|
||||
#else
|
||||
return QRect();
|
||||
#endif
|
||||
}
|
||||
71
Linphone/tool/native/DesktopToolsLinux.hpp
Normal file
71
Linphone/tool/native/DesktopToolsLinux.hpp
Normal file
|
|
@ -0,0 +1,71 @@
|
|||
/*
|
||||
* Copyright (c) 2010-2020 Belledonne Communications SARL.
|
||||
*
|
||||
* This file is part of linphone-desktop
|
||||
* (see https://www.linphone.org).
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef DESKTOP_TOOLS_LINUX_H_
|
||||
#define DESKTOP_TOOLS_LINUX_H_
|
||||
|
||||
#include "screen-saver/ScreenSaverDBus.hpp"
|
||||
#include "screen-saver/ScreenSaverXdg.hpp"
|
||||
|
||||
// =============================================================================
|
||||
class VideoSourceDescriptorModel;
|
||||
|
||||
class DesktopTools : public QObject {
|
||||
Q_OBJECT
|
||||
|
||||
Q_PROPERTY(
|
||||
bool screenSaverStatus READ getScreenSaverStatus WRITE setScreenSaverStatus NOTIFY screenSaverStatusChanged)
|
||||
|
||||
public:
|
||||
DesktopTools(QObject *parent = Q_NULLPTR) : QObject(parent) {
|
||||
}
|
||||
~DesktopTools();
|
||||
|
||||
bool getScreenSaverStatus() const;
|
||||
void setScreenSaverStatus(bool status);
|
||||
|
||||
static void init() {
|
||||
}
|
||||
static void applicationStateChanged(Qt::ApplicationState){};
|
||||
static QList<QVariantMap> getWindows();
|
||||
static QImage takeScreenshot(void *window);
|
||||
static QImage getWindowIcon(void *window);
|
||||
|
||||
static void *getDisplay(uintptr_t screenIndex) {
|
||||
return reinterpret_cast<void *>(screenIndex);
|
||||
}
|
||||
static uintptr_t getDisplayIndex(void *screenSharing);
|
||||
static QRect getWindowGeometry(void *screenSharing);
|
||||
|
||||
signals:
|
||||
void screenSaverStatusChanged(bool status);
|
||||
|
||||
private:
|
||||
bool mScreenSaverStatus = true;
|
||||
|
||||
ScreenSaverDBus screenSaverDBus;
|
||||
ScreenSaverXdg screenSaverXdg;
|
||||
|
||||
// X11 headers cannot be used in hpp. moc don't' compile.
|
||||
void *mDisplay = nullptr; // Display
|
||||
unsigned int mWindow = 0; // Window
|
||||
};
|
||||
|
||||
#endif // DESKTOP_TOOLS_LINUX_H_
|
||||
43
Linphone/tool/native/DesktopToolsMacOs.cpp
Normal file
43
Linphone/tool/native/DesktopToolsMacOs.cpp
Normal file
|
|
@ -0,0 +1,43 @@
|
|||
/*
|
||||
* Copyright (c) 2010-2020 Belledonne Communications SARL.
|
||||
*
|
||||
* This file is part of linphone-desktop
|
||||
* (see https://www.linphone.org).
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "DesktopToolsMacOs.hpp"
|
||||
|
||||
// =============================================================================
|
||||
|
||||
extern "C" bool enableScreenSaverMacOs ();
|
||||
extern "C" bool disableScreenSaverMacOs ();
|
||||
|
||||
DesktopTools::DesktopTools (QObject *parent) : QObject(parent) {}
|
||||
|
||||
DesktopTools::~DesktopTools () {
|
||||
setScreenSaverStatus(true);
|
||||
}
|
||||
|
||||
bool DesktopTools::getScreenSaverStatus () const {
|
||||
return mScreenSaverStatus;
|
||||
}
|
||||
|
||||
void DesktopTools::setScreenSaverStatus (bool status) {
|
||||
if (status != mScreenSaverStatus && (status ? enableScreenSaverMacOs() : disableScreenSaverMacOs())) {
|
||||
mScreenSaverStatus = status;
|
||||
emit screenSaverStatusChanged(mScreenSaverStatus);
|
||||
}
|
||||
}
|
||||
62
Linphone/tool/native/DesktopToolsMacOs.hpp
Normal file
62
Linphone/tool/native/DesktopToolsMacOs.hpp
Normal file
|
|
@ -0,0 +1,62 @@
|
|||
/*
|
||||
* Copyright (c) 2010-2020 Belledonne Communications SARL.
|
||||
*
|
||||
* This file is part of linphone-desktop
|
||||
* (see https://www.linphone.org).
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef DESKTOP_TOOLS_MAC_OS_H_
|
||||
#define DESKTOP_TOOLS_MAC_OS_H_
|
||||
|
||||
#include <QObject>
|
||||
#include <QImage>
|
||||
#include <QVariantList>
|
||||
#include <QList>
|
||||
// =============================================================================
|
||||
class VideoSourceDescriptorModel;
|
||||
|
||||
class DesktopTools : public QObject {
|
||||
Q_OBJECT;
|
||||
|
||||
Q_PROPERTY(
|
||||
bool screenSaverStatus READ getScreenSaverStatus WRITE setScreenSaverStatus NOTIFY screenSaverStatusChanged);
|
||||
|
||||
public:
|
||||
DesktopTools(QObject *parent = Q_NULLPTR);
|
||||
~DesktopTools();
|
||||
|
||||
bool getScreenSaverStatus() const;
|
||||
void setScreenSaverStatus(bool status);
|
||||
|
||||
static void init(); // Do first initialization
|
||||
static void applicationStateChanged(Qt::ApplicationState currentState);
|
||||
|
||||
static QList<QVariantMap> getWindows();
|
||||
static QImage takeScreenshot(void *window);
|
||||
static QImage getWindowIcon(void *window);
|
||||
|
||||
static void *getDisplay(int screenIndex);
|
||||
static int getDisplayIndex(void *screenSharing);
|
||||
static QRect getWindowGeometry(void *screenSharing);
|
||||
|
||||
signals:
|
||||
void screenSaverStatusChanged(bool status);
|
||||
|
||||
private:
|
||||
bool mScreenSaverStatus = true;
|
||||
};
|
||||
|
||||
#endif // DESKTOP_TOOLS_MAC_OS_H_
|
||||
228
Linphone/tool/native/DesktopToolsMacOsNative.mm
Normal file
228
Linphone/tool/native/DesktopToolsMacOsNative.mm
Normal file
|
|
@ -0,0 +1,228 @@
|
|||
#include "DesktopToolsMacOs.hpp"
|
||||
#include "config.h"
|
||||
|
||||
#import <AVFoundation/AVFoundation.h>
|
||||
#import <ScreenCaptureKit/ScreenCaptureKit.h>
|
||||
#include <QDebug>
|
||||
#include <QRect>
|
||||
#include <QThread>
|
||||
|
||||
void DesktopTools::init(){
|
||||
// Request permissions
|
||||
if([AVCaptureDevice authorizationStatusForMediaType:AVMediaTypeVideo] != AVAuthorizationStatusAuthorized) {
|
||||
qDebug() << "Requesting Video permission";
|
||||
[AVCaptureDevice requestAccessForMediaType:AVMediaTypeVideo completionHandler:^(BOOL) {}];
|
||||
}
|
||||
if([AVCaptureDevice authorizationStatusForMediaType:AVMediaTypeAudio] != AVAuthorizationStatusAuthorized){
|
||||
qDebug() << "Requesting Audio permission";
|
||||
[AVCaptureDevice requestAccessForMediaType:AVMediaTypeAudio completionHandler:^(BOOL) {}];
|
||||
}
|
||||
}
|
||||
|
||||
bool isWindowMinimized(CGWindowID id) {
|
||||
CFArrayRef ids = CFArrayCreate(NULL, reinterpret_cast<const void **>(&id), 1, NULL);
|
||||
CFArrayRef descriptions = CGWindowListCreateDescriptionFromArray(ids);
|
||||
bool minimized = false;
|
||||
|
||||
if (descriptions && CFArrayGetCount(descriptions)) {
|
||||
CFDictionaryRef window = reinterpret_cast<CFDictionaryRef>(CFArrayGetValueAtIndex(descriptions, 0));
|
||||
minimized = ! reinterpret_cast<CFBooleanRef>(CFDictionaryGetValue(window, kCGWindowIsOnscreen));
|
||||
}
|
||||
|
||||
CFRelease(descriptions);
|
||||
CFRelease(ids);
|
||||
|
||||
return minimized;
|
||||
}
|
||||
|
||||
QList<QVariantMap> DesktopTools::getWindows() {
|
||||
QList<QVariantMap> windows;
|
||||
bool haveAccess = CGPreflightScreenCaptureAccess();
|
||||
//Requests event listening access if absent, potentially prompting
|
||||
if(!haveAccess) haveAccess = CGRequestScreenCaptureAccess();
|
||||
|
||||
CFArrayRef infos = CGWindowListCopyWindowInfo(kCGWindowListExcludeDesktopElements, kCGNullWindowID);
|
||||
for(int windowIndex = 0 ; windowIndex < CFArrayGetCount(infos) ; ++windowIndex) {
|
||||
CFDictionaryRef description = (CFDictionaryRef)CFArrayGetValueAtIndex ((CFArrayRef)infos, windowIndex);
|
||||
if(CFDictionaryContainsKey(description, kCGWindowNumber)
|
||||
&& CFDictionaryContainsKey(description, kCGWindowLayer)
|
||||
&& CFDictionaryContainsKey(description, kCGWindowName)
|
||||
) {
|
||||
CFNumberRef idRef = (CFNumberRef)CFDictionaryGetValue (description, kCGWindowNumber);
|
||||
CFNumberRef layerRef = (CFNumberRef)CFDictionaryGetValue (description, kCGWindowLayer);
|
||||
CFStringRef titleRef = (CFStringRef)CFDictionaryGetValue (description, kCGWindowName);
|
||||
CGWindowID id=0, layer=0;
|
||||
|
||||
if (!CFNumberGetValue(idRef, kCFNumberIntType, &id) || !CFNumberGetValue(layerRef, kCFNumberIntType, &layer)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
QVariantMap window;
|
||||
if(CFDictionaryContainsKey(description, kCGWindowName)) {
|
||||
window["name"] = QString::fromCFString(titleRef);
|
||||
}
|
||||
if( window["name"] == "") continue;
|
||||
window["windowId"] = id;
|
||||
|
||||
// Skip layer != 0 like menu or dock
|
||||
if(layer != 0 || isWindowMinimized(id))
|
||||
continue;
|
||||
// Remove System status indicator from the list as they are on layer 0
|
||||
CFStringRef ownerName = reinterpret_cast<CFStringRef>(CFDictionaryGetValue(description, kCGWindowOwnerName));
|
||||
if (titleRef && CFEqual(titleRef, CFSTR("StatusIndicator")) && ownerName && CFEqual(ownerName, CFSTR("Window Server"))) {
|
||||
continue;
|
||||
}
|
||||
windows << window;
|
||||
}
|
||||
}
|
||||
if(infos) CFRelease(infos);
|
||||
return windows;
|
||||
}
|
||||
CGBitmapInfo CGBitmapInfoForQImage(const QImage &image) {
|
||||
CGBitmapInfo bitmapInfo = kCGImageAlphaNone;
|
||||
|
||||
switch (image.format()) {
|
||||
case QImage::Format_ARGB32:
|
||||
bitmapInfo = kCGImageAlphaFirst | kCGBitmapByteOrder32Host;
|
||||
break;
|
||||
case QImage::Format_RGB32:
|
||||
bitmapInfo = kCGImageAlphaNoneSkipFirst | kCGBitmapByteOrder32Host;
|
||||
break;
|
||||
case QImage::Format_RGBA8888_Premultiplied:
|
||||
bitmapInfo = kCGImageAlphaPremultipliedLast | kCGBitmapByteOrder32Big;
|
||||
break;
|
||||
case QImage::Format_RGBA8888:
|
||||
bitmapInfo = kCGImageAlphaLast | kCGBitmapByteOrder32Big;
|
||||
break;
|
||||
case QImage::Format_RGBX8888:
|
||||
bitmapInfo = kCGImageAlphaNoneSkipLast | kCGBitmapByteOrder32Big;
|
||||
break;
|
||||
case QImage::Format_ARGB32_Premultiplied:
|
||||
bitmapInfo = kCGImageAlphaPremultipliedFirst | kCGBitmapByteOrder32Host;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return bitmapInfo;
|
||||
}
|
||||
|
||||
QImage CGImageToQImage(CGImageRef cgImage) {
|
||||
const size_t width = CGImageGetWidth(cgImage);
|
||||
const size_t height = CGImageGetHeight(cgImage);
|
||||
QImage image(width, height, QImage::Format_ARGB32_Premultiplied);
|
||||
image.fill(Qt::transparent);
|
||||
|
||||
CGColorSpaceRef colorSpace = CGColorSpaceCreateWithName(kCGColorSpaceSRGB);
|
||||
CGContextRef context = CGBitmapContextCreate((void *)image.bits(), image.width(), image.height(), 8,
|
||||
image.bytesPerLine(), colorSpace, CGBitmapInfoForQImage(image));
|
||||
|
||||
// Scale the context so that painting happens in device-independent pixels
|
||||
const qreal devicePixelRatio = image.devicePixelRatio();
|
||||
CGContextScaleCTM(context, devicePixelRatio, devicePixelRatio);
|
||||
|
||||
CGRect rect = CGRectMake(0, 0, width, height);
|
||||
CGContextDrawImage(context, rect, cgImage);
|
||||
|
||||
if(colorSpace) CFRelease(colorSpace);
|
||||
if(context) CFRelease(context);
|
||||
|
||||
return image;
|
||||
}
|
||||
|
||||
QImage DesktopTools::getWindowIcon(void *window) {
|
||||
CGWindowID windowId = *(CGWindowID*)&window;
|
||||
pid_t pid=0;
|
||||
|
||||
CFArrayRef infos = CGWindowListCopyWindowInfo(kCGWindowListOptionIncludingWindow, windowId);
|
||||
NSString *bundleIdentifier = @"";
|
||||
if (infos && CFArrayGetCount(infos)) {
|
||||
CFDictionaryRef w = reinterpret_cast<CFDictionaryRef>(CFArrayGetValueAtIndex(infos, 0));
|
||||
CFNumberRef pidRef = reinterpret_cast<CFNumberRef>(CFDictionaryGetValue(w, kCGWindowOwnerPID));
|
||||
CFNumberGetValue(pidRef, kCFNumberIntType, &pid) ;
|
||||
bundleIdentifier = [[NSRunningApplication runningApplicationWithProcessIdentifier:pid] bundleIdentifier];
|
||||
}
|
||||
|
||||
if(infos) CFRelease(infos);
|
||||
|
||||
if(bundleIdentifier) {
|
||||
NSURL* url = [[NSWorkspace sharedWorkspace] URLForApplicationWithBundleIdentifier:bundleIdentifier];
|
||||
NSString * noScheme = [[url absoluteString] substringFromIndex:7];
|
||||
NSImage *nsImage = [[NSWorkspace sharedWorkspace] iconForFile:noScheme];
|
||||
|
||||
NSRect rect = NSMakeRect(0, 0, nsImage.size.width, nsImage.size.height);
|
||||
CGImageRef cgImage = [nsImage CGImageForProposedRect:&rect context:NULL hints:nil];
|
||||
|
||||
return CGImageToQImage(cgImage);
|
||||
}else {
|
||||
qWarning() << "Screensharing : Bundle identifier is null for CGID=" << windowId << " pid="<< pid;
|
||||
return QImage();
|
||||
}
|
||||
}
|
||||
|
||||
QImage DesktopTools::takeScreenshot(void *window) {
|
||||
|
||||
CGWindowID windowId = *(CGWindowID*)&window;
|
||||
CGImageRef capture = CGWindowListCreateImage(CGRectNull, kCGWindowListOptionIncludingWindow, windowId, kCGWindowImageBoundsIgnoreFraming);
|
||||
return CGImageToQImage(capture);
|
||||
}
|
||||
|
||||
|
||||
void *DesktopTools::getDisplay(int screenIndex){
|
||||
Q_UNUSED(screenIndex)
|
||||
#ifdef ENABLE_SCREENSHARING
|
||||
CGDirectDisplayID displays[screenIndex+1];
|
||||
CGDisplayCount displayCount;
|
||||
CGGetOnlineDisplayList(screenIndex+1, displays, &displayCount);
|
||||
CGDirectDisplayID display = 0;
|
||||
if(displayCount > screenIndex)
|
||||
display = displays[screenIndex];
|
||||
return reinterpret_cast<void*>(display);
|
||||
#else
|
||||
return NULL;
|
||||
#endif
|
||||
}
|
||||
|
||||
int DesktopTools::getDisplayIndex(void* screenSharing){
|
||||
Q_UNUSED(screenSharing)
|
||||
#ifdef ENABLE_SCREENSHARING
|
||||
CGDirectDisplayID displayId = *(CGDirectDisplayID*)&screenSharing;
|
||||
int maxDisplayCount = 10;
|
||||
CGDisplayCount displayCount;
|
||||
do {
|
||||
CGDirectDisplayID displays[maxDisplayCount];
|
||||
CGGetOnlineDisplayList(maxDisplayCount, displays, &displayCount);
|
||||
for(int i = 0 ; i < displayCount ; ++i)
|
||||
if( displays[i] == displayId) {
|
||||
return i;
|
||||
}
|
||||
maxDisplayCount *= 2;
|
||||
}while(displayCount == maxDisplayCount/2);
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
QRect DesktopTools::getWindowGeometry(void* screenSharing) {
|
||||
Q_UNUSED(screenSharing)
|
||||
QRect result;
|
||||
#ifdef ENABLE_SCREENSHARING
|
||||
CGWindowID windowId = *(CGWindowID*)&screenSharing;
|
||||
CFArrayRef descriptions = CGWindowListCopyWindowInfo(kCGWindowListOptionIncludingWindow, windowId);
|
||||
if(CFArrayGetCount(descriptions) > 0) {
|
||||
CFDictionaryRef description = (CFDictionaryRef)CFArrayGetValueAtIndex ((CFArrayRef)descriptions, 0);
|
||||
if(CFDictionaryContainsKey(description, kCGWindowBounds)) {
|
||||
CFDictionaryRef bounds = (CFDictionaryRef)CFDictionaryGetValue (description, kCGWindowBounds);
|
||||
if(bounds) {
|
||||
CGRect windowRect;
|
||||
CGRectMakeWithDictionaryRepresentation(bounds, &windowRect);
|
||||
result = QRect(windowRect.origin.x, windowRect.origin.y, windowRect.size.width, windowRect.size.height);
|
||||
}else
|
||||
qWarning() << "Bounds found be cannot be parsed for Window ID : " << windowId;
|
||||
}else
|
||||
qWarning() << "No bounds specified in Apple description for Window ID : " << windowId;
|
||||
}else
|
||||
qWarning() << "No description found for Window ID : " << windowId;
|
||||
if(descriptions) CFRelease(descriptions);
|
||||
#endif
|
||||
return result;
|
||||
}
|
||||
188
Linphone/tool/native/DesktopToolsWindows.cpp
Normal file
188
Linphone/tool/native/DesktopToolsWindows.cpp
Normal file
|
|
@ -0,0 +1,188 @@
|
|||
/*
|
||||
* Copyright (c) 2010-2020 Belledonne Communications SARL.
|
||||
*
|
||||
* This file is part of linphone-desktop
|
||||
* (see https://www.linphone.org).
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "DesktopToolsWindows.hpp"
|
||||
|
||||
#include <QDebug>
|
||||
#include <QRect>
|
||||
#include <Windows.h>
|
||||
#include <atlimage.h>
|
||||
#include <dwmapi.h>
|
||||
#include <wingdi.h>
|
||||
#include <winuser.h>
|
||||
// =============================================================================
|
||||
|
||||
DesktopTools::DesktopTools(QObject *parent) : QObject(parent) {
|
||||
}
|
||||
|
||||
DesktopTools::~DesktopTools() {
|
||||
setScreenSaverStatus(true);
|
||||
}
|
||||
|
||||
bool DesktopTools::getScreenSaverStatus() const {
|
||||
return mScreenSaverStatus;
|
||||
}
|
||||
|
||||
void DesktopTools::setScreenSaverStatus(bool status) {
|
||||
if (status == mScreenSaverStatus) return;
|
||||
|
||||
if (status) SetThreadExecutionState(ES_CONTINUOUS);
|
||||
else SetThreadExecutionState(ES_CONTINUOUS | ES_DISPLAY_REQUIRED);
|
||||
|
||||
mScreenSaverStatus = status;
|
||||
emit screenSaverStatusChanged(status);
|
||||
}
|
||||
|
||||
//----------- Get Windows
|
||||
void getWindowMap(HWND hwnd, LPARAM lParam) {
|
||||
const DWORD TITLE_SIZE = 1024;
|
||||
WCHAR windowTitle[TITLE_SIZE];
|
||||
|
||||
GetWindowTextW(hwnd, windowTitle, TITLE_SIZE);
|
||||
std::wstring title(&windowTitle[0]);
|
||||
int length = ::GetWindowTextLength(hwnd);
|
||||
if (!IsWindowVisible(hwnd) || length == 0) {
|
||||
return;
|
||||
}
|
||||
QList<QVariantMap> &windowsMap = *reinterpret_cast<QList<QVariantMap> *>(lParam);
|
||||
QVariantMap windowMap;
|
||||
windowMap["name"] = QString::fromStdWString(title);
|
||||
windowMap["windowId"] = (quint64)hwnd;
|
||||
windowsMap << windowMap;
|
||||
}
|
||||
|
||||
BOOL CALLBACK getChildWindowsCb(HWND hwnd, LPARAM lParam) {
|
||||
getWindowMap(hwnd, lParam);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
BOOL CALLBACK getWindowsCb(HWND hwnd, LPARAM lParam) {
|
||||
getWindowMap(hwnd, lParam);
|
||||
// EnumChildWindows(hwnd, getChildWindowsCb, lParam);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
QList<QVariantMap> DesktopTools::getWindows() {
|
||||
#ifdef ENABLE_SCREENSHARING
|
||||
QList<QVariantMap> windowsMap;
|
||||
EnumWindows(getWindowsCb, reinterpret_cast<LPARAM>(&windowsMap));
|
||||
return windowsMap;
|
||||
#else
|
||||
return QList<QVariantMap>();
|
||||
#endif
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------
|
||||
|
||||
#ifndef GCL_HICON
|
||||
#define GCL_HICON -14
|
||||
#endif
|
||||
|
||||
QImage DesktopTools::getWindowIcon(void *window) {
|
||||
#ifdef ENABLE_SCREENSHARING
|
||||
#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
|
||||
QPixmap pixmap = QtWin::fromHICON(icon);
|
||||
return pixmap.toImage();
|
||||
#else
|
||||
return QImage::fromHICON(icon);
|
||||
#endif
|
||||
|
||||
#else
|
||||
return QImage();
|
||||
#endif
|
||||
}
|
||||
|
||||
QImage DesktopTools::takeScreenshot(void *window) {
|
||||
QImage image;
|
||||
#ifdef ENABLE_SCREENSHARING
|
||||
RECT rect = {0};
|
||||
|
||||
if (!GetWindowRect((HWND)window, &rect)) {
|
||||
qCritical() << "[DesktopTools] Cannot get window size";
|
||||
return image;
|
||||
}
|
||||
HDC hDC = GetDC((HWND)window);
|
||||
if (hDC == NULL) {
|
||||
qCritical() << "[DesktopTools] GetDC failed.";
|
||||
return image;
|
||||
}
|
||||
HDC hTargetDC = CreateCompatibleDC(hDC);
|
||||
if (hTargetDC == NULL) {
|
||||
ReleaseDC((HWND)window, hDC);
|
||||
qCritical() << "[DesktopTools] CreateCompatibleDC failed.";
|
||||
return image;
|
||||
}
|
||||
HBITMAP hBitmap = CreateCompatibleBitmap(hDC, rect.right - rect.left, rect.bottom - rect.top);
|
||||
if (hBitmap == NULL) {
|
||||
ReleaseDC((HWND)window, hDC);
|
||||
ReleaseDC((HWND)window, hTargetDC);
|
||||
qCritical() << "[DesktopTools] CreateCompatibleBitmap failed.";
|
||||
return image;
|
||||
}
|
||||
if (!SelectObject(hTargetDC, hBitmap)) {
|
||||
DeleteObject(hBitmap);
|
||||
ReleaseDC((HWND)window, hDC);
|
||||
ReleaseDC((HWND)window, hTargetDC);
|
||||
qCritical() << "[DesktopTools] SelectObject failed.";
|
||||
return image;
|
||||
}
|
||||
|
||||
if (!PrintWindow((HWND)window, hTargetDC, PW_RENDERFULLCONTENT)) {
|
||||
DeleteObject(hBitmap);
|
||||
ReleaseDC((HWND)window, hDC);
|
||||
ReleaseDC((HWND)window, hTargetDC);
|
||||
qCritical() << "[DesktopTools] PrintWindow failed.";
|
||||
return image;
|
||||
}
|
||||
|
||||
#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
|
||||
QPixmap pixmap = QtWin::fromHBITMAP(hBitmap);
|
||||
image = pixmap.toImage();
|
||||
#else
|
||||
image = QImage::fromHBITMAP(hBitmap);
|
||||
#endif
|
||||
DeleteObject(hBitmap);
|
||||
ReleaseDC((HWND)window, hDC);
|
||||
ReleaseDC((HWND)window, hTargetDC);
|
||||
#endif
|
||||
return image;
|
||||
}
|
||||
|
||||
uintptr_t DesktopTools::getDisplayIndex(void *screenSharing) {
|
||||
Q_UNUSED(screenSharing)
|
||||
#ifdef ENABLE_SCREENSHARING
|
||||
return *(uintptr_t *)(&screenSharing);
|
||||
#else
|
||||
return NULL;
|
||||
#endif
|
||||
}
|
||||
|
||||
QRect DesktopTools::getWindowGeometry(void *screenSharing) {
|
||||
Q_UNUSED(screenSharing)
|
||||
QRect result;
|
||||
#ifdef ENABLE_SCREENSHARING
|
||||
HWND windowId = *(HWND *)&screenSharing;
|
||||
RECT area;
|
||||
if (S_OK == DwmGetWindowAttribute(windowId, DWMWA_EXTENDED_FRAME_BOUNDS, &area, sizeof(RECT))) {
|
||||
result = QRect(area.left + 1, area.top, area.right - area.left, area.bottom - area.top); // +1 for border
|
||||
} else qWarning() << "Cannot get attributes from HWND: " << windowId;
|
||||
#endif
|
||||
return result;
|
||||
}
|
||||
70
Linphone/tool/native/DesktopToolsWindows.hpp
Normal file
70
Linphone/tool/native/DesktopToolsWindows.hpp
Normal file
|
|
@ -0,0 +1,70 @@
|
|||
/*
|
||||
* Copyright (c) 2010-2020 Belledonne Communications SARL.
|
||||
*
|
||||
* This file is part of linphone-desktop
|
||||
* (see https://www.linphone.org).
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef DESKTOP_TOOLS_WINDOWS_H_
|
||||
#define DESKTOP_TOOLS_WINDOWS_H_
|
||||
|
||||
#include <QImage>
|
||||
#include <QObject>
|
||||
#include <QVariantMap>
|
||||
#include <windows.h>
|
||||
|
||||
class VideoSourceDescriptorModel;
|
||||
// =============================================================================
|
||||
|
||||
class DesktopTools : public QObject {
|
||||
Q_OBJECT
|
||||
|
||||
Q_PROPERTY(
|
||||
bool screenSaverStatus READ getScreenSaverStatus WRITE setScreenSaverStatus NOTIFY screenSaverStatusChanged)
|
||||
|
||||
public:
|
||||
DesktopTools(QObject *parent = Q_NULLPTR);
|
||||
~DesktopTools();
|
||||
|
||||
bool getScreenSaverStatus() const;
|
||||
void setScreenSaverStatus(bool status);
|
||||
|
||||
static void init() {
|
||||
}
|
||||
static void applicationStateChanged(Qt::ApplicationState){};
|
||||
|
||||
static QList<QVariantMap> getWindows();
|
||||
static QImage takeScreenshot(void *window);
|
||||
static QImage getWindowIcon(void *window);
|
||||
|
||||
static void *getDisplay(uintptr_t screenIndex) {
|
||||
return reinterpret_cast<void *>(screenIndex);
|
||||
}
|
||||
static uintptr_t getDisplayIndex(void *screenSharing);
|
||||
static QRect getWindowGeometry(void *screenSharing);
|
||||
HWND mWindowId = 0; // Window
|
||||
VideoSourceDescriptorModel *mVideoSourceDescriptorModel = nullptr;
|
||||
|
||||
signals:
|
||||
void screenSaverStatusChanged(bool status);
|
||||
void windowIdSelectionStarted();
|
||||
void windowIdSelectionEnded();
|
||||
|
||||
private:
|
||||
bool mScreenSaverStatus = true;
|
||||
};
|
||||
|
||||
#endif // DESKTOP_TOOLS_WINDOWS_H_
|
||||
75
Linphone/tool/native/screen-saver/ScreenSaverDBus.cpp
Normal file
75
Linphone/tool/native/screen-saver/ScreenSaverDBus.cpp
Normal file
|
|
@ -0,0 +1,75 @@
|
|||
/*
|
||||
* Copyright (c) 2010-2020 Belledonne Communications SARL.
|
||||
*
|
||||
* This file is part of linphone-desktop
|
||||
* (see https://www.linphone.org).
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <QCoreApplication>
|
||||
#include <QDBusPendingCallWatcher>
|
||||
#include <QDBusPendingReply>
|
||||
#include <QDebug>
|
||||
|
||||
#include "ScreenSaverDBus.hpp"
|
||||
|
||||
// =============================================================================
|
||||
|
||||
namespace {
|
||||
constexpr char ServiceName[] = "org.freedesktop.ScreenSaver";
|
||||
constexpr char ServicePath[] = "/ScreenSaver";
|
||||
}
|
||||
|
||||
ScreenSaverDBus::ScreenSaverDBus (QObject *parent) : QObject(parent), mBus(ServiceName, ServicePath, ServiceName) {}
|
||||
|
||||
ScreenSaverDBus::~ScreenSaverDBus () {
|
||||
setScreenSaverStatus(true);
|
||||
}
|
||||
|
||||
bool ScreenSaverDBus::getScreenSaverStatus () const {
|
||||
return mScreenSaverStatus;
|
||||
}
|
||||
|
||||
void ScreenSaverDBus::setScreenSaverStatus (bool status) {
|
||||
if (status == mScreenSaverStatus)
|
||||
return;
|
||||
|
||||
if (status) {
|
||||
QDBusMessage reply(mBus.call("UnInhibit", mToken));
|
||||
if (reply.type() == QDBusMessage::ErrorMessage) {
|
||||
qWarning() << QStringLiteral("Uninhibit screen saver failed: `%1: %2`.")
|
||||
.arg(reply.errorName()).arg(reply.errorMessage());
|
||||
return;
|
||||
} else
|
||||
qInfo("Uninhibit screen saver.");
|
||||
|
||||
mToken = uint32_t(reply.arguments().first().toULongLong());
|
||||
mScreenSaverStatus = status;
|
||||
emit screenSaverStatusChanged(mScreenSaverStatus);
|
||||
return;
|
||||
}
|
||||
|
||||
QDBusMessage reply(mBus.call("Inhibit", QCoreApplication::applicationName(), "Inhibit asked for video stream"));
|
||||
if (reply.type() == QDBusMessage::ErrorMessage) {
|
||||
if (reply.errorName() != QLatin1String("org.freedesktop.DBus.Error.ServiceUnknown"))
|
||||
qWarning() << QStringLiteral("Inhibit screen saver failed: `%1: %2`.")
|
||||
.arg(reply.errorName()).arg(reply.errorMessage());
|
||||
return;
|
||||
} else
|
||||
qInfo("Inhibit screen saver.");
|
||||
|
||||
mScreenSaverStatus = status;
|
||||
emit screenSaverStatusChanged(mScreenSaverStatus);
|
||||
}
|
||||
50
Linphone/tool/native/screen-saver/ScreenSaverDBus.hpp
Normal file
50
Linphone/tool/native/screen-saver/ScreenSaverDBus.hpp
Normal file
|
|
@ -0,0 +1,50 @@
|
|||
/*
|
||||
* Copyright (c) 2010-2020 Belledonne Communications SARL.
|
||||
*
|
||||
* This file is part of linphone-desktop
|
||||
* (see https://www.linphone.org).
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef SCREEN_SAVER_DBUS_H_
|
||||
#define SCREEN_SAVER_DBUS_H_
|
||||
|
||||
#include <QDBusInterface>
|
||||
|
||||
// =============================================================================
|
||||
|
||||
class QDBusPendingCallWatcher;
|
||||
|
||||
class ScreenSaverDBus : public QObject {
|
||||
Q_OBJECT;
|
||||
|
||||
public:
|
||||
ScreenSaverDBus (QObject *parent = Q_NULLPTR);
|
||||
~ScreenSaverDBus ();
|
||||
|
||||
bool getScreenSaverStatus () const;
|
||||
void setScreenSaverStatus (bool status);
|
||||
|
||||
signals:
|
||||
void screenSaverStatusChanged (bool status);
|
||||
|
||||
private:
|
||||
bool mScreenSaverStatus = true;
|
||||
|
||||
QDBusInterface mBus;
|
||||
uint32_t mToken;
|
||||
};
|
||||
|
||||
#endif // SCREEN_SAVER_DBUS_H_
|
||||
49
Linphone/tool/native/screen-saver/ScreenSaverMacOs.m
Normal file
49
Linphone/tool/native/screen-saver/ScreenSaverMacOs.m
Normal file
|
|
@ -0,0 +1,49 @@
|
|||
/*
|
||||
* ScreenSaverMacOS.m
|
||||
* Copyright (C) 2017-2018 Belledonne Communications, Grenoble, France
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*
|
||||
* Created on: August 3, 2018
|
||||
* Author: Ronan Abhamon
|
||||
*/
|
||||
|
||||
#import <IOKit/pwr_mgt/IOPMLib.h>
|
||||
|
||||
// =============================================================================
|
||||
|
||||
static bool ScreenSaverEnabled = true;
|
||||
static IOPMAssertionID AssertionID;
|
||||
|
||||
bool enableScreenSaverMacOs () {
|
||||
if (ScreenSaverEnabled)
|
||||
return true;
|
||||
|
||||
ScreenSaverEnabled = IOPMAssertionRelease(AssertionID) == kIOReturnSuccess;
|
||||
return ScreenSaverEnabled;
|
||||
}
|
||||
|
||||
bool disableScreenSaverMacOs () {
|
||||
if (!ScreenSaverEnabled)
|
||||
return true;
|
||||
|
||||
ScreenSaverEnabled = IOPMAssertionCreateWithName(
|
||||
kIOPMAssertionTypeNoDisplaySleep,
|
||||
kIOPMAssertionLevelOn,
|
||||
CFSTR("Inhibit asked for video stream"),
|
||||
&AssertionID
|
||||
) != kIOReturnSuccess;
|
||||
return !ScreenSaverEnabled;
|
||||
}
|
||||
56
Linphone/tool/native/screen-saver/ScreenSaverXdg.cpp
Normal file
56
Linphone/tool/native/screen-saver/ScreenSaverXdg.cpp
Normal file
|
|
@ -0,0 +1,56 @@
|
|||
/*
|
||||
* Copyright (c) 2010-2020 Belledonne Communications SARL.
|
||||
*
|
||||
* This file is part of linphone-desktop
|
||||
* (see https://www.linphone.org).
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <QProcess>
|
||||
|
||||
#include "ScreenSaverXdg.hpp"
|
||||
|
||||
// =============================================================================
|
||||
|
||||
namespace {
|
||||
constexpr char Program[] = "xdg-screensaver";
|
||||
const QStringList Arguments{"reset"};
|
||||
|
||||
constexpr int Interval = 30000;
|
||||
}
|
||||
|
||||
ScreenSaverXdg::ScreenSaverXdg (QObject *parent) : QObject(parent) {
|
||||
mTimer.setInterval(Interval);
|
||||
QObject::connect(&mTimer, &QTimer::timeout, []() {
|
||||
// Legacy for systems without DBus screensaver.
|
||||
QProcess::startDetached(Program, Arguments);
|
||||
});
|
||||
}
|
||||
|
||||
bool ScreenSaverXdg::getScreenSaverStatus () const {
|
||||
return !mTimer.isActive();
|
||||
}
|
||||
|
||||
void ScreenSaverXdg::setScreenSaverStatus (bool status) {
|
||||
if (status == !mTimer.isActive())
|
||||
return;
|
||||
|
||||
if (status)
|
||||
mTimer.stop();
|
||||
else
|
||||
mTimer.start();
|
||||
|
||||
emit screenSaverStatusChanged(status);
|
||||
}
|
||||
44
Linphone/tool/native/screen-saver/ScreenSaverXdg.hpp
Normal file
44
Linphone/tool/native/screen-saver/ScreenSaverXdg.hpp
Normal file
|
|
@ -0,0 +1,44 @@
|
|||
/*
|
||||
* Copyright (c) 2010-2020 Belledonne Communications SARL.
|
||||
*
|
||||
* This file is part of linphone-desktop
|
||||
* (see https://www.linphone.org).
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef SCREEN_SAVER_XDG_H_
|
||||
#define SCREEN_SAVER_XDG_H_
|
||||
|
||||
#include <QTimer>
|
||||
|
||||
// =============================================================================
|
||||
|
||||
class ScreenSaverXdg : public QObject {
|
||||
Q_OBJECT;
|
||||
|
||||
public:
|
||||
ScreenSaverXdg (QObject *parent = Q_NULLPTR);
|
||||
|
||||
bool getScreenSaverStatus () const;
|
||||
void setScreenSaverStatus (bool status);
|
||||
|
||||
signals:
|
||||
void screenSaverStatusChanged (bool status);
|
||||
|
||||
private:
|
||||
QTimer mTimer;
|
||||
};
|
||||
|
||||
#endif // SCREEN_SAVER_XDG_H_
|
||||
20
Linphone/tool/native/state-process/StateProcessMacOs.mm
Normal file
20
Linphone/tool/native/state-process/StateProcessMacOs.mm
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
#include "../DesktopToolsMacOs.hpp"
|
||||
#import <Foundation/NSString.h>
|
||||
#import <Foundation/NSProcessInfo.h>
|
||||
|
||||
// Store a unique global instance of Activity to avoid App Nap of MacOs
|
||||
static id g_backgroundActivity =0;
|
||||
|
||||
void DesktopTools::applicationStateChanged(Qt::ApplicationState p_currentState)
|
||||
{
|
||||
if( p_currentState == Qt::ApplicationActive && g_backgroundActivity != 0 )
|
||||
{// Entering Foreground
|
||||
[[NSProcessInfo processInfo] endActivity:g_backgroundActivity];
|
||||
[g_backgroundActivity release];
|
||||
g_backgroundActivity = 0;
|
||||
}else if( g_backgroundActivity == 0 )
|
||||
{// Doesn't begin activity if it is already started
|
||||
g_backgroundActivity = [[NSProcessInfo processInfo] beginActivityWithOptions:NSActivityUserInitiatedAllowingIdleSystemSleep reason:@"Linphone : Continue to receive requests while in Background"];
|
||||
[g_backgroundActivity retain];
|
||||
}
|
||||
}
|
||||
118
Linphone/tool/providers/ScreenProvider.cpp
Normal file
118
Linphone/tool/providers/ScreenProvider.cpp
Normal file
|
|
@ -0,0 +1,118 @@
|
|||
/*
|
||||
* Copyright (c) 2010-2024 Belledonne Communications SARL.
|
||||
*
|
||||
* This file is part of linphone-desktop
|
||||
* (see https://www.linphone.org).
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "ScreenProvider.hpp"
|
||||
#include "tool/native/DesktopTools.hpp"
|
||||
#include <QGuiApplication>
|
||||
#include <QScreen>
|
||||
#include <QThread>
|
||||
#include <QWindow>
|
||||
|
||||
// =============================================================================
|
||||
|
||||
const QString ScreenProvider::ProviderId = "screen";
|
||||
|
||||
ScreenProvider::ScreenProvider()
|
||||
: QQuickImageProvider(QQmlImageProviderBase::Image, QQmlImageProviderBase::ForceAsynchronousImageLoading) {
|
||||
}
|
||||
|
||||
QImage ScreenProvider::requestImage(const QString &id, QSize *size, const QSize &requestedSize) {
|
||||
if (!requestedSize.isNull()) {
|
||||
int index = id.toInt();
|
||||
auto screens = QGuiApplication::screens();
|
||||
if (index >= 0 && index < screens.size()) {
|
||||
auto screen = screens[index];
|
||||
auto geometry = screen->geometry();
|
||||
#if __APPLE__
|
||||
auto image = screen->grabWindow(0, geometry.x(), geometry.y(), geometry.width(), geometry.height());
|
||||
#else
|
||||
auto image = screen->grabWindow(0, 0, 0, geometry.width(), geometry.height());
|
||||
#endif
|
||||
if (requestedSize.isValid() && requestedSize.height() > 0 && requestedSize.width() > 0 && !image.isNull()) {
|
||||
image = image.scaled(requestedSize, Qt::KeepAspectRatio,
|
||||
Qt::FastTransformation); // Qt::SmoothTransformation);
|
||||
}
|
||||
*size = image.size();
|
||||
qDebug() << "Screen(" << index << ") = " << screen->geometry() << " VG:" << screen->virtualGeometry()
|
||||
<< " / " << screen->size() << " VS:" << screen->virtualSize()
|
||||
<< " DeviceRatio: " << screen->devicePixelRatio() << ", " << *size << " / " << requestedSize;
|
||||
return image.toImage();
|
||||
}
|
||||
}
|
||||
QImage image(10, 10, QImage::Format_Indexed8);
|
||||
image.fill(Qt::gray);
|
||||
*size = image.size();
|
||||
return image;
|
||||
}
|
||||
|
||||
// =============================================================================
|
||||
|
||||
const QString WindowProvider::ProviderId = "window";
|
||||
|
||||
WindowProvider::WindowProvider()
|
||||
: QQuickImageProvider(QQmlImageProviderBase::Image, QQmlImageProviderBase::ForceAsynchronousImageLoading) {
|
||||
}
|
||||
|
||||
// Note: Using WId don't work with Window/Mac (For Mac, NSView cannot be used while we are working with CGWindowID)
|
||||
// Also WId only work for the current application.
|
||||
QImage WindowProvider::requestImage(const QString &id, QSize *size, const QSize &requestedSize) {
|
||||
if (!requestedSize.isNull()) {
|
||||
auto winId = id.toLongLong();
|
||||
if (winId > 0) {
|
||||
auto image = DesktopTools::takeScreenshot((void *)winId);
|
||||
if (requestedSize.isValid() && !image.isNull())
|
||||
image = image.scaled(requestedSize, Qt::KeepAspectRatio,
|
||||
Qt::FastTransformation); // Qt::SmoothTransformation);
|
||||
*size = image.size();
|
||||
return image;
|
||||
}
|
||||
}
|
||||
QImage image(10, 10, QImage::Format_Indexed8);
|
||||
image.fill(Qt::gray);
|
||||
*size = image.size();
|
||||
return image;
|
||||
}
|
||||
|
||||
// =============================================================================
|
||||
|
||||
const QString WindowIconProvider::ProviderId = "window_icon";
|
||||
|
||||
WindowIconProvider::WindowIconProvider()
|
||||
: QQuickImageProvider(QQmlImageProviderBase::Image, QQmlImageProviderBase::ForceAsynchronousImageLoading) {
|
||||
}
|
||||
|
||||
// Note: Using WId don't work with Window/Mac (For Mac, NSView cannot be used while we are working with CGWindowID)
|
||||
// Also WId only work for the current application.
|
||||
QImage WindowIconProvider::requestImage(const QString &id, QSize *size, const QSize &requestedSize) {
|
||||
if (!requestedSize.isNull()) {
|
||||
auto winId = id.toLongLong();
|
||||
if (winId > 0) {
|
||||
auto image = DesktopTools::getWindowIcon((void *)winId);
|
||||
if (requestedSize.isValid() && !image.isNull())
|
||||
image = image.scaled(requestedSize, Qt::KeepAspectRatio, Qt::SmoothTransformation);
|
||||
*size = image.size();
|
||||
return image;
|
||||
}
|
||||
}
|
||||
QImage image(10, 10, QImage::Format_Indexed8);
|
||||
image.fill(Qt::gray);
|
||||
*size = image.size();
|
||||
return image;
|
||||
}
|
||||
55
Linphone/tool/providers/ScreenProvider.hpp
Normal file
55
Linphone/tool/providers/ScreenProvider.hpp
Normal file
|
|
@ -0,0 +1,55 @@
|
|||
/*
|
||||
* Copyright (c) 2010-2024 Belledonne Communications SARL.
|
||||
*
|
||||
* This file is part of linphone-desktop
|
||||
* (see https://www.linphone.org).
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef SCREEN_PROVIDER_H_
|
||||
#define SCREEN_PROVIDER_H_
|
||||
|
||||
#include <QQuickImageProvider>
|
||||
|
||||
// =============================================================================
|
||||
|
||||
class ScreenProvider : public QQuickImageProvider {
|
||||
public:
|
||||
ScreenProvider();
|
||||
|
||||
QImage requestImage(const QString &id, QSize *size, const QSize &requestedSize) override;
|
||||
|
||||
static const QString ProviderId;
|
||||
};
|
||||
|
||||
class WindowProvider : public QQuickImageProvider {
|
||||
public:
|
||||
WindowProvider();
|
||||
|
||||
QImage requestImage(const QString &id, QSize *size, const QSize &requestedSize) override;
|
||||
|
||||
static const QString ProviderId;
|
||||
};
|
||||
|
||||
class WindowIconProvider : public QQuickImageProvider {
|
||||
public:
|
||||
WindowIconProvider();
|
||||
|
||||
QImage requestImage(const QString &id, QSize *size, const QSize &requestedSize) override;
|
||||
|
||||
static const QString ProviderId;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
@ -719,11 +719,11 @@ AppWindow {
|
|||
Control.StackView.onActivated: rightPanel.headerTitleText = qsTr("Paramètres")
|
||||
InCallSettingsPanel {
|
||||
anchors.fill: parent
|
||||
call: mainWindow.call
|
||||
anchors.topMargin: 16 * DefaultStyle.dp
|
||||
anchors.bottomMargin: 16 * DefaultStyle.dp
|
||||
anchors.leftMargin: 17 * DefaultStyle.dp
|
||||
anchors.rightMargin: 17 * DefaultStyle.dp
|
||||
call: mainWindow.call
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -732,6 +732,7 @@ AppWindow {
|
|||
Item {
|
||||
Control.StackView.onActivated: rightPanel.headerTitleText = qsTr("Partage de votre écran")
|
||||
ScreencastPanel {
|
||||
anchors.fill: parent
|
||||
anchors.topMargin: 16 * DefaultStyle.dp
|
||||
anchors.bottomMargin: 16 * DefaultStyle.dp
|
||||
anchors.leftMargin: 17 * DefaultStyle.dp
|
||||
|
|
|
|||
|
|
@ -6,10 +6,16 @@ import Linphone
|
|||
import UtilsCpp 1.0
|
||||
|
||||
ColumnLayout {
|
||||
id: mainItem
|
||||
property CallGui call
|
||||
property ConferenceGui conference: call.core.conference
|
||||
property var desc: call.core.videoSourceDescriptor
|
||||
property bool isLocalScreenSharing : conference?.core.isLocalScreenSharing || false
|
||||
property bool screenSharingAvailable: !!conference && (!conference.core.isScreenSharingEnabled || isLocalScreenSharing)
|
||||
|
||||
spacing: 12 * DefaultStyle.dp
|
||||
|
||||
onIsLocalScreenSharingChanged: {if(isLocalScreenSharing) mainItem.call.core.videoSourceDescriptor = mainItem.desc }
|
||||
Text {
|
||||
Layout.fillWidth: true
|
||||
text: qsTr("Veuillez choisir l’écran ou la fenêtre que vous souihaitez partager au autres participants")
|
||||
|
|
@ -28,12 +34,16 @@ ColumnLayout {
|
|||
property var screenSource
|
||||
property int screenIndex
|
||||
property bool selected: false
|
||||
property bool displayScreen: true
|
||||
property int horizontalMargin: 0
|
||||
leftPadding: 18 * DefaultStyle.dp
|
||||
rightPadding: 18 * DefaultStyle.dp
|
||||
topPadding: 13 * DefaultStyle.dp
|
||||
bottomPadding: 13 * DefaultStyle.dp
|
||||
background: Rectangle {
|
||||
anchors.fill: parent
|
||||
anchors.leftMargin: screenPreview.horizontalMargin
|
||||
anchors.rightMargin: screenPreview.horizontalMargin
|
||||
color: screenPreview.selected ? DefaultStyle.main2_100 : DefaultStyle.grey_0
|
||||
border.width: 2 * DefaultStyle.dp
|
||||
border.color: screenPreview.selected ? DefaultStyle.main2_400 : DefaultStyle.main2_200
|
||||
|
|
@ -47,42 +57,105 @@ ColumnLayout {
|
|||
}
|
||||
contentItem: ColumnLayout {
|
||||
spacing: 0
|
||||
// TODO : replace this by screen preview
|
||||
Rectangle {
|
||||
Item{
|
||||
Layout.fillWidth: true
|
||||
Layout.preferredHeight: 170 * DefaultStyle.dp
|
||||
Layout.fillHeight: true
|
||||
Image {
|
||||
anchors.centerIn: parent
|
||||
//Layout.preferredHeight: 170 * DefaultStyle.dp
|
||||
source: $modelData?.windowId ? "image://window/"+ $modelData.windowId : "image://screen/"+ $modelData.screenIndex
|
||||
sourceSize.width: parent.width
|
||||
sourceSize.height: parent.height
|
||||
cache: false
|
||||
}
|
||||
}
|
||||
Text {
|
||||
text: qsTr("Ecran %1").arg(screenIndex)
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
font.pixelSize: 14 * DefaultStyle.dp
|
||||
Layout.fillWidth: true
|
||||
RowLayout{
|
||||
Layout.topMargin: 6 * DefaultStyle.dp
|
||||
spacing: 5 * DefaultStyle.dp
|
||||
Image{
|
||||
Layout.preferredHeight: 15 * DefaultStyle.dp
|
||||
Layout.preferredWidth: 15 * DefaultStyle.dp
|
||||
visible: !!$modelData?.windowId
|
||||
source: visible ? "image://window_icon/"+ $modelData.windowId : ''
|
||||
sourceSize.width: width
|
||||
sourceSize.height: height
|
||||
cache: false
|
||||
}
|
||||
Text {
|
||||
Layout.fillWidth: true
|
||||
text: !!$modelData?.windowId ? $modelData.name : qsTr("Ecran %1").arg(screenIndex+1)
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
font.pixelSize: (displayScreen ? 14 : 10)* DefaultStyle.dp
|
||||
elide: Text.ElideRight
|
||||
maximumLineCount: 1
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
StackLayout {
|
||||
currentIndex: bar.currentIndex
|
||||
ColumnLayout {
|
||||
ListView{
|
||||
id: screensLayout
|
||||
spacing: 0
|
||||
property int selectedIndex
|
||||
Repeater {
|
||||
model: 2 //TODO : screensModel
|
||||
ScreenPreviewLayout {
|
||||
Layout.fillWidth: true
|
||||
screenIndex: index
|
||||
onClicked: screensLayout.selectedIndex = index
|
||||
selected: screensLayout.selectedIndex === index
|
||||
}
|
||||
spacing: 16 * DefaultStyle.dp
|
||||
clip: true
|
||||
//property int selectedIndex
|
||||
model: ScreenProxy{
|
||||
id: screensList
|
||||
mode: ScreenList.SCREENS
|
||||
}
|
||||
onVisibleChanged: if(visible) screensList.update()
|
||||
delegate: ScreenPreviewLayout {
|
||||
horizontalMargin: (28 - 20 ) * DefaultStyle.dp // 20 coming from CallsWindow panel
|
||||
width: screensLayout.width
|
||||
height: 219 * DefaultStyle.dp
|
||||
screenIndex: index
|
||||
onClicked: {//screensLayout.selectedIndex = index
|
||||
mainItem.desc.core.screenSharingIndex = index
|
||||
if( mainItem.conference.core.isLocalScreenSharing)
|
||||
mainItem.call.core.videoSourceDescriptor = mainItem.desc
|
||||
}
|
||||
selected: //screensLayout.selectedIndex === index
|
||||
mainItem.desc.core.screenSharingIndex === index
|
||||
}
|
||||
}
|
||||
Text {
|
||||
Layout.topMargin: 30 * DefaultStyle.dp
|
||||
font.pixelSize: 20 * DefaultStyle.dp
|
||||
text: qsTr("Cliquez sur la fenêtre à partager")
|
||||
|
||||
GridView{
|
||||
id: windowsLayout
|
||||
//property int selectedIndex
|
||||
model: ScreenProxy{
|
||||
id: windowsList
|
||||
mode: ScreenList.WINDOWS
|
||||
}
|
||||
onVisibleChanged: if(visible) windowsList.update()
|
||||
cellWidth: width / 2
|
||||
cellHeight: (112 + 15) * DefaultStyle.dp
|
||||
clip: true
|
||||
delegate: Item{
|
||||
width: windowsLayout.cellWidth
|
||||
height: windowsLayout.cellHeight
|
||||
ScreenPreviewLayout {
|
||||
anchors.fill: parent
|
||||
anchors.margins: 7 * DefaultStyle.dp
|
||||
displayScreen: false
|
||||
screenIndex: index
|
||||
onClicked: {
|
||||
mainItem.desc.core.windowId = $modelData.windowId
|
||||
if( mainItem.conference.core.isLocalScreenSharing)
|
||||
mainItem.call.core.videoSourceDescriptor = mainItem.desc
|
||||
}
|
||||
selected: mainItem.desc.core.windowId == $modelData.windowId
|
||||
|
||||
//onClicked: screensLayout.selectedIndex = index
|
||||
//selected: screensLayout.selectedIndex === index
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Button {
|
||||
text: qsTr("Partager")
|
||||
visible: mainItem.screenSharingAvailable
|
||||
text: mainItem.conference && mainItem.conference.core.isLocalScreenSharing
|
||||
? qsTr("Stop")
|
||||
: qsTr("Partager")
|
||||
onClicked: mainItem.conference.core.lToggleScreenSharing()
|
||||
}
|
||||
}
|
||||
|
|
@ -46,8 +46,7 @@ Control.TabBar {
|
|||
Control.TabButton {
|
||||
required property string modelData
|
||||
required property int index
|
||||
// width: Math.min(txtMeter.advanceWidth, Math.max(50, mainItem.width - (x - mainItem.x)))
|
||||
width: txtMeter.advanceWidth
|
||||
width: implicitWidth
|
||||
hoverEnabled: true
|
||||
ToolTip {
|
||||
visible: tabText.truncated && hovered
|
||||
|
|
@ -70,22 +69,15 @@ Control.TabBar {
|
|||
|
||||
contentItem: Text {
|
||||
id: tabText
|
||||
anchors.fill: parent
|
||||
width: Math.min(implicitWidth, mainItem.width / mainItem.model.length)
|
||||
font.weight: mainItem.textWeight
|
||||
color: mainItem.currentIndex === index ? DefaultStyle.main2_600 : DefaultStyle.main2_400
|
||||
font.family: DefaultStyle.defaultFont
|
||||
font.pixelSize: mainItem.pixelSize
|
||||
elide: Text.ElideRight
|
||||
maximumLineCount: 1
|
||||
text: txtMeter.elidedText
|
||||
// width: Math.min(txtMeter.advanceWidth, Math.max(50, mainItem.width - (x - mainItem.x)))
|
||||
bottomPadding: 5 * DefaultStyle.dp
|
||||
}
|
||||
|
||||
TextMetrics {
|
||||
id: txtMeter
|
||||
font: tabText.font
|
||||
text: modelData
|
||||
bottomPadding: 5 * DefaultStyle.dp
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -109,8 +109,8 @@ Item{
|
|||
id: activeSpeakerSticker
|
||||
previewEnabled: false
|
||||
call: mainItem.call
|
||||
width: parent.width
|
||||
height: parent.height
|
||||
width: mainStackView.width
|
||||
height: mainStackView.height
|
||||
participantDevice: mainItem.conference && mainItem.conference.core.activeSpeaker
|
||||
property var address: participantDevice && participantDevice.core.address
|
||||
videoEnabled: (participantDevice && participantDevice.core.videoEnabled) || (!participantDevice && call && call.core.remoteVideoEnabled)
|
||||
|
|
@ -125,18 +125,19 @@ Item{
|
|||
}
|
||||
}
|
||||
ListView{
|
||||
id: sideStickers
|
||||
Layout.fillHeight: true
|
||||
Layout.preferredWidth: 300 * DefaultStyle.dp
|
||||
Layout.rightMargin: 10 * DefaultStyle.dp
|
||||
Layout.bottomMargin: 10 * DefaultStyle.dp
|
||||
visible: allDevices.count > 2
|
||||
visible: allDevices.count > 2 || !!mainItem.conference?.core.isScreenSharingEnabled
|
||||
//spacing: 15 * DefaultStyle.dp // bugged? First item has twice margins
|
||||
model: allDevices
|
||||
snapMode: ListView.SnapOneItem
|
||||
clip: true
|
||||
delegate: Item{ // Spacing workaround
|
||||
visible: $modelData && mainItem.callState != LinphoneEnums.CallState.End && mainItem.callState != LinphoneEnums.CallState.Released
|
||||
&& $modelData.core.address != activeSpeakerAddress || false
|
||||
&& ($modelData.core.address != activeSpeakerAddress || mainItem.conference?.core.isScreenSharingEnabled) || false
|
||||
height: visible ? (180 + 15) * DefaultStyle.dp : 0
|
||||
width: 300 * DefaultStyle.dp
|
||||
Sticker {
|
||||
|
|
@ -157,7 +158,7 @@ Item{
|
|||
id: preview
|
||||
qmlName: 'P'
|
||||
previewEnabled: true
|
||||
visible: mainItem.call && allDevices.count <= 2
|
||||
visible: !sideStickers.visible
|
||||
onVisibleChanged: console.log(visible + " : " +allDevices.count)
|
||||
height: 180 * DefaultStyle.dp
|
||||
width: 300 * DefaultStyle.dp
|
||||
|
|
|
|||
|
|
@ -113,6 +113,9 @@ foreach(_FILE IN LISTS ${_BINARIES})
|
|||
endif()
|
||||
endif()
|
||||
endforeach()
|
||||
execute_process(COMMAND codesign --force --deep --sign - "${MAIN_INSTALL_DIR}/${LINPHONEAPP_EXENAME}.app")#If not code signed, app can crash because of APPLE on "Code Signature Invalid".
|
||||
|
||||
|
||||
#[[
|
||||
if(NOT ENABLE_FAT_BINARY)
|
||||
# Generate XCFrameworks
|
||||
|
|
|
|||
|
|
@ -20,13 +20,22 @@
|
|||
#
|
||||
############################################################################
|
||||
|
||||
set(LINPHONEAPP_MACOS_ARCHS "x86_64" CACHE STRING "MacOS architectures to build: comma-separated list of values in [arm64, x86_64]")
|
||||
option(ENABLE_FAT_BINARY "Enable fat binary generation using lipo." ON)
|
||||
|
||||
set(_MACOS_ARCHS ${LINPHONEAPP_MACOS_ARCHS})
|
||||
#linphone_sdk_convert_comma_separated_list_to_cmake_list("${LINPHONESDK_MACOS_ARCHS}" _MACOS_ARCHS)
|
||||
macro(linphone_app_convert_comma_separated_list_to_cmake_list INPUT OUTPUT)
|
||||
string(REPLACE " " "" ${OUTPUT} "${INPUT}")
|
||||
string(REPLACE "," ";" ${OUTPUT} "${${OUTPUT}}")
|
||||
endmacro()
|
||||
linphone_app_convert_comma_separated_list_to_cmake_list("${LINPHONEAPP_MACOS_ARCHS}" _MACOS_ARCHS)
|
||||
|
||||
|
||||
|
||||
#linphone_sdk_convert_comma_separated_list_to_cmake_list("${LINPHONESDK_MACOS_ARCHS}" _MACOS_ARCHS)
|
||||
|
||||
set(LINPHONEAPP_NAME "Linphone")
|
||||
set(LINPHONEAPP_EXENAME "Linphone60")
|
||||
set(LINPHONEAPP_PLATFORM "macos")
|
||||
set(SUB_TARGET app_macos)
|
||||
string(TOLOWER "${LINPHONEAPP_PLATFORM}" LINPHONEAPP_PLATFORM_LOWER)
|
||||
|
|
@ -40,15 +49,15 @@ set(_MACOS_INSTALL_DIR "${APPLICATION_OUTPUT_DIR}/${_MACOS_INSTALL_RELATIVE_DIR}
|
|||
|
||||
#linphone_sdk_get_inherited_cmake_args(_CMAKE_CONFIGURE_ARGS _CMAKE_BUILD_ARGS)
|
||||
#linphone_sdk_get_enable_cmake_args(_MACOS_CMAKE_ARGS)
|
||||
set(_MACOS_CMAKE_ARGS -DCMAKE_OSX_DEPLOYMENT_TARGET=${CMAKE_OSX_DEPLOYMENT_TARGET})
|
||||
set(_MACOS_CMAKE_ARGS "-DCMAKE_OSX_DEPLOYMENT_TARGET=${CMAKE_OSX_DEPLOYMENT_TARGET}")
|
||||
set(_MACOS_TARGETS)
|
||||
foreach(_MACOS_ARCH IN LISTS _MACOS_ARCHS)
|
||||
set(_TARGET_NAME ${SUB_TARGET}-${_MACOS_ARCH}) # app_macos-x86_64
|
||||
set(_MACOS_ARCH_BINARY_DIR "${PROJECT_BINARY_DIR}/${_TARGET_NAME}") # build/app_macos-x86_64
|
||||
set(_MACOS_ARCH_INSTALL_DIR "${_MACOS_INSTALL_DIR}-${_MACOS_ARCH}") # build/OUTPUT/Linphone/macos-x86_64
|
||||
set(_MACOS_ARCH_INSTALL_DIR "${_MACOS_INSTALL_DIR}-${_MACOS_ARCH}") # build/OUTPUT/linphone-app/macos-x86_64
|
||||
|
||||
add_custom_target(${_TARGET_NAME} ALL
|
||||
COMMAND ${CMAKE_COMMAND} -B ${_MACOS_ARCH_BINARY_DIR} -DMONO_ARCH=${_MACOS_ARCH} ${USER_ARGS} ${OPTION_LIST} ${_MACOS_CMAKE_ARGS} -DLINPHONEAPP_INSTALL_PREFIX=${_MACOS_ARCH_INSTALL_DIR} -DCMAKE_OSX_DEPLOYMENT_TARGET=${CMAKE_OSX_DEPLOYMENT_TARGET} -DCMAKE_TOOLCHAIN_FILE=${PROJECT_SOURCE_DIR}/cmake/toolchains/toolchain-mac-x86_64.cmake -DLINPHONEAPP_BUILD_TYPE="Normal"
|
||||
COMMAND ${CMAKE_COMMAND} -B ${_MACOS_ARCH_BINARY_DIR} -DMONO_ARCH=${_MACOS_ARCH} ${USER_ARGS} ${OPTION_LIST} ${_MACOS_CMAKE_ARGS} -DLINPHONEAPP_INSTALL_PREFIX=${_MACOS_ARCH_INSTALL_DIR} -DCMAKE_TOOLCHAIN_FILE=${PROJECT_SOURCE_DIR}/cmake/toolchains/toolchain-mac-${_MACOS_ARCH}.cmake -DLINPHONEAPP_BUILD_TYPE="Normal"
|
||||
COMMAND ${CMAKE_COMMAND} --build ${_MACOS_ARCH_BINARY_DIR} --target install ${_CMAKE_BUILD_ARGS}
|
||||
WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}
|
||||
COMMENT "Building Linphone APP for MacOS ${_MACOS_ARCH}"
|
||||
|
|
@ -68,6 +77,7 @@ add_custom_target(gen-apps ALL
|
|||
"-DLINPHONEAPP_BUILD_DIR=${CMAKE_BINARY_DIR}"
|
||||
"-DLINPHONEAPP_MACOS_ARCHS=${LINPHONEAPP_MACOS_ARCHS}"
|
||||
"-DLINPHONEAPP_NAME=${_MACOS_INSTALL_RELATIVE_DIR}"
|
||||
"-DLINPHONEAPP_EXENAME=${LINPHONEAPP_EXENAME}"
|
||||
"-DLINPHONEAPP_PLATFORM=${LINPHONEAPP_PLATFORM_LOWER}"
|
||||
"-DCMAKE_INSTALL_PREFIX=${CMAKE_INSTALL_PREFIX}"
|
||||
"-DCMAKE_INSTALL_LIBDIR=${CMAKE_INSTALL_LIBDIR}"
|
||||
|
|
|
|||
|
|
@ -52,6 +52,8 @@ if(APPLE)
|
|||
if (DO_SIGNING)
|
||||
execute_process(COMMAND bash "@CMAKE_SOURCE_DIR@/cmake/install/sign_package.sh" codesign "@LINPHONE_BUILDER_SIGNING_IDENTITY@" "${CPACK_TEMPORARY_INSTALL_DIRECTORY}/ALL_IN_ONE")
|
||||
#execute_process(COMMAND codesign --entitlements" "@CMAKE_CURRENT_BINARY_DIR@/../../entitlements.xml" "--force" "--deep" "--timestamp" "--options" "runtime,library" "--verbose" "-s" "@LINPHONE_BUILDER_SIGNING_IDENTITY@" "@APPLICATION_OUTPUT_DIR@/@APPLICATION_NAME@.app")
|
||||
else()
|
||||
execute_process(COMMAND codesign --force --deep --sign "${CPACK_TEMPORARY_INSTALL_DIRECTORY}/ALL_IN_ONE/@APPLICATION_NAME@.app" )#If not code signed, app can crash because of APPLE on "Code Signature Invalid" (spotted for ARM64)
|
||||
endif()
|
||||
elseif(WIN32)
|
||||
message(STATUS "Execute : @DEPLOYQT_PROGRAM@ ${CPACK_TEMPORARY_INSTALL_DIRECTORY}/@CMAKE_INSTALL_BINDIR@/@EXECUTABLE_NAME@.exe --qmldir=@LINPHONE_QML_DIR@ --verbose=2 --no-compiler-runtime")
|
||||
|
|
|
|||
|
|
@ -96,10 +96,10 @@ if(APPLE)
|
|||
if (NOT DEPLOYQT_PROGRAM)
|
||||
message(FATAL_ERROR "Could not find the macdeployqt program. Make sure it is in the PATH.")
|
||||
endif()
|
||||
#Packaging is done by CPack in the cleanCpack.cmake file. But on mac, we need Qt files in .app
|
||||
#Packaging is done by CPack in the cleanCPack.cmake file. But on mac, we need Qt files in .app
|
||||
if(NOT ENABLE_APP_PACKAGING)
|
||||
install(CODE "MESSAGE(\"MacDeploy install: execute_process(COMMAND ${DEPLOYQT_PROGRAM} ${APPLICATION_OUTPUT_DIR}/${APPLICATION_NAME}.app -qmldir=${LINPHONE_QML_DIR} -no-strip -verbose=2 -always-overwrite) \")")
|
||||
install(CODE "execute_process(COMMAND ${DEPLOYQT_PROGRAM} ${APPLICATION_OUTPUT_DIR}/${APPLICATION_NAME}.app -qmldir=${LINPHONE_QML_DIR} -no-strip -verbose=2 -always-overwrite)")
|
||||
install(CODE "MESSAGE(\"MacDeploy install: execute_process(COMMAND ${DEPLOYQT_PROGRAM} ${APPLICATION_OUTPUT_DIR}/${APPLICATION_NAME}.app -qmldir=${LINPHONE_QML_DIR} -no-strip -verbose=0 -always-overwrite) \")")
|
||||
install(CODE "execute_process(COMMAND ${DEPLOYQT_PROGRAM} ${APPLICATION_OUTPUT_DIR}/${APPLICATION_NAME}.app -qmldir=${LINPHONE_QML_DIR} -no-strip -verbose=0 -always-overwrite)")
|
||||
endif()
|
||||
elseif(WIN32)
|
||||
set(BIN_ARCH "win32")
|
||||
|
|
@ -175,7 +175,7 @@ if(${ENABLE_APP_PACKAGING})
|
|||
set(CPACK_PACKAGE_ICON "${CMAKE_SOURCE_DIR}/Linphone/data/icon.ico")
|
||||
set(PERFORM_SIGNING 0)
|
||||
|
||||
configure_file("${CMAKE_SOURCE_DIR}/cmake/install/cleanCpack.cmake.in" "${CMAKE_BINARY_DIR}/cmake/install/cleanCpack.cmake" @ONLY)
|
||||
configure_file("${CMAKE_SOURCE_DIR}/cmake/install/cleanCPack.cmake.in" "${CMAKE_BINARY_DIR}/cmake/install/cleanCPack.cmake" @ONLY)
|
||||
set(CPACK_PRE_BUILD_SCRIPTS "${CMAKE_BINARY_DIR}/cmake/install/cleanCPack.cmake")
|
||||
|
||||
if(APPLE)
|
||||
|
|
|
|||
|
|
@ -51,6 +51,8 @@
|
|||
</array>
|
||||
</dict>
|
||||
</array>
|
||||
<key>LSApplicationCategoryType</key>
|
||||
<string>public.app-category.social-networking</string>
|
||||
<key>NSPrincipalClass</key>
|
||||
<string>NSApplication</string>
|
||||
<key>NSHighResolutionCapable</key>
|
||||
|
|
|
|||
|
|
@ -16,7 +16,7 @@
|
|||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
################################################################################
|
||||
message(FATAL_ERROR A)
|
||||
|
||||
set(CMAKE_SYSTEM_PROCESSOR "arm64")
|
||||
set(CMAKE_OSX_ARCHITECTURES "arm64")
|
||||
set(CLANG_TARGET "arm64-apple-macos")
|
||||
|
|
|
|||
2
external/linphone-sdk
vendored
2
external/linphone-sdk
vendored
|
|
@ -1 +1 @@
|
|||
Subproject commit 54bb7fb4d84141bb94042a09b157257df84d8be9
|
||||
Subproject commit ea3bb6f2284ce16383c3251b9b899dc9b06d0ead
|
||||
Loading…
Add table
Reference in a new issue