<div dir="ltr">Note that the coding style is quite off and it messes up the existing style in all those files; can you please run astyle on it before merging so it can all be the same?<div><br></div><div>Cheers<br>-- <br>
<div><span style="color:rgb(102,102,102)">Martin Klapetek | KDE Developer</span></div><div class="gmail_extra"><br><br><div class="gmail_quote">On Thu, May 1, 2014 at 3:42 AM, Aleix Pol <span dir="ltr"><<a href="mailto:aleixpol@kde.org" target="_blank">aleixpol@kde.org</a>></span> wrote:<br>


<blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-color:rgb(204,204,204);border-left-style:solid;padding-left:1ex">Git commit 168c15a463746cf9039f2f9e188b1827ed809f97 by Aleix Pol.<br>



Committed on 01/05/2014 at 01:41.<br>
Pushed by apol into branch 'plasmashell+libkscreen'.<br>
<br>
Adopt libkscreen to get information of the screens<br>
<br>
Qt subsystem has deficiencies on their approximation to multiple<br>
screens. [1]<br>
This patch adopts libkscreen to figure out screen additions and primary<br>
modifications.<br>
I'm not merging to master yet as I'm experiencing some issues but it's<br>
already far more comfortable to work with than QGuiApplication::screens().<br>
<br>
[1] <a href="https://bugreports.qt-project.org/browse/QTBUG-38404" target="_blank">https://bugreports.qt-project.org/browse/QTBUG-38404</a><br>
<br>
CCMAIL: <a href="mailto:plasma-devel@kde.org" target="_blank">plasma-devel@kde.org</a><br>
<br>
M  +1    -0    CMakeLists.txt<br>
M  +1    -0    shell/CMakeLists.txt<br>
M  +151  -42   shell/shellcorona.cpp<br>
M  +11   -2    shell/shellcorona.h<br>
<br>
<a href="http://commits.kde.org/plasma-workspace/168c15a463746cf9039f2f9e188b1827ed809f97" target="_blank">http://commits.kde.org/plasma-workspace/168c15a463746cf9039f2f9e188b1827ed809f97</a><br>
<br>
diff --git a/CMakeLists.txt b/CMakeLists.txt<br>
index 31e29b2..8078b0b 100644<br>
--- a/CMakeLists.txt<br>
+++ b/CMakeLists.txt<br>
@@ -13,6 +13,7 @@ find_package(KF5 REQUIRED COMPONENTS<br>
                     IdleTime ThreadWeaver Declarative PlasmaQuick WebKit KDELibs4Support)<br>
<br>
 find_package(KF5 REQUIRED COMPONENTS SysGuard)<br>
+find_package(KF5 REQUIRED COMPONENTS Screen)<br>
 find_package(KWinDBusInterface CONFIG REQUIRED)<br>
<br>
 include(KDEInstallDirs)<br>
diff --git a/shell/CMakeLists.txt b/shell/CMakeLists.txt<br>
index 5f58d8c..5b2a290 100644<br>
--- a/shell/CMakeLists.txt<br>
+++ b/shell/CMakeLists.txt<br>
@@ -87,6 +87,7 @@ target_link_libraries(plasma-shell<br>
  KF5::Activities<br>
  KF5::GlobalAccel<br>
  KF5::DBusAddons<br>
+ KF5::Screen<br>
 )<br>
 if (TARGET KF5::TextEditor)<br>
  target_link_libraries(plasma-shell KF5::TextEditor)<br>
diff --git a/shell/shellcorona.cpp b/shell/shellcorona.cpp<br>
index 2f82132..0670b43 100644<br>
--- a/shell/shellcorona.cpp<br>
+++ b/shell/shellcorona.cpp<br>
@@ -42,6 +42,9 @@<br>
 #include <KAuthorized><br>
 #include <KWindowSystem><br>
<br>
+#include <KScreen/Config><br>
+#include <kscreen/configmonitor.h><br>
+<br>
 #include "config-ktexteditor.h" // HAVE_KTEXTEDITOR<br>
<br>
<br>
@@ -59,8 +62,6 @@<br>
<br>
 #include "plasmashelladaptor.h"<br>
<br>
-<br>
-<br>
 static const int s_configSyncDelay = 10000; // 10 seconds<br>
