<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>