File indexing completed on 2024-05-05 04:45:39

0001 /*
0002     SnoreNotify is a Notification Framework based on Qt
0003     Copyright (C) 2014-2015  Hannah von Reth <vonreth@kde.org>
0004 
0005     SnoreNotify is free software: you can redistribute it and/or modify
0006     it under the terms of the GNU Lesser General Public License as published by
0007     the Free Software Foundation, either version 3 of the License, or
0008     (at your option) any later version.
0009 
0010     SnoreNotify is distributed in the hope that it will be useful,
0011     but WITHOUT ANY WARRANTY; without even the implied warranty of
0012     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
0013     GNU Lesser General Public License for more details.
0014 
0015     You should have received a copy of the GNU Lesser General Public License
0016     along with SnoreNotify.  If not, see <http://www.gnu.org/licenses/>.
0017 */
0018 
0019 #include <libsnore/snore.h>
0020 #include <libsnore/notification/notification.h>
0021 #include <libsnore/version.h>
0022 #include <libsnore/utils.h>
0023 #include <libsnore/snore_static_plugins.h>
0024 
0025 
0026 #include <QGuiApplication>
0027 #include <QCommandLineParser>
0028 
0029 #include <iostream>
0030 
0031 #ifdef Q_OS_WIN
0032 #include <windows.h>
0033 #include <windowsx.h>
0034 #include <shellapi.h>
0035 #include <winuser.h>
0036 #endif
0037 
0038 using namespace Snore;
0039 using namespace std;
0040 
0041 void bringToFront(const QString &pid)
0042 {
0043     qCDebug(SNORE) << pid;
0044 #ifdef Q_OS_WIN
0045     auto findWindowForPid = [](ulong pid) {
0046         // based on http://stackoverflow.com/a/21767578
0047         pair<ulong, HWND> data = make_pair(pid, (HWND)0);
0048         ::EnumWindows((WNDENUMPROC)static_cast<BOOL(*)(HWND, LPARAM)>([](HWND handle, LPARAM lParam) -> BOOL {
0049             auto isMainWindow = [](HWND handle)
0050             {
0051                 return ::GetWindow(handle, GW_OWNER) == (HWND)0 && IsWindowVisible(handle);
0052             };
0053             pair<ulong, HWND> &data = *(pair<ulong, HWND> *)lParam;
0054             ulong process_id = 0;
0055             ::GetWindowThreadProcessId(handle, &process_id);
0056             if (data.first != process_id || !isMainWindow(handle))
0057             {
0058                 return TRUE;
0059             }
0060             data.second = handle;
0061             return FALSE;
0062         }), (LPARAM)&data);
0063         return data.second;
0064     };
0065 
0066     HWND wid = findWindowForPid(pid.toInt());
0067     if (wid) {
0068         Utils::bringWindowToFront(wid, true);
0069     }
0070 #endif
0071 }
0072 
0073 int main(int argc, char *argv[])
0074 {
0075     QGuiApplication app(argc, argv);
0076     app.setApplicationName(QStringLiteral("snoresend"));
0077     app.setOrganizationName(QStringLiteral("Snorenotify"));
0078     app.setApplicationVersion(Snore::Version::version());
0079 
0080     QCommandLineParser parser;
0081     parser.setApplicationDescription(QStringLiteral("A command line interface for Snorenotify."));
0082     parser.addHelpOption();
0083     parser.addVersionOption();
0084 
0085     QCommandLineOption title(QStringList() << QStringLiteral("t") << QStringLiteral("title"), QStringLiteral("Set the notification title."), QStringLiteral("title"));
0086     parser.addOption(title);
0087 
0088     QCommandLineOption message(QStringList() << QStringLiteral("m") << QStringLiteral("message"), QStringLiteral("Set the notification body."), QStringLiteral("message"));
0089     parser.addOption(message);
0090 
0091     QCommandLineOption applicationName(QStringList() << QStringLiteral("a") << QStringLiteral("application"), QStringLiteral("Set the notification applicattion."), QStringLiteral("application"), app.applicationName());
0092     parser.addOption(applicationName);
0093 
0094     QCommandLineOption alertName(QStringList() << QStringLiteral("c") << QStringLiteral("alert"), QStringLiteral("Set the notification alert class."), QStringLiteral("alert"), QStringLiteral("Default"));
0095     parser.addOption(alertName);
0096 
0097     QCommandLineOption iconPath(QStringList() << QStringLiteral("i") << QStringLiteral("icon"), QStringLiteral("Set the notification icon."), QStringLiteral("icon"));
0098     parser.addOption(iconPath);
0099 
0100     QCommandLineOption priority(QStringList() << QStringLiteral("p") << QStringLiteral("priority"), QStringLiteral("Set the notification's priority."), QStringLiteral("[-2, 2]"), QStringLiteral("0"));
0101     parser.addOption(priority);
0102 
0103     QCommandLineOption markup(QStringList() << QStringLiteral("markup"), QStringLiteral("Enable markup support."), QStringLiteral("[0,1]"), QStringLiteral("0"));
0104     parser.addOption(markup);
0105 
0106     QCommandLineOption silent(QStringList() << QStringLiteral("silent"), QStringLiteral("Don't print to stdout."));
0107     parser.addOption(silent);
0108 
0109 #ifdef Q_OS_WIN
0110     QCommandLineOption _bringProcessToFront(QStringList() << QStringLiteral("bring-process-to-front"), QStringLiteral("Bring process with pid to front if notification is clicked."), QStringLiteral("pid"));
0111     parser.addOption(_bringProcessToFront);
0112 
0113     QCommandLineOption _bringWindowToFront(QStringList() << QStringLiteral("bring-window-to-front"), QStringLiteral("Bring window with wid to front if notification is clicked."), QStringLiteral("wid"));
0114     parser.addOption(_bringWindowToFront);
0115 #endif
0116     parser.process(app);
0117     qCDebug(SNORE) << app.arguments();
0118     if (parser.isSet(title) && parser.isSet(message)) {
0119         SnoreCore &core = SnoreCore::instance();
0120 
0121         core.loadPlugins(Snore::SnorePlugin::Backend | Snore::SnorePlugin::SecondaryBackend);
0122 
0123         Icon icon = Icon::defaultIcon();
0124         if (parser.isSet(iconPath)) {
0125             icon = Icon(parser.value(iconPath));
0126         }
0127         Application application(parser.value(applicationName), icon);
0128         Alert alert(parser.value(alertName), icon);
0129         application.addAlert(alert);
0130 
0131         if (parser.value(markup).toInt() == 1) {
0132             application.hints().setValue("use-markup", true);
0133         }
0134 
0135         core.registerApplication(application);
0136 
0137         int prio = parser.value(priority).toInt();
0138         if (prio < -2 || prio > 2) {
0139             parser.showHelp(-1);
0140         }
0141         Notification n(application, alert, parser.value(title), parser.value(message), icon, Notification::defaultTimeout(), static_cast<Notification::Prioritys>(prio));
0142 #ifdef Q_OS_WIN
0143         if (parser.isSet(_bringProcessToFront) || parser.isSet(_bringWindowToFront)) {
0144             n.addAction(Action(1, qApp->translate("SnoreSend", "Bring to Front")));
0145         }
0146 #endif
0147         int returnCode = -1;
0148 
0149         app.connect(&core, &SnoreCore::notificationClosed, [&](Notification noti) {
0150             if (!parser.isSet(silent)) {
0151                 QString reason;
0152                 QDebug(&reason) << noti.closeReason();
0153                 cout << qPrintable(reason) << endl;
0154             }
0155             if (noti.closeReason() == Notification::Closed) {
0156 #ifdef Q_OS_WIN
0157                 if (parser.isSet(_bringProcessToFront)) {
0158                     bringToFront(parser.value(_bringProcessToFront));
0159                 } else if (parser.isSet(_bringWindowToFront)) {
0160                     Utils::bringWindowToFront((HWND)parser.value(_bringWindowToFront).toULongLong(), true);
0161                 }
0162 #endif
0163             }
0164             returnCode = noti.closeReason();
0165         });
0166         app.connect(&core, &SnoreCore::notificationClosed, &app, &QGuiApplication::quit);
0167         app.processEvents();
0168         core.broadcastNotification(n);
0169 
0170         app.exec();
0171         return returnCode;
0172     }
0173     parser.showHelp(1);
0174 }
0175