<br>
 class ShellCorona::Private {<br>
@@ -70,7 +71,8 @@ public:<br>
           activityController(new KActivities::Controller(q)),<br>
           activityConsumer(new KActivities::Consumer(q)),<br>
           addPanelAction(nullptr),<br>
-          addPanelsMenu(nullptr)<br>
+          addPanelsMenu(nullptr),<br>
+          screenConfiguration(nullptr)<br>
     {<br>
         appConfigSyncTimer.setSingleShot(true);<br>
         appConfigSyncTimer.setInterval(s_configSyncDelay);<br>
@@ -99,10 +101,20 @@ public:<br>
     QWeakPointer<InteractiveConsole> console;<br>
 #endif<br>
<br>
+    KScreen::Config* screenConfiguration;<br>
     QTimer waitingPanelsTimer;<br>
     QTimer appConfigSyncTimer;<br>
 };<br>
<br>
+static QScreen* outputToScreen(KScreen::Output* output)<br>
+{<br>
+    foreach(QScreen* screen, QGuiApplication::screens()) {<br>
+        if(screen->name() == output->name()) {<br>
+            return screen;<br>
+        }<br>
+    }<br>
+    return 0;<br>
+}<br>
<br>
 WorkspaceScripting::DesktopScriptEngine * ShellCorona::scriptEngine() const<br>
 {<br>
@@ -233,6 +245,20 @@ QString ShellCorona::shell() const<br>
     return d->shell;<br>
 }<br>
<br>
+static QList<KScreen::Output*> sortOutputs(const QHash<int, KScreen::Output*> &outputs)<br>
+{<br>
+    QList<KScreen::Output*> ret;<br>
+    foreach(KScreen::Output* output, outputs) {<br>
+        if(!output->isEnabled())<br>
+            ;<br>
+        else if(output->isPrimary())<br>
+            ret.prepend(output);<br>
+        else<br>
+            ret.append(output);<br>
+    }<br>
+    return ret;<br>
+}<br>
+<br>
 void ShellCorona::load()<br>
 {<br>
     if (d->shell.isEmpty() ||<br>
@@ -269,17 +295,73 @@ void ShellCorona::load()<br>
         }<br>
     }<br>
<br>
-    for (QScreen *screen : QGuiApplication::screens()) {<br>
-        screenAdded(screen);<br>
+    d->screenConfiguration = KScreen::Config::current();<br>
+    KScreen::ConfigMonitor::instance()->addConfig(d->screenConfiguration);<br>
+    for (KScreen::Output *output : sortOutputs(d->screenConfiguration->connectedOutputs())) {<br>
+        outputAdded(output);<br>
     }<br>
-    connect(qApp, &QGuiApplication::screenAdded,<br>
-            this, &ShellCorona::screenAdded);<br>
+    connect(d->screenConfiguration, &KScreen::Config::outputAdded,<br>
+            this, &ShellCorona::outputAdded);<br>
+    connect(d->screenConfiguration, &KScreen::Config::primaryOutputChanged,<br>
+            this, &ShellCorona::primaryOutputChanged);<br>
<br>
     if (!d->waitingPanels.isEmpty()) {<br>
         d->waitingPanelsTimer.start();<br>
     }<br>
 }<br>
<br>
+void ShellCorona::primaryOutputChanged()<br>
+{<br>
+    KScreen::Config* current = d->screenConfiguration;<br>
+    QScreen* newPrimary = outputToScreen(current->primaryOutput());<br>
+    int i=0;<br>
+    foreach(DesktopView* view, d->views) {<br>
+        if(view->screen() == newPrimary)<br>
+            break;<br>
+        i++;<br>
+    }<br>
+    QScreen* oldPrimary = d->views.first()->screen();<br>
+    qDebug() << "primary changed!" << oldPrimary->name() << newPrimary->name() << i;<br>
+//<br>
+//     //if it was not found, it means that outputAdded hasn't been called yet<br>
+    if (i>=d->views.count() || i==0)<br>
+        return;<br>
+//<br>
+    Q_ASSERT(oldPrimary != newPrimary);<br>
+    Q_ASSERT(d->views[0]->screen() != d->views[i]->screen());<br>
+    Q_ASSERT(d->views[0]->screen() == oldPrimary);<br>
+    Q_ASSERT(d->views[0]->screen() != newPrimary);<br>
+    Q_ASSERT(d->views[0]->geometry() == oldPrimary->geometry());<br>
+    qDebug() << "adapting" << newPrimary->geometry() << d->views[0]->containment()->wallpaper()<br>
+                           << oldPrimary->geometry() << d->views[i]->containment()->wallpaper() << i;<br>
+<br>
+    d->views[0]->setScreen(newPrimary);<br>
+    d->views[i]->setScreen(oldPrimary);<br>
+    screenInvariants();<br>
+<br>
+    QList<Plasma::Containment*> panels;<br>
+    foreach(PanelView* panel, d->panelViews) {<br>
+        if(panel->screen() == oldPrimary)<br>
+            panel->setScreen(newPrimary);<br>
+        else if(panel->screen() == newPrimary)<br>
+            panel->setScreen(oldPrimary);<br>
+    }<br>
+}<br>
+<br>
+void ShellCorona::screenInvariants()<br>
+{<br>
+    QScreen* s = outputToScreen(d->screenConfiguration->primaryOutput());<br>
+    Q_ASSERT(d->views[0]->screen()->name() == s->name());<br>
+    Q_ASSERT(d->views[0]->geometry() == s->geometry());<br>
+<br>
+    QSet<QScreen*> screens;<br>
+    foreach(DesktopView* view, d->views) {<br>
+        Q_ASSERT(!screens.contains(view->screen()));<br>
+        screens.insert(view->screen());<br>
+    }<br>
+}<br>
+<br>
+<br>
 void ShellCorona::unload()<br>
 {<br>
     if (d->shell.isEmpty()) {<br>
@@ -356,7 +438,7 @@ QRegion ShellCorona::availableScreenRegion(int id) const<br>
<br>
     if (view) {<br>
         QRegion r = view->geometry();<br>
-        foreach (PanelView *v, d->panelViews.values()) {<br>
+        foreach (PanelView *v, d->panelViews) {<br>
             if (v->containment()->screen() == id && v->visibilityMode() != PanelView::AutoHide) {<br>
                 r -= v->geometry();<br>
             }<br>
@@ -375,7 +457,7 @@ QRect ShellCorona::availableScreenRect(int id) const<br>
<br>
     QRect r(screenGeometry(id));<br>
<br>
-    foreach (PanelView *view, d->panelViews.values()) {<br>
+    foreach (PanelView *view, d->panelViews) {<br>
         if (view->containment()->screen() == id && view->visibilityMode() != PanelView::AutoHide) {<br>
             QRect v = view->geometry();<br>
             switch (view->location()) {<br>
@@ -417,11 +499,13 @@ PanelView *ShellCorona::panelView(Plasma::Containment *containment) const<br>
     return d->panelViews.value(containment);<br>
 }<br>
<br>
-<br>
 ///// SLOTS<br>
<br>
-void ShellCorona::screenAdded(QScreen *screen)<br>
+void ShellCorona::outputAdded(KScreen::Output* output)<br>
 {<br>
+    QScreen* screen = outputToScreen(output);<br>
+    Q_ASSERT(screen);<br>
+<br>
     //FIXME: QScreen doesn't have any idea of "this qscreen is clone of this other one<br>
     //so this ultra inefficient heuristic has to stay until we have a slightly better api<br>
     foreach (QScreen *s, QGuiApplication::screens()) {<br>
@@ -433,16 +517,14 @@ void ShellCorona::screenAdded(QScreen *screen)<br>
     }<br>
<br>
     DesktopView *view = new DesktopView(this, screen);<br>
-    connect(screen, &QObject::destroyed, [=](){<br>
-        d->views.removeAll(view);<br>
-        view->containment()->reactToScreenChange();<br>
-        view->deleteLater();<br>
-    });<br>
<br>
+    //We have to do it in a lambda,<br>
+    connect(screen, &QObject::destroyed, this, [=]() { removeDesktop(view); });<br>
<br>
     const QString currentActivity = d->activityController->currentActivity();<br>
<br>
-    if (!d->views.isEmpty() && screen == QGuiApplication::primaryScreen()) {<br>
+    qDebug() << "adding screen" << output->name() << output->isPrimary();<br>
+    if (!d->views.isEmpty() && output->isPrimary()) {<br>
         DesktopView* oldPrimaryView = d->views.first();<br>
         QScreen* oldPrimaryScreen = oldPrimaryView->screen();<br>
<br>
@@ -462,6 +544,7 @@ void ShellCorona::screenAdded(QScreen *screen)<br>
         d->views.prepend(view);<br>
         view = oldPrimaryView;<br>
     } else {<br>
+        Q_ASSERT(d->views.isEmpty() || !output->isPrimary());<br>
         d->views.append(view);<br>
     }<br>
<br>
@@ -488,8 +571,30 @@ void ShellCorona::screenAdded(QScreen *screen)<br>
<br>
     emit availableScreenRectChanged();<br>
     emit availableScreenRegionChanged();<br>
+<br>
+    screenInvariants();<br>
+}<br>
+<br>
+void ShellCorona::removeDesktop(DesktopView* view)<br>
+{<br>
+    int idx = d->views.indexOf(view);<br>
+    DesktopView* lastView = d->views.takeAt(d->views.count()-1);<br>
+    lastView->containment()->reactToScreenChange();<br>
+    lastView->deleteLater();<br>
+<br>
+    for(int i = idx; i<d->views.count()-1; ++i) {<br>
+        d->views[i]->setScreen(d->views[i+1]->screen());<br>
+    }<br>
+<br>
+    screenInvariants();<br>
 }<br>
<br>
+void ShellCorona::removePanel(Plasma::Containment* cont)<br>
+{<br>
+    d->panelViews[cont]->deleteLater();<br>
+    d->waitingPanels << cont;<br>
+    d->panelViews.remove(cont);<br>
+}<br>
<br>
 Plasma::Containment* ShellCorona::createContainmentForActivity(const QString& activity, int screenNum)<br>
 {<br>
@@ -517,30 +622,32 @@ void ShellCorona::createWaitingPanels()<br>
<br>
     foreach (Plasma::Containment *cont, d->waitingPanels) {<br>
         //ignore non existing (yet?) screens<br>
-        if (cont->lastScreen() > (QGuiApplication::screens().size() - 1)) {<br>
+        int requestedScreen = cont->lastScreen();<br>
+        if (requestedScreen < 0)<br>
+            ++requestedScreen;<br>
+<br>
+        if (requestedScreen > (d->views.size() - 1)) {<br>
             stillWaitingPanels << cont;<br>
             continue;<br>
         }<br>
<br>
         d->panelViews[cont] = new PanelView(cont);<br>
<br>
-        //keep screen suggestions within bounds of screens we actually have<br>
-        int screen = qBound(0, cont->lastScreen(), QGuiApplication::screens().size() -1);<br>
+        Q_ASSERT(qBound(0, requestedScreen, d->views.size() -1) == requestedScreen);<br>
+        QScreen* screen = d->views[requestedScreen]->screen();<br>
<br>
-        d->panelViews[cont]->setScreen(QGuiApplication::screens()[screen]);<br>
+        d->panelViews[cont]->setScreen(screen);<br>
         cont->reactToScreenChange();<br>
         connect(cont, &QObject::destroyed,<br>
-                [=](QObject *obj) {<br>
+                [=](QObject* ) {<br>
                     d->panelViews.remove(cont);<br>
                     emit availableScreenRectChanged();<br>
                     emit availableScreenRegionChanged();<br>
                 });<br>
<br>
-        connect(QGuiApplication::screens()[screen], &QObject::destroyed,<br>
-                [=](QObject *obj) {<br>
-                    d->panelViews[cont]->deleteLater();<br>
-                    d->waitingPanels << cont;<br>
-                    d->panelViews.remove(cont);<br>
+        connect(screen, &QObject::destroyed,<br>
+                [=](QObject*) {<br>
+                    removePanel(cont);<br>
                 });<br>
     }<br>
     d->waitingPanels.clear();<br>
@@ -549,6 +656,8 @@ void ShellCorona::createWaitingPanels()<br>
     emit availableScreenRegionChanged();<br>
 }<br>
<br>
+<br>
+<br>
 void ShellCorona::handleContainmentAdded(Plasma::Containment* c)<br>
 {<br>
     connect(c, &Plasma::Containment::showAddWidgetsInterface,<br>
@@ -883,34 +992,34 @@ void ShellCorona::addPanel(const QString &plugin)<br>
<br>
     d->waitingPanels << panel;<br>
     createWaitingPanels();<br>
-    if (d->panelViews.contains(panel)) {<br>
-        const QPoint cursorPos(QCursor::pos());<br>
-        foreach (QScreen *screen, QGuiApplication::screens()) {<br>
-            if (screen->geometry().contains(cursorPos)) {<br>
-                d->panelViews[panel]->setScreen(screen);<br>
-                break;<br>
-            }<br>
+    Q_ASSERT(d->panelViews.contains(panel));<br>
+    const QPoint cursorPos(QCursor::pos());<br>
+    foreach (QScreen *screen, QGuiApplication::screens()) {<br>
+        if (screen->geometry().contains(cursorPos)) {<br>
+            d->panelViews[panel]->setScreen(screen);<br>
+            break;<br>
         }<br>
     }<br>
 }<br>
<br>
 int ShellCorona::screenForContainment(const Plasma::Containment *containment) const<br>
 {<br>
-    QScreen *screen = nullptr;<br>
     for (int i = 0; i < d->views.size(); i++) {<br>
         if (d->views[i]->containment() == containment) {<br>
-            screen = d->views[i]->screen();<br>
+            return i;<br>
         }<br>
     }<br>
<br>
-    if (!screen) {<br>
-        PanelView *view = d->panelViews.value(containment);<br>
-        if (view) {<br>
-            screen = view->screen();<br>
+    PanelView *view = d->panelViews.value(containment);<br>
+    if (view) {<br>
+        QScreen *screen = view->screen();<br>
+        for (int i = 0; i < d->views.size(); i++) {<br>
+            if (d->views[i]->screen() == screen) {<br>
+                return i;<br>
+            }<br>
         }<br>
     }<br>
-<br>
-    return screen ? qApp->screens().indexOf(screen) : -1;<br>
+    return -1;<br>
 }<br>
<br>
 void ShellCorona::activityOpened()<br>
diff --git a/shell/shellcorona.h b/shell/shellcorona.h<br>
index d71f648..dc74500 100644<br>
--- a/shell/shellcorona.h<br>
+++ b/shell/shellcorona.h<br>
@@ -27,6 +27,9 @@<br>
<br>
 #include <Plasma/Package><br>
<br>
+namespace KScreen {<br>
+class Output;<br>
+}<br>
<br>
 namespace Plasma<br>
 {<br>
@@ -34,6 +37,7 @@ namespace Plasma<br>
 } // namespace Plasma<br>
<br>
 class Activity;<br>
+class DesktopView;<br>
 class PanelView;<br>
 class QScreen;<br>
 namespace WorkspaceScripting {<br>
@@ -102,8 +106,6 @@ public Q_SLOTS:<br>
     void loadScriptInInteractiveConsole(const QString &script);<br>
<br>
 protected Q_SLOTS:<br>
-    void screenAdded(QScreen *screen);<br>
-<br>
     /**<br>
      * Loads the layout and performs the needed checks<br>
      */<br>
@@ -141,11 +143,18 @@ private Q_SLOTS:<br>
     void addPanel(QAction *action);<br>
     void addPanel(const QString &plugin);<br>
<br>
+    void removePanel(Plasma::Containment* cont);<br>
+    void removeDesktop(DesktopView* screen);<br>
+    void outputAdded(KScreen::Output* output);<br>
+    void primaryOutputChanged();<br>
+<br>
     void activityOpened();<br>
     void activityClosed();<br>
     void activityRemoved();<br>
<br>
 private:<br>
+    void screenInvariants();<br>
+<br>
     /**<br>
      * @returns a new containment associated with the specified @p activity and @p screen.<br>
      */<br>
<br>
_______________________________________________<br>
Plasma-devel mailing list<br>
<a href="mailto:Plasma-devel@kde.org" target="_blank">Plasma-devel@kde.org</a><br>
<a href="https://mail.kde.org/mailman/listinfo/plasma-devel" target="_blank">https://mail.kde.org/mailman/listinfo/plasma-devel</a><br>
</blockquote></div><div><br></div>
</div></div></div>