File indexing completed on 2024-04-28 15:29:11

0001 /*
0002     This file is part of the KDE libraries
0003     SPDX-FileCopyrightText: 2009 Marco Martin <notmart@gmail.com>
0004 
0005     SPDX-License-Identifier: LGPL-2.0-or-later
0006 */
0007 
0008 #ifndef KSTATUSNOTIFIERITEM_H
0009 #define KSTATUSNOTIFIERITEM_H
0010 
0011 #include <QObject>
0012 #include <QPoint>
0013 #include <QString>
0014 
0015 #include <knotifications_export.h>
0016 
0017 #include <memory>
0018 
0019 class QAction;
0020 class QMenu;
0021 
0022 class KStatusNotifierItemPrivate;
0023 
0024 /**
0025  * @class KStatusNotifierItem kstatusnotifieritem.h KStatusNotifierItem
0026  *
0027  * \brief %KDE Status notifier Item protocol implementation
0028  *
0029  * This class implements the Status notifier Item D-Bus specification.
0030  * It provides an icon similar to the classical systemtray icons,
0031  * with some key differences:
0032  *
0033  * - the actual representation is done by the systemtray (or the app behaving
0034  *   like it) itself, not by this app.  Since 4.5 this also includes the menu,
0035  *   which means you cannot use embed widgets in the menu.
0036  *
0037  * - there is communication between the systemtray and the icon owner, so the
0038  *   system tray can know if the application is in a normal or in a requesting
0039  *   attention state.
0040  *
0041  * - icons are divided in categories, so the systemtray can represent in a
0042  *   different way the icons from normal applications and for instance the ones
0043  *   about hardware status.
0044  *
0045  * Whenever possible you should prefer passing icon by name rather than by
0046  * pixmap because:
0047  *
0048  * - it is much lighter on D-Bus (no need to pass all image pixels).
0049  *
0050  * - it makes it possible for the systemtray to load an icon of the appropriate
0051  *   size or to replace your icon with a systemtray specific icon which matches
0052  *   with the desktop theme.
0053  *
0054  * - some implementations of the system tray do not support passing icons by
0055  *   pixmap and will show a blank icon instead.
0056  *
0057  * @author Marco Martin <notmart@gmail.com>
0058  * @since 4.4
0059  */
0060 class KNOTIFICATIONS_EXPORT KStatusNotifierItem : public QObject
0061 {
0062     Q_OBJECT
0063 
0064     Q_PROPERTY(ItemCategory category READ category WRITE setCategory)
0065     Q_PROPERTY(QString title READ title WRITE setTitle)
0066     Q_PROPERTY(ItemStatus status READ status WRITE setStatus)
0067     Q_PROPERTY(QString iconName READ iconName WRITE setIconByName)
0068     Q_PROPERTY(QString overlayIconName READ overlayIconName WRITE setOverlayIconByName)
0069     Q_PROPERTY(QString attentionIconName READ attentionIconName WRITE setAttentionIconByName)
0070     Q_PROPERTY(QString toolTipIconName READ toolTipIconName WRITE setToolTipIconByName)
0071     Q_PROPERTY(QString toolTipTitle READ toolTipTitle WRITE setToolTipTitle)
0072     Q_PROPERTY(QString toolTipSubTitle READ toolTipSubTitle WRITE setToolTipSubTitle)
0073 
0074     friend class KStatusNotifierItemDBus;
0075     friend class KStatusNotifierItemPrivate;
0076 
0077 public:
0078     /**
0079      * All the possible status this icon can have, depending on the
0080      * importance of the events that happens in the parent application
0081      */
0082     enum ItemStatus {
0083         /// Nothing is happening in the application, so showing this icon is not required. This is the default value
0084         Passive = 1,
0085         /// The application is doing something, or it is important that the
0086         /// icon is always reachable from the user
0087         Active = 2,
0088         /// The application requests the attention of the user, for instance
0089         /// battery running out or a new IM message was received
0090         NeedsAttention = 3,
0091     };
0092     Q_ENUM(ItemStatus)
0093 
0094     /**
0095      * Different kinds of applications announce their type to the systemtray,
0096      * so can be drawn in a different way or in a different place
0097      */
0098     enum ItemCategory {
0099         /// An icon for a normal application, can be seen as its taskbar entry. This is the default value
0100         ApplicationStatus = 1,
0101         /// This is a communication oriented application; this icon will be used
0102         /// for things such as the notification of a new message
0103         Communications = 2,
0104         /// This is a system service, it can show itself in the system tray if
0105         /// it requires interaction from the user or wants to inform him about
0106         /// something
0107         SystemServices = 3,
0108         /// This application shows hardware status or a means to control it
0109         Hardware = 4,
0110         Reserved = 129,
0111     };
0112     Q_ENUM(ItemCategory)
0113 
0114     /**
0115      * Construct a new status notifier item
0116      *
0117      * @param parent the parent object for this object. If the object passed in as
0118      * a parent is also a QWidget, it will  be used as the main application window
0119      * represented by this icon and will be shown/hidden when an activation is requested.
0120      * @see associatedWidget
0121      **/
0122     explicit KStatusNotifierItem(QObject *parent = nullptr);
0123 
0124     /**
0125      * Construct a new status notifier item with a unique identifier.
0126      * If your application has more than one status notifier item and the user
0127      * should be able to manipulate them separately (e.g. mark them for hiding
0128      * in a user interface), the id can be used to differentiate between them.
0129      *
0130      * The id should remain consistent even between application restarts.
0131      * Status notifier items without ids default to the application's name for the id.
0132      * This id may be used, for instance, by hosts displaying status notifier items to
0133      * associate configuration information with this item in a way that can persist
0134      * between sessions or application restarts.
0135      *
0136      * @param id the unique id for this icon
0137      * @param parent the parent object for this object. If the object passed in as
0138      * a parent is also a QWidget, it will  be used as the main application window
0139      * represented by this icon and will be shown/hidden when an activation is requested.
0140      * @see associatedWidget
0141      **/
0142     explicit KStatusNotifierItem(const QString &id, QObject *parent = nullptr);
0143 
0144     ~KStatusNotifierItem() override;
0145 
0146     /**
0147      * @return The id which was specified in the constructor. This should be
0148      * guaranteed to be consistent between application starts and
0149      * untranslated, as host applications displaying items may use it for
0150      * storing configuration related to this item.
0151      */
0152     QString id() const;
0153 
0154     /**
0155      * Sets the category for this icon, usually it's needed to call this function only once
0156      *
0157      * @param category the new category for this icon
0158      */
0159     void setCategory(const ItemCategory category);
0160 
0161     /**
0162      * @return the application category
0163      */
0164     ItemCategory category() const;
0165 
0166     /**
0167      * Sets a title for this icon
0168      */
0169     void setTitle(const QString &title);
0170 
0171     /**
0172      * @return the title of this icon
0173      */
0174     QString title() const;
0175 
0176     /**
0177      * Sets a new status for this icon.
0178      */
0179     void setStatus(const ItemStatus status);
0180 
0181     /**
0182      * @return the current application status
0183      */
0184     ItemStatus status() const;
0185 
0186     // Main icon related functions
0187     /**
0188      * Sets a new main icon for the system tray
0189      *
0190      * @param name it must be a QIcon::fromTheme compatible name, this is
0191      * the preferred way to set an icon
0192      */
0193     void setIconByName(const QString &name);
0194 
0195     /**
0196      * @return the name of the main icon to be displayed
0197      * if image() is not empty this will always return an empty string
0198      */
0199     QString iconName() const;
0200 
0201     /**
0202      * Sets a new main icon for the system tray
0203      *
0204      * @param pixmap our icon, use setIcon(const QString) when possible
0205      */
0206     void setIconByPixmap(const QIcon &icon);
0207 
0208     /**
0209      * @return a pixmap of the icon
0210      */
0211     QIcon iconPixmap() const;
0212 
0213     /**
0214      * Sets an icon to be used as overlay for the main one
0215      * @param icon name, if name is and empty QString()
0216      *     (and overlayIconPixmap() is empty too) the icon will be removed
0217      */
0218     void setOverlayIconByName(const QString &name);
0219 
0220     /**
0221      * @return the name of the icon to be used as overlay fr the main one
0222      */
0223     QString overlayIconName() const;
0224 
0225     /**
0226      * Sets an icon to be used as overlay for the main one
0227      *   setOverlayIconByPixmap(QIcon()) will remove the overlay when
0228      *   overlayIconName() is empty too.
0229      *
0230      * @param pixmap our overlay icon, use setOverlayIcon(const QString) when possible.
0231      */
0232     void setOverlayIconByPixmap(const QIcon &icon);
0233 
0234     /**
0235      * @return a pixmap of the icon
0236      */
0237     QIcon overlayIconPixmap() const;
0238 
0239     // Requesting attention icon
0240 
0241     /**
0242      * Sets a new icon that should be used when the application
0243      * wants to request attention (usually the systemtray
0244      * will blink between this icon and the main one)
0245      *
0246      * @param name QIcon::fromTheme compatible name of icon to use
0247      */
0248     void setAttentionIconByName(const QString &name);
0249 
0250     /**
0251      * @return the name of the icon to be displayed when the application
0252      * is requesting the user's attention
0253      * if attentionImage() is not empty this will always return an empty string
0254      */
0255     QString attentionIconName() const;
0256 
0257     /**
0258      * Sets the pixmap of the requesting attention icon.
0259      * Use setAttentionIcon(const QString) instead when possible.
0260      *
0261      * @param icon QIcon to use for requesting attention.
0262      */
0263     void setAttentionIconByPixmap(const QIcon &icon);
0264 
0265     /**
0266      * @return a pixmap of the requesting attention icon
0267      */
0268     QIcon attentionIconPixmap() const;
0269 
0270     /**
0271      * Sets a movie as the requesting attention icon.
0272      * This overrides anything set in setAttentionIcon()
0273      */
0274     void setAttentionMovieByName(const QString &name);
0275 
0276     /**
0277      * @return the name of the movie to be displayed when the application is
0278      * requesting the user attention
0279      */
0280     QString attentionMovieName() const;
0281 
0282     // ToolTip handling
0283     /**
0284      * Sets a new toolTip or this icon, a toolTip is composed of an icon,
0285      * a title and a text, all fields are optional.
0286      *
0287      * @param iconName a QIcon::fromTheme compatible name for the tootip icon
0288      * @param title tootip title
0289      * @param subTitle subtitle for the toolTip
0290      */
0291     void setToolTip(const QString &iconName, const QString &title, const QString &subTitle);
0292 
0293     /**
0294      * Sets a new toolTip or this status notifier item.
0295      * This is an overloaded member provided for convenience
0296      */
0297     void setToolTip(const QIcon &icon, const QString &title, const QString &subTitle);
0298 
0299     /**
0300      * Set a new icon for the toolTip
0301      *
0302      * @param name the name for the icon
0303      */
0304     void setToolTipIconByName(const QString &name);
0305 
0306     /**
0307      * @return the name of the toolTip icon
0308      * if toolTipImage() is not empty this will always return an empty string
0309      */
0310     QString toolTipIconName() const;
0311 
0312     /**
0313      * Set a new icon for the toolTip.
0314      *
0315      * Use setToolTipIconByName(QString) if possible.
0316      * @param pixmap representing the icon
0317      */
0318     void setToolTipIconByPixmap(const QIcon &icon);
0319 
0320     /**
0321      * @return a serialization of the toolTip icon data
0322      */
0323     QIcon toolTipIconPixmap() const;
0324 
0325     /**
0326      * Sets a new title for the toolTip
0327      */
0328     void setToolTipTitle(const QString &title);
0329 
0330     /**
0331      * @return the title of the main icon toolTip
0332      */
0333     QString toolTipTitle() const;
0334 
0335     /**
0336      * Sets a new subtitle for the toolTip
0337      */
0338     void setToolTipSubTitle(const QString &subTitle);
0339 
0340     /**
0341      * @return the subtitle of the main icon toolTip
0342      */
0343     QString toolTipSubTitle() const;
0344 
0345     /**
0346      * Sets a new context menu for this StatusNotifierItem.
0347      * the menu will be shown with a contextMenu(int,int)
0348      * call by the systemtray over D-Bus
0349      * usually you don't need to call this unless you want to use
0350      * a custom QMenu subclass as context menu.
0351      *
0352      * The KStatusNotifierItem instance takes ownership of the menu,
0353      * and will delete it upon its destruction.
0354      */
0355     void setContextMenu(QMenu *menu);
0356 
0357     /**
0358      * Access the context menu associated to this status notifier item
0359      */
0360     QMenu *contextMenu() const;
0361 
0362     /**
0363      * Sets the main widget associated with this StatusNotifierItem
0364      *
0365      * If you pass contextMenu() as a parent then the menu will be displayed
0366      * when the user activate the icon. In this case the activate() method will
0367      * not be called and the activateRequested() signal will not be emitted
0368      *
0369      * @param parent the new main widget: must be a top level window,
0370      *               if it's not parent->window() will be used instead.
0371      */
0372     void setAssociatedWidget(QWidget *parent);
0373 
0374     /**
0375      * Access the main widget associated with this StatusNotifierItem
0376      */
0377     QWidget *associatedWidget() const;
0378 
0379     /**
0380      * All the actions present in the menu
0381      */
0382     QList<QAction *> actionCollection() const;
0383 
0384     /**
0385      * Adds an action to the actionCollection()
0386      *
0387      * @param name the name of the action
0388      * @param action the action we want to add
0389      */
0390     void addAction(const QString &name, QAction *action);
0391 
0392     /**
0393      * Removes an action from the collection
0394      *
0395      * @param name the name of the action
0396      */
0397     void removeAction(const QString &name);
0398 
0399     /**
0400      * Retrieves an action from the action collection
0401      * by the action name
0402      *
0403      * @param name the name of the action to retrieve
0404      * @since 5.12
0405      */
0406     QAction *action(const QString &name) const;
0407 
0408     /**
0409      * Sets whether to show the standard items in the menu, such as Quit
0410      */
0411     void setStandardActionsEnabled(bool enabled);
0412 
0413     /**
0414      * @return if the standard items in the menu, such as Quit
0415      */
0416     bool standardActionsEnabled() const;
0417 
0418     /**
0419      * Shows the user a notification. If possible use KNotify instead
0420      *
0421      * @param title message title
0422      * @param message the actual text shown to the user
0423      * @param icon icon to be shown to the user
0424      * @param timeout how much time will elaps before hiding the message
0425      */
0426     void showMessage(const QString &title, const QString &message, const QString &icon, int timeout = 10000);
0427 
0428     /**
0429      * @return the last provided token to be used with Wayland's xdg_activation_v1
0430      */
0431     QString providedToken() const;
0432 
0433 public Q_SLOTS:
0434 
0435     /**
0436      * Shows the main widget and try to position it on top
0437      * of the other windows, if the widget is already visible, hide it.
0438      *
0439      * @param pos if it's a valid position it represents the mouse coordinates when the event was triggered
0440      */
0441     virtual void activate(const QPoint &pos = QPoint());
0442 
0443     /**
0444      * Hides the main widget, if not already hidden.
0445      *
0446      * Stores some information about the window which otherwise would be lost due to unmapping
0447      * from the window system. Use when toggling the main widget via activate(const QPoint &)
0448      * is not wanted, but instead the hidden state should be reached in any case.
0449      *
0450      * @since 5.91
0451      */
0452     void hideAssociatedWidget();
0453 
0454 Q_SIGNALS:
0455     /**
0456      * Inform the host application that the mouse wheel
0457      * (or another mean of scrolling that the visualization provides) has been used
0458      *
0459      * @param delta the amount of scrolling, can be either positive or negative
0460      * @param orientation direction of the scrolling, can be either horizontal or vertical
0461      */
0462     void scrollRequested(int delta, Qt::Orientation orientation);
0463 
0464     /**
0465      * Inform the host application that an activation has been requested,
0466      *           for instance left mouse click, but this is not guaranteed since
0467      *           it's dependent from the visualization
0468      * @param active if it's true the application asked for the activation
0469      *              of the main window, if it's false it asked for hiding
0470      * @param pos the position in the screen where the user clicked to
0471      *  trigger this signal, QPoint() if it's not the consequence of a mouse click.
0472      */
0473     void activateRequested(bool active, const QPoint &pos);
0474 
0475     /**
0476      * Alternate activate action,
0477      * for instance right mouse click, but this is not guaranteed since
0478      * it's dependent from the visualization
0479      *
0480      * @param pos the position in the screen where the user clicked to
0481      *  trigger this signal, QPoint() if it's not the consequence of a mouse click.
0482      */
0483     void secondaryActivateRequested(const QPoint &pos);
0484 
0485 protected:
0486     bool eventFilter(QObject *watched, QEvent *event) override;
0487 
0488 private:
0489     std::unique_ptr<KStatusNotifierItemPrivate> const d;
0490 
0491     Q_PRIVATE_SLOT(d, void serviceChange(const QString &name, const QString &oldOwner, const QString &newOwner))
0492     Q_PRIVATE_SLOT(d, void contextMenuAboutToShow())
0493     Q_PRIVATE_SLOT(d, void maybeQuit())
0494     Q_PRIVATE_SLOT(d, void minimizeRestore())
0495     Q_PRIVATE_SLOT(d, void legacyWheelEvent(int))
0496     Q_PRIVATE_SLOT(d, void legacyActivated(QSystemTrayIcon::ActivationReason))
0497 };
0498 
0499 #endif