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