qt: Notify on Next Command shows armed state via checkmark icon

The context-menu entry previously used a fixed bell icon
(`preferences-desktop-notification`), which was misleading for a
one-shot toggle: the user couldn't tell whether they'd already armed
it, and the only way to "disarm" was to wait for a command to finish
and consume the flag.

Render the armed state with a themed checkmark icon
(emblem-ok → object-select → dialog-ok fallback) drawn in the
menu's regular icon column, and toggle the flag on click. Tried
QAction::setCheckable() first, but Breeze/KDE renders the checkable
indicator in a separate column from QAction icons — the checkmark
was floating to the left of the icon column instead of aligned
with Copy/Paste/Find.

Co-Authored-By: claude-flow <ruv@ruv.net>
pull/12846/head
Nathan 2026-05-23 16:50:56 -05:00
parent 13f139dcf2
commit 566e2f1ead
2 changed files with 30 additions and 4 deletions

View File

@ -882,8 +882,26 @@ void GhosttySurface::contextMenuEvent(QContextMenuEvent *ev) {
!QGuiApplication::clipboard()->text().isEmpty());
add(&menu, "Select All", "edit-select-all", "select_all", true);
add(&menu, "Find…", "edit-find", "start_search", true);
add(&menu, "Notify on Next Command Finish",
"preferences-desktop-notification", "@notify-command", true);
// "Notify on Next Command Finish" is a togglable arm. We render the
// checked state with a themed checkmark icon in the regular icon
// column rather than QAction::setCheckable() — Breeze/KDE draws the
// checkable indicator in its own column, misaligned with the rest
// of the menu's icons. The bell icon previously used here was also
// misleading (suggested a stateless trigger, not a one-shot flag).
{
QAction *notify = menu.addAction(
QStringLiteral("Notify on Next Command Finish"));
notify->setData(QStringLiteral("@notify-command"));
if (commandNotifyArmed()) {
QIcon ok = QIcon::fromTheme(QStringLiteral("emblem-ok"));
if (ok.isNull())
ok = QIcon::fromTheme(QStringLiteral("object-select"));
if (ok.isNull()) ok = QIcon::fromTheme(QStringLiteral("dialog-ok"));
if (!ok.isNull()) notify->setIcon(ok);
}
if (QKeySequence sc = shortcutFor("@notify-command"); !sc.isEmpty())
notify->setShortcut(sc);
}
menu.addSeparator();
add(&menu, "Clear", "edit-clear-all", "clear_screen", true);
add(&menu, "Reset", "view-refresh", "reset", true);
@ -919,9 +937,15 @@ void GhosttySurface::contextMenuEvent(QContextMenuEvent *ev) {
if (!chosen || !m_surface) return;
const QString data = chosen->data().toString();
// Arm the one-shot "command finished" notification (no keybind action).
// Toggle the one-shot "command finished" notification (no keybind
// action). Not a checkable QAction — see the icon-column comment in
// the menu-build section above — so flip by reading the current
// armed state.
if (data == QLatin1String("@notify-command")) {
armCommandNotify();
if (commandNotifyArmed())
clearCommandNotify();
else
armCommandNotify();
return;
}

View File

@ -61,6 +61,8 @@ public:
// Arm a one-shot desktop notification for the next command to finish
// (context-menu item); consumeCommandNotify reads-and-clears the flag.
void armCommandNotify() { m_notifyOnCommand = true; }
void clearCommandNotify() { m_notifyOnCommand = false; }
bool commandNotifyArmed() const { return m_notifyOnCommand; }
bool consumeCommandNotify() {
const bool armed = m_notifyOnCommand;
m_notifyOnCommand = false;