diff --git a/linphone-app/CMakeLists.txt b/linphone-app/CMakeLists.txt index 1934f5e2e..ce5c1aa8c 100644 --- a/linphone-app/CMakeLists.txt +++ b/linphone-app/CMakeLists.txt @@ -833,9 +833,12 @@ endif() target_link_libraries(${TARGET_NAME} ${APP_PLUGIN}) -if(WIN32 AND ENABLE_LDAP) - find_package(OpenLDAP REQUIRED) - target_link_libraries(${TARGET_NAME} wsock32 ws2_32 ${OPENLDAP_LIBRARIES}) +if(WIN32) + if(ENABLE_LDAP) + find_package(OpenLDAP REQUIRED) + target_link_libraries(${TARGET_NAME} wsock32 ws2_32 ${OPENLDAP_LIBRARIES}) + endif() + target_link_libraries(${TARGET_NAME} Dwmapi) endif() if(NOT WIN32) diff --git a/linphone-app/src/app/App.cpp b/linphone-app/src/app/App.cpp index cb7ff8ae8..d397c3788 100644 --- a/linphone-app/src/app/App.cpp +++ b/linphone-app/src/app/App.cpp @@ -495,6 +495,7 @@ void App::initContentApp () { mEngine->addImageProvider(QRCodeProvider::ProviderId, new QRCodeProvider()); mEngine->addImageProvider(ThumbnailProvider::ProviderId, new ThumbnailProvider()); mEngine->addImageProvider(ScreenProvider::ProviderId, new ScreenProvider()); + mEngine->addImageProvider(WindowProvider::ProviderId, new WindowProvider()); mEngine->rootContext()->setContextProperty("applicationName", APPLICATION_NAME); mEngine->rootContext()->setContextProperty("executableName", EXECUTABLE_NAME); diff --git a/linphone-app/src/app/providers/ScreenProvider.cpp b/linphone-app/src/app/providers/ScreenProvider.cpp index 77ce58763..d3ffc4ac5 100644 --- a/linphone-app/src/app/providers/ScreenProvider.cpp +++ b/linphone-app/src/app/providers/ScreenProvider.cpp @@ -21,6 +21,9 @@ #include "ScreenProvider.hpp" #include #include +#include +#include +#include "components/other/desktop-tools/DesktopTools.hpp" // ============================================================================= @@ -31,13 +34,73 @@ ScreenProvider::ScreenProvider () : QQuickImageProvider( QQmlImageProviderBase::ForceAsynchronousImageLoading ) {} -QImage ScreenProvider::requestImage (const QString &id, QSize *size, const QSize &) { - int index = id.toInt(); - auto screens = QGuiApplication::screens(); - if(index >= 0 && index < screens.size()){ - auto image = screens[index]->grabWindow(0); - *size = image.size(); - return image.toImage(); - }else - return QImage(); +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()).scaled(requestedSize, Qt::KeepAspectRatio,Qt::SmoothTransformation); + #else + auto image = screen->grabWindow(0, 0, 0,geometry.width(), geometry.height()).scaled(requestedSize, Qt::KeepAspectRatio,Qt::SmoothTransformation); + #endif + *size = image.size(); + qDebug() << "Screen(" << index << ") = " << screen->geometry() << " VG:" << screen->virtualGeometry() << " / " << screen->size() << " VS:" << screen->virtualSize() << " DeviceRatio: " << screen->devicePixelRatio(); + 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) +// Linux seems to be ok but we want to use the same code. +QImage WindowProvider::requestImage (const QString &id, QSize *size, const QSize &requestedSize) { + if(!requestedSize.isNull()) { + auto winId = id.toLongLong(); + if(winId > 0){ + QRect area = DesktopTools::getWindowGeometry(reinterpret_cast(winId)); + if(!area.isNull()) { + qDebug() << "Window (" << winId << ") = " << area; + auto screens = QGuiApplication::screens(); + for(auto screen : screens){ + auto geometry = screen->geometry(); + auto devicePixelRatio = screen->devicePixelRatio(); + // Warning: there are inconsistencies in geomtries from OS. + #if defined(__APPLE__) + devicePixelRatio = 1.0;// Doesn't apply device ratio. + // Change area to be absolute + area.setRect(area.x() + geometry.x(), area.y() + geometry.y(), area.width(), area.height()); + #endif + geometry.setWidth(geometry.width() * devicePixelRatio); + geometry.setHeight(geometry.height() * devicePixelRatio); + if( geometry.contains(area.center())){ + QThread::msleep(40);// Let OS some time to display properly the Window after a click. + qDebug() << "Grab (" << (area.x() - geometry.x())/devicePixelRatio<< ", " << (area.y() - geometry.y())/devicePixelRatio << ", " << area.width()/devicePixelRatio << ", " << area.height()/devicePixelRatio << ")"; + auto image = screen->grabWindow(0, (area.x() - geometry.x())/devicePixelRatio, (area.y() - geometry.y())/devicePixelRatio, area.width()/devicePixelRatio, area.height()/devicePixelRatio).scaled(requestedSize, Qt::KeepAspectRatio,Qt::SmoothTransformation); + *size = image.size(); + return image.toImage(); + } + } + + } + } + } + QImage image(10,10, QImage::Format_Indexed8); + image.fill(Qt::gray); + *size = image.size(); + return image; } diff --git a/linphone-app/src/app/providers/ScreenProvider.hpp b/linphone-app/src/app/providers/ScreenProvider.hpp index 47b58b3c1..e2e96bc54 100644 --- a/linphone-app/src/app/providers/ScreenProvider.hpp +++ b/linphone-app/src/app/providers/ScreenProvider.hpp @@ -34,4 +34,13 @@ public: 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; +}; + #endif diff --git a/linphone-app/src/components/other/desktop-tools/DesktopToolsLinux.cpp b/linphone-app/src/components/other/desktop-tools/DesktopToolsLinux.cpp index ada2658af..1ca9d8787 100644 --- a/linphone-app/src/components/other/desktop-tools/DesktopToolsLinux.cpp +++ b/linphone-app/src/components/other/desktop-tools/DesktopToolsLinux.cpp @@ -120,3 +120,17 @@ void DesktopTools::getWindowIdFromMouse(VideoSourceDescriptorModel *model) { uintptr_t DesktopTools::getDisplayIndex(void* screenSharing){ return *(uintptr_t*)(&screenSharing); } + +QRect DesktopTools::getWindowGeometry(void* 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); +} diff --git a/linphone-app/src/components/other/desktop-tools/DesktopToolsLinux.hpp b/linphone-app/src/components/other/desktop-tools/DesktopToolsLinux.hpp index fee309cc1..489783031 100644 --- a/linphone-app/src/components/other/desktop-tools/DesktopToolsLinux.hpp +++ b/linphone-app/src/components/other/desktop-tools/DesktopToolsLinux.hpp @@ -48,6 +48,7 @@ public: Q_INVOKABLE void getWindowIdFromMouse(VideoSourceDescriptorModel *model); static void *getDisplay(uintptr_t screenIndex){return reinterpret_cast(screenIndex);} static uintptr_t getDisplayIndex(void* screenSharing); + static QRect getWindowGeometry(void* screenSharing); signals: void screenSaverStatusChanged(bool status); diff --git a/linphone-app/src/components/other/desktop-tools/DesktopToolsMacOs.hpp b/linphone-app/src/components/other/desktop-tools/DesktopToolsMacOs.hpp index fc0b698cd..69785889a 100644 --- a/linphone-app/src/components/other/desktop-tools/DesktopToolsMacOs.hpp +++ b/linphone-app/src/components/other/desktop-tools/DesktopToolsMacOs.hpp @@ -43,6 +43,7 @@ public: static void *getDisplay(int screenIndex); static int getDisplayIndex(void *screenSharing); Q_INVOKABLE void getWindowIdFromMouse(VideoSourceDescriptorModel *model); + static QRect getWindowGeometry(void* screenSharing); signals: void screenSaverStatusChanged(bool status); diff --git a/linphone-app/src/components/other/desktop-tools/DesktopToolsMacOsNative.mm b/linphone-app/src/components/other/desktop-tools/DesktopToolsMacOsNative.mm index 70e65fb3a..84bdb7069 100644 --- a/linphone-app/src/components/other/desktop-tools/DesktopToolsMacOsNative.mm +++ b/linphone-app/src/components/other/desktop-tools/DesktopToolsMacOsNative.mm @@ -2,6 +2,7 @@ #import #import #include +#include #include #include "components/videoSource/VideoSourceDescriptorModel.hpp" @@ -69,3 +70,25 @@ void DesktopTools::getWindowIdFromMouse(VideoSourceDescriptorModel *model) { return nil; }]; } + +QRect DesktopTools::getWindowGeometry(void* screenSharing) { + QRect result; + 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; + CFRelease(descriptions); + return result; +} diff --git a/linphone-app/src/components/other/desktop-tools/DesktopToolsWindows.cpp b/linphone-app/src/components/other/desktop-tools/DesktopToolsWindows.cpp index bfec21f9e..111c30ac3 100644 --- a/linphone-app/src/components/other/desktop-tools/DesktopToolsWindows.cpp +++ b/linphone-app/src/components/other/desktop-tools/DesktopToolsWindows.cpp @@ -26,6 +26,7 @@ #include #include +#include // ============================================================================= DesktopTools::DesktopTools(QObject *parent) : QObject(parent) { @@ -79,3 +80,14 @@ void DesktopTools::getWindowIdFromMouse(VideoSourceDescriptorModel *model) { uintptr_t DesktopTools::getDisplayIndex(void* screenSharing) { return *(uintptr_t*)(&screenSharing); } + +QRect DesktopTools::getWindowGeometry(void* screenSharing) { + QRect result; + 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; + return result; +} diff --git a/linphone-app/src/components/other/desktop-tools/DesktopToolsWindows.hpp b/linphone-app/src/components/other/desktop-tools/DesktopToolsWindows.hpp index 92c8352d4..3d6956ec7 100644 --- a/linphone-app/src/components/other/desktop-tools/DesktopToolsWindows.hpp +++ b/linphone-app/src/components/other/desktop-tools/DesktopToolsWindows.hpp @@ -49,6 +49,7 @@ public: return reinterpret_cast(screenIndex); } static uintptr_t getDisplayIndex(void *screenSharing); + static QRect getWindowGeometry(void* screenSharing); HWND mWindowId = 0; // Window VideoSourceDescriptorModel *mVideoSourceDescriptorModel = nullptr; diff --git a/linphone-app/src/components/videoSource/VideoSourceDescriptorModel.cpp b/linphone-app/src/components/videoSource/VideoSourceDescriptorModel.cpp index f312483fe..155f1d572 100644 --- a/linphone-app/src/components/videoSource/VideoSourceDescriptorModel.cpp +++ b/linphone-app/src/components/videoSource/VideoSourceDescriptorModel.cpp @@ -52,6 +52,14 @@ void * VideoSourceDescriptorModel::getScreenSharing() const{ return mDesc->getScreenSharing(); } +quint64 VideoSourceDescriptorModel::getWindowId() const{ + if(!mDesc) return 0; + else{ + void * temp = mDesc->getScreenSharing(); + return *(quint64*)&temp; + } +} + bool VideoSourceDescriptorModel::isScreenSharing() const{ return mDesc && mDesc->getType() == linphone::VideoSourceType::ScreenSharing; } diff --git a/linphone-app/src/components/videoSource/VideoSourceDescriptorModel.hpp b/linphone-app/src/components/videoSource/VideoSourceDescriptorModel.hpp index 276f969f9..113d01cee 100644 --- a/linphone-app/src/components/videoSource/VideoSourceDescriptorModel.hpp +++ b/linphone-app/src/components/videoSource/VideoSourceDescriptorModel.hpp @@ -36,12 +36,14 @@ class VideoSourceDescriptorModel : public QObject{ Q_PROPERTY(bool isScreenSharing READ isScreenSharing NOTIFY videoDescriptorChanged) Q_PROPERTY(LinphoneEnums::VideoSourceScreenSharingType screenSharingType READ getVideoSourceType NOTIFY videoDescriptorChanged) Q_PROPERTY(int screenSharingIndex READ getScreenSharingIndex WRITE setScreenSharingDisplay NOTIFY videoDescriptorChanged) + Q_PROPERTY(quint64 windowId READ getWindowId NOTIFY videoDescriptorChanged) public: VideoSourceDescriptorModel(); VideoSourceDescriptorModel(std::shared_ptr desc); void setScreenSharingDisplay(int index); void setScreenSharingWindow(void *window); // Get data from DesktopTools. void *getScreenSharing() const; + quint64 getWindowId() const; bool isScreenSharing() const; LinphoneEnums::VideoSourceScreenSharingType getVideoSourceType() const; diff --git a/linphone-app/ui/modules/Common/Image/RoundedImage.qml b/linphone-app/ui/modules/Common/Image/RoundedImage.qml index 90a7f36b1..9fbb52e82 100644 --- a/linphone-app/ui/modules/Common/Image/RoundedImage.qml +++ b/linphone-app/ui/modules/Common/Image/RoundedImage.qml @@ -13,6 +13,7 @@ Item { property color foregroundColor: '#00000000' readonly property alias status: image.status property int radius: width/2 + property alias cache: image.cache Rectangle { id: backgroundArea diff --git a/linphone-app/ui/modules/Linphone/Menus/IncallMenu.qml b/linphone-app/ui/modules/Linphone/Menus/IncallMenu.qml index ea7a8ddc9..3079bb60e 100644 --- a/linphone-app/ui/modules/Linphone/Menus/IncallMenu.qml +++ b/linphone-app/ui/modules/Linphone/Menus/IncallMenu.qml @@ -377,6 +377,7 @@ Rectangle{ backgroundColor: 'white' source: 'image://screen/'+index radius: 10 + cache: false } Text{ Layout.fillWidth: true @@ -421,6 +422,18 @@ Rectangle{ mainItem.callModel.setVideoSourceDescriptorModel(screenSharingItem.desc) } } + + RoundedImage{ + visible: windowSharingRadioButton.checked + Layout.leftMargin: 15 + Layout.preferredWidth: 114 + Layout.preferredHeight: 64 + backgroundColor: 'white' + source: windowSharingRadioButton.checked ? 'image://window/'+screenSharingItem.desc.windowId : '' + radius: 10 + cache: false + } + Rectangle{ Layout.fillWidth: true Layout.preferredHeight: IncallMenuStyle.list.border.width diff --git a/linphone-app/ui/views/App/Calls/Incall.qml b/linphone-app/ui/views/App/Calls/Incall.qml index 02a845692..24ca76eb9 100644 --- a/linphone-app/ui/views/App/Calls/Incall.qml +++ b/linphone-app/ui/views/App/Calls/Incall.qml @@ -675,12 +675,18 @@ Rectangle { } Connections{ target: DesktopTools - onWindowIdSelectionStarted: window.attachVirtualWindow(Utils.buildCommonDialogUri('ConfirmDialog'), { - descriptionText: "Click on the window that you want to share." - , showButtonOnly: 42 - , buttonTexts : [''] - }) - onWindowIdSelectionEnded: window.detachVirtualWindow() + onWindowIdSelectionStarted: { + mainItem.enabled = false + window.attachVirtualWindow(Utils.buildCommonDialogUri('ConfirmDialog'), { + descriptionText: "Click on the window that you want to share." + , showButtonOnly: 42 + , buttonTexts : [''] + }) + } + onWindowIdSelectionEnded: { + window.detachVirtualWindow() + mainItem.enabled = true + } } // ---------------------------------------------------------------------------