diff --git a/containmentactions/contextmenu/menu.cpp b/containmentactions/contextmenu/menu.cpp index 07d732236..90da5fc84 100644 --- a/containmentactions/contextmenu/menu.cpp +++ b/containmentactions/contextmenu/menu.cpp @@ -1,315 +1,315 @@ /* * Copyright 2009 by Chani Armitage * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Library General Public License as * published by the Free Software Foundation; either version 2, or * (at your option) any later version. * * This program 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 Library General Public * License along with this program; if not, write to the * Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "menu.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include "kworkspace.h" #include "krunner_interface.h" #include "screensaver_interface.h" #ifdef Q_OS_WIN #define _WIN32_WINNT 0x0500 // require NT 5.0 (win 2k pro) #include #endif // Q_OS_WIN ContextMenu::ContextMenu(QObject *parent, const QVariantList &args) : Plasma::ContainmentActions(parent, args), m_runCommandAction(nullptr), m_lockScreenAction(nullptr), m_logoutAction(nullptr), m_separator1(nullptr), m_separator2(nullptr), m_separator3(nullptr), m_buttons(nullptr) { } 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; if (c->containmentType() == Plasma::Types::PanelContainment || c->containmentType() == Plasma::Types::CustomPanelContainment) { m_actionOrder << QStringLiteral("add widgets") << QStringLiteral("_add panel") << QStringLiteral("lock widgets") << QStringLiteral("_context") << QStringLiteral("configure") << QStringLiteral("remove"); } else { actions.insert(QStringLiteral("configure shortcuts"), false); m_actionOrder << QStringLiteral("_context") << QStringLiteral("_run_command") << QStringLiteral("add widgets") << QStringLiteral("_add panel") << QStringLiteral("manage activities") << QStringLiteral("remove") << QStringLiteral("lock widgets") << QStringLiteral("_sep1") < 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"), QStringLiteral("run command")).value(0)); + m_runCommandAction->setShortcut(KGlobalAccel::self()->globalShortcut(QStringLiteral("krunner.desktop"), QStringLiteral("_launch")).value(0)); connect(m_runCommandAction, &QAction::triggered, this, &ContextMenu::runCommand); 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)); connect(m_lockScreenAction, &QAction::triggered, this, &ContextMenu::lockScreen); m_logoutAction = new QAction(i18nc("plasma_containmentactions_contextmenu", "Leave..."), this); m_logoutAction->setIcon(QIcon::fromTheme(QStringLiteral("system-log-out"))); m_logoutAction->setShortcut(KGlobalAccel::self()->globalShortcut(QStringLiteral("ksmserver"), QStringLiteral("Log Out")).value(0)); connect(m_logoutAction, &QAction::triggered, this, &ContextMenu::startLogout); 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 *c = containment(); Q_ASSERT(c); QList actions; foreach (const QString &name, m_actionOrder) { if (!m_actions.value(name)) { continue; } if (name == QLatin1String("_context")) { actions << c->contextualActions(); } if (name == QLatin1String("_wallpaper")) { if (!c->wallpaper().isEmpty()) { QObject *wallpaperGraphicsObject = c->property("wallpaperGraphicsObject").value(); if (wallpaperGraphicsObject) { actions << wallpaperGraphicsObject->property("contextualActions").value >(); } } } else if (QAction *a = action(name)) { // Bug 364292: show "Remove this Panel" option only when panelcontroller is opened if (name != QLatin1String("remove") || c->isUserConfiguring() || (c->containmentType() != Plasma::Types::PanelContainment && c->containmentType() != Plasma::Types::CustomPanelContainment)) { 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()->actions()->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("_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("lock widgets")) { if (c->corona()) { return c->corona()->actions()->action(QStringLiteral("lock widgets")); } } else if (name == QLatin1String("manage activities")) { if (c->corona()) { return c->corona()->actions()->action(QStringLiteral("manage activities")); } } else { //FIXME: remove action: make removal of current activity possible return c->actions()->action(name); } return nullptr; } 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::lockScreen() { if (!KAuthorized::authorizeAction(QStringLiteral("lock_screen"))) { return; } #ifndef Q_OS_WIN QString interface(QStringLiteral("org.freedesktop.ScreenSaver")); org::freedesktop::ScreenSaver screensaver(interface, QStringLiteral("/ScreenSaver"), QDBusConnection::sessionBus()); if (screensaver.isValid()) { screensaver.Lock(); } #else LockWorkStation(); #endif // !Q_OS_WIN } void ContextMenu::startLogout() { // this short delay is due to two issues: // a) KWorkSpace's DBus alls are all synchronous // b) the destrution of the menu that this action is in is delayed // // (a) leads to the menu hanging out where everyone can see it because // the even loop doesn't get returned to allowing it to close. // // (b) leads to a 0ms timer not working since a 0ms timer just appends to // the event queue, and then the menu closing event gets appended to that. // // ergo a timer with small timeout QTimer::singleShot(10, this, &ContextMenu::logout); } void ContextMenu::logout() { if (!KAuthorized::authorizeAction(QStringLiteral("logout"))) { return; } KWorkSpace::requestShutDown(); } 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); foreach (const QString &name, 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_EXPORT_PLASMA_CONTAINMENTACTIONS_WITH_JSON(contextmenu, ContextMenu, "plasma-containmentactions-contextmenu.json") #include "menu.moc" diff --git a/krunner/CMakeLists.txt b/krunner/CMakeLists.txt index 083c1c7ce..170b3e712 100644 --- a/krunner/CMakeLists.txt +++ b/krunner/CMakeLists.txt @@ -1,42 +1,41 @@ set(krunner_SRCS main.cpp view.cpp ) set(krunner_dbusAppXML dbus/org.kde.krunner.App.xml) qt5_add_dbus_adaptor(krunner_SRCS ${krunner_dbusAppXML} view.h View) configure_file(dbus/org.kde.krunner.service.in ${CMAKE_CURRENT_BINARY_DIR}/org.kde.krunner.service) install(FILES ${CMAKE_CURRENT_BINARY_DIR}/org.kde.krunner.service DESTINATION ${KDE_INSTALL_DBUSSERVICEDIR}) add_executable(krunner ${krunner_SRCS}) target_link_libraries(krunner Qt5::Quick KF5::Declarative KF5::I18n KF5::PlasmaQuick - KF5::GlobalAccel KF5::DBusAddons KF5::Crash KF5::WaylandClient KF5::QuickAddons PW::KWorkspace ) target_compile_definitions(krunner PRIVATE -DPROJECT_VERSION="${PROJECT_VERSION}") install(TARGETS krunner ${KDE_INSTALL_TARGETS_DEFAULT_ARGS}) install(FILES ${krunner_dbusAppXML} DESTINATION ${KDE_INSTALL_DBUSINTERFACEDIR} ) -install(FILES krunner.desktop DESTINATION ${KDE_INSTALL_AUTOSTARTDIR}) +install(FILES krunner.desktop DESTINATION ${DATA_INSTALL_DIR}/kglobalaccel) set(CMAKECONFIG_INSTALL_DIR "${KDE_INSTALL_CMAKEPACKAGEDIR}/KRunnerAppDBusInterface") configure_package_config_file(KRunnerAppDBusInterfaceConfig.cmake.in "${CMAKE_CURRENT_BINARY_DIR}/KRunnerAppDBusInterfaceConfig.cmake" PATH_VARS KDE_INSTALL_DBUSINTERFACEDIR INSTALL_DESTINATION ${CMAKECONFIG_INSTALL_DIR}) install(FILES ${CMAKE_CURRENT_BINARY_DIR}/KRunnerAppDBusInterfaceConfig.cmake DESTINATION ${CMAKECONFIG_INSTALL_DIR}) add_subdirectory(update) diff --git a/krunner/krunner.desktop b/krunner/krunner.desktop index 4ca4c36cf..7cd08baae 100644 --- a/krunner/krunner.desktop +++ b/krunner/krunner.desktop @@ -1,52 +1,58 @@ [Desktop Entry] Exec=krunner Name=KRunner Name[ar]=مشغّل.ك Name[bs]=KPokretač Name[ca]=KRunner Name[ca@valencia]=KRunner Name[cs]=KRunner Name[da]=KRunner Name[de]=KRunner Name[el]=KRunner Name[en_GB]=KRunner Name[es]=KRunner Name[et]=KRunner Name[eu]=KRunner Name[fi]=KRunner Name[fr]=KRunner Name[gl]=KRunner Name[hu]=KRunner Name[id]=KRunner Name[is]=KRunner Name[it]=KRunner Name[ja]=KRunner Name[ko]=KRunner Name[lt]=KRunner Name[nb]=KRunner Name[nds]=KRunner Name[nl]=KRunner Name[nn]=KRunner Name[pa]=ਕੇਰਨਰ Name[pl]=KRunner Name[pt]=KRunner Name[pt_BR]=KRunner Name[ru]=KRunner Name[sk]=KRunner Name[sl]=KRunner Name[sr]=К‑извођач Name[sr@ijekavian]=К‑извођач Name[sr@ijekavianlatin]=K‑izvođač Name[sr@latin]=K‑izvođač Name[sv]=Kör program Name[tr]=KRunner Name[uk]=KRunner Name[x-test]=xxKRunnerxx Name[zh_CN]=KRunner Name[zh_TW]=KRunner OnlyShowIn=KDE; Type=Application X-DBUS-StartupType=Unique X-DBUS-ServiceName=org.kde.krunner X-KDE-StartupNotify=false -X-KDE-autostart-phase=2 +X-KDE-Shortcuts=Alt+Space,Alt+F2,Search +Actions=RunClipboard + +[Desktop Action RunClipboard] +Exec=krunner -c +Name=Run command on clipboard contents +X-KDE-Shortcuts=Alt+Shift+F2 diff --git a/krunner/main.cpp b/krunner/main.cpp index e0395cfff..cc46cc217 100644 --- a/krunner/main.cpp +++ b/krunner/main.cpp @@ -1,108 +1,135 @@ /* * Copyright 2012 Marco Martin * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program 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, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "view.h" int main(int argc, char **argv) { qunsetenv("QT_DEVICE_PIXEL_RATIO"); + QCommandLineParser parser; QCoreApplication::setAttribute(Qt::AA_DisableHighDpiScaling); const bool qpaVariable = qEnvironmentVariableIsSet("QT_QPA_PLATFORM"); KWorkSpace::detectPlatform(argc, argv); QQuickWindow::setDefaultAlphaBuffer(true); QApplication app(argc, argv); if (!qpaVariable) { // don't leak the env variable to processes we start qunsetenv("QT_QPA_PLATFORM"); } KLocalizedString::setApplicationDomain("krunner"); KQuickAddons::QtQuickSettings::init(); // TODO: Make it a QGuiApplication once we don't depend on KDELibs4Support // QGuiApplication app(argc, argv); KAboutData aboutData(QStringLiteral("krunner"), i18n("krunner"), QStringLiteral(PROJECT_VERSION), i18n("Run Command interface"), KAboutLicense::GPL); KAboutData::setApplicationData(aboutData); app.setQuitOnLastWindowClosed(false); - { - QCommandLineParser parser; - QCommandLineOption replaceOption({QStringLiteral("replace")}, i18n("Replace an existing instance")); - parser.addOption(replaceOption); - aboutData.setupCommandLine(&parser); - - parser.process(app); - aboutData.processCommandLine(&parser); - if (parser.isSet(replaceOption)) { - auto message = QDBusMessage::createMethodCall(QStringLiteral("org.kde.krunner"), - QStringLiteral("/MainApplication"), - QStringLiteral("org.qtproject.Qt.QCoreApplication"), - QStringLiteral("quit")); - QDBusConnection::sessionBus().call(message); //deliberately block until it's done, so we register the name after the app quits - } + QCommandLineOption clipboardOption({QStringLiteral("c"), QStringLiteral("clipboard")}, + i18n("Use the clipboard contents as query for KRunner")); + QCommandLineOption daemonOption({QStringLiteral("d"), QStringLiteral("daemon")}, + i18n("Start KRunner in the background, don't show it.")); + QCommandLineOption replaceOption({QStringLiteral("replace")}, i18n("Replace an existing instance")); + + parser.addOption(clipboardOption); + parser.addOption(daemonOption); + parser.addOption(replaceOption); + parser.addPositionalArgument(QStringLiteral("query"), i18n("The query to run, only used if -c is not provided")); + + aboutData.setupCommandLine(&parser); + + parser.process(app); + aboutData.processCommandLine(&parser); + + if (parser.isSet(replaceOption)) { + auto message = QDBusMessage::createMethodCall(QStringLiteral("org.kde.krunner"), + QStringLiteral("/MainApplication"), + QStringLiteral("org.qtproject.Qt.QCoreApplication"), + QStringLiteral("quit")); + QDBusConnection::sessionBus().call(message); //deliberately block until it's done, so we register the name after the app quits } if (!KAuthorized::authorize(QStringLiteral("run_command"))) { return -1; } KDBusService service(KDBusService::Unique); QGuiApplication::setFallbackSessionManagementEnabled(false); auto disableSessionManagement = [](QSessionManager &sm) { sm.setRestartHint(QSessionManager::RestartNever); }; QObject::connect(&app, &QGuiApplication::commitDataRequest, disableSessionManagement); QObject::connect(&app, &QGuiApplication::saveStateRequest, disableSessionManagement); View view; - view.setVisible(false); - QObject::connect(&service, &KDBusService::activateRequested, &view, &View::display); + auto updateVisibility = [&]() { + const QString query = parser.positionalArguments().value(0); + + if (parser.isSet(daemonOption)) { + view.setVisible(false); + } else if (parser.isSet(clipboardOption)) { + view.displayWithClipboardContents(); + } else if (!query.isEmpty()) { + view.query(query); + } else { + view.display(); + } + }; + + updateVisibility(); + + QObject::connect(&service, &KDBusService::activateRequested, &view, [&](const QStringList &arguments, const QString &workingDirectory) { + Q_UNUSED(workingDirectory) + parser.parse(arguments); + updateVisibility(); + }); return app.exec(); } diff --git a/krunner/update/CMakeLists.txt b/krunner/update/CMakeLists.txt index 245601414..7c6b2afce 100644 --- a/krunner/update/CMakeLists.txt +++ b/krunner/update/CMakeLists.txt @@ -1,12 +1,22 @@ set(krunnerplugins_SRCS - main.cpp + krunnerplugins.cpp ) add_executable(krunnerplugins ${krunnerplugins_SRCS}) target_link_libraries(krunnerplugins KF5::CoreAddons KF5::Service KF5::Runner KF5::ConfigCore) install(TARGETS krunnerplugins DESTINATION ${KDE_INSTALL_LIBDIR}/kconf_update_bin/) install(FILES krunnerplugins.upd DESTINATION ${KDE_INSTALL_KCONFUPDATEDIR}) +set(krunnerglobalshortcuts_SRCS + krunnerglobalshortcuts.cpp + ) + +add_executable(krunnerglobalshortcuts ${krunnerglobalshortcuts_SRCS}) + +target_link_libraries(krunnerglobalshortcuts KF5::CoreAddons KF5::Service KF5::Runner KF5::ConfigCore KF5::GlobalAccel KF5::XmlGui) + +install(TARGETS krunnerglobalshortcuts DESTINATION ${KDE_INSTALL_LIBDIR}/kconf_update_bin/) +install(FILES krunnerglobalshortcuts.upd DESTINATION ${KDE_INSTALL_KCONFUPDATEDIR}) diff --git a/krunner/update/krunnerglobalshortcuts.cpp b/krunner/update/krunnerglobalshortcuts.cpp new file mode 100644 index 000000000..b15ea9049 --- /dev/null +++ b/krunner/update/krunnerglobalshortcuts.cpp @@ -0,0 +1,85 @@ +/*************************************************************************** + * Copyright (C) 2019 by Kai Uwe Broulik * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program 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, write to the * + * Free Software Foundation, Inc., * + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA . * + ***************************************************************************/ + +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +int main(int argc, char **argv) +{ + QCoreApplication app(argc, argv); + + const auto oldRunCommand = KGlobalAccel::self()->globalShortcut(QStringLiteral("krunner"), QStringLiteral("run command")); + const auto oldRunClipboard = KGlobalAccel::self()->globalShortcut(QStringLiteral("krunner"), QStringLiteral("run command on clipboard contents")); + + // Fake krunner and remove the old shortcuts + { + KActionCollection oldCollection(static_cast(nullptr)); + oldCollection.setComponentName(QStringLiteral("krunner")); + + QAction *oldAction = new QAction(); + oldCollection.addAction(QStringLiteral("run command"), oldAction); + KGlobalAccel::self()->setDefaultShortcut(oldAction, {}); + KGlobalAccel::self()->removeAllShortcuts(oldAction); + + QAction *oldClipboard = new QAction(); + oldCollection.addAction(QStringLiteral("run command on clipboard contents"), oldClipboard); + KGlobalAccel::self()->setDefaultShortcut(oldClipboard, {}); + KGlobalAccel::self()->removeAllShortcuts(oldClipboard); + } + + // Fake krunner.desktop launcher and transfer the shortcuts over + { + // Since we need to fake those actions, read the translated names from the desktop file + KDesktopFile df(QStandardPaths::GenericDataLocation, QStringLiteral("kglobalaccel/krunner.desktop")); + + QString displayName = QStringLiteral("KRunner"); + if (!df.readName().isEmpty()) { + displayName = df.readName(); + } + + const QString clipboardActionName = df.actionGroup(QStringLiteral("RunClipboard")).readEntry(QStringLiteral("Name"), QStringLiteral("Run command on clipboard contents")); + + KActionCollection shortCutActions(static_cast(nullptr)); + shortCutActions.setComponentName(QStringLiteral("krunner.desktop")); + shortCutActions.setComponentDisplayName(displayName); + + if (!oldRunCommand.isEmpty()) { + QAction *runCommandAction = new QAction(displayName); + shortCutActions.addAction(QStringLiteral("_launch"), runCommandAction); + KGlobalAccel::self()->setShortcut(runCommandAction, oldRunCommand, KGlobalAccel::NoAutoloading); + } + + if (!oldRunClipboard.isEmpty()) { + QAction *runClipboardAction = new QAction(clipboardActionName); + shortCutActions.addAction(QStringLiteral("RunClipboard"), runClipboardAction); + KGlobalAccel::self()->setShortcut(runClipboardAction, oldRunClipboard, KGlobalAccel::NoAutoloading); + } + } + + return 0; +} + diff --git a/krunner/update/krunnerglobalshortcuts.upd b/krunner/update/krunnerglobalshortcuts.upd new file mode 100644 index 000000000..35030aaae --- /dev/null +++ b/krunner/update/krunnerglobalshortcuts.upd @@ -0,0 +1,3 @@ +Version=5 +Id=5.17KRunnerGlobalShortcuts +Script=krunnerglobalshortcuts diff --git a/krunner/update/main.cpp b/krunner/update/krunnerplugins.cpp similarity index 100% rename from krunner/update/main.cpp rename to krunner/update/krunnerplugins.cpp diff --git a/krunner/view.cpp b/krunner/view.cpp index 9863be335..61c1e4ed0 100644 --- a/krunner/view.cpp +++ b/krunner/view.cpp @@ -1,405 +1,388 @@ /* * Copyright 2014 Marco Martin * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program 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, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "view.h" #include #include #include #include #include #include #include #include #include #include #include #include -#include #include #include #include #include #include #include #include #include #include #include #include "appadaptor.h" View::View(QWindow *) : PlasmaQuick::Dialog(), m_offset(.5), m_floating(false) { setClearBeforeRendering(true); setColor(QColor(Qt::transparent)); setFlags(Qt::FramelessWindowHint | Qt::WindowStaysOnTopHint); KCrash::setFlags(KCrash::AutoRestart); //used only by screen readers setTitle(i18n("KRunner")); m_config = KConfigGroup(KSharedConfig::openConfig(QStringLiteral("krunnerrc")), "General"); setFreeFloating(m_config.readEntry("FreeFloating", false)); reloadConfig(); new AppAdaptor(this); QDBusConnection::sessionBus().registerObject(QStringLiteral("/App"), this); - QAction *a = new QAction(nullptr); - QObject::connect(a, &QAction::triggered, this, &View::displayOrHide); - a->setText(i18n("Show KRunner")); - a->setObjectName(QStringLiteral("run command")); - a->setProperty("componentDisplayName", i18nc("Name for krunner shortcuts category", "KRunner")); - KGlobalAccel::self()->setDefaultShortcut(a, QList() << QKeySequence(Qt::ALT + Qt::Key_Space), KGlobalAccel::NoAutoloading); - KGlobalAccel::self()->setShortcut(a, QList() << QKeySequence(Qt::ALT + Qt::Key_Space) << QKeySequence(Qt::ALT + Qt::Key_F2) << Qt::Key_Search); - - a = new QAction(nullptr); - QObject::connect(a, &QAction::triggered, this, &View::displayWithClipboardContents); - a->setText(i18n("Run Command on clipboard contents")); - a->setObjectName(QStringLiteral("run command on clipboard contents")); - a->setProperty("componentDisplayName", i18nc("Name for krunner shortcuts category", "KRunner")); - KGlobalAccel::self()->setDefaultShortcut(a, QList() << QKeySequence(Qt::ALT+Qt::SHIFT+Qt::Key_F2)); - KGlobalAccel::self()->setShortcut(a, QList() << QKeySequence(Qt::ALT+Qt::SHIFT+Qt::Key_F2)); - m_qmlObj = new KDeclarative::QmlObject(this); m_qmlObj->setInitializationDelayed(true); connect(m_qmlObj, &KDeclarative::QmlObject::finished, this, &View::objectIncubated); KPackage::Package package = KPackage::PackageLoader::self()->loadPackage(QStringLiteral("Plasma/LookAndFeel")); KConfigGroup cg(KSharedConfig::openConfig(QStringLiteral("kdeglobals")), "KDE"); const QString packageName = cg.readEntry("LookAndFeelPackage", QString()); if (!packageName.isEmpty()) { package.setPath(packageName); } m_qmlObj->setSource(package.fileUrl("runcommandmainscript")); m_qmlObj->engine()->rootContext()->setContextProperty(QStringLiteral("runnerWindow"), this); m_qmlObj->completeInitialization(); auto screenRemoved = [this](QScreen* screen) { if (screen == this->screen()) { setScreen(qGuiApp->primaryScreen()); hide(); } }; auto screenAdded = [this](QScreen* screen) { connect(screen, &QScreen::geometryChanged, this, &View::screenGeometryChanged); screenGeometryChanged(); }; foreach(QScreen* s, QGuiApplication::screens()) screenAdded(s); connect(qGuiApp, &QGuiApplication::screenAdded, this, screenAdded); connect(qGuiApp, &QGuiApplication::screenRemoved, this, screenRemoved); connect(KWindowSystem::self(), &KWindowSystem::workAreaChanged, this, &View::resetScreenPos); connect(this, &View::visibleChanged, this, &View::resetScreenPos); KDirWatch::self()->addFile(m_config.name()); // Catch both, direct changes to the config file ... connect(KDirWatch::self(), &KDirWatch::dirty, this, &View::reloadConfig); connect(KDirWatch::self(), &KDirWatch::created, this, &View::reloadConfig); if (m_floating) { setLocation(Plasma::Types::Floating); } else { setLocation(Plasma::Types::TopEdge); } connect(qGuiApp, &QGuiApplication::focusWindowChanged, this, &View::slotFocusWindowChanged); } View::~View() { } void View::objectIncubated() { connect(m_qmlObj->rootObject(), SIGNAL(widthChanged()), this, SLOT(resetScreenPos())); setMainItem(qobject_cast(m_qmlObj->rootObject())); } void View::slotFocusWindowChanged() { if (!QGuiApplication::focusWindow()) { setVisible(false); } } bool View::freeFloating() const { return m_floating; } void View::setFreeFloating(bool floating) { if (m_floating == floating) { return; } m_floating = floating; if (m_floating) { setLocation(Plasma::Types::Floating); } else { setLocation(Plasma::Types::TopEdge); } positionOnScreen(); } void View::reloadConfig() { m_config.config()->reparseConfiguration(); setFreeFloating(m_config.readEntry("FreeFloating", false)); const QStringList history = m_config.readEntry("history", QStringList()); if (m_history != history) { m_history = history; emit historyChanged(); } } bool View::event(QEvent *event) { // QXcbWindow overwrites the state in its show event. There are plans // to fix this in 5.4, but till then we must explicitly overwrite it // each time. const bool retval = Dialog::event(event); bool setState = event->type() == QEvent::Show; if (event->type() == QEvent::PlatformSurface) { setState = (static_cast(event)->surfaceEventType() == QPlatformSurfaceEvent::SurfaceCreated); } if (setState) { KWindowSystem::setState(winId(), NET::SkipTaskbar | NET::SkipPager); } return retval; } void View::resizeEvent(QResizeEvent *event) { if (event->oldSize().width() != event->size().width()) { positionOnScreen(); } } void View::showEvent(QShowEvent *event) { KWindowSystem::setOnAllDesktops(winId(), true); Dialog::showEvent(event); positionOnScreen(); requestActivate(); } void View::screenGeometryChanged() { if (isVisible()) { positionOnScreen(); } } void View::resetScreenPos() { if (isVisible() && !m_floating) { positionOnScreen(); } } void View::positionOnScreen() { QScreen *shownOnScreen = QGuiApplication::primaryScreen(); Q_FOREACH (QScreen* screen, QGuiApplication::screens()) { if (screen->geometry().contains(QCursor::pos(screen))) { shownOnScreen = screen; break; } } setScreen(shownOnScreen); const QRect r = shownOnScreen->availableGeometry(); if (m_floating && !m_customPos.isNull()) { int x = qBound(r.left(), m_customPos.x(), r.right() - width()); int y = qBound(r.top(), m_customPos.y(), r.bottom() - height()); setPosition(x, y); show(); return; } const int w = width(); int x = r.left() + (r.width() * m_offset) - (w / 2); int y = r.top(); if (m_floating) { y += r.height() / 3; } x = qBound(r.left(), x, r.right() - width()); y = qBound(r.top(), y, r.bottom() - height()); setPosition(x, y); if (m_floating) { KWindowSystem::setOnDesktop(winId(), KWindowSystem::currentDesktop()); KWindowSystem::setType(winId(), NET::Normal); //Turn the sliding effect off KWindowEffects::slideWindow(winId(), KWindowEffects::NoEdge, 0); } else { KWindowSystem::setOnAllDesktops(winId(), true); KWindowEffects::slideWindow(winId(), KWindowEffects::TopEdge, 0); } KWindowSystem::forceActiveWindow(winId()); //qDebug() << "moving to" << m_screenPos[screen]; } void View::displayOrHide() { if (isVisible() && !QGuiApplication::focusWindow()) { KWindowSystem::forceActiveWindow(winId()); return; } setVisible(!isVisible()); } void View::display() { setVisible(true); } void View::displaySingleRunner(const QString &runnerName) { setVisible(true); m_qmlObj->rootObject()->setProperty("runner", runnerName); m_qmlObj->rootObject()->setProperty("query", QString()); } void View::displayWithClipboardContents() { setVisible(true); m_qmlObj->rootObject()->setProperty("runner", QString()); m_qmlObj->rootObject()->setProperty("query", QGuiApplication::clipboard()->text(QClipboard::Selection)); } void View::query(const QString &term) { setVisible(true); m_qmlObj->rootObject()->setProperty("runner", QString()); m_qmlObj->rootObject()->setProperty("query", term); } void View::querySingleRunner(const QString &runnerName, const QString &term) { setVisible(true); m_qmlObj->rootObject()->setProperty("runner", runnerName); m_qmlObj->rootObject()->setProperty("query", term); } void View::switchUser() { QDBusConnection::sessionBus().asyncCall( QDBusMessage::createMethodCall(QStringLiteral("org.kde.ksmserver"), QStringLiteral("/KSMServer"), QStringLiteral("org.kde.KSMServerInterface"), QStringLiteral("openSwitchUserDialog")) ); } void View::displayConfiguration() { QProcess::startDetached(QStringLiteral("kcmshell5"), QStringList() << QStringLiteral("plasmasearch")); } bool View::canConfigure() const { return KAuthorized::authorizeControlModule(QStringLiteral("kcm_plasmasearch.desktop")); } QStringList View::history() const { return m_history; } void View::addToHistory(const QString &item) { if (item.isEmpty()) { return; } if (item == QLatin1String("SESSIONS")) { return; } // Mimic shell behavior of not storing lines starting with a space if (item.at(0).isSpace()) { return; } // Avoid removing the same item from the front and prepending it again if (!m_history.isEmpty() && m_history.constFirst() == item) { return; } if (!KAuthorized::authorize(QStringLiteral("lineedit_text_completion"))) { return; } m_history.removeOne(item); m_history.prepend(item); while (m_history.count() > 50) { // make configurable? m_history.removeLast(); } emit historyChanged(); writeHistory(); m_config.sync(); } void View::removeFromHistory(int index) { if (index < 0 || index >= m_history.count()) { return; } m_history.removeAt(index); emit historyChanged(); writeHistory(); } void View::writeHistory() { m_config.writeEntry("history", m_history); }