/* SPDX-FileCopyrightText: 2009 Chani Armitage SPDX-License-Identifier: LGPL-2.0-or-later */ #include "menu.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "krunner_interface.h" #include "kworkspace.h" #include using namespace Qt::StringLiterals; ContextMenu::ContextMenu(QObject *parent, const QVariantList &args) : Plasma::ContainmentActions(parent, args) , m_session(new SessionManagement(this)) { } ContextMenu::~ContextMenu() { } void ContextMenu::restore(const KConfigGroup &config) { Plasma::Containment *c = containment(); Q_ASSERT(c); m_actions.clear(); m_actionOrder.clear(); QHash actions; QSet disabled; // clang-format off // because it really wants to mangle this nice aligned list if (c->containmentType() == Plasma::Containment::Panel || c->containmentType() == Plasma::Containment::CustomPanel) { m_actionOrder << QStringLiteral("add widgets") << QStringLiteral("_context") << QStringLiteral("configure") << QStringLiteral("remove"); } else { actions.insert(QStringLiteral("configure shortcuts"), false); m_actionOrder << QStringLiteral("configure") << QStringLiteral("_display_settings") << QStringLiteral("configure shortcuts") << QStringLiteral("_sep1") << QStringLiteral("_context") << QStringLiteral("_open_terminal") << QStringLiteral("_run_command") << QStringLiteral("add widgets") << QStringLiteral("_add panel") << QStringLiteral("manage activities") << QStringLiteral("remove"); if (c->containmentType() == Plasma::Containment::Desktop) { m_actionOrder << QStringLiteral("desktop edit mode"); } else { m_actionOrder << QStringLiteral("edit mode"); } m_actionOrder << QStringLiteral("_sep2") << QStringLiteral("_lock_screen") << QStringLiteral("_logout") << QStringLiteral("_sep3") << QStringLiteral("_wallpaper"); disabled.insert(QStringLiteral("add widgets")); disabled.insert(QStringLiteral("_add panel")); disabled.insert(QStringLiteral("configure shortcuts")); disabled.insert(QStringLiteral("_open_terminal")); disabled.insert(QStringLiteral("_run_command")); disabled.insert(QStringLiteral("_lock_screen")); disabled.insert(QStringLiteral("_logout")); } // clang-format on for (const QString &name : std::as_const(m_actionOrder)) { actions.insert(name, !disabled.contains(name)); } QHashIterator it(actions); while (it.hasNext()) { it.next(); m_actions.insert(it.key(), config.readEntry(it.key(), it.value())); } // everything below should only happen once, so check for it if (!m_runCommandAction) { m_runCommandAction = new QAction(i18nc("plasma_containmentactions_contextmenu", "Show KRunner"), this); m_runCommandAction->setIcon(QIcon::fromTheme(QStringLiteral("plasma-search"))); m_runCommandAction->setShortcut(KGlobalAccel::self()->globalShortcut(QStringLiteral("krunner.desktop"), QStringLiteral("_launch")).value(0)); connect(m_runCommandAction, &QAction::triggered, this, &ContextMenu::runCommand); m_openTerminalAction = new QAction(i18n("Open Terminal"), this); m_openTerminalAction->setIcon(QIcon::fromTheme(u"utilities-terminal"_s)); connect(m_openTerminalAction, &QAction::triggered, this, &ContextMenu::openTerminal); m_lockScreenAction = new QAction(i18nc("plasma_containmentactions_contextmenu", "Lock Screen"), this); m_lockScreenAction->setIcon(QIcon::fromTheme(QStringLiteral("system-lock-screen"))); m_lockScreenAction->setShortcut(KGlobalAccel::self()->globalShortcut(QStringLiteral("ksmserver"), QStringLiteral("Lock Session")).value(0)); m_lockScreenAction->setEnabled(m_session->canLock()); connect(m_session, &SessionManagement::canLockChanged, this, [this]() { m_lockScreenAction->setEnabled(m_session->canLock()); }); connect(m_lockScreenAction, &QAction::triggered, m_session, &SessionManagement::lock); m_logoutAction = new QAction(i18nc("plasma_containmentactions_contextmenu", "Show Logout Screen"), this); m_logoutAction->setIcon(QIcon::fromTheme(QStringLiteral("system-log-out"))); m_logoutAction->setShortcut(KGlobalAccel::self()->globalShortcut(QStringLiteral("ksmserver"), QStringLiteral("Show Logout Prompt")).value(0)); connect(m_logoutAction, &QAction::triggered, this, &ContextMenu::startLogout); m_configureDisplaysAction = new QAction(i18nc("plasma_containmentactions_contextmenu", "Display Configuration"), this); m_configureDisplaysAction->setIcon(QIcon::fromTheme(QStringLiteral("preferences-desktop-display"))); connect(m_configureDisplaysAction, &QAction::triggered, this, &ContextMenu::configureDisplays); m_separator1 = new QAction(this); m_separator1->setSeparator(true); m_separator2 = new QAction(this); m_separator2->setSeparator(true); m_separator3 = new QAction(this); m_separator3->setSeparator(true); } } QList ContextMenu::contextualActions() { Plasma::Containment *cont = containment(); Q_ASSERT(cont); QList actions; for (const QString &name : std::as_const(m_actionOrder)) { if (!m_actions.value(name)) { continue; } if (name == QLatin1String("_context")) { actions << cont->contextualActions(); } if (name == QLatin1String("_wallpaper")) { if (!cont->wallpaperPlugin().isEmpty()) { QObject *wallpaperGraphicsObject = cont->property("wallpaperGraphicsObject").value(); if (wallpaperGraphicsObject) { QQmlListProperty l = wallpaperGraphicsObject->property("contextualActions").value>(); int nActions = l.count(&l); for (int i = 0; i < nActions; ++i) { actions << l.at(&l, i); } } } } else if (QAction *a = action(name)) { // Bug 364292: show "Remove this Panel" option only when panelcontroller is opened if (name != QLatin1String("remove") || cont->isUserConfiguring() || (cont->containmentType() != Plasma::Containment::Panel && cont->containmentType() != Plasma::Containment::CustomPanel && cont->corona()->immutability() != Plasma::Types::Mutable)) { actions << a; } } } return actions; } QAction *ContextMenu::action(const QString &name) { Plasma::Containment *c = containment(); Q_ASSERT(c); if (name == QLatin1String("_sep1")) { return m_separator1; } else if (name == QLatin1String("_sep2")) { return m_separator2; } else if (name == QLatin1String("_sep3")) { return m_separator3; } else if (name == QLatin1String("_add panel")) { if (c->corona() && c->corona()->immutability() == Plasma::Types::Mutable) { return c->corona()->action(QStringLiteral("add panel")); } } else if (name == QLatin1String("_run_command")) { if (KAuthorized::authorizeAction(QStringLiteral("run_command")) && KAuthorized::authorize(QStringLiteral("run_command"))) { return m_runCommandAction; } } else if (name == QLatin1String("_open_terminal")) { if (KAuthorized::authorizeAction(QStringLiteral("shell_access"))) { return m_openTerminalAction; } } else if (name == QLatin1String("_lock_screen")) { if (KAuthorized::authorizeAction(QStringLiteral("lock_screen"))) { return m_lockScreenAction; } } else if (name == QLatin1String("_logout")) { if (KAuthorized::authorize(QStringLiteral("logout"))) { return m_logoutAction; } } else if (name == QLatin1String("_display_settings")) { if (KAuthorized::authorizeControlModule(QStringLiteral("kcm_kscreen.desktop")) && KService::serviceByStorageId(QStringLiteral("kcm_kscreen"))) { return m_configureDisplaysAction; } } else if (name == QLatin1String("edit mode")) { if (c->corona()) { return c->corona()->action(QStringLiteral("edit mode")); } } else if (name == QLatin1String("manage activities")) { if (c->corona()) { // Don't show the action if there's only one activity since in this // case it's clear that the user doesn't use activities if (KActivities::Consumer().activities().length() == 1) { return nullptr; } return c->corona()->action(QStringLiteral("manage activities")); } } else { // FIXME: remove action: make removal of current activity possible return c->internalAction(name); } return nullptr; } void ContextMenu::openTerminal() { if (!KAuthorized::authorizeAction(QStringLiteral("shell_access"))) { return; } auto job = new KTerminalLauncherJob(QString()); job->setWorkingDirectory(QDir::homePath()); job->start(); } void ContextMenu::runCommand() { if (!KAuthorized::authorizeAction(QStringLiteral("run_command"))) { return; } QString interface(QStringLiteral("org.kde.krunner")); org::kde::krunner::App krunner(interface, QStringLiteral("/App"), QDBusConnection::sessionBus()); krunner.display(); } void ContextMenu::startLogout() { KConfig config(u"ksmserverrc"_s); const auto group = config.group(u"General"_s); switch (group.readEntry("shutdownType", int(KWorkSpace::ShutdownTypeDefault))) { case int(KWorkSpace::ShutdownTypeHalt): m_session->requestShutdown(); break; case int(KWorkSpace::ShutdownTypeReboot): m_session->requestReboot(); break; case int(KWorkSpace::ShutdownTypeLogout): m_session->requestLogout(); break; case int(KWorkSpace::ShutdownTypeDefault): default: m_session->requestLogoutPrompt(); break; } } void ContextMenu::configureDisplays() { if (auto service = KService::serviceByDesktopName(QStringLiteral("kcm_kscreen"))) { auto job = new KIO::ApplicationLauncherJob(service); job->start(); } } QWidget *ContextMenu::createConfigurationInterface(QWidget *parent) { QWidget *widget = new QWidget(parent); QVBoxLayout *lay = new QVBoxLayout(); widget->setLayout(lay); widget->setWindowTitle(i18nc("plasma_containmentactions_contextmenu", "Configure Contextual Menu Plugin")); m_buttons = new QButtonGroup(widget); m_buttons->setExclusive(false); for (const QString &name : std::as_const(m_actionOrder)) { QCheckBox *item = nullptr; if (name == QLatin1String("_context")) { item = new QCheckBox(widget); // FIXME better text item->setText(i18nc("plasma_containmentactions_contextmenu", "[Other Actions]")); } else if (name == QLatin1String("_wallpaper")) { item = new QCheckBox(widget); item->setText(i18nc("plasma_containmentactions_contextmenu", "Wallpaper Actions")); item->setIcon(QIcon::fromTheme(QStringLiteral("user-desktop"))); } else if (name == QLatin1String("_sep1") || name == QLatin1String("_sep2") || name == QLatin1String("_sep3")) { item = new QCheckBox(widget); item->setText(i18nc("plasma_containmentactions_contextmenu", "[Separator]")); } else { QAction *a = action(name); if (a) { item = new QCheckBox(widget); item->setText(a->text()); item->setIcon(a->icon()); } } if (item) { item->setChecked(m_actions.value(name)); item->setProperty("actionName", name); lay->addWidget(item); m_buttons->addButton(item); } } return widget; } void ContextMenu::configurationAccepted() { QList buttons = m_buttons->buttons(); QListIterator it(buttons); while (it.hasNext()) { QAbstractButton *b = it.next(); if (b) { m_actions.insert(b->property("actionName").toString(), b->isChecked()); } } } void ContextMenu::save(KConfigGroup &config) { QHashIterator it(m_actions); while (it.hasNext()) { it.next(); config.writeEntry(it.key(), it.value()); } } K_PLUGIN_CLASS_WITH_JSON(ContextMenu, "plasma-containmentactions-contextmenu.json") #include "menu.moc" #include "moc_menu.cpp"