swift
contextapplicationproxy.cpp
1 // SPDX-FileCopyrightText: Copyright (C) 2013 swift Project Community / Contributors
2 // SPDX-License-Identifier: GPL-3.0-or-later OR LicenseRef-swift-pilot-client-1
3 
5 
6 #include <QDBusConnection>
7 #include <QLatin1String>
8 #include <QObject>
9 #include <QtGlobal>
10 
11 #include "core/application.h"
12 #include "misc/dbus.h"
13 #include "misc/dbusserver.h"
15 #include "misc/identifierlist.h"
16 #include "misc/loghandler.h"
17 
18 using namespace swift::misc;
19 
20 namespace swift::core::context
21 {
22  CContextApplicationProxy::CContextApplicationProxy(const QString &serviceName, QDBusConnection &connection,
24  : IContextApplication(mode, runtime)
25  {
26  m_dBusInterface = new CGenericDBusInterface(serviceName, IContextApplication::ObjectPath(),
27  IContextApplication::InterfaceName(), connection, this);
28  this->relaySignals(serviceName, connection);
29 
31  &CContextApplicationProxy::processRemoteHotkeyActionCall);
32 
33  m_pingTimer.setObjectName(serviceName + "::m_pingTimer");
34  connect(&m_pingTimer, &QTimer::timeout, this, &CContextApplicationProxy::reRegisterApplications);
35  m_pingTimer.start(PingIdentifiersMs);
36  }
37 
38  void CContextApplicationProxy::relaySignals(const QString &serviceName, QDBusConnection &connection)
39  {
40  // signals originating from impl side
41  bool s = connection.connect(serviceName, IContextApplication::ObjectPath(),
42  IContextApplication::InterfaceName(), "settingsChanged", this,
44  Q_ASSERT(s);
45  s = connection.connect(serviceName, IContextApplication::ObjectPath(), IContextApplication::InterfaceName(),
46  "registrationChanged", this, SIGNAL(registrationChanged()));
47  Q_ASSERT(s);
48  s = connection.connect(serviceName, IContextApplication::ObjectPath(), IContextApplication::InterfaceName(),
49  "hotkeyActionsRegistered", this,
51  Q_ASSERT(s);
52  s = connection.connect(serviceName, IContextApplication::ObjectPath(), IContextApplication::InterfaceName(),
53  "remoteHotkeyAction", this,
54  SIGNAL(remoteHotkeyAction(QString, bool, swift::misc::CIdentifier)));
55  Q_ASSERT(s);
56  Q_UNUSED(s);
57  this->relayBaseClassSignals(serviceName, connection, IContextApplication::ObjectPath(),
59  }
60 
62  {
63  m_dBusInterface->callDBus(QLatin1String("changeSettings"), settings, origin);
64  }
65 
67  {
68  return m_dBusInterface->callDBusRet<swift::misc::CValueCachePacket>(QLatin1String("getAllSettings"));
69  }
70 
72  {
73  return m_dBusInterface->callDBusRet<QStringList>(QLatin1String("getUnsavedSettingsKeys"));
74  }
75 
77  {
78  CSettingsDictionary result =
79  m_dBusInterface->callDBusRet<CSettingsDictionary>(QLatin1String("getUnsavedSettingsKeysDescribed"));
80  for (auto it = result.begin(); it != result.end(); ++it)
81  {
82  // consolidate with local names to fill any gaps in remote names
83  if (it.value().isEmpty()) { it.value() = CSettingsCache::instance()->getHumanReadableName(it.key()); }
84  }
85  return result;
86  }
87 
89  {
90  // note this proxy method does not call synchronizeLocalSettings in core
92  }
93 
95  {
96  return m_dBusInterface->callDBusRet<swift::misc::CStatusMessage>(QLatin1String("saveSettings"), keyPrefix);
97  }
98 
100  {
101  return m_dBusInterface->callDBusRet<swift::misc::CStatusMessage>(QLatin1String("saveSettingsByKey"), keys);
102  }
103 
105  {
106  return m_dBusInterface->callDBusRet<swift::misc::CStatusMessage>(QLatin1String("loadSettings"));
107  }
108 
109  void CContextApplicationProxy::registerHotkeyActions(const QStringList &actions, const CIdentifier &origin)
110  {
111  m_dBusInterface->callDBus(QLatin1String("registerHotkeyActions"), actions, origin);
112  }
113 
114  void CContextApplicationProxy::callHotkeyActionRemotely(const QString &action, bool argument,
115  const CIdentifier &origin)
116  {
117  m_dBusInterface->callDBus(QLatin1String("callHotkeyActionRemotely"), action, argument, origin);
118  }
119 
121  {
122  m_proxyPingIdentifiers.insert(application);
123  if (m_pingTimer.isActive()) { m_pingTimer.start(); } // restart, no need to ping again
124  return m_dBusInterface->callDBusRet<swift::misc::CIdentifier>(QLatin1String("registerApplication"),
125  application);
126  }
127 
129  {
130  m_proxyPingIdentifiers.remove(application);
131  m_dBusInterface->callDBus(QLatin1String("unregisterApplication"), application);
132  }
133 
135  {
136  return m_dBusInterface->callDBusRet<swift::misc::CIdentifierList>(QLatin1String("getRegisteredApplications"));
137  }
138 
140  {
141  return m_dBusInterface->callDBusRet<swift::misc::CIdentifier>(QLatin1String("getApplicationIdentifier"));
142  }
143 
144  void CContextApplicationProxy::reRegisterApplications()
145  {
146  if (!m_dBusInterface) { return; }
147  if (m_proxyPingIdentifiers.isEmpty()) { return; }
148  const QSet<swift::misc::CIdentifier> identifiers = m_proxyPingIdentifiers; // copy so member can be modified
149  for (const CIdentifier &identifier : identifiers) { this->registerApplication(identifier); }
150  }
151 
152  bool CContextApplicationProxy::isContextResponsive(const QString &dBusAddress, QString &msg, int timeoutMs)
153  {
154  const bool connected = CDBusServer::isDBusAvailable(dBusAddress, msg, timeoutMs);
155  if (!connected) { return false; }
156 
157  static const QString dBusName("contexttest");
158  QDBusConnection connection = CDBusServer::connectToDBus(dBusAddress, dBusName);
160  CCoreFacadeConfig::Remote, nullptr);
161  const CIdentifier id("swift proxy test");
162  const CIdentifier pingId = proxy.registerApplication(id);
163  const bool ok = (id == pingId);
164  if (ok) { proxy.unregisterApplication(id); }
165  else { msg = "Mismatch in proxy ping, context not ready."; }
166  CDBusServer::disconnectFromDBus(connection, dBusAddress);
167  return ok;
168  }
169 
170  void CContextApplicationProxy::processRemoteHotkeyActionCall(const QString &action, bool argument,
171  const CIdentifier &origin)
172  {
173  if (!sApp || origin.isFromLocalMachine()) { return; }
174  sApp->getInputManager()->callFunctionsBy(action, argument);
176  << "Calling function" << action << "from origin" << origin.getMachineName();
177  }
178 } // namespace swift::core::context
SWIFT_CORE_EXPORT swift::core::CApplication * sApp
Single instance of application object.
Definition: application.cpp:71
CInputManager * getInputManager() const
The input manager, if available.
Definition: application.h:302
ContextMode
How to handle a given context.
@ Remote
context runs in a different process.
The class providing facades (the contexts) for all DBus relevant operations.
Definition: corefacade.h:57
void callFunctionsBy(const QString &action, bool isKeyDown, bool shouldEmit=true)
Call functions by hotkeyfunction.
virtual void changeSettings(const swift::misc::CValueCachePacket &settings, const swift::misc::CIdentifier &origin)
Ratify some settings changed by another process.
virtual QStringList getUnsavedSettingsKeys() const
Get keys of all unsaved settings currently in core settings cache.
virtual swift::misc::CIdentifier getApplicationIdentifier() const
Identifier of application, remote side if distributed.
virtual swift::misc::CStatusMessage loadSettings()
Load core settings from disk.
virtual swift::misc::CStatusMessage saveSettings(const QString &keyPrefix={})
Save core settings to disk.
virtual void unregisterApplication(const swift::misc::CIdentifier &application)
Unregister application.
virtual void synchronizeLocalSettings()
Update local settings with settings from core.
virtual swift::core::context::CSettingsDictionary getUnsavedSettingsKeysDescribed() const
Get keys and descriptions of all unsaved settings currently in core settings cache.
virtual swift::misc::CStatusMessage saveSettingsByKey(const QStringList &keys)
Save core settings to disk.
static bool isContextResponsive(const QString &dbusAddress, QString &msg, int timeoutMs=1500)
Used to test if there is a core running?
virtual swift::misc::CIdentifier registerApplication(const swift::misc::CIdentifier &application)
Register application, can also be used for ping.
virtual swift::misc::CIdentifierList getRegisteredApplications() const
All registered applications.
virtual swift::misc::CValueCachePacket getAllSettings() const
Get all settings currently in core settings cache.
virtual void registerHotkeyActions(const QStringList &actions, const swift::misc::CIdentifier &origin)
Register hotkey action implemented by another process.
virtual void callHotkeyActionRemotely(const QString &action, bool argument, const swift::misc::CIdentifier &origin)
Call a hotkey action on a remote process.
void remoteHotkeyAction(const QString &action, bool argument, const swift::misc::CIdentifier &origin)
Call a hotkey action on a remote process.
static const QString & ObjectPath()
Service path.
static const QString & InterfaceName()
Service name.
void registrationChanged()
A component changes.
void hotkeyActionsRegistered(const QStringList &actions, const swift::misc::CIdentifier &origin)
New action was registered.
static constexpr int PingIdentifiersMs
how often identifiers are pinged
void settingsChanged(const swift::misc::CValueCachePacket &settings, const swift::misc::CIdentifier &origin)
One or more settings were changed.
void relayBaseClassSignals(const QString &serviceName, QDBusConnection &connection, const QString &objectPath, const QString &interfaceName)
Relay signals from this class.
Definition: context.cpp:61
static void disconnectFromDBus(const QDBusConnection &connection, const QString &dBusAddress)
Disconnect from Bus/Peer to peer.
Definition: dbusserver.cpp:351
static QDBusConnection connectToDBus(const QString &dbusAddress, const QString &name={})
Connect to DBus.
Definition: dbusserver.cpp:331
static bool isDBusAvailable(const QString &host, int port, int timeoutMs=1500)
Is there a DBus server running at the given address?
Definition: dbusserver.cpp:445
static const QString & coreServiceName()
Default service name.
Definition: dbusserver.cpp:98
const Value value(const Key &key) const
Returns the value associated with the key.
Definition: dictionary.h:404
iterator end()
Returns iterator at the end of the dictionary.
Definition: dictionary.h:305
iterator begin()
Returns iterator at the beginning of the dictionary.
Definition: dictionary.h:296
Used for hand written interface based on virtual methods.
void callDBus(QLatin1String method, Args &&...args)
Call DBus, no return value.
Ret callDBusRet(QLatin1String method, Args &&...args)
Call DBus with synchronous return value.
Value object encapsulating information identifying a component of a modular distributed swift process...
Definition: identifier.h:29
const QString & getMachineName() const
Machine name.
Definition: identifier.h:103
bool isFromLocalMachine() const
Check if originating from the same local machine.
Definition: identifier.cpp:173
static const CIdentifier & null()
Null (empty) identifier.
Definition: identifier.cpp:84
Value object encapsulating a list of object identifiers.
static const QString & contextSlot()
Context slots.
Definition: logcategories.h:87
Class for emitting a log message.
Definition: logmessage.h:27
Derived & debug()
Set the severity to debug.
static CSettingsCache * instance()
Return the singleton instance.
Streamable status message, e.g.
void changeValuesFromRemote(const swift::misc::CValueCachePacket &values, const swift::misc::CIdentifier &originator)
Notify this cache that values have been changed by one of the duplicate caches in the multi-process e...
QString getHumanReadableName(const QString &key) const
Return the human readable name of the given key, or the raw key string if there is none.
Value class used for signalling changed values in the cache.
Definition: valuecache.h:67
Free functions in swift::misc.