summaryrefslogtreecommitdiffstats
path: root/src/plugins/platforminputcontexts/ibus/qibusplatforminputcontext.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/plugins/platforminputcontexts/ibus/qibusplatforminputcontext.cpp')
-rw-r--r--src/plugins/platforminputcontexts/ibus/qibusplatforminputcontext.cpp230
1 files changed, 204 insertions, 26 deletions
diff --git a/src/plugins/platforminputcontexts/ibus/qibusplatforminputcontext.cpp b/src/plugins/platforminputcontexts/ibus/qibusplatforminputcontext.cpp
index 673942b5d9..dca21245aa 100644
--- a/src/plugins/platforminputcontexts/ibus/qibusplatforminputcontext.cpp
+++ b/src/plugins/platforminputcontexts/ibus/qibusplatforminputcontext.cpp
@@ -39,6 +39,10 @@
#include <qwindow.h>
#include <qevent.h>
+#include <qpa/qplatformcursor.h>
+#include <qpa/qplatformscreen.h>
+#include <qpa/qwindowsysteminterface.h>
+
#include "qibusproxy.h"
#include "qibusinputcontextproxy.h"
#include "qibustypes.h"
@@ -48,8 +52,14 @@
#include <QtDBus>
+#ifndef IBUS_RELEASE_MASK
+#define IBUS_RELEASE_MASK (1 << 30)
+#endif
+
QT_BEGIN_NAMESPACE
+Q_LOGGING_CATEGORY(qtQpaInputMethods, "qt.qpa.input.methods")
+
enum { debug = 0 };
class QIBusPlatformInputContextPrivate
@@ -63,13 +73,18 @@ public:
delete connection;
}
+ static QString getSocketPath();
static QDBusConnection *createConnection();
+ void initBus();
+ void createBusProxy();
+
QDBusConnection *connection;
QIBusProxy *bus;
QIBusInputContextProxy *context;
bool valid;
+ bool busConnected;
QString predit;
bool needsSurroundingText;
};
@@ -78,14 +93,30 @@ public:
QIBusPlatformInputContext::QIBusPlatformInputContext ()
: d(new QIBusPlatformInputContextPrivate())
{
- if (d->context) {
- connect(d->context, SIGNAL(CommitText(QDBusVariant)), SLOT(commitText(QDBusVariant)));
- connect(d->context, SIGNAL(UpdatePreeditText(QDBusVariant,uint,bool)), this, SLOT(updatePreeditText(QDBusVariant,uint,bool)));
- connect(d->context, SIGNAL(DeleteSurroundingText(int,uint)), this, SLOT(deleteSurroundingText(int,uint)));
- connect(d->context, SIGNAL(RequireSurroundingText()), this, SLOT(surroundingTextRequired()));
+ QString socketPath = QIBusPlatformInputContextPrivate::getSocketPath();
+ QFile file(socketPath);
+ if (file.open(QFile::ReadOnly)) {
+ // If KDE session save is used or restart ibus-daemon,
+ // the applications could run before ibus-daemon runs.
+ // We watch the getSocketPath() to get the launching ibus-daemon.
+ m_socketWatcher.addPath(socketPath);
+ connect(&m_socketWatcher, SIGNAL(fileChanged(QString)), this, SLOT(socketChanged(QString)));
}
+
+ m_timer.setSingleShot(true);
+ connect(&m_timer, SIGNAL(timeout()), this, SLOT(connectToBus()));
+
+ connectToContextSignals();
+
QInputMethod *p = qApp->inputMethod();
connect(p, SIGNAL(cursorRectangleChanged()), this, SLOT(cursorRectChanged()));
+ m_eventFilterUseSynchronousMode = false;
+ if (qEnvironmentVariableIsSet("IBUS_ENABLE_SYNC_MODE")) {
+ bool ok;
+ int enableSync = qgetenv("IBUS_ENABLE_SYNC_MODE").toInt(&ok);
+ if (ok && enableSync == 1)
+ m_eventFilterUseSynchronousMode = true;
+ }
}
QIBusPlatformInputContext::~QIBusPlatformInputContext (void)
@@ -100,7 +131,7 @@ bool QIBusPlatformInputContext::isValid() const
void QIBusPlatformInputContext::invokeAction(QInputMethod::Action a, int)
{
- if (!d->valid)
+ if (!d->busConnected)
return;
if (a == QInputMethod::Click)
@@ -111,7 +142,7 @@ void QIBusPlatformInputContext::reset()
{
QPlatformInputContext::reset();
- if (!d->valid)
+ if (!d->busConnected)
return;
d->context->Reset();
@@ -122,7 +153,7 @@ void QIBusPlatformInputContext::commit()
{
QPlatformInputContext::commit();
- if (!d->valid)
+ if (!d->busConnected)
return;
QObject *input = qApp->focusObject();
@@ -176,7 +207,7 @@ void QIBusPlatformInputContext::update(Qt::InputMethodQueries q)
void QIBusPlatformInputContext::cursorRectChanged()
{
- if (!d->valid)
+ if (!d->busConnected)
return;
QRect r = qApp->inputMethod()->cursorRectangle().toRect();
@@ -194,7 +225,7 @@ void QIBusPlatformInputContext::cursorRectChanged()
void QIBusPlatformInputContext::setFocusObject(QObject *object)
{
- if (!d->valid)
+ if (!d->busConnected)
return;
if (debug)
@@ -272,33 +303,175 @@ void QIBusPlatformInputContext::deleteSurroundingText(int offset, uint n_chars)
QCoreApplication::sendEvent(input, &event);
}
-bool
-QIBusPlatformInputContext::x11FilterEvent(uint keyval, uint keycode, uint state, bool press)
+bool QIBusPlatformInputContext::filterEvent(const QEvent *event)
{
- if (!d->valid)
+ if (!d->busConnected)
return false;
if (!inputMethodAccepted())
return false;
- if (!press)
- return false;
+ const QKeyEvent *keyEvent = static_cast<const QKeyEvent *>(event);
+ quint32 sym = keyEvent->nativeVirtualKey();
+ quint32 code = keyEvent->nativeScanCode();
+ quint32 state = keyEvent->nativeModifiers();
+ quint32 ibusState = state;
+
+ if (keyEvent->type() != QEvent::KeyPress)
+ ibusState |= IBUS_RELEASE_MASK;
+
+ QDBusPendingReply<bool> reply = d->context->ProcessKeyEvent(sym, code - 8, ibusState);
+
+ if (m_eventFilterUseSynchronousMode || reply.isFinished()) {
+ bool retval = reply.value();
+ qCDebug(qtQpaInputMethods) << "filterEvent return" << code << sym << state << retval;
+ return retval;
+ }
+
+ Qt::KeyboardModifiers modifiers = keyEvent->modifiers();
+ const int qtcode = keyEvent->key();
+
+ // From QKeyEvent::modifiers()
+ switch (qtcode) {
+ case Qt::Key_Shift:
+ modifiers ^= Qt::ShiftModifier;
+ break;
+ case Qt::Key_Control:
+ modifiers ^= Qt::ControlModifier;
+ break;
+ case Qt::Key_Alt:
+ modifiers ^= Qt::AltModifier;
+ break;
+ case Qt::Key_Meta:
+ modifiers ^= Qt::MetaModifier;
+ break;
+ case Qt::Key_AltGr:
+ modifiers ^= Qt::GroupSwitchModifier;
+ break;
+ }
+
+ QVariantList args;
+ args << QVariant::fromValue(keyEvent->timestamp());
+ args << QVariant::fromValue(static_cast<uint>(keyEvent->type()));
+ args << QVariant::fromValue(qtcode);
+ args << QVariant::fromValue(code) << QVariant::fromValue(sym) << QVariant::fromValue(state);
+ args << QVariant::fromValue(keyEvent->text());
+ args << QVariant::fromValue(keyEvent->isAutoRepeat());
+
+ QIBusFilterEventWatcher *watcher = new QIBusFilterEventWatcher(reply, this, QGuiApplication::focusWindow(), modifiers, args);
+ QObject::connect(watcher, &QDBusPendingCallWatcher::finished, this, &QIBusPlatformInputContext::filterEventFinished);
+
+ return true;
+}
+
+void QIBusPlatformInputContext::filterEventFinished(QDBusPendingCallWatcher *call)
+{
+ QIBusFilterEventWatcher *watcher = (QIBusFilterEventWatcher *) call;
+ QDBusPendingReply<bool> reply = *call;
+
+ if (reply.isError()) {
+ call->deleteLater();
+ return;
+ }
+
+ // Use watcher's window instead of the current focused window
+ // since there is a time lag until filterEventFinished() returns.
+ QWindow *window = watcher->window();
+
+ if (!window) {
+ call->deleteLater();
+ return;
+ }
+
+ Qt::KeyboardModifiers modifiers = watcher->modifiers();
+ QVariantList args = watcher->arguments();
+ const ulong time = static_cast<const ulong>(args.at(0).toUInt());
+ const QEvent::Type type = static_cast<const QEvent::Type>(args.at(1).toUInt());
+ const int qtcode = args.at(2).toInt();
+ const quint32 code = args.at(3).toUInt();
+ const quint32 sym = args.at(4).toUInt();
+ const quint32 state = args.at(5).toUInt();
+ const QString string = args.at(6).toString();
+ const bool isAutoRepeat = args.at(7).toBool();
+
+ // copied from QXcbKeyboard::handleKeyEvent()
+ bool retval = reply.value();
+ qCDebug(qtQpaInputMethods) << "filterEventFinished return" << code << sym << state << retval;
+ if (!retval) {
+ if (type == QEvent::KeyPress && qtcode == Qt::Key_Menu
+ && window != NULL) {
+ const QPoint globalPos = window->screen()->handle()->cursor()->pos();
+ const QPoint pos = window->mapFromGlobal(globalPos);
+ QWindowSystemInterface::handleContextMenuEvent(window, false, pos,
+ globalPos, modifiers);
+ }
+ QWindowSystemInterface::handleExtendedKeyEvent(window, time, type, qtcode, modifiers,
+ code, sym, state, string, isAutoRepeat);
+
+ }
+ call->deleteLater();
+}
+
+void QIBusPlatformInputContext::socketChanged(const QString &str)
+{
+ qCDebug(qtQpaInputMethods) << "socketChanged";
+ Q_UNUSED (str);
+
+ m_timer.stop();
- keycode -= 8; // ###
- QDBusReply<bool> reply = d->context->ProcessKeyEvent(keyval, keycode, state);
+ if (d->context)
+ disconnect(d->context);
+ if (d->connection)
+ d->connection->disconnectFromBus(QLatin1String("QIBusProxy"));
-// qDebug() << "x11FilterEvent return" << reply.value();
+ m_timer.start(100);
+}
+
+// When getSocketPath() is modified, the bus is not established yet
+// so use m_timer.
+void QIBusPlatformInputContext::connectToBus()
+{
+ qCDebug(qtQpaInputMethods) << "QIBusPlatformInputContext::connectToBus";
+ d->initBus();
+ connectToContextSignals();
+
+ if (m_socketWatcher.files().size() == 0)
+ m_socketWatcher.addPath(QIBusPlatformInputContextPrivate::getSocketPath());
+}
- return reply.value();
+void QIBusPlatformInputContext::connectToContextSignals()
+{
+ if (d->context) {
+ connect(d->context, SIGNAL(CommitText(QDBusVariant)), SLOT(commitText(QDBusVariant)));
+ connect(d->context, SIGNAL(UpdatePreeditText(QDBusVariant,uint,bool)), this, SLOT(updatePreeditText(QDBusVariant,uint,bool)));
+ connect(d->context, SIGNAL(DeleteSurroundingText(int,uint)), this, SLOT(deleteSurroundingText(int,uint)));
+ connect(d->context, SIGNAL(RequireSurroundingText()), this, SLOT(surroundingTextRequired()));
+ }
}
QIBusPlatformInputContextPrivate::QIBusPlatformInputContextPrivate()
- : connection(createConnection()),
+ : connection(0),
bus(0),
context(0),
valid(false),
+ busConnected(false),
needsSurroundingText(false)
{
+ valid = !QStandardPaths::findExecutable(QString::fromLocal8Bit("ibus-daemon"), QStringList()).isEmpty();
+ if (!valid)
+ return;
+ initBus();
+}
+
+void QIBusPlatformInputContextPrivate::initBus()
+{
+ connection = createConnection();
+ busConnected = false;
+ createBusProxy();
+}
+
+void QIBusPlatformInputContextPrivate::createBusProxy()
+{
if (!connection || !connection->isConnected())
return;
@@ -334,13 +507,13 @@ QIBusPlatformInputContextPrivate::QIBusPlatformInputContextPrivate()
context->SetCapabilities(IBUS_CAP_PREEDIT_TEXT|IBUS_CAP_FOCUS|IBUS_CAP_SURROUNDING_TEXT);
if (debug)
- qDebug(">>>> valid!");
- valid = true;
+ qDebug(">>>> bus connected!");
+ busConnected = true;
}
-QDBusConnection *QIBusPlatformInputContextPrivate::createConnection()
+QString QIBusPlatformInputContextPrivate::getSocketPath()
{
- QByteArray display(getenv("DISPLAY"));
+ QByteArray display(qgetenv("DISPLAY"));
QByteArray host = "unix";
QByteArray displayNumber = "0";
@@ -356,9 +529,14 @@ QDBusConnection *QIBusPlatformInputContextPrivate::createConnection()
if (debug)
qDebug() << "host=" << host << "displayNumber" << displayNumber;
- QFile file(QDir::homePath() + QLatin1String("/.config/ibus/bus/") +
+ return QDir::homePath() + QLatin1String("/.config/ibus/bus/") +
QLatin1String(QDBusConnection::localMachineId()) +
- QLatin1Char('-') + QString::fromLocal8Bit(host) + QLatin1Char('-') + QString::fromLocal8Bit(displayNumber));
+ QLatin1Char('-') + QString::fromLocal8Bit(host) + QLatin1Char('-') + QString::fromLocal8Bit(displayNumber);
+}
+
+QDBusConnection *QIBusPlatformInputContextPrivate::createConnection()
+{
+ QFile file(getSocketPath());
if (!file.open(QFile::ReadOnly))
return 0;