File indexing completed on 2024-04-21 05:36:06

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