diff --git a/jami-qt.pro b/jami-qt.pro
index 473442d67f789756fb464b37d7d6fee0a4f2933d..842d012980abdd3184c2da2137039f9b44603279 100644
--- a/jami-qt.pro
+++ b/jami-qt.pro
@@ -103,10 +103,17 @@ unix {
 
     LIBS += -L$${LRC}/lib -lringclient
     LIBS += -lqrencode
+    LIBS += -lX11
 
     isEmpty(PREFIX) { PREFIX = /tmp/$${TARGET}/bin }
     target.path = $$PREFIX/bin
     INSTALLS += target
+
+    # unix specific
+    HEADERS += \
+               src/xrectsel.h
+    SOURCES += \
+               src/xrectsel.c
 }
 
 # Input
diff --git a/src/MainApplicationWindow.qml b/src/MainApplicationWindow.qml
index d61215fdc87754941ffbd1769bacdb84c83f6ed5..32319ce29b5914eafb9aaf8f63f9075247e988df 100644
--- a/src/MainApplicationWindow.qml
+++ b/src/MainApplicationWindow.qml
@@ -169,9 +169,12 @@ ApplicationWindow {
 
     onClosing: root.close()
 
+    onScreenChanged: JamiQmlUtils.mainApplicationScreen = root.screen
+
     Component.onCompleted: {
         if(!startAccountMigration()){
             startClient()
         }
+        JamiQmlUtils.mainApplicationScreen = root.screen
     }
 }
diff --git a/src/avadapter.cpp b/src/avadapter.cpp
index e1e750df384b527785354ee4a2205351d3577a62..cd5bcfb8e5eb50515348f8b856e6be2b2a25f417 100644
--- a/src/avadapter.cpp
+++ b/src/avadapter.cpp
@@ -23,8 +23,13 @@
 #include "lrcinstance.h"
 #include "qtutils.h"
 
+#ifdef Q_OS_LINUX
+#include "xrectsel.h"
+#endif
+
 #include <QtConcurrent/QtConcurrent>
 #include <QApplication>
+#include <QPainter>
 #include <QScreen>
 
 AvAdapter::AvAdapter(QObject* parent)
@@ -66,71 +71,152 @@ AvAdapter::populateVideoDeviceContextMenuItem()
 void
 AvAdapter::onVideoContextMenuDeviceItemClicked(const QString& deviceName)
 {
-    auto* convModel = LRCInstance::getCurrentConversationModel();
-    const auto conversation = convModel->getConversationForUID(LRCInstance::getCurrentConvUid());
-    auto call = LRCInstance::getCallInfoForConversation(conversation);
-    if (!call)
-        return;
-
     auto deviceId = LRCInstance::avModel().getDeviceIdFromName(deviceName);
     if (deviceId.isEmpty()) {
         qWarning() << "Couldn't find device: " << deviceName;
         return;
     }
     LRCInstance::avModel().setCurrentVideoCaptureDevice(deviceId);
-    LRCInstance::avModel().switchInputTo(deviceId, call->id);
+    LRCInstance::avModel().switchInputTo(deviceId, getCurrentCallId());
 }
 
 void
 AvAdapter::shareEntireScreen(int screenNumber)
 {
-    QScreen* screen = qApp->screens().at(screenNumber);
+    QScreen* screen = QGuiApplication::screens().at(screenNumber);
     if (!screen)
         return;
-    QRect rect = screen ? screen->geometry() : qApp->primaryScreen()->geometry();
-    LRCInstance::avModel().setDisplay(screenNumber, rect.x(), rect.y(), rect.width(), rect.height());
+    QRect rect = screen->geometry();
+
+    int display = 0;
+#ifdef Q_OS_WIN
+    display = screenNumber;
+#else
+    QString display_env {getenv("DISPLAY")};
+    if (!display_env.isEmpty()) {
+        auto list = display_env.split(":", Qt::SkipEmptyParts);
+        // Should only be one display, so get the first one
+        if (list.size() > 0) {
+            display = list.at(0).toInt();
+        }
+    }
+#endif
+    LRCInstance::avModel()
+        .setDisplay(display, rect.x(), rect.y(), rect.width(), rect.height(), getCurrentCallId());
+}
+
+void
+AvAdapter::shareAllScreens()
+{
+    auto screens = QGuiApplication::screens();
+
+    int width = 0, height = 0;
+    for (auto scr : screens) {
+        width += scr->geometry().width();
+        if (height < scr->geometry().height())
+            height = scr->geometry().height();
+    }
+
+    LRCInstance::avModel().setDisplay(0, 0, 0, width, height, getCurrentCallId());
 }
 
-const QString
+void
 AvAdapter::captureScreen(int screenNumber)
 {
-    QScreen* screen = qApp->screens().at(screenNumber);
-    if (!screen)
-        return QString("");
-    /*
-     * The screen window id is always 0.
-     */
-    auto pixmap = screen->grabWindow(0);
+    QtConcurrent::run([this, screenNumber]() {
+        QScreen* screen = QGuiApplication::screens().at(screenNumber);
+        if (!screen)
+            return;
+        /*
+         * The screen window id is always 0.
+         */
+        auto pixmap = screen->grabWindow(0);
 
-    QBuffer buffer;
-    buffer.open(QIODevice::WriteOnly);
-    pixmap.save(&buffer, "PNG");
-    return Utils::byteArrayToBase64String(buffer.data());
+        QBuffer buffer;
+        buffer.open(QIODevice::WriteOnly);
+        pixmap.save(&buffer, "PNG");
+
+        emit screenCaptured(screenNumber, Utils::byteArrayToBase64String(buffer.data()));
+    });
+}
+
+void
+AvAdapter::captureAllScreens()
+{
+    QtConcurrent::run([this]() {
+        auto screens = QGuiApplication::screens();
+
+        QList<QPixmap> scrs;
+        int width = 0, height = 0, currentPoint = 0;
+
+        foreach (auto scr, screens) {
+            QPixmap pix = scr->grabWindow(0);
+            width += pix.width();
+            if (height < pix.height())
+                height = pix.height();
+            scrs << pix;
+        }
+
+        QPixmap final(width, height);
+        QPainter painter(&final);
+        final.fill(Qt::black);
+
+        foreach (auto scr, scrs) {
+            painter.drawPixmap(QPoint(currentPoint, 0), scr);
+            currentPoint += scr.width();
+        }
+
+        QBuffer buffer;
+        buffer.open(QIODevice::WriteOnly);
+        final.save(&buffer, "PNG");
+        emit screenCaptured(-1, Utils::byteArrayToBase64String(buffer.data()));
+    });
 }
 
 void
 AvAdapter::shareFile(const QString& filePath)
 {
-    LRCInstance::avModel().setInputFile(filePath);
+    LRCInstance::avModel().setInputFile(filePath, getCurrentCallId());
 }
 
 void
