From 7bd9ae8d0bcb3f3da96345b266ae41a70e9a130a Mon Sep 17 00:00:00 2001 From: Kai Uwe Broulik Date: Thu, 23 Nov 2023 23:28:13 +0100 Subject: [PATCH] helpers/killer: Modernize UI This overhauls the kill prompt UI to make it more modern and more easily to grasp. * Reduce the amount of text and redundancy. Give the window a title and drop the "app is not responding" heading. Try to remove the application name from the displayed window title. Also use the bold emphasis used in other places like deleting files. * Use the application icon if available with a warning overlay. This makes it easier to grasp which application it's talking about. * Move technical information (like PID and hostname) into an expandable "Details" section. KGuiAddons has been implicitly pulled in by KConfigWidgets already. --- CMakeLists.txt | 1 + src/helpers/killer/CMakeLists.txt | 2 ++ src/helpers/killer/killer.cpp | 55 +++++++++++++++++++++++-------- 3 files changed, 45 insertions(+), 13 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 6821d00ad9..de7b03a8b9 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -83,6 +83,7 @@ find_package(KF6 ${KF6_MIN_VERSION} REQUIRED COMPONENTS Crash DBusAddons GlobalAccel + GuiAddons I18n IdleTime Package diff --git a/src/helpers/killer/CMakeLists.txt b/src/helpers/killer/CMakeLists.txt index bb6a5774a5..741773aa6d 100644 --- a/src/helpers/killer/CMakeLists.txt +++ b/src/helpers/killer/CMakeLists.txt @@ -8,7 +8,9 @@ qt6_generate_wayland_protocol_client_sources(kwin_killer_helper FILES ${WaylandP target_link_libraries(kwin_killer_helper KF6::AuthCore + KF6::GuiAddons KF6::I18n + KF6::Service KF6::WidgetsAddons Qt::GuiPrivate Qt::WaylandClient diff --git a/src/helpers/killer/killer.cpp b/src/helpers/killer/killer.cpp index fc8d2dd6cc..0d54f1e220 100644 --- a/src/helpers/killer/killer.cpp +++ b/src/helpers/killer/killer.cpp @@ -7,9 +7,11 @@ */ #include +#include #include #include #include +#include #include #include @@ -65,7 +67,7 @@ int main(int argc, char *argv[]) { KLocalizedString::setApplicationDomain(QByteArrayLiteral("kwin")); QApplication app(argc, argv); - QApplication::setWindowIcon(QIcon::fromTheme(QStringLiteral("dialog-warning"))); + QApplication::setWindowIcon(QIcon::fromTheme(QStringLiteral("tools-report-bug"))); QCoreApplication::setApplicationName(QStringLiteral("kwin_killer_helper")); QCoreApplication::setOrganizationDomain(QStringLiteral("kde.org")); QApplication::setApplicationDisplayName(i18n("Window Manager")); @@ -126,23 +128,32 @@ int main(int argc, char *argv[]) } bool isLocal = hostname == QStringLiteral("localhost"); + const auto service = KService::serviceByDesktopName(appname); + if (service) { + appname = service->name(); + QApplication::setApplicationDisplayName(appname); + } + + // Drop redundant application name, cf. QXcbWindow::setWindowTitle. + const QString titleSeparator = QString::fromUtf8(" \xe2\x80\x94 "); // // U+2014, EM DASH + caption.remove(titleSeparator + appname); + caption.remove(QStringLiteral(" – ") + appname); // EN dash (Firefox) + caption.remove(QStringLiteral(" - ") + appname); // classic minus :-) + caption = caption.toHtmlEscaped(); appname = appname.toHtmlEscaped(); hostname = hostname.toHtmlEscaped(); QString pidString = QString::number(pid); // format pid ourself as it does not make sense to format an ID according to locale settings - QString question = i18nc("@info", "Application \"%1\" is not responding", appname); - question += isLocal - ? xi18nc("@info", "You tried to close window \"%1\" from application \"%2\" (Process ID: %3) but the application is not responding.", - caption, appname, pidString) - : xi18nc("@info", "You tried to close window \"%1\" from application \"%2\" (Process ID: %3), running on host \"%4\", but the application is not responding.", - caption, appname, pidString, hostname); + QString question = (caption == appname) ? xi18nc("@info", "%1 is not responding. Do you want to terminate this application?", + appname) + : xi18nc("@info \"window title\" of application name is not responding.", "\"%1\" of %2 is not responding. Do you want to terminate this application?", + caption, appname); question += xi18nc("@info", - "Do you want to terminate this application?" - "Terminating the application will close all of its child windows. Any unsaved data will be lost."); + "Terminating this application will close all of its windows. Any unsaved data will be lost."); - KGuiItem continueButton = KGuiItem(i18n("&Terminate Application %1", appname), QStringLiteral("edit-bomb")); - KGuiItem cancelButton = KGuiItem(i18n("Wait Longer"), QStringLiteral("chronometer")); + KGuiItem continueButton = KGuiItem(i18nc("@action:button Terminate app", "&Terminate %1", appname), QStringLiteral("application-exit")); + KGuiItem cancelButton = KGuiItem(i18nc("@action:button Wait for frozen app to maybe respond again", "&Wait Longer"), QStringLiteral("chronometer")); if (isX11) { QX11Info::setAppUserTime(timestamp); @@ -150,9 +161,27 @@ int main(int argc, char *argv[]) auto *dialog = new KMessageDialog(KMessageDialog::WarningContinueCancel, question); dialog->setAttribute(Qt::WA_DeleteOnClose); - dialog->setCaption(QString()); // use default caption. - dialog->setIcon(QIcon()); // use default warning icon. + dialog->setCaption(i18nc("@title:window", "Not Responding")); + + QIcon icon; + if (service) { + const QIcon appIcon = QIcon::fromTheme(service->icon()); + if (!appIcon.isNull()) { + // emblem-warning is non-standard, fall back to emblem-important if necessary. + const QIcon warningBadge = QIcon::fromTheme(QStringLiteral("emblem-warning"), QIcon::fromTheme(QStringLiteral("emblem-important"))); + + icon = KIconUtils::addOverlay(appIcon, warningBadge, qApp->isRightToLeft() ? Qt::BottomLeftCorner : Qt::BottomRightCorner); + } + } + dialog->setIcon(icon); // null icon will result in default warning icon. dialog->setButtons(continueButton, KGuiItem(), cancelButton); + + QStringList details{ + i18nc("@info", "Process ID: %1", pidString)}; + if (!isLocal) { + details << i18nc("@info", "Host name: %1", hostname); + } + dialog->setDetails(details.join(QLatin1Char('\n'))); dialog->winId(); std::unique_ptr xdgImporter;