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