-AvAdapter::shareScreenArea(int screenNumber, int x, int y, int width, int height)
+AvAdapter::shareScreenArea(unsigned x, unsigned y, unsigned width, unsigned height)
 {
-    QScreen* screen = qApp->screens().at(screenNumber);
-    if (!screen)
-        return;
-    QRect rect = screen ? screen->geometry() : qApp->primaryScreen()->geometry();
+#ifdef Q_OS_LINUX
+    int display;
 
-    /*
-     * Provide minimum width, height.
-     * Need to add screen x, y initial value to the setDisplay api call.
-     */
-    LRCInstance::avModel().setDisplay(screenNumber,
-                                      rect.x() + x,
-                                      rect.y() + y,
+    // Get display
+    QString display_env {getenv("DISPLAY")};
+    if (!display_env.isEmpty()) {
+        auto list = display_env.split(":", Qt::SkipEmptyParts);
+        // Should only be one display, so get the first one
+        if (list.size() > 0) {
+            display = list.at(0).toInt();
+        }
+    }
+
+    // xrectsel will freeze all displays too fast so that the call
+    // context menu will not be closed even closed signal is emitted
+    // use timer to wait until popup is closed
+    QTimer::singleShot(100, [=]() mutable {
+        x = y = width = height = 0;
+        xrectsel(&x, &y, &width, &height);
+
+        LRCInstance::avModel().setDisplay(0,
+                                          x,
+                                          y,
+                                          width < 128 ? 128 : width,
+                                          height < 128 ? 128 : height,
+                                          getCurrentCallId());
+    });
+#else
+    LRCInstance::avModel().setDisplay(0,
+                                      x,
+                                      y,
                                       width < 128 ? 128 : width,
-                                      height < 128 ? 128 : height);
+                                      height < 128 ? 128 : height,
+                                      getCurrentCallId());
+#endif
 }
 
 void
@@ -145,19 +231,24 @@ AvAdapter::stopAudioMeter(bool async)
     LRCInstance::stopAudioMeter(async);
 }
 
