File indexing completed on 2024-04-28 16:55:02

0001 /*
0002     SPDX-FileCopyrightText: 2008 Aaron Seigo <aseigo@kde.org>
0003     SPDX-FileCopyrightText: 2013 Sebastian Kügler <sebas@kde.org>
0004     SPDX-FileCopyrightText: 2013 Ivan Cukic <ivan.cukic@kde.org>
0005     SPDX-FileCopyrightText: 2013 Marco Martin <mart@kde.org>
0006 
0007     SPDX-License-Identifier: LGPL-2.0-or-later
0008 */
0009 
0010 #pragma once
0011 
0012 #include "config-X11.h"
0013 #include "plasma/corona.h"
0014 
0015 #include <QDBusContext>
0016 #include <QDBusVariant>
0017 #include <QPointer>
0018 #include <QSet>
0019 #include <QTimer>
0020 
0021 #include <KConfigWatcher>
0022 #include <KPackage/Package>
0023 
0024 class DesktopView;
0025 class PanelView;
0026 class QMenu;
0027 class QScreen;
0028 class ScreenPool;
0029 class StrutManager;
0030 class ShellContainmentConfig;
0031 
0032 namespace KActivities
0033 {
0034 class Controller;
0035 } // namespace KActivities
0036 
0037 namespace KDeclarative
0038 {
0039 class QmlObjectSharedEngine;
0040 } // namespace KDeclarative
0041 
0042 namespace KScreen
0043 {
0044 class Output;
0045 } // namespace KScreen
0046 
0047 namespace Plasma
0048 {
0049 class Applet;
0050 } // namespace Plasma
0051 
0052 namespace KWayland
0053 {
0054 namespace Client
0055 {
0056 class PlasmaShell;
0057 class PlasmaShellSurface;
0058 class PlasmaWindow;
0059 class PlasmaWindowManagement;
0060 }
0061 }
0062 
0063 class ShellCorona : public Plasma::Corona, QDBusContext
0064 {
0065     Q_OBJECT
0066     Q_PROPERTY(QString shell READ shell WRITE setShell)
0067     Q_PROPERTY(int numScreens READ numScreens)
0068     Q_CLASSINFO("D-Bus Interface", "org.kde.PlasmaShell")
0069 
0070 public:
0071     explicit ShellCorona(QObject *parent = nullptr);
0072     ~ShellCorona() override;
0073 
0074     KPackage::Package lookAndFeelPackage();
0075     void init();
0076 
0077     /**
0078      * Where to save global configuration that doesn't have anything to do with the scene (e.g. views)
0079      */
0080     KSharedConfig::Ptr applicationConfig();
0081 
0082     int numScreens() const override;
0083     Q_INVOKABLE QRect screenGeometry(int id) const override;
0084     Q_INVOKABLE QRegion availableScreenRegion(int id) const override;
0085     Q_INVOKABLE QRect availableScreenRect(int id) const override;
0086 
0087     // plasmashellCorona's value
0088     QRegion _availableScreenRegion(int id) const;
0089     QRect _availableScreenRect(int id) const;
0090 
0091     Q_INVOKABLE QStringList availableActivities() const;
0092 
0093     PanelView *panelView(Plasma::Containment *containment) const;
0094     void savePreviousWindow();
0095     void restorePreviousWindow();
0096     void clearPreviousWindow();
0097 
0098     // This one is a bit of an hack but are just for desktop scripting
0099     void insertActivity(const QString &id, const QString &plugin);
0100 
0101     Plasma::Containment *setContainmentTypeForScreen(int screen, const QString &plugin);
0102 
0103     void removeDesktop(DesktopView *desktopView);
0104 
0105     /**
0106      * @returns a new containment associated with the specified @p activity and @p screen.
0107      */
0108     Plasma::Containment *createContainmentForActivity(const QString &activity, int screenNum);
0109 
0110     KWayland::Client::PlasmaShell *waylandPlasmaShellInterface() const;
0111 
0112     ScreenPool *screenPool() const;
0113 
0114     QList<int> screenIds() const;
0115 
0116     QString defaultContainmentPlugin() const;
0117 
0118     static QString defaultShell();
0119 
0120     // Set all Desktop containments (for all activities) associated to a given screen to this new screen.
0121     // swapping ones that had newScreen to oldScreen if existing. Panels are ignored
0122     void swapDesktopScreens(int oldScreen, int newScreen);
0123 
0124     // Set a single containment to a new screen.
0125     // If it is a Desktop contaiment, swap it with the other containment that was associated with same screen and activity if existent
0126     void setScreenForContainment(Plasma::Containment *containment, int screen);
0127 
0128     // Grab a screenshot of the contaiment if it has a view in an async fashion
0129     // containmentPreviewReady will be emitted when done
0130     // If there is no view, this will have no effect
0131     void grabContainmentPreview(Plasma::Containment *containment);
0132 
0133     // If a containment preview has been grabbed, for this containment, return its path
0134     QString containmentPreviewPath(Plasma::Containment *containment) const;
0135 
0136     /**
0137      * Whether "accent color from wallpaper" option is enabled in global settings
0138      */
0139     bool accentColorFromWallpaperEnabled() const;
0140 
0141 Q_SIGNALS:
0142     void glInitializationFailed();
0143     // A preview for this containment has been rendered and saved to disk
0144     void containmentPreviewReady(Plasma::Containment *containment, const QString &path);
0145     void accentColorFromWallpaperEnabledChanged();
0146     void colorChanged(const QColor &color);
0147     // This API is used only by autotests, do we need something else?
0148     void screenOrderChanged(QList<QScreen *> screens);
0149 
0150 public Q_SLOTS:
0151     /**
0152      * Request saving applicationConfig on disk, it's event compressed, not immediate
0153      */
0154     void requestApplicationConfigSync();
0155 
0156     /**
0157      * Cycle through all panels
0158      */
0159     void slotCyclePanelFocus();
0160 
0161     /**
0162      * Sets the shell that the corona should display
0163      */
0164     void setShell(const QString &shell);
0165 
0166     /**
0167      * Gets the currently shown shell
0168      */
0169     QString shell() const;
0170 
0171     /// DBUS methods
0172     void toggleDashboard();
0173     void setDashboardShown(bool show);
0174     void toggleActivityManager();
0175     void toggleWidgetExplorer();
0176     QString evaluateScript(const QString &string);
0177     void activateLauncherMenu();
0178     QRgb color() const;
0179 
0180     QByteArray dumpCurrentLayoutJS() const;
0181 
0182     /**
0183      * loads the shell layout from a look and feel package,
0184      * resetting it to the default layout exported in the
0185      * look and feel package
0186      */
0187     void loadLookAndFeelDefaultLayout(const QString &layout);
0188 
0189     Plasma::Containment *addPanel(const QString &plugin);
0190 
0191     void nextActivity();
0192     void previousActivity();
0193     void stopCurrentActivity();
0194 
0195     void setTestModeLayout(const QString &layout)
0196     {
0197         m_testModeLayout = layout;
0198     }
0199 
0200     int panelCount() const
0201     {
0202         return m_panelViews.count();
0203     }
0204 
0205     void refreshCurrentShell();
0206 
0207 protected Q_SLOTS:
0208     /**
0209      * Loads the layout and performs the needed checks
0210      */
0211     void load();
0212 
0213     /**
0214      * Unloads everything
0215      */
0216     void unload();
0217 
0218     /**
0219      * Loads the default (system wide) layout for this user
0220      **/
0221     void loadDefaultLayout() override;
0222 
0223     /**
0224      * Execute any update script
0225      */
0226     void processUpdateScripts();
0227 
0228     int screenForContainment(const Plasma::Containment *containment) const override;
0229 
0230     void showAlternativesForApplet(Plasma::Applet *applet);
0231 
0232 private Q_SLOTS:
0233     void createWaitingPanels();
0234     void handleContainmentAdded(Plasma::Containment *c);
0235     void syncAppConfig();
0236     void checkActivities();
0237     void currentActivityChanged(const QString &newActivity);
0238     void activityAdded(const QString &id);
0239     void activityRemoved(const QString &id);
0240     void checkAddPanelAction();
0241     void addPanel();
0242     void addPanel(QAction *action);
0243     void populateAddPanelsMenu();
0244 
0245     void addOutput(QScreen *screen);
0246 
0247     void panelContainmentDestroyed(QObject *cont);
0248     void handleScreenRemoved(QScreen *screen);
0249     void handleScreenOrderChanged(QList<QScreen *> screens);
0250 
0251     void activateTaskManagerEntry(int index);
0252 
0253 private:
0254     void sanitizeScreenLayout(const QString &configFileName);
0255     void updateStruts();
0256     void configurationChanged(const QString &path);
0257     DesktopView *desktopForScreen(QScreen *screen) const;
0258     void setupWaylandIntegration();
0259     void executeSetupPlasmoidScript(Plasma::Containment *containment, Plasma::Applet *applet);
0260     void checkAllDesktopsUiReady(bool ready);
0261     void activateLauncherMenu(const QString &screenName);
0262     void handleColorRequestedFromDBus(const QDBusMessage &msg);
0263 
0264 #ifndef NDEBUG
0265     void screenInvariants() const;
0266 #endif
0267 
0268     KSharedConfig::Ptr m_config;
0269     QString m_configPath;
0270 
0271     // Accent color setting
0272     KConfigWatcher::Ptr m_accentColorConfigWatcher;
0273     bool m_accentColorFromWallpaperEnabled = false;
0274     QMetaObject::Connection m_fakeColorRequestConn;
0275 
0276     ScreenPool *m_screenPool;
0277     QString m_shell;
0278     KActivities::Controller *m_activityController;
0279     QMap<const Plasma::Containment *, PanelView *> m_panelViews;
0280     // map from QScreen to desktop view
0281     QHash<int, DesktopView *> m_desktopViewForScreen;
0282     QHash<const Plasma::Containment *, int> m_pendingScreenChanges;
0283     KConfigGroup m_desktopDefaultsConfig;
0284     KConfigGroup m_lnfDefaultsConfig;
0285     QList<Plasma::Containment *> m_waitingPanels;
0286     QHash<QString, QString> m_activityContainmentPlugins;
0287     QAction *m_addPanelAction;
0288     std::unique_ptr<QMenu> m_addPanelsMenu;
0289     KPackage::Package m_lookAndFeelPackage;
0290 
0291     // Used to restore the previous activated window after the panel loses focus
0292     KWayland::Client::PlasmaShellSurface *m_shellSurface = nullptr;
0293 #if HAVE_X11
0294     WId m_previousWId = 0;
0295 #endif
0296     bool m_blockRestorePreviousWindow = false;
0297 
0298     QTimer m_waitingPanelsTimer;
0299     QTimer m_appConfigSyncTimer;
0300 #ifndef NDEBUG
0301     QTimer m_invariantsTimer;
0302 #endif
0303     KWayland::Client::PlasmaShell *m_waylandPlasmaShell;
0304     // For getting the active window on Wayland
0305     KWayland::Client::PlasmaWindowManagement *m_waylandWindowManagement = nullptr;
0306     QPointer<KWayland::Client::PlasmaWindow> m_previousPlasmaWindow;
0307     bool m_closingDown : 1;
0308     bool m_screenReorderInProgress = false;
0309     QString m_testModeLayout;
0310 
0311     StrutManager *m_strutManager;
0312     QPointer<ShellContainmentConfig> m_shellContainmentConfig;
0313     friend class ShellTest;
0314 };