/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2024 Symless Ltd. * * This package is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * found in the file LICENSE that should have accompanied this file. * * This package is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "messages.h" #include "Logger.h" #include "constants.h" #include "styles.h" #include #include #include #include #include #include namespace synergy::gui::messages { struct Errors { static std::unique_ptr s_criticalMessage; static QStringList s_ignoredErrors; }; std::unique_ptr Errors::s_criticalMessage; QStringList Errors::s_ignoredErrors; void showErrorDialog( const QString &message, const QMessageLogContext &context, QtMsgType type) { auto filename = QFileInfo(context.file).fileName(); auto contextString = QString("%1:%2").arg(filename).arg(context.line); auto title = type == QtFatalMsg ? "Fatal error" : "Critical error"; QString text; if (type == QtFatalMsg) { text = "

Sorry, a fatal error has occurred and the application must " "now exit.

"; } else { text = "

Sorry, a critical error has occurred.

"; } if (kLicensedProduct) { text += QString(R"(

Please contact us)" " and copy/paste the following error:

") .arg(kUrlContact, kColorSecondary); } else { text += QString(R"(

Please report a bug)" " and copy/paste the following error:

") .arg(kUrlBugReport, kColorSecondary); } text += QString("
%3\n\n%4
").arg(message, contextString); if (type == QtFatalMsg) { // create a blocking message box for fatal errors, as we want to wait // until the dialog is dismissed before aborting the app. QMessageBox::critical(nullptr, title, text); } else if (!Errors::s_ignoredErrors.contains(message)) { // prevent message boxes piling up by deleting the last one if it exists. // if none exists yet, then nothing will happen. Errors::s_criticalMessage.reset(); // as we don't abort for critical messages, create a new non-blocking // message box. this is so that we don't block the message handler; if we // did, we would prevent new messages from being logged properly. // the memory will stay allocated until the app exits, which is acceptable. Errors::s_criticalMessage = std::make_unique( QMessageBox::Critical, title, text, QMessageBox::Ok | QMessageBox::Ignore); Errors::s_criticalMessage->open(); QAction::connect( Errors::s_criticalMessage.get(), &QMessageBox::finished, // [message](int result) { if (result == QMessageBox::Ignore) { Errors::s_ignoredErrors.append(message); } }); } } void messageHandler( QtMsgType type, const QMessageLogContext &context, const QString &message) { Logger::instance().handleMessage(type, context, message); if (type == QtFatalMsg || type == QtCriticalMsg) { showErrorDialog(message, context, type); } if (type == QtFatalMsg) { // developers: if you hit this line in your debugger, traverse the stack // to find the cause of the fatal error. important: crash the app on fatal // error to prevent the app being used in a broken state. // // hint: if you don't want to crash, but still want to show an error // message, use `qCritical()` instead of `qFatal()`. you should use // fatal errors when the app is in an unrecoverable state; i.e. it cannot // function correctly in it's current state and must be restarted. abort(); } } void showCloseReminder(QWidget *parent) { QString message = "

Synergy will continue to run in the background and can be accessed " "via the Synergy icon in your system notifications area. This setting " "can be disabled.

"; #if defined(Q_OS_LINUX) message += QString("

On some Linux systems such as GNOME 3, the " "notification area might be disabled. " "You may need to " R"(enable an extension)" " to see the Synergy tray icon.

") .arg(kUrlGnomeTrayFix, kStyleLink); #endif QMessageBox::information(parent, "Notification area icon", message); } void showFirstRunMessage( QWidget *parent, bool closeToTray, bool enableService, bool isServer) { auto message = QString("

Synergy is now connected!

"); if (isServer) { message += "

Try moving your mouse to your other computer. Once there, go ahead " "and type something.

" "

Don't forget, you can copy and paste between computers too.

"; } else { message += "

Try controlling this computer remotely.

"; } if (!closeToTray && !enableService) { message += "

As you do not have the setting enabled to keep Synergy running in " "the background, you'll need to keep this window open or minimized to " "keep Synergy running.

"; } else { message += "

You can now close this window and Synergy will continue to run in " "the background. This setting can be disabled.

"; } QMessageBox::information(parent, "Connected", message); } void showDevThanks(QWidget *parent, const QString &productName) { if (productName.isEmpty()) { qFatal("product name not set"); } QMessageBox::information( parent, "Thank you!", QString("

Thanks for using %1.

" "

If you enjoy using this app, you can support the
" "developers by " R"(purchasing a license)" " or " R"(contributing code.)" "

" "

This message will only appear once.

") .arg( productName, kUrlPurchase, kColorSecondary, kUrlGitHub, kColorSecondary)); } } // namespace synergy::gui::messages