[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