diff --git a/screens.cpp b/screens.cpp index df119f649..e0cbb9d61 100644 --- a/screens.cpp +++ b/screens.cpp @@ -1,320 +1,249 @@ /******************************************************************** KWin - the KDE window manager This file is part of the KDE project. Copyright (C) 2013 Martin Gräßlin 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 2 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 . *********************************************************************/ #include "screens.h" #include #include #include "cursor.h" #include "orientation_sensor.h" #include "utils.h" #include "settings.h" #include #include #include "platform.h" #include "wayland_server.h" #ifdef KWIN_UNIT_TEST #include #endif namespace KWin { Screens *Screens::s_self = nullptr; Screens *Screens::create(QObject *parent) { Q_ASSERT(!s_self); #ifdef KWIN_UNIT_TEST s_self = new MockScreens(parent); #else s_self = kwinApp()->platform()->createScreens(parent); #endif Q_ASSERT(s_self); s_self->init(); return s_self; } Screens::Screens(QObject *parent) : QObject(parent) , m_count(0) , m_current(0) , m_currentFollowsMouse(false) , m_changedTimer(new QTimer(this)) , m_orientationSensor(new OrientationSensor(this)) , m_maxScale(1.0) { connect(this, &Screens::changed, this, [this] { int internalIndex = -1; for (int i = 0; i < m_count; i++) { if (isInternal(i)) { internalIndex = i; break; } } m_orientationSensor->setEnabled(internalIndex != -1 && supportsTransformations(internalIndex)); } ); } Screens::~Screens() { s_self = NULL; } void Screens::init() { m_changedTimer->setSingleShot(true); m_changedTimer->setInterval(100); connect(m_changedTimer, SIGNAL(timeout()), SLOT(updateCount())); connect(m_changedTimer, SIGNAL(timeout()), SIGNAL(changed())); connect(this, &Screens::countChanged, this, &Screens::changed, Qt::QueuedConnection); connect(this, &Screens::changed, this, &Screens::updateSize); connect(this, &Screens::sizeChanged, this, &Screens::geometryChanged); Settings settings; settings.setDefaults(); m_currentFollowsMouse = settings.activeMouseScreen(); } QString Screens::name(int screen) const { Q_UNUSED(screen) qCWarning(KWIN_CORE, "%s::name(int screen) is a stub, please reimplement it!", metaObject()->className()); return QLatin1String("DUMMY"); } float Screens::refreshRate(int screen) const { Q_UNUSED(screen) qCWarning(KWIN_CORE, "%s::refreshRate(int screen) is a stub, please reimplement it!", metaObject()->className()); return 60.0f; } qreal Screens::maxScale() const { return m_maxScale; } qreal Screens::scale(int screen) const { Q_UNUSED(screen) return 1; } void Screens::reconfigure() { if (!m_config) { return; } Settings settings(m_config); settings.read(); setCurrentFollowsMouse(settings.activeMouseScreen()); } void Screens::updateSize() { QRect bounding; qreal maxScale = 1.0; for (int i = 0; i < count(); ++i) { bounding = bounding.united(geometry(i)); maxScale = qMax(maxScale, scale(i)); } if (m_boundingSize != bounding.size()) { m_boundingSize = bounding.size(); emit sizeChanged(); } if (!qFuzzyCompare(m_maxScale, maxScale)) { m_maxScale = maxScale; emit maxScaleChanged(); } } void Screens::setCount(int count) { if (m_count == count) { return; } const int previous = m_count; m_count = count; emit countChanged(previous, count); } void Screens::setCurrent(int current) { if (m_current == current) { return; } m_current = current; emit currentChanged(); } void Screens::setCurrent(const QPoint &pos) { setCurrent(number(pos)); } void Screens::setCurrent(const AbstractClient *c) { if (!c->isActive()) { return; } if (!c->isOnScreen(m_current)) { setCurrent(c->screen()); } } void Screens::setCurrentFollowsMouse(bool follows) { if (m_currentFollowsMouse == follows) { return; } m_currentFollowsMouse = follows; } int Screens::current() const { if (m_currentFollowsMouse) { return number(Cursor::pos()); } AbstractClient *client = Workspace::self()->activeClient(); if (client && !client->isOnScreen(m_current)) { return client->screen(); } return m_current; } int Screens::intersecting(const QRect &r) const { int cnt = 0; for (int i = 0; i < count(); ++i) { if (geometry(i).intersects(r)) { ++cnt; } } return cnt; } QSize Screens::displaySize() const { return size(); } QSizeF Screens::physicalSize(int screen) const { return QSizeF(size(screen)) / 3.8; } bool Screens::isInternal(int screen) const { Q_UNUSED(screen) return false; } bool Screens::supportsTransformations(int screen) const { Q_UNUSED(screen) return false; } Qt::ScreenOrientation Screens::orientation(int screen) const { Q_UNUSED(screen) return Qt::PrimaryOrientation; } void Screens::setConfig(KSharedConfig::Ptr config) { m_config = config; if (m_orientationSensor) { m_orientationSensor->setConfig(config); } } -BasicScreens::BasicScreens(Platform *backend, QObject *parent) - : Screens(parent) - , m_backend(backend) -{ -} - -BasicScreens::~BasicScreens() = default; - -void BasicScreens::init() -{ - updateCount(); - KWin::Screens::init(); -#ifndef KWIN_UNIT_TEST - connect(m_backend, &Platform::screenSizeChanged, - this, &BasicScreens::startChangedTimer); -#endif - emit changed(); -} - -QRect BasicScreens::geometry(int screen) const -{ - if (screen < m_geometries.count()) { - return m_geometries.at(screen); - } - return QRect(); -} - -QSize BasicScreens::size(int screen) const -{ - if (screen < m_geometries.count()) { - return m_geometries.at(screen).size(); - } - return QSize(); -} - -qreal BasicScreens::scale(int screen) const -{ - if (screen < m_scales.count()) { - return m_scales.at(screen); - } - return 1; -} - -void BasicScreens::updateCount() -{ - m_geometries = m_backend->screenGeometries(); - m_scales = m_backend->screenScales(); - setCount(m_geometries.count()); -} - -int BasicScreens::number(const QPoint &pos) const -{ - int bestScreen = 0; - int minDistance = INT_MAX; - for (int i = 0; i < m_geometries.count(); ++i) { - const QRect &geo = m_geometries.at(i); - if (geo.contains(pos)) { - return i; - } - int distance = QPoint(geo.topLeft() - pos).manhattanLength(); - distance = qMin(distance, QPoint(geo.topRight() - pos).manhattanLength()); - distance = qMin(distance, QPoint(geo.bottomRight() - pos).manhattanLength()); - distance = qMin(distance, QPoint(geo.bottomLeft() - pos).manhattanLength()); - if (distance < minDistance) { - minDistance = distance; - bestScreen = i; - } - } - return bestScreen; -} - } // namespace diff --git a/screens.h b/screens.h index 45120e889..9b5532968 100644 --- a/screens.h +++ b/screens.h @@ -1,278 +1,255 @@ /******************************************************************** KWin - the KDE window manager This file is part of the KDE project. Copyright (C) 2013 Martin Gräßlin 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 2 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 . *********************************************************************/ #ifndef KWIN_SCREENS_H #define KWIN_SCREENS_H // KWin includes #include // KDE includes #include #include // Qt includes #include #include #include #include namespace KWin { class AbstractClient; class Platform; class OrientationSensor; class KWIN_EXPORT Screens : public QObject { Q_OBJECT Q_PROPERTY(int count READ count WRITE setCount NOTIFY countChanged) Q_PROPERTY(int current READ current WRITE setCurrent NOTIFY currentChanged) Q_PROPERTY(bool currentFollowsMouse READ isCurrentFollowsMouse WRITE setCurrentFollowsMouse) public: virtual ~Screens(); /** * @internal **/ void setConfig(KSharedConfig::Ptr config); int count() const; int current() const; void setCurrent(int current); /** * Called e.g. when a user clicks on a window, set current screen to be the screen * where the click occurred **/ void setCurrent(const QPoint &pos); /** * Check whether a client moved completely out of what's considered the current screen, * if yes, set a new active screen. **/ void setCurrent(const AbstractClient *c); bool isCurrentFollowsMouse() const; void setCurrentFollowsMouse(bool follows); virtual QRect geometry(int screen) const = 0; /** * The bounding geometry of all screens combined. Overlapping areas * are not counted multiple times. * @see geometryChanged() **/ QRect geometry() const; /** * The output name of the screen (usually eg. LVDS-1, VGA-0 or DVI-I-1 etc.) **/ virtual QString name(int screen) const; /** * @returns current refreshrate of the @p screen. **/ virtual float refreshRate(int screen) const; /** * @returns size of the @p screen. * * To get the size of all screens combined use size(). * @see size() **/ virtual QSize size(int screen) const = 0; /** * The highest scale() of all connected screens * for use when deciding what scale to load global assets at * Similar to QGuiApplication::scale * @see scale **/ qreal maxScale() const; /** * The output scale for this display, for use by high DPI displays **/ virtual qreal scale(int screen) const; /** * The bounding size of all screens combined. Overlapping areas * are not counted multiple times. * * @see geometry() * @see sizeChanged() **/ QSize size() const; virtual int number(const QPoint &pos) const = 0; inline bool isChanging() { return m_changedTimer->isActive(); } int intersecting(const QRect &r) const; /** * The virtual bounding size of all screens combined. * The default implementation returns the same as @ref size and that is the * method which should be preferred. * * This method is only for cases where the platform specific implementation needs * to support different virtual sizes like on X11 with XRandR panning. * * @see size **/ virtual QSize displaySize() const; /** * The physical size of @p screen in mm. * Default implementation returns a size derived from 96 DPI. **/ virtual QSizeF physicalSize(int screen) const; /** * @returns @c true if the @p screen is connected through an internal display (e.g. LVDS). * Default implementation returns @c false. **/ virtual bool isInternal(int screen) const; /** * @returns @c true if the @p screen can be rotated. * Default implementation returns @c false **/ virtual bool supportsTransformations(int screen) const; virtual Qt::ScreenOrientation orientation(int screen) const; /** * Provides access to the OrientationSensor. The OrientationSensor is controlled by the * base implementation. The implementing subclass can use this to get notifications about * changes of the orientation and current orientation. There is no need to enable/disable it, * that is done by the base implementation **/ OrientationSensor *orientationSensor() const { return m_orientationSensor; } public Q_SLOTS: void reconfigure(); Q_SIGNALS: void countChanged(int previousCount, int newCount); /** * Emitted whenever the screens are changed either count or geometry. **/ void changed(); void currentChanged(); /** * Emitted when the geometry of all screens combined changes. * Not emitted when the geometry of an individual screen changes. * @see geometry() **/ void geometryChanged(); /** * Emitted when the size of all screens combined changes. * Not emitted when the size of an individual screen changes. * @see size() **/ void sizeChanged(); /** * Emitted when the maximum scale of all attached screens changes * @see maxScale **/ void maxScaleChanged(); protected Q_SLOTS: void setCount(int count); void startChangedTimer(); virtual void updateCount() = 0; protected: /** * Called once the singleton instance has been created. * Any initialization code should go into this method. Overriding classes have to call * the base implementation first. **/ virtual void init(); private Q_SLOTS: void updateSize(); private: int m_count; int m_current; bool m_currentFollowsMouse; QTimer *m_changedTimer; KSharedConfig::Ptr m_config; QSize m_boundingSize; OrientationSensor *m_orientationSensor; qreal m_maxScale; KWIN_SINGLETON(Screens) }; -/** - * @brief A base implementation for backends with just a (nested) window - **/ -class KWIN_EXPORT BasicScreens : public Screens -{ - Q_OBJECT -public: - BasicScreens(Platform *backend, QObject *parent = nullptr); - virtual ~BasicScreens(); - - void init() override; - QRect geometry(int screen) const override; - int number(const QPoint &pos) const override; - QSize size(int screen) const override; - qreal scale(int screen) const override; - void updateCount() override; - -private: - Platform *m_backend; - QVector m_geometries; - QVector m_scales; -}; - inline int Screens::count() const { return m_count; } inline bool Screens::isCurrentFollowsMouse() const { return m_currentFollowsMouse; } inline void Screens::startChangedTimer() { m_changedTimer->start(); } inline QSize Screens::size() const { return m_boundingSize; } inline QRect Screens::geometry() const { return QRect(QPoint(0,0), size()); } inline Screens *screens() { return Screens::self(); } } #endif // KWIN_SCREENS_H