+const QString&
+AvAdapter::getCurrentCallId()
+{
+    auto* convModel = LRCInstance::getCurrentConversationModel();
+    const auto conversation = convModel->getConversationForUID(LRCInstance::getCurrentConvUid());
+    auto call = LRCInstance::getCallInfoForConversation(conversation);
+    if (!call)
+        return QString();
+    return call->id;
+}
+
 void
 AvAdapter::slotDeviceEvent()
 {
     auto& avModel = LRCInstance::avModel();
     auto defaultDevice = avModel.getDefaultDevice();
     auto currentCaptureDevice = avModel.getCurrentVideoCaptureDevice();
-    QString callId {};
-
-    auto* convModel = LRCInstance::getCurrentConversationModel();
-    const auto conversation = convModel->getConversationForUID(LRCInstance::getCurrentConvUid());
-    auto call = LRCInstance::getCallInfoForConversation(conversation);
-    if (call)
-        callId = call->id;
+    QString callId = getCurrentCallId();
 
     /*
      * Decide whether a device has plugged, unplugged, or nothing has changed.
@@ -211,4 +302,4 @@ AvAdapter::slotDeviceEvent()
     emit videoDeviceListChanged(currentDeviceListSize == 0);
 
     deviceListSize_ = currentDeviceListSize;
-}
\ No newline at end of file
+}
diff --git a/src/avadapter.h b/src/avadapter.h
index 3c7d619bb6f84e3cbfd51fce16de1e9b7b8b47b1..d3e961d60015881897b97135a1ae5d141fdf8012 100644
--- a/src/avadapter.h
+++ b/src/avadapter.h
@@ -39,6 +39,8 @@ signals:
      */
     void videoDeviceListChanged(bool listIsEmpty);
 
+    void screenCaptured(int screenNumber, QString source);
+
 protected:
     void safeInit() override {};
 
@@ -58,9 +60,19 @@ protected:
     Q_INVOKABLE void shareEntireScreen(int screenNumber);
 
     /*
-     * Take snap shot of the screen by returning base64 image string.
+     * Share the all screens connected.
+     */
+    Q_INVOKABLE void shareAllScreens();
+
+    /*
+     * Take snap shot of the screen and return emitting signal.
+     */
+    Q_INVOKABLE void captureScreen(int screenNumber);
+
+    /*
+     * Take snap shot of the all screens and return by emitting signal.
      */
-    Q_INVOKABLE const QString captureScreen(int screenNumber);
+    Q_INVOKABLE void captureAllScreens();
 
     /*
      * Share a media file.
@@ -68,14 +80,19 @@ protected:
     Q_INVOKABLE void shareFile(const QString& filePath);
 
     /*
-     * Select screen area to display.
+     * Select screen area to display (from all screens).
      */
-    Q_INVOKABLE void shareScreenArea(int screenNumber, int x, int y, int width, int height);
+    Q_INVOKABLE void shareScreenArea(unsigned x, unsigned y, unsigned width, unsigned height);
 
     Q_INVOKABLE void startAudioMeter(bool async);
     Q_INVOKABLE void stopAudioMeter(bool async);
 
 private:
+    /*
+     * Get current callId from current selected conv id.
+     */
+    const QString& getCurrentCallId();
+
     /*
      * Used to classify capture device events.
      */
diff --git a/src/commoncomponents/js/contextmenugenerator.js b/src/commoncomponents/js/contextmenugenerator.js
index c68f6efbb7ae7ece88a7a75ffa6b7c1f5eec98e5..ef93c309152566e0239fac9b8b162cf2a5b166cf 100644
--- a/src/commoncomponents/js/contextmenugenerator.js
+++ b/src/commoncomponents/js/contextmenugenerator.js
@@ -107,8 +107,16 @@ function addMenuItem(itemName,
         console.log("Error loading component:",
                     menuItemComponent.errorString())
     if (menuItemObject !== null) {
-        menuItemObject.clicked.connect(function () {baseContextMenuObject.close()})
-        menuItemObject.clicked.connect(onClickedCallback)
+        menuItemObject.clicked.connect(function () {
+            var callback = function(){
+                onClickedCallback()
+                baseContextMenuObject.onVisibleChanged.disconnect(callback)
+                baseContextMenuObject.close()
+            }
+
+            baseContextMenuObject.onVisibleChanged.connect(callback)
+            baseContextMenuObject.visible = false
+        })
         menuItemObject.icon.color = "green"
 
         baseContextMenuObject.addItem(menuItemObject)
diff --git a/src/constant/JamiQmlUtils.qml b/src/constant/JamiQmlUtils.qml
index 6a75fce9e78e392de145ffc90f6370ede25b878c..4cb1670c4c378f7afeb3f2d71f3e623f051d914d 100644
--- a/src/constant/JamiQmlUtils.qml
+++ b/src/constant/JamiQmlUtils.qml
@@ -24,7 +24,9 @@ import QtQuick 2.14
 Item {
     readonly property string mainViewLoadPath: "qrc:/src/mainview/MainView.qml"
     readonly property string wizardViewLoadPath: "qrc:/src/wizardview/WizardView.qml"
+    readonly property string base64StringTitle: "data:image/png;base64,"
 
+    property var mainApplicationScreen: ""
     property bool callIsFullscreen: false
 
     TextMetrics {
diff --git a/src/distantrenderer.cpp b/src/distantrenderer.cpp
index 14b7f6db4a9669292454b44f82f552a2f9488785..55b15fa15f02ea59fcc8250de38cf3d5b05749cd 100644
--- a/src/distantrenderer.cpp
+++ b/src/distantrenderer.cpp
@@ -70,25 +70,29 @@ DistantRenderer::getScaledHeight() const
 void
 DistantRenderer::paint(QPainter* painter)
 {
-    auto distantImage = LRCInstance::renderer()->getFrame(distantRenderId_);
-    if (distantImage) {
-        auto scaledDistant = distantImage->scaled(size().toSize(), Qt::KeepAspectRatio);
-        auto tempScaledWidth = static_cast<int>(scaledWidth_ * 1000);
-        auto tempScaledHeight = static_cast<int>(scaledHeight_ * 1000);
-        auto tempXOffset = xOffset_;
-        auto tempYOffset = yOffset_;
-        scaledWidth_ = static_cast<double>(scaledDistant.width())
-                       / static_cast<double>(distantImage->width());
-        scaledHeight_ = static_cast<double>(scaledDistant.height())
-                        / static_cast<double>(distantImage->height());
-        xOffset_ = (width() - scaledDistant.width()) / 2;
-        yOffset_ = (height() - scaledDistant.height()) / 2;
-        if (tempXOffset != xOffset_ or tempYOffset != yOffset_
-            or static_cast<int>(scaledWidth_ * 1000) != tempScaledWidth
-            or static_cast<int>(scaledHeight_ * 1000) != tempScaledHeight) {
-            emit offsetChanged();
+    LRCInstance::renderer()->drawFrame(distantRenderId_, [this, painter](QImage* distantImage) {
+        if (distantImage) {
+            auto scaledDistant = distantImage->scaled(size().toSize(), Qt::KeepAspectRatio);
+            auto tempScaledWidth = static_cast<int>(scaledWidth_ * 1000);
+            auto tempScaledHeight = static_cast<int>(scaledHeight_ * 1000);
+            auto tempXOffset = xOffset_;
+            auto tempYOffset = yOffset_;
+            scaledWidth_ = static_cast<double>(scaledDistant.width())
+                           / static_cast<double>(distantImage->width());
+            scaledHeight_ = static_cast<double>(scaledDistant.height())
+                            / static_cast<double>(distantImage->height());
+            xOffset_ = (width() - scaledDistant.width()) / 2;
+            yOffset_ = (height() - scaledDistant.height()) / 2;
+            if (tempXOffset != xOffset_ or tempYOffset != yOffset_
+                or static_cast<int>(scaledWidth_ * 1000) != tempScaledWidth
+                or static_cast<int>(scaledHeight_ * 1000) != tempScaledHeight) {
+                emit offsetChanged();
+            }
+            painter->drawImage(QRect(xOffset_,
+                                     yOffset_,
+                                     scaledDistant.width(),
+                                     scaledDistant.height()),
+                               scaledDistant);
         }
-        painter->drawImage(QRect(xOffset_, yOffset_, scaledDistant.width(), scaledDistant.height()),
-                           scaledDistant);
-    }
+    });
 }
diff --git a/src/mainview/components/CallViewContextMenu.qml b/src/mainview/components/CallViewContextMenu.qml
index a0dbdfed0b1052fb65cd5dad9b2fd29b38b51c1e..33378136d5e27338294fa6c5c255bd4679dbc751 100644
--- a/src/mainview/components/CallViewContextMenu.qml
+++ b/src/mainview/components/CallViewContextMenu.qml
@@ -115,13 +115,11 @@ Item {
             ContextMenuGenerator.addMenuItem(JamiStrings.shareScreenArea,
                                              "qrc:/images/icons/screen_share-24px.svg",
                                              function (){
-                                                 if (Qt.application.screens.length === 1) {
-                                                     ScreenRubberBandCreation.createScreenRubberBandWindowObject(
-                                                                 null, 0)
-                                                     ScreenRubberBandCreation.showScreenRubberBandWindow()
+                                                 if (Qt.platform.os !== "windows") {
+                                                     AvAdapter.shareScreenArea(0, 0, 0, 0)
                                                  } else {
-                                                     SelectScreenWindowCreation.createSelectScreenWindowObject(true)
-                                                     SelectScreenWindowCreation.showSelectScreenWindow()
+                                                     ScreenRubberBandCreation.createScreenRubberBandWindowObject()
+                                                     ScreenRubberBandCreation.showScreenRubberBandWindow()
                                                  }
                                              })
             ContextMenuGenerator.addMenuItem(JamiStrings.shareFile,
diff --git a/src/mainview/components/ParticipantOverlay.qml b/src/mainview/components/ParticipantOverlay.qml
index 7a090acac976a50ba33cb7cdca6cf32473cd09fa..f187bef9c2593d0f9c5d19642284f2dd6effc524 100644
--- a/src/mainview/components/ParticipantOverlay.qml
+++ b/src/mainview/components/ParticipantOverlay.qml
@@ -51,7 +51,7 @@ Rectangle {
         if (avatar === "") {
             contactImage.source = ""
         } else {
-            contactImage.source = "data:image/png;base64," + avatar
+            contactImage.source = JamiQmlUtils.base64StringTitle + avatar
         }
     }
 
diff --git a/src/mainview/components/ScreenRubberBand.qml b/src/mainview/components/ScreenRubberBand.qml
index 0115351a536e73cbd47c4c718741707ff05a4135..79e85328398ca2421fe4e616bc316ae05090061d 100644
--- a/src/mainview/components/ScreenRubberBand.qml
+++ b/src/mainview/components/ScreenRubberBand.qml
@@ -32,16 +32,32 @@ import net.jami.Constants 1.0
 Window {
     id: screenRubberBandWindow
 
-    property int screenNumber: 0
+    function setAllScreensGeo() {
+        var width = 0, height = 0
+        var screens = Qt.application.screens
+        for (var i = 0; i < screens.length; ++i) {
+            width += screens[i].width
+            if (height < screens[i].height)
+                height = screens[i].height
+        }
 
-    flags: Qt.FramelessWindowHint | Qt.WindowStaysOnTopHint | Qt.WA_TranslucentBackground
+        screenRubberBandWindow.width = width
+        screenRubberBandWindow.height = height
+        screenRubberBandWindow.x = 0
+        screenRubberBandWindow.y = 0
+    }
 
+    flags: Qt.FramelessWindowHint | Qt.WindowStaysOnTopHint | Qt.WA_TranslucentBackground
 
     // Opacity with 0.7 window that will fill the entire screen,
     // provide the users to select the area that they
     // want to share.
     color: Qt.rgba(0, 0, 0, 0.7)
+    // +1 so that it does not fallback to the previous screen
+    x: screen.virtualX + 1
+    y: screen.virtualY + 1
 
+    screen: Qt.application.screens[0]
 
     // Rect for selection.
     Rectangle {
@@ -67,7 +83,6 @@ Window {
         hoverEnabled: true
         cursorShape: Qt.CrossCursor
 
-
         // Geo changing for user selection.
         onPressed: {
             originalX = mouseX
@@ -97,7 +112,7 @@ Window {
 
         onReleased: {
             recSelect.visible = false
-            AvAdapter.shareScreenArea(screenNumber, recSelect.x, recSelect.y,
+            AvAdapter.shareScreenArea(recSelect.x, recSelect.y,
                                       recSelect.width, recSelect.height)
             screenRubberBandWindow.close()
         }
diff --git a/src/mainview/components/SelectScreen.qml b/src/mainview/components/SelectScreen.qml
index 04f3cfcd2c08e744f59c70a8e98ffc3ef45825d3..60ab8bd10f245e672f427217e11e1aa86c3c1acb 100644
--- a/src/mainview/components/SelectScreen.qml
+++ b/src/mainview/components/SelectScreen.qml
@@ -37,9 +37,7 @@ Window {
     property int minHeight: 500
 
     property int selectedScreenNumber: -1
-
-    // Decide whether to show screen area or entire screen.
-    property bool selectArea: false
+    property bool selectAllScreens: false
 
     // How many rows the ScrollView should have.
     function calculateRepeaterModel() {
@@ -55,10 +53,10 @@ Window {
     minimumWidth: minWidth
     minimumHeight: minHeight
 
-    title: "Screen sharing"
+    width: minWidth
+    height: minHeight
 
-    // Note: Qt.application.screens[0] is the app's current existing screen.
-    screen: Qt.application.screens[0]
+    screen: JamiQmlUtils.mainApplicationScreen
 
     modality: Qt.ApplicationModal
 
@@ -96,6 +94,7 @@ Window {
             clip: true
 
             ScrollBar.horizontal.policy: ScrollBar.AlwaysOff
+            ScrollBar.vertical.policy: ScrollBar.AlwaysOn
 
             // Column of rows repeater (two screen captures in a row).
             Column {
@@ -125,6 +124,21 @@ Window {
                             }
                         }
 
+                        Connections {
+                            target: AvAdapter
+
+                            function onScreenCaptured(screenNumber, source) {
+                                if (screenNumber === -1)
+                                    screenShotAll.source = JamiQmlUtils.base64StringTitle + source
+                                if (screenNumber !== index && screenNumber !== index + 1)
+                                    return
+                                if (screenNumber % 2 !== 1)
+                                    screenShotOdd.source = JamiQmlUtils.base64StringTitle + source
+                                else
+                                    screenShotEven.source = JamiQmlUtils.base64StringTitle + source
+                            }
+                        }
+
                         // To make sure that two screen captures in one row,
                         // a repeater of two rect is needed, which one in charge
                         // of odd number screen, one in charge of even number screen.
@@ -154,11 +168,8 @@ Window {
                                 fillMode: Image.PreserveAspectFit
                                 mipmap: true
 
-                                Component.onCompleted: {
-                                    screenShotOdd.source = "data:image/png;base64,"
-                                            + AvAdapter.captureScreen(
-                                                calculateScreenNumber(index, false) - 1)
-                                }
+                                Component.onCompleted: AvAdapter.captureScreen(
+                                                           calculateScreenNumber(index, false) - 1)
                             }
 
                             Text {
@@ -224,8 +235,7 @@ Window {
 
                                 Component.onCompleted: {
                                     if (screenSelectionRectEven.visible)
-                                        screenShotEven.source = "data:image/png;base64,"
-                                                + AvAdapter.captureScreen(
+                                        AvAdapter.captureScreen(
                                                     calculateScreenNumber(index, true) - 1)
                                 }
                             }
@@ -259,6 +269,71 @@ Window {
                         }
                     }
                 }
+
+                Rectangle {
+                    id: screenSelectionRectAll
+
+                    property string borderColor: JamiTheme.tabbarBorderColor
+
+                    anchors.horizontalCenter: screenSelectionScrollViewColumn.horizontalCenter
+
+                    color: JamiTheme.secondaryBackgroundColor
+
+                    height: screenSelectionScrollView.height
+                    width: screenSelectionScrollView.width - 2 * JamiTheme.preferredMarginSize
+
+                    border.color: borderColor
+
+                    Connections {
+                        target: selectScreenWindow
+
+                        function onSelectedScreenNumberChanged() {
+                            // Recover from green state.
+                            selectAllScreens = false
+                            screenSelectionRectAll.borderColor = JamiTheme.tabbarBorderColor
+                        }
+                    }
+
+                    Image {
+                        id: screenShotAll
+
+                        anchors.top: screenSelectionRectAll.top
+                        anchors.topMargin: 10
+                        anchors.horizontalCenter: screenSelectionRectAll.horizontalCenter
+
+                        height: screenSelectionRectAll.height - 50
+                        width: screenSelectionRectAll.width - 50
+
+                        fillMode: Image.PreserveAspectFit
+                        mipmap: true
+
+                        Component.onCompleted: AvAdapter.captureAllScreens()
+                    }
+
+                    Text {
+                        id: screenNameAll
+
+                        anchors.top: screenShotAll.bottom
+                        anchors.topMargin: 10
+                        anchors.horizontalCenter: screenSelectionRectAll.horizontalCenter
+
+                        font.pointSize: JamiTheme.textFontSize - 2
+                        text: qsTr("All Screens")
+                        color: JamiTheme.textColor
+                    }
+
+                    MouseArea {
+                        anchors.fill: parent
+                        acceptedButtons: Qt.LeftButton
+
+                        onClicked: {
+                            selectedScreenNumber = -1
+                            selectAllScreens = true
+                            screenSelectionRectAll.borderColor
+                                    = JamiTheme.screenSelectionBorderGreen
+                        }
+                    }
+                }
             }
         }
     }
@@ -273,7 +348,7 @@ Window {
         width: 200
         height: 36
 
-        visible: selectedScreenNumber != -1
+        visible: selectedScreenNumber != -1 || selectAllScreens
 
         color: JamiTheme.buttonTintedBlack
         hoveredColor: JamiTheme.buttonTintedBlackHovered
@@ -284,21 +359,11 @@ Window {
         text: JamiStrings.shareScreen
 
         onClicked: {
-            if (selectArea) {
-                selectScreenWindow.hide()
-                ScreenRubberBandCreation.createScreenRubberBandWindowObject(
-                            selectScreenWindow, selectedScreenNumber - 1)
-                ScreenRubberBandCreation.showScreenRubberBandWindow()
-
-
-                // Destory selectScreenWindow once screenRubberBand is closed.
-                ScreenRubberBandCreation.connectOnClosingEvent(function () {
-                    selectScreenWindow.close()
-                })
-            } else {
+            if (selectAllScreens)
+                AvAdapter.shareAllScreens()
+            else
                 AvAdapter.shareEntireScreen(selectedScreenNumber - 1)
-                selectScreenWindow.close()
-            }
+            selectScreenWindow.close()
         }
     }
 }
diff --git a/src/mainview/components/VideoCallFullScreenWindowContainer.qml b/src/mainview/components/VideoCallFullScreenWindowContainer.qml
index f585b8ea9d81fe7e00c76c70cc2059b65332f9b8..2c76179fefb9ba458c8208677f7d80467ae392b3 100644
--- a/src/mainview/components/VideoCallFullScreenWindowContainer.qml
+++ b/src/mainview/components/VideoCallFullScreenWindowContainer.qml
@@ -18,6 +18,7 @@
 
 import QtQuick 2.14
 import QtQuick.Window 2.14
+import net.jami.Models 1.0
 
 Window {
     id: videoWindow
@@ -28,7 +29,11 @@ Window {
 
     flags: Qt.FramelessWindowHint
 
-    screen: Qt.application.screens[0]
+    screen: JamiQmlUtils.mainApplicationScreen
+
+    // +1 so that it does not fallback to the previous screen
+    x: screen.virtualX + 1
+    y: screen.virtualY + 1
 
     visible: false
 
diff --git a/src/mainview/js/callfullscreenwindowcontainercreation.js b/src/mainview/js/callfullscreenwindowcontainercreation.js
index 9eba21925935fde1b376c7610cee19bf1e8ba7bc..2ce42c14e02bd87cd6aa8cc0db53c7debf7038c9 100644
--- a/src/mainview/js/callfullscreenwindowcontainercreation.js
+++ b/src/mainview/js/callfullscreenwindowcontainercreation.js
@@ -42,7 +42,7 @@ function finishCreation() {
 
     // Signal connection.
     callFullScreenWindowContainerObject.onClosing.connect(
-                destoryVideoCallFullScreenWindowContainer)
+                destroyVideoCallFullScreenWindowContainer)
 }
 
 function checkIfVisible() {
@@ -57,7 +57,7 @@ function setAsContainerChild(obj) {
 }
 
 // Destroy and reset callFullScreenWindowContainerObject when window is closed.
-function destoryVideoCallFullScreenWindowContainer() {
+function destroyVideoCallFullScreenWindowContainer() {
     if (!callFullScreenWindowContainerObject)
         return
     callFullScreenWindowContainerObject.destroy()
diff --git a/src/mainview/js/screenrubberbandcreation.js b/src/mainview/js/screenrubberbandcreation.js
index 38a22fdbd9f49ee3e6961c44868358f8409b1ae0..4be315f2bcdc7da25d87d7a92b56735e44d6d02b 100644
--- a/src/mainview/js/screenrubberbandcreation.js
+++ b/src/mainview/js/screenrubberbandcreation.js
@@ -1,4 +1,3 @@
-
 /*
  * Copyright (C) 2020 by Savoir-faire Linux
  * Author: Mingrui Zhang <mingrui.zhang@savoirfairelinux.com>
@@ -17,64 +16,45 @@
  * along with this program.  If not, see <https://www.gnu.org/licenses/>.
  */
 
-
-/*
- * Global screen rubber band window component, object variable for creation.
- */
+// Global screen rubber band window component, object variable for creation.
 var screenRubberBandWindowComponent
 var screenRubberBandWindowObject
 
-function createScreenRubberBandWindowObject(parent, screenNumber) {
+var selectAllScreens = false
+
+function createScreenRubberBandWindowObject() {
     if (screenRubberBandWindowObject)
         return
     screenRubberBandWindowComponent = Qt.createComponent(
                 "../components/ScreenRubberBand.qml")
     if (screenRubberBandWindowComponent.status === Component.Ready)
-        finishCreation(parent, screenNumber)
+        finishCreation()
     else if (screenRubberBandWindowComponent.status === Component.Error)
         console.log("Error loading component:",
                     screenRubberBandWindowComponent.errorString())
 }
 
-function finishCreation(parent, screenNumber) {
-    screenRubberBandWindowObject = screenRubberBandWindowComponent.createObject(
-                parent)
+function finishCreation() {
+    screenRubberBandWindowObject = screenRubberBandWindowComponent.createObject()
     if (screenRubberBandWindowObject === null) {
-
-
-        /*
-         * Error Handling.
-         */
+        // Error Handling.
         console.log("Error creating screen rubber band object")
     }
 
-    screenRubberBandWindowObject.screenNumber = screenNumber
-    screenRubberBandWindowObject.screen = Qt.application.screens[screenNumber]
-
-
-    /*
-     * Signal connection.
-     */
+    // Signal connection.
     screenRubberBandWindowObject.onClosing.connect(
-                destoryScreenRubberBandWindow)
+                destroyScreenRubberBandWindow)
 }
 
 function showScreenRubberBandWindow() {
-    screenRubberBandWindowObject.showFullScreen()
+    screenRubberBandWindowObject.show()
+    screenRubberBandWindowObject.setAllScreensGeo()
 }
 
-
-/*
- * Destroy and reset screenRubberBandWindowObject when window is closed.
- */
-function destoryScreenRubberBandWindow() {
+// Destroy and reset screenRubberBandWindowObject when window is closed.
+function destroyScreenRubberBandWindow() {
     if (!screenRubberBandWindowObject)
         return
     screenRubberBandWindowObject.destroy()
     screenRubberBandWindowObject = false
 }
-
-function connectOnClosingEvent(func) {
-    if (screenRubberBandWindowObject)
-        screenRubberBandWindowObject.onClosing.connect(func)
-}
diff --git a/src/mainview/js/selectscreenwindowcreation.js b/src/mainview/js/selectscreenwindowcreation.js
index 15bfbd157beae1f737c6d0f594e5d1945bb9aa4c..d4bbed83e48e15b73b38f529165fdaabf7138e62 100644
--- a/src/mainview/js/selectscreenwindowcreation.js
+++ b/src/mainview/js/selectscreenwindowcreation.js
@@ -1,4 +1,3 @@
-
 /*
  * Copyright (C) 2020 by Savoir-faire Linux
  * Author: Mingrui Zhang <mingrui.zhang@savoirfairelinux.com>
@@ -17,54 +16,45 @@
  * along with this program.  If not, see <https://www.gnu.org/licenses/>.
  */
 
-
-/*
- * Global select screen window component, object variable for creation.
- */
+// Global select screen window component, object variable for creation.
 var selectScreenWindowComponent
 var selectScreenWindowObject
 
-function createSelectScreenWindowObject(selectArea = false) {
+function createSelectScreenWindowObject() {
     if (selectScreenWindowObject)
         return
     selectScreenWindowComponent = Qt.createComponent(
                 "../components/SelectScreen.qml")
     if (selectScreenWindowComponent.status === Component.Ready)
-        finishCreation(selectArea)
+        finishCreation()
     else if (selectScreenWindowComponent.status === Component.Error)
         console.log("Error loading component:",
                     selectScreenWindowComponent.errorString())
 }
 
-function finishCreation(selectArea) {
+function finishCreation() {
     selectScreenWindowObject = selectScreenWindowComponent.createObject()
     if (selectScreenWindowObject === null) {
-
-
-        /*
-         * Error Handling.
-         */
+        // Error Handling.
         console.log("Error creating select screen object")
     }
 
-    selectScreenWindowObject.selectArea = selectArea
-
-
-    /*
-     * Signal connection.
-     */
-    selectScreenWindowObject.onClosing.connect(destorySelectScreenWindow)
+    // Signal connection.
+    selectScreenWindowObject.onClosing.connect(destroySelectScreenWindow)
 }
 
 function showSelectScreenWindow() {
     selectScreenWindowObject.show()
-}
 
+    var screen = selectScreenWindowObject.screen
+    selectScreenWindowObject.x = screen.virtualX +
+            (screen.width - selectScreenWindowObject.width) / 2
+    selectScreenWindowObject.y = screen.virtualY +
+            (screen.height - selectScreenWindowObject.height) / 2
+}
 
-/*
- * Destroy and reset selectScreenWindowObject when window is closed.
- */
-function destorySelectScreenWindow() {
+// Destroy and reset selectScreenWindowObject when window is closed.
+function destroySelectScreenWindow() {
     if(!selectScreenWindowObject)
         return
     selectScreenWindowObject.destroy()
diff --git a/src/previewrenderer.cpp b/src/previewrenderer.cpp
index 22e1796537e6f7a8e27176bcb24a6622d3066a89..2861c2bb43bd87cea556f03532065b27513b8755 100644
--- a/src/previewrenderer.cpp
+++ b/src/previewrenderer.cpp
@@ -31,46 +31,48 @@ PreviewRenderer::PreviewRenderer(QQuickItem* parent)
 
     previewFrameUpdatedConnection_ = connect(LRCInstance::renderer(),
                                              &RenderManager::previewFrameUpdated,
-                                             [this]() { update(QRect(0, 0, width(), height())); });
-
-    previewRenderingStopped_ = connect(LRCInstance::renderer(),
-                                       &RenderManager::previewRenderingStopped,
-                                       [this]() { update(QRect(0, 0, width(), height())); });
+                                             [this]() {
+                                                 if (isVisible())
+                                                     update(QRect(0, 0, width(), height()));
+                                             });
 }
 
 PreviewRenderer::~PreviewRenderer()
 {
     disconnect(previewFrameUpdatedConnection_);
-    disconnect(previewRenderingStopped_);
 }
 
 void
 PreviewRenderer::paint(QPainter* painter)
 {
-    auto previewImage = LRCInstance::renderer()->getPreviewFrame();
-    if (previewImage) {
-        QImage scaledPreview;
-        auto aspectRatio = static_cast<qreal>(previewImage->width())
-                           / static_cast<qreal>(previewImage->height());
-        auto previewHeight = height();
-        auto previewWidth = previewHeight * aspectRatio;
-
-        /* Instead of setting fixed size, we could get an x offset for the preview
-         * but this would render the horizontal spacers in the parent widget useless.
-         * e.g.
-         * auto parent = qobject_cast<QWidget*>(this->parent());
-         * auto xPos = (parent->width() - previewWidth) / 2;
-         * setGeometry(QRect(QPoint(xPos, this->pos().y()), QSize(previewWidth, previewHeight)));
-         */
-        setWidth(previewWidth);
-        setHeight(previewHeight);
-
-        scaledPreview = previewImage->scaled(size().toSize(), Qt::KeepAspectRatio);
-        painter->drawImage(QRect(0, 0, scaledPreview.width(), scaledPreview.height()),
-                           scaledPreview);
-    } else {
-        paintBackground(painter);
-    }
+    LRCInstance::renderer()
+        ->drawFrame(lrc::api::video::PREVIEW_RENDERER_ID, [this, painter](QImage* previewImage) {
+            if (previewImage) {
+                auto aspectRatio = static_cast<qreal>(previewImage->width())
+                                   / static_cast<qreal>(previewImage->height());
+                auto previewHeight = height();
+                auto previewWidth = previewHeight * aspectRatio;
+
+                /* Instead of setting fixed size, we could get an x offset for the preview
+                 * but this would render the horizontal spacers in the parent widget useless.
+                 * e.g.
+                 * auto parent = qobject_cast<QWidget*>(this->parent());
+                 * auto xPos = (parent->width() - previewWidth) / 2;
+                 * setGeometry(QRect(QPoint(xPos, this->pos().y()),
+                 *             QSize(previewWidth, previewHeight)));
+                 */
+                setWidth(previewWidth);
+                setHeight(previewHeight);
+
+                // If the given size is empty, this function returns a null image.
+                QImage scaledPreview;
+                scaledPreview = previewImage->scaled(size().toSize(), Qt::KeepAspectRatio);
+                painter->drawImage(QRect(0, 0, scaledPreview.width(), scaledPreview.height()),
+                                   scaledPreview);
+            } else {
+                paintBackground(painter);
+            }
+        });
 }
 
 void
@@ -93,16 +95,18 @@ VideoCallPreviewRenderer::~VideoCallPreviewRenderer() {}
 void
 VideoCallPreviewRenderer::paint(QPainter* painter)
 {
-    auto previewImage = LRCInstance::renderer()->getPreviewFrame();
-    if (previewImage) {
-        auto scalingFactor = static_cast<qreal>(previewImage->height())
-                             / static_cast<qreal>(previewImage->width());
-        setProperty("previewImageScalingFactor", scalingFactor);
-        QImage scaledPreview;
-        scaledPreview = previewImage->scaled(size().toSize(), Qt::KeepAspectRatio);
-        painter->drawImage(QRect(0, 0, scaledPreview.width(), scaledPreview.height()),
-                           scaledPreview);
-    }
+    LRCInstance::renderer()
+        ->drawFrame(lrc::api::video::PREVIEW_RENDERER_ID, [this, painter](QImage* previewImage) {
+            if (previewImage) {
+                auto scalingFactor = static_cast<qreal>(previewImage->height())
+                                     / static_cast<qreal>(previewImage->width());
+                setProperty("previewImageScalingFactor", scalingFactor);
+                QImage scaledPreview;
+                scaledPreview = previewImage->scaled(size().toSize(), Qt::KeepAspectRatio);
+                painter->drawImage(QRect(0, 0, scaledPreview.width(), scaledPreview.height()),
+                                   scaledPreview);
+            }
+        });
 }
 
 PhotoboothPreviewRender::PhotoboothPreviewRender(QQuickItem* parent)
@@ -130,12 +134,14 @@ PhotoboothPreviewRender::paint(QPainter* painter)
 {
     painter->setRenderHint(QPainter::Antialiasing, true);
 
-    auto previewImage = LRCInstance::renderer()->getPreviewFrame();
-    if (previewImage) {
-        QImage scaledPreview;
-        scaledPreview = Utils::getCirclePhoto(*previewImage,
-                                              height() <= width() ? height() : width());
-        painter->drawImage(QRect(0, 0, scaledPreview.width(), scaledPreview.height()),
-                           scaledPreview);
-    }
+    LRCInstance::renderer()
+        ->drawFrame(lrc::api::video::PREVIEW_RENDERER_ID, [this, painter](QImage* previewImage) {
+            if (previewImage) {
+                QImage scaledPreview;
+                scaledPreview = Utils::getCirclePhoto(*previewImage,
+                                                      height() <= width() ? height() : width());
+                painter->drawImage(QRect(0, 0, scaledPreview.width(), scaledPreview.height()),
+                                   scaledPreview);
+            }
+        });
 }
diff --git a/src/previewrenderer.h b/src/previewrenderer.h
index b607f2901506a962737b1edb028ba90aa50c8057..646365e3f22c00aaf747a69ce9a19000fd213cb9 100644
--- a/src/previewrenderer.h
+++ b/src/previewrenderer.h
@@ -38,7 +38,6 @@ protected:
 
 private:
     QMetaObject::Connection previewFrameUpdatedConnection_;
-    QMetaObject::Connection previewRenderingStopped_;
 };
 
 class VideoCallPreviewRenderer : public PreviewRenderer
diff --git a/src/rendermanager.cpp b/src/rendermanager.cpp
index f6d59158b53725d67a320883a848b768627ac312..2565e317738151126bc9c0a04e9ca81e7fa2492c 100644
--- a/src/rendermanager.cpp
+++ b/src/rendermanager.cpp
@@ -85,7 +85,10 @@ FrameWrapper::stopRendering()
 QImage*
 FrameWrapper::getFrame()
 {
-    return isRendering_ ? image_.get() : nullptr;
+    if (image_.get()) {
+        return isRendering_ ? (image_.get()->isNull() ? nullptr : image_.get()) : nullptr;
+    }
+    return nullptr;
 }
 
 bool
@@ -94,6 +97,18 @@ FrameWrapper::isRendering()
     return isRendering_;
 }
 
+bool
+FrameWrapper::frameMutexTryLock()
+{
+    return mutex_.tryLock();
+}
+
+void
+FrameWrapper::frameMutexUnlock()
+{
+    mutex_.unlock();
+}
+
 void
 FrameWrapper::slotRenderingStarted(const QString& id)
 {
@@ -127,23 +142,25 @@ FrameWrapper::slotFrameUpdated(const QString& id)
 
         unsigned int width = renderer_->size().width();
         unsigned int height = renderer_->size().height();
-
 #ifndef Q_OS_LINUX
         unsigned int size = frame_.storage.size();
+        auto imageFormat = QImage::Format_ARGB32_Premultiplied;
+#else
+        unsigned int size = frame_.size;
+        auto imageFormat = QImage::Format_ARGB32;
+#endif
         /*
          * If the frame is empty or not the expected size,
          * do nothing and keep the last rendered QImage.
          */
         if (size != 0 && size == width * height * 4) {
+#ifndef Q_OS_LINUX
             buffer_ = std::move(frame_.storage);
-            image_.reset(new QImage((uchar*) buffer_.data(),
-                                    width,
-                                    height,
-                                    QImage::Format_ARGB32_Premultiplied));
 #else
-        if (frame_.ptr) {
-            image_.reset(new QImage(frame_.ptr, width, height, QImage::Format_ARGB32));
+            buffer_.reserve(size);
+            std::move(frame_.ptr, frame_.ptr + size, buffer_.begin());
 #endif
+            image_.reset(new QImage((uchar*) buffer_.data(), width, height, imageFormat));
         }
     }
     emit frameUpdated(id);
@@ -161,7 +178,10 @@ FrameWrapper::slotRenderingStopped(const QString& id)
 
     renderer_ = nullptr;
 
-    image_.reset();
+    {
+        QMutexLocker lock(&mutex_);
+        image_.reset();
+    }
 
     emit renderingStopped(id);
 }
@@ -202,12 +222,6 @@ RenderManager::isPreviewing()
     return previewFrameWrapper_->isRendering();
 }
 
-QImage*
-RenderManager::getPreviewFrame()
-{
-    return previewFrameWrapper_->getFrame();
-}
-
 void
 RenderManager::stopPreviewing()
 {
@@ -232,16 +246,6 @@ RenderManager::startPreviewing(bool force)
     avModel_.startPreview();
 }
 
-QImage*
-RenderManager::getFrame(const QString& id)
-{
-    auto dfwIt = distantFrameWrapperMap_.find(id);
-    if (dfwIt != distantFrameWrapperMap_.end()) {
-        return dfwIt->second->getFrame();
-    }
-    return nullptr;
-}
-
 void
 RenderManager::addDistantRenderer(const QString& id)
 {
@@ -304,4 +308,29 @@ RenderManager::removeDistantRenderer(const QString& id)
          */
         distantFrameWrapperMap_.erase(dfwIt);
     }
-}
\ No newline at end of file
+}
+
+void
+RenderManager::drawFrame(const QString& id, DrawFrameCallback cb)
+{
+    if (id == lrc::api::video::PREVIEW_RENDERER_ID) {
+        if (previewFrameWrapper_->frameMutexTryLock()) {
+            cb(previewFrameWrapper_->getFrame());
+            previewFrameWrapper_->frameMutexUnlock();
+        }
+    } else {
+        auto dfwIt = distantFrameWrapperMap_.find(id);
+        if (dfwIt != distantFrameWrapperMap_.end()) {
+            if (dfwIt->second->frameMutexTryLock()) {
+                cb(dfwIt->second->getFrame());
+                dfwIt->second->frameMutexUnlock();
+            }
+        }
+    }
+}
+
+QImage*
+RenderManager::getPreviewFrame()
+{
+    return previewFrameWrapper_->getFrame();
+}
diff --git a/src/rendermanager.h b/src/rendermanager.h
index 298f9d76a8c56bbb918cca728df842f801d43596..98380b38c32ad815bca0fd308efdac14694ddbb0 100644
--- a/src/rendermanager.h
+++ b/src/rendermanager.h
@@ -77,6 +77,10 @@ public:
      */
     bool isRendering();
 
+    bool frameMutexTryLock();
+
+    void frameMutexUnlock();
+
 signals:
     /*
      * Emitted each time a frame is ready to be displayed.
@@ -168,15 +172,12 @@ public:
     explicit RenderManager(AVModel& avModel);
     ~RenderManager();
 
+    using DrawFrameCallback = std::function<void(QImage*)>;
+
     /*
      * Check if the preview is active.
      */
     bool isPreviewing();
-    /*
-     * Get the most recently rendered preview frame as a QImage.
-     * @return the rendered preview image
-     */
-    QImage* getPreviewFrame();
     /*
      * Start capturing and rendering preview frames.
      * @param force if the capture device should be started
@@ -186,13 +187,6 @@ public:
      * Stop capturing.
      */
     void stopPreviewing();
-
-    /*
-     * Get the most recently rendered distant frame for a given id
-     * as a QImage.
-     * @return the rendered preview image
-     */
-    QImage* getFrame(const QString& id);
     /*
      * Add and connect a distant renderer for a given id
      * to a FrameWrapper object
@@ -205,6 +199,18 @@ public:
      * @param id
      */
     void removeDistantRenderer(const QString& id);
+    /*
+     * Frame will be provided in the callback thread safely
+     * @param id
+     * @param cb
+     */
+    void drawFrame(const QString& id, DrawFrameCallback cb);
+
+    /*
+     * Get the most recently rendered preview frame as a QImage (none thread safe).
+     * @return the rendered preview image
+     */
+    QImage* getPreviewFrame();
 
 signals:
 
diff --git a/src/xrectsel.c b/src/xrectsel.c
new file mode 100644
index 0000000000000000000000000000000000000000..df682a2d12642f51107014de56974b16de43be49
--- /dev/null
+++ b/src/xrectsel.c
@@ -0,0 +1,123 @@
+/*
+ * This code is based and adapted from:
+ * https://github.com/lolilolicon/FFcast2/blob/master/xrectsel.c
+ *
+ * now located at:
+ * https://github.com/lolilolicon/xrectsel/blob/master/xrectsel.c
+ *
+ * xrectsel.c -- print the geometry of a rectangular screen region.
+ * Copyright (C) 2011-2014 lolilolicon <lolilolicon@gmail.com>
+ * 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 <X11/Xlib.h>
+#include <X11/cursorfont.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+void
+xrectsel(unsigned* x_sel, unsigned* y_sel, unsigned* w_sel, unsigned* h_sel)
+{
+    Display* dpy = XOpenDisplay(NULL);
+    if (!dpy)
+        return;
+
+    Window root = DefaultRootWindow(dpy);
+
+    XEvent ev;
+
+    GC sel_gc;
+    XGCValues sel_gv;
+
+    int btn_pressed = 0;
+    int x = 0, y = 0;
+    unsigned int width = 0, height = 0;
+    int start_x = 0, start_y = 0;
+
+    Cursor cursor;
+    cursor = XCreateFontCursor(dpy, XC_crosshair);
+
+    /* Grab pointer for these events */
+    XGrabPointer(dpy,
+                 root,
+                 True,
+                 PointerMotionMask | ButtonPressMask | ButtonReleaseMask,
+                 GrabModeAsync,
+                 GrabModeAsync,
+                 None,
+                 cursor,
+                 CurrentTime);
+
+    sel_gv.function = GXinvert;
+    sel_gv.subwindow_mode = IncludeInferiors;
+    sel_gv.line_width = 1;
+    sel_gc = XCreateGC(dpy, root, GCFunction | GCSubwindowMode | GCLineWidth, &sel_gv);
+
+    for (;;) {
+        XNextEvent(dpy, &ev);
+
+        if (ev.type == ButtonPress) {
+            btn_pressed = 1;
+            x = start_x = ev.xbutton.x_root;
+            y = start_y = ev.xbutton.y_root;
+            width = height = 0;
+
+        } else if (ev.type == MotionNotify) {
+            if (!btn_pressed)
+                continue; /* Draw only if button is pressed */
+
+            /* Re-draw last Rectangle to clear it */
+            XDrawRectangle(dpy, root, sel_gc, x, y, width, height);
+
+            x = ev.xbutton.x_root;
+            y = ev.xbutton.y_root;
+
+            if (x > start_x) {
+                width = x - start_x;
+                x = start_x;
+            } else {
+                width = start_x - x;
+            }
+
+            if (y > start_y) {
+                height = y - start_y;
+                y = start_y;
+            } else {
+                height = start_y - y;
+            }
+
+            /* Draw Rectangle */
+            XDrawRectangle(dpy, root, sel_gc, x, y, width, height);
+            XFlush(dpy);
+
+        } else if (ev.type == ButtonRelease)
+            break;
+    }
+
+    /* Re-draw last Rectangle to clear it */
+    XDrawRectangle(dpy, root, sel_gc, x, y, width, height);
+    XFlush(dpy);
+
+    XUngrabPointer(dpy, CurrentTime);
+    XFreeCursor(dpy, cursor);
+    XFreeGC(dpy, sel_gc);
+    XSync(dpy, 1);
+
+    *x_sel = x;
+    *y_sel = y;
+    *w_sel = width;
+    *h_sel = height;
+
+    XCloseDisplay(dpy);
+}
diff --git a/src/xrectsel.h b/src/xrectsel.h
new file mode 100644
index 0000000000000000000000000000000000000000..5d2fca5e7995f21a58bad293e3226cd046f4e5c0
--- /dev/null
+++ b/src/xrectsel.h
@@ -0,0 +1,26 @@
+/*
+ * This code is based and adapted from:
+ * https://github.com/lolilolicon/FFcast2/blob/master/xrectsel.c
+ *
+ * now located at:
+ * https://github.com/lolilolicon/xrectsel/blob/master/xrectsel.c
+ *
+ * xrectsel.c -- print the geometry of a rectangular screen region.
+ * Copyright (C) 2011-2014 lolilolicon <lolilolicon@gmail.com>
+ * 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/>.
+ */
+
+#pragma once
+
+extern "C" {
+void xrectsel(unsigned* x_sel, unsigned* y_sel, unsigned* w_sel, unsigned* h_sel);
+}