1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152
|
/*
* SPDX-FileCopyrightText: 2012~2023 CSSlayer <wengxt@gmail.com>
*
* SPDX-License-Identifier: BSD-3-Clause
*
*/
#ifndef _FCITX4INPUTCONTEXTPROXY_P_H_
#define _FCITX4INPUTCONTEXTPROXY_P_H_
#include "fcitx4inputcontextproxy.h"
#include "fcitx4inputcontextproxyimpl.h"
#include "fcitx4inputmethodproxy.h"
#include "fcitx4watcher.h"
#include <QDBusServiceWatcher>
#include <cstddef>
#include <unistd.h>
namespace fcitx {
class Fcitx4InputContextProxyPrivate {
public:
Fcitx4InputContextProxyPrivate(Fcitx4Watcher *watcher,
Fcitx4InputContextProxy *q)
: q_ptr(q), fcitxWatcher_(watcher), watcher_(q) {
registerFcitxQtDBusTypes();
QObject::connect(fcitxWatcher_, &Fcitx4Watcher::availabilityChanged, q,
[this]() { availabilityChanged(); });
watcher_.setWatchMode(QDBusServiceWatcher::WatchForUnregistration);
QObject::connect(&watcher_, &QDBusServiceWatcher::serviceUnregistered,
q, [this]() {
cleanUp();
availabilityChanged();
});
availabilityChanged();
}
~Fcitx4InputContextProxyPrivate() {
if (isValid()) {
icproxy_->DestroyIC();
}
cleanUp();
}
bool isValid() const { return (icproxy_ && icproxy_->isValid()); }
void availabilityChanged() {
QTimer::singleShot(100, q_ptr, [this]() { recheck(); });
}
void recheck() {
if (!isValid() && fcitxWatcher_->availability()) {
createInputContext();
}
if (!fcitxWatcher_->availability()) {
cleanUp();
}
}
void cleanUp() {
auto services = watcher_.watchedServices();
for (const auto &service : services) {
watcher_.removeWatchedService(service);
}
delete improxy_;
improxy_ = nullptr;
delete icproxy_;
icproxy_ = nullptr;
delete createInputContextWatcher_;
createInputContextWatcher_ = nullptr;
}
void createInputContext() {
Q_Q(Fcitx4InputContextProxy);
if (!fcitxWatcher_->availability()) {
return;
}
cleanUp();
auto service = fcitxWatcher_->service();
auto connection = fcitxWatcher_->connection();
auto owner = connection.interface()->serviceOwner(service);
if (!owner.isValid()) {
return;
}
watcher_.setConnection(connection);
watcher_.setWatchedServices(QStringList() << owner);
// Avoid race, query again.
if (!connection.interface()->isServiceRegistered(owner)) {
cleanUp();
return;
}
QFileInfo info(QCoreApplication::applicationFilePath());
improxy_ =
new Fcitx4InputMethodProxy(owner, "/inputmethod", connection, q);
auto result = improxy_->CreateICv3(info.fileName(), getpid());
createInputContextWatcher_ = new QDBusPendingCallWatcher(result);
QObject::connect(createInputContextWatcher_,
&QDBusPendingCallWatcher::finished, q,
[this]() { createInputContextFinished(); });
}
void createInputContextFinished() {
Q_Q(Fcitx4InputContextProxy);
if (createInputContextWatcher_->isError()) {
cleanUp();
return;
}
QDBusPendingReply<int, bool, unsigned int, unsigned int, unsigned int,
unsigned int>
reply(*createInputContextWatcher_);
QString path = QStringLiteral("/inputcontext_%1").arg(reply.value());
icproxy_ = new Fcitx4InputContextProxyImpl(improxy_->service(), path,
improxy_->connection(), q);
QObject::connect(icproxy_, &Fcitx4InputContextProxyImpl::CommitString,
q, &Fcitx4InputContextProxy::commitString);
QObject::connect(icproxy_, &Fcitx4InputContextProxyImpl::CurrentIM, q,
&Fcitx4InputContextProxy::currentIM);
QObject::connect(icproxy_,
&Fcitx4InputContextProxyImpl::DeleteSurroundingText, q,
&Fcitx4InputContextProxy::deleteSurroundingText);
QObject::connect(icproxy_, &Fcitx4InputContextProxyImpl::ForwardKey, q,
&Fcitx4InputContextProxy::forwardKey);
QObject::connect(icproxy_,
&Fcitx4InputContextProxyImpl::UpdateFormattedPreedit,
q, &Fcitx4InputContextProxy::updateFormattedPreedit);
delete createInputContextWatcher_;
createInputContextWatcher_ = nullptr;
Q_EMIT q->inputContextCreated();
}
Fcitx4InputContextProxy *q_ptr;
Q_DECLARE_PUBLIC(Fcitx4InputContextProxy);
Fcitx4Watcher *fcitxWatcher_;
QDBusServiceWatcher watcher_;
Fcitx4InputMethodProxy *improxy_ = nullptr;
Fcitx4InputContextProxyImpl *icproxy_ = nullptr;
QDBusPendingCallWatcher *createInputContextWatcher_ = nullptr;
QString display_;
};
} // namespace fcitx
#endif // _FCITX4INPUTCONTEXTPROXY_P_H_
|