File indexing completed on 2025-01-19 03:56:07

0001 /* ============================================================
0002  *
0003  * This file is a part of digiKam project
0004  * https://www.digikam.org
0005  *
0006  * Date        : 2008-07-03
0007  * Description : A wrapper send desktop notifications
0008  *
0009  * SPDX-FileCopyrightText: 2009-2024 by Gilles Caulier <caulier dot gilles at gmail dot com>
0010  * SPDX-FileCopyrightText: 2009-2011 by Michael G. Hansen <mike at mghansen dot de>
0011  *
0012  * SPDX-License-Identifier: GPL-2.0-or-later
0013  *
0014  * ============================================================ */
0015 
0016 #include "dnotificationwrapper.h"
0017 #include "digikam_config.h"
0018 
0019 // Qt includes
0020 
0021 #include <QProcess>
0022 #include <QApplication>
0023 #include <QStandardPaths>
0024 #include <QIcon>
0025 
0026 #ifdef HAVE_DBUS
0027 #   include <QDBusConnection>
0028 #   include <QDBusConnectionInterface>
0029 #endif
0030 
0031 // KDE includes
0032 
0033 #ifdef HAVE_KNOTIFICATIONS
0034 #    include <knotification.h>
0035 #endif
0036 
0037 // Local includes
0038 
0039 #include "digikam_debug.h"
0040 #include "digikam_globals.h"
0041 #include "dnotificationpopup.h"
0042 
0043 namespace Digikam
0044 {
0045 
0046 /**
0047  * Re-implementation of DNotificationPopup to move pop-up notification
0048  * window on the bottom right corner of parent window. The goal is to simulate
0049  * the position of KDE notifier pop-up from task bar if this one is not available,
0050  * as for ex under Windows, Gnome, or using a remote connection through ssh.
0051  */
0052 class Q_DECL_HIDDEN NotificationPassivePopup : public DNotificationPopup
0053 {
0054     Q_OBJECT
0055 
0056 public:
0057 
0058     explicit NotificationPassivePopup(QWidget* const parent)
0059         : DNotificationPopup(parent),
0060           m_parent          (parent)
0061     {
0062     }
0063 
0064     void showNotification(const QString& caption, const QString& text, const QPixmap& icon)
0065     {
0066         setView(caption, text, icon);
0067         QPoint ppos = m_parent->pos();
0068         QSize psize = m_parent->frameSize();
0069         int offsetx = minimumSizeHint().width()  + 30;
0070         int offsety = minimumSizeHint().height() + 30;
0071         show(QPoint(ppos.x() + psize.width()  - offsetx,
0072                     ppos.y() + psize.height() - offsety));
0073     }
0074 
0075 private:
0076 
0077     QWidget* m_parent = nullptr;
0078 };
0079 
0080 // ----------------------------------------------------------------------------------------------
0081 
0082 #if defined HAVE_KNOTIFICATIONS && defined HAVE_DBUS
0083 
0084 static inline bool detectKDEDesktopIsRunning()
0085 {
0086     const QByteArray xdgCurrentDesktop = qgetenv("XDG_CURRENT_DESKTOP");
0087 
0088     if (!xdgCurrentDesktop.isEmpty())
0089     {
0090         return (xdgCurrentDesktop.toUpper() == "KDE");
0091     }
0092 
0093     // Classic fallbacks
0094 
0095     if (!qEnvironmentVariableIsEmpty("KDE_FULL_SESSION"))
0096     {
0097         return true;
0098     }
0099 
0100     return false;
0101 }
0102 
0103 #endif
0104 
0105 // ----------------------------------------------------------------------------------------------
0106 
0107 void DNotificationWrapper(const QString& eventId, const QString& message,
0108                           QWidget* const parent, const QString& windowTitle,
0109                           const QPixmap& pixmap)
0110 {
0111     QPixmap logoPixmap = pixmap;
0112 
0113     if (logoPixmap.isNull())
0114     {
0115         if (QApplication::applicationName() == QLatin1String("digikam"))
0116         {
0117             logoPixmap = QIcon::fromTheme(QLatin1String("digikam")).pixmap(QSize(48,48));
0118         }
0119         else
0120         {
0121             logoPixmap = QIcon::fromTheme(QLatin1String("showfoto")).pixmap(QSize(48,48));
0122         }
0123     }
0124 
0125 #if defined HAVE_KNOTIFICATIONS && defined HAVE_DBUS
0126 
0127     // NOTE: This detection of KDE desktop is not perfect because KNotification service may never be started.
0128     //       But in a regular KDE session, KNotification service should be running already.
0129 
0130     if (detectKDEDesktopIsRunning() &&
0131         QDBusConnection::sessionBus().interface()->
0132             isServiceRegistered(QLatin1String("org.kde.StatusNotifierWatcher")).value())
0133     {
0134         qCDebug(DIGIKAM_GENERAL_LOG) << "Event is dispatched to KDE desktop notifier";
0135 
0136         if (eventId.isEmpty())
0137         {
0138 
0139 #if (QT_VERSION >= QT_VERSION_CHECK(6, 0, 0))
0140 
0141             KNotification::event(KNotification::Notification, message, logoPixmap);
0142 
0143 #else
0144 
0145             KNotification::event(KNotification::Notification, message, logoPixmap, parent);
0146 
0147 #endif
0148 
0149         }
0150         else
0151         {
0152 
0153 #if (QT_VERSION >= QT_VERSION_CHECK(6, 0, 0))
0154 
0155             KNotification::event(eventId, message, logoPixmap);
0156 
0157 #else
0158 
0159             KNotification::event(eventId, message, logoPixmap, parent);
0160 
0161 #endif
0162 
0163         }
0164     }
0165     else
0166 
0167 #else
0168 
0169     {
0170         Q_UNUSED(eventId);
0171     }
0172 
0173 #endif
0174 
0175 #ifdef Q_OS_DARWIN
0176 
0177     // OSX support
0178 
0179     if (MacNativeDispatchNotify(windowTitle, message))
0180     {
0181         qCDebug(DIGIKAM_GENERAL_LOG) << "Event is dispatched to OSX desktop notifier";
0182 
0183         return;
0184     }
0185     else
0186 
0187 #endif // Q_OS_DARWIN
0188 
0189     {
0190         // Other Linux Desktops
0191 
0192         QProcess proc;
0193 
0194         proc.setProcessEnvironment(adjustedEnvironmentForAppImage());
0195         proc.start(QLatin1String("notify-send"),
0196                    QStringList() << windowTitle
0197                                  << message
0198                                  << QLatin1String("-a")
0199                                  << QApplication::applicationName());
0200 
0201         if (proc.waitForFinished() && proc.exitCode() == 0)
0202         {
0203             qCDebug(DIGIKAM_GENERAL_LOG) << "Event is dispatched to desktop notifier through DBUS";
0204 
0205             return;
0206         }
0207         else
0208         {
0209             if (!parent)
0210             {
0211                 qCWarning(DIGIKAM_GENERAL_LOG) << "parent is null";
0212 
0213                 return;
0214             }
0215 
0216             qCDebug(DIGIKAM_GENERAL_LOG) << "Event is dispatched through a passive pop-up";
0217 
0218             NotificationPassivePopup* const popup = new NotificationPassivePopup(parent);
0219             popup->showNotification(windowTitle, message, logoPixmap);
0220         }
0221     }
0222 }
0223 
0224 } // namespace Digikam
0225 
0226 #include "dnotificationwrapper.moc"