Fcitx
servicewatcher.cpp
1 /*
2  * SPDX-FileCopyrightText: 2016-2016 CSSlayer <wengxt@gmail.com>
3  *
4  * SPDX-License-Identifier: LGPL-2.1-or-later
5  *
6  */
7 
8 #include "servicewatcher.h"
9 #include <memory>
10 #include <string>
11 #include <tuple>
12 #include <unordered_map>
13 #include <utility>
14 #include "../handlertable.h"
15 #include "../macros.h"
16 #include "../trackableobject.h"
17 #include "matchrule.h"
18 #include "message.h"
19 
20 namespace fcitx::dbus {
21 
22 class ServiceWatcherPrivate : public TrackableObject<ServiceWatcherPrivate> {
23 public:
25  : bus_(&bus),
26  watcherMap_(
27  [this](const std::string &key) {
28  auto slot = bus_->addMatch(
29  MatchRule("org.freedesktop.DBus", "/org/freedesktop/DBus",
30  "org.freedesktop.DBus", "NameOwnerChanged",
31  {key}),
32  [this](Message &msg) {
33  std::string name;
34  std::string oldOwner;
35  std::string newOwner;
36  msg >> name >> oldOwner >> newOwner;
37  querySlots_.erase(name);
38 
39  auto view = watcherMap_.view(name);
40  for (auto &entry : view) {
41  entry(name, oldOwner, newOwner);
42  }
43  return false;
44  });
45  auto querySlot = bus_->serviceOwnerAsync(
46  key, 0, [this, key](Message &msg) {
47  // Key itself may be gone later, put it on the stack.
48  const std::string &pivotKey = key;
49  auto protector = watch();
50  std::string newName;
51  if (msg.type() != dbus::MessageType::Error) {
52  msg >> newName;
53  } else {
54  if (msg.errorName() !=
55  "org.freedesktop.DBus.Error.NameHasNoOwner") {
56  return false;
57  }
58  }
59  for (auto &entry : watcherMap_.view(pivotKey)) {
60  entry(pivotKey, "", newName);
61  }
62  // "this" maybe deleted as well because it's a member
63  // in lambda.
64  if (auto *that = protector.get()) {
65  that->querySlots_.erase(pivotKey);
66  }
67  return false;
68  });
69  if (!slot || !querySlot) {
70  return false;
71  }
72  slots_.emplace(std::piecewise_construct,
73  std::forward_as_tuple(key),
74  std::forward_as_tuple(std::move(slot)));
75  querySlots_.emplace(
76  std::piecewise_construct, std::forward_as_tuple(key),
77  std::forward_as_tuple(std::move(querySlot)));
78  return true;
79  },
80  [this](const std::string &key) {
81  slots_.erase(key);
82  querySlots_.erase(key);
83  }) {}
84 
85  Bus *bus_;
87  std::unordered_map<std::string, std::unique_ptr<Slot>> slots_;
88  std::unordered_map<std::string, std::unique_ptr<Slot>> querySlots_;
89 };
90 
91 ServiceWatcher::ServiceWatcher(Bus &bus)
92  : d_ptr(std::make_unique<ServiceWatcherPrivate>(bus)) {}
93 
94 std::unique_ptr<HandlerTableEntry<ServiceWatcherCallback>>
95 ServiceWatcher::watchService(const std::string &name,
96  ServiceWatcherCallback callback) {
97  FCITX_D();
98  return d->watcherMap_.add(name, std::move(callback));
99 }
100 
101 ServiceWatcher::~ServiceWatcher() {}
102 } // namespace fcitx::dbus
Basic DBus type of a DBus message.
Definition: message.h:224
A dbus matching rule to be used with add match.
Definition: matchrule.h:36
A class that represents a connection to the Bus.
Definition: bus.h:51
API for DBus message.
API for service monitoring.
MessageType type() const
Return the message type.
Definition: message.cpp:71
Helper class to be used with TrackableObjectReference.
API for DBus matching rule.
std::string errorName() const
Return the error name of the message.
Definition: message.cpp:134