File indexing completed on 2024-05-19 05:29:57
0001 /* 0002 SPDX-FileCopyrightText: 2008 Michael Jansen <kde@michael-jansen.biz> 0003 SPDX-FileCopyrightText: 2016 Marco Martin <mart@kde.org> 0004 SPDX-FileCopyrightText: 2021 David Redondo <kde@david-redondo.de> 0005 0006 SPDX-License-Identifier: LGPL-2.0-or-later 0007 */ 0008 0009 #include "kserviceactioncomponent.h" 0010 #include "globalshortcutcontext.h" 0011 #include "logging_p.h" 0012 0013 #include <QFileInfo> 0014 0015 #include <KIO/ApplicationLauncherJob> 0016 #include <KIO/UntrustedProgramHandlerInterface> 0017 #include <KNotificationJobUiDelegate> 0018 0019 #include "config-kglobalaccel.h" 0020 #if HAVE_X11 0021 #include <KStartupInfo> 0022 #include <private/qtx11extras_p.h> 0023 #endif 0024 0025 class UntrustedProgramHandler : public KIO::UntrustedProgramHandlerInterface 0026 { 0027 public: 0028 UntrustedProgramHandler(QObject *parent) 0029 : KIO::UntrustedProgramHandlerInterface(parent) 0030 { 0031 } 0032 0033 void showUntrustedProgramWarning(KJob * /*job*/, const QString & /*programName*/) override 0034 { 0035 Q_EMIT result(true); 0036 } 0037 }; 0038 0039 QString makeUniqueName(const KService::Ptr &service) 0040 { 0041 if (service->storageId().startsWith(QLatin1Char('/'))) { 0042 return QFileInfo(service->storageId()).fileName(); 0043 } 0044 0045 return service->storageId(); 0046 } 0047 0048 KServiceActionComponent::KServiceActionComponent(KService::Ptr service) 0049 : Component(makeUniqueName(service), service->name()) 0050 , m_service(service) 0051 { 0052 } 0053 0054 KServiceActionComponent::~KServiceActionComponent() = default; 0055 0056 void KServiceActionComponent::emitGlobalShortcutPressed(const GlobalShortcut &shortcut) 0057 { 0058 KIO::ApplicationLauncherJob *job = nullptr; 0059 0060 if (shortcut.uniqueName() == QLatin1String("_launch")) { 0061 job = new KIO::ApplicationLauncherJob(m_service); 0062 } else { 0063 const auto actions = m_service->actions(); 0064 const auto it = std::find_if(actions.cbegin(), actions.cend(), [&shortcut](const KServiceAction &action) { 0065 return action.name() == shortcut.uniqueName(); 0066 }); 0067 if (it == actions.cend()) { 0068 qCCritical(KGLOBALACCELD, "failed to find an action matching the '%s' name", qPrintable(shortcut.uniqueName())); 0069 return; 0070 } else { 0071 job = new KIO::ApplicationLauncherJob(*it); 0072 } 0073 } 0074 0075 auto *delegate = new KNotificationJobUiDelegate(KJobUiDelegate::AutoHandlingEnabled); 0076 // ApplicationLauncherJob refuses to launch desktop files in /usr/share/kglobalaccel/ unless they are marked as executable 0077 // to avoid that add our own UntrustedProgramHandler that accepts the launch regardless 0078 new UntrustedProgramHandler(delegate); 0079 job->setUiDelegate(delegate); 0080 #if HAVE_X11 0081 if (QX11Info::isPlatformX11()) { 0082 // Create a startup id ourselves. Otherwise ApplicationLauncherJob will query X11 to get a timestamp, which causes a deadlock 0083 auto startupId = KStartupInfo::createNewStartupIdForTimestamp(QX11Info::appTime()); 0084 job->setStartupId(startupId); 0085 } 0086 #endif 0087 job->start(); 0088 } 0089 0090 void KServiceActionComponent::loadFromService() 0091 { 0092 const QString type = m_service->property<QString>(QStringLiteral("X-KDE-GlobalShortcutType")); 0093 0094 // Type can be Application or Service 0095 // For applications add a lauch shortcut 0096 // If no type is set assume Application 0097 if (type.isEmpty() || type == QLatin1String("Application")) { 0098 const QString shortcutString = m_service->property<QStringList>(QStringLiteral("X-KDE-Shortcuts")).join(QLatin1Char('\t')); 0099 GlobalShortcut *shortcut = registerShortcut(QStringLiteral("_launch"), m_service->name(), shortcutString, shortcutString); 0100 shortcut->setIsPresent(true); 0101 } 0102 0103 const auto lstActions = m_service->actions(); 0104 for (const KServiceAction &action : lstActions) { 0105 const QString shortcutString = action.property<QStringList>(QStringLiteral("X-KDE-Shortcuts")).join(QLatin1Char('\t')); 0106 GlobalShortcut *shortcut = registerShortcut(action.name(), action.text(), shortcutString, shortcutString); 0107 shortcut->setIsPresent(true); 0108 } 0109 } 0110 0111 bool KServiceActionComponent::cleanUp() 0112 { 0113 qCDebug(KGLOBALACCELD) << "Disabling desktop file"; 0114 0115 const auto shortcuts = allShortcuts(); 0116 for (GlobalShortcut *shortcut : shortcuts) { 0117 shortcut->setIsPresent(false); 0118 } 0119 0120 return Component::cleanUp(); 0121 } 0122 0123 void KServiceActionComponent::writeSettings(KConfigGroup &config) const 0124 { 0125 // Clear the config so we remove entries after forgetGlobalShortcut 0126 config.deleteGroup(); 0127 0128 // Now write all contexts 0129 for (GlobalShortcutContext *context : std::as_const(_contexts)) { 0130 KConfigGroup contextGroup; 0131 0132 if (context->uniqueName() == QLatin1String("default")) { 0133 contextGroup = config; 0134 } else { 0135 contextGroup = KConfigGroup(&config, context->uniqueName()); 0136 } 0137 0138 for (const GlobalShortcut *shortcut : std::as_const(context->_actionsMap)) { 0139 // We do not write fresh shortcuts. 0140 // We do not write session shortcuts 0141 if (shortcut->isFresh() || shortcut->isSessionShortcut()) { 0142 continue; 0143 } 0144 0145 if (shortcut->keys() != shortcut->defaultKeys()) { 0146 contextGroup.writeEntry(shortcut->uniqueName(), stringFromKeys(shortcut->keys())); 0147 } else { 0148 contextGroup.revertToDefault(shortcut->uniqueName()); 0149 } 0150 } 0151 } 0152 } 0153 0154 void KServiceActionComponent::loadSettings(KConfigGroup &configGroup) 0155 { 0156 // Action shortcuts 0157 const auto actions = m_service->actions(); 0158 for (const KServiceAction &action : actions) { 0159 const QString defaultShortcutString = action.property<QString>(QStringLiteral("X-KDE-Shortcuts")).replace(QLatin1Char(','), QLatin1Char('\t')); 0160 const QString shortcutString = configGroup.readEntry(action.name(), defaultShortcutString); 0161 0162 GlobalShortcut *shortcut = registerShortcut(action.name(), action.text(), shortcutString, defaultShortcutString); 0163 shortcut->setIsPresent(true); 0164 } 0165 0166 const QString type = m_service->property<QString>(QStringLiteral("X-KDE-GlobalShortcutType")); 0167 0168 // Type can be Application or Service 0169 // For applications add a lauch shortcut 0170 // If no type is set assume Application 0171 if (type.isEmpty() || type == QLatin1String("Application")) { 0172 const QString defaultShortcutString = m_service->property<QString>(QStringLiteral("X-KDE-Shortcuts")).replace(QLatin1Char(','), QLatin1Char('\t')); 0173 const QString shortcutString = configGroup.readEntry("_launch", defaultShortcutString); 0174 GlobalShortcut *shortcut = registerShortcut(QStringLiteral("_launch"), m_service->name(), shortcutString, defaultShortcutString); 0175 shortcut->setIsPresent(true); 0176 } 0177 } 0178 0179 #include "moc_kserviceactioncomponent.cpp"