From 7134200e0e73d813896a7c6be04df02c81e1d63a Mon Sep 17 00:00:00 2001 From: Derek Dai <daiderek@gmail.com> Date: Sun, 1 Mar 2020 23:08:26 +0800 Subject: [PATCH 7/7] Add QT5 support --- .gitignore | 3 - configure.ac | 70 ++- extras/immodules/Makefile.am | 2 +- .../immodules/client-qt/im-scim-bridge-qt.cpp | 82 ++-- .../immodules/client-qt/im-scim-bridge-qt.h | 57 +++ extras/immodules/client-qt/qt3/Makefile.am | 72 +++ extras/immodules/client-qt/qt4/Makefile.am | 73 +++ extras/immodules/client-qt/qt5/Makefile.am | 72 +++ .../client-qt/scim-bridge-client-common-qt.h | 6 + .../scim-bridge-client-imcontext-qt.cpp | 414 +++++++++++++++--- .../scim-bridge-client-imcontext-qt.h | 74 +++- ...cim-bridge-client-key-event-utility-qt.cpp | 128 +++++- .../scim-bridge-client-key-event-utility-qt.h | 28 ++ .../client-qt/scim-bridge-client-qt.cpp | 2 + .../client-qt/scim-bridge-client-qt.h | 5 + extras/immodules/configure.ac | 31 +- utils/Makefile.am | 3 +- 17 files changed, 986 insertions(+), 136 deletions(-) delete mode 100644 .gitignore create mode 100644 extras/immodules/client-qt/im-scim-bridge-qt.h create mode 100644 extras/immodules/client-qt/qt3/Makefile.am create mode 100644 extras/immodules/client-qt/qt4/Makefile.am create mode 100644 extras/immodules/client-qt/qt5/Makefile.am diff --git a/.gitignore b/.gitignore deleted file mode 100644 index bb9bba5..0000000 --- a/.gitignore +++ /dev/null @@ -1,3 +0,0 @@ -.c* -.project -.settings diff --git a/configure.ac b/configure.ac index 2841926..8c9eca6 100644 --- a/configure.ac +++ b/configure.ac @@ -297,7 +297,7 @@ if test "$SCIM_HAS_QT3" = "yes"; then AC_SUBST(QT3_LIBDIR) fi -PKG_CHECK_MODULES(QT4, [QtGui >= 4.0, QtCore >= 4.0], +PKG_CHECK_MODULES(QT4, [x11, QtGui >= 4.0], [SCIM_HAS_QT4=yes], [SCIM_HAS_QT4=no]) @@ -306,7 +306,7 @@ if test "$SCIM_HAS_QT4" = "yes"; then QT4_PREFIX=`$PKG_CONFIG --variable=prefix QtCore` QT4_LIBDIR=`$PKG_CONFIG --variable=libdir QtCore` fi - QT4_MOC=$QT4_PREFIX/bin/moc + QT4_MOC=`$PKG_CONFIG --variable=moc_location QtCore` QT4_IM_MODULEDIR=$QT4_LIBDIR/qt4/plugins/inputmethods AC_SUBST(QT4_MOC) AC_SUBST(QT4_IM_MODULEDIR) @@ -314,6 +314,35 @@ if test "$SCIM_HAS_QT4" = "yes"; then AC_SUBST(QT4_LIBDIR) fi +PKG_CHECK_MODULES(QT5, [xproto, xcb-keysyms, Qt5X11Extras >= 5.0, Qt5Widgets >= 5.0], + [SCIM_HAS_QT5=yes], + [SCIM_HAS_QT5=no]) + +if test "$SCIM_HAS_QT5" = "yes"; then + if test -z "$QT5_PREFIX"; then + QT5_PREFIX=`$PKG_CONFIG --variable=prefix Qt5Core` + QT5_LIBDIR=`$PKG_CONFIG --variable=libdir Qt5Core` + fi + QT5_INCDIR=`$PKG_CONFIG --variable=includedir Qt5Core` + QT5_VERSION=`$PKG_CONFIG --modversion Qt5Core` + QT5_CFLAGS="$QT5_CFLAGS -I$QT5_INCDIR/QtCore/$QT5_VERSION -I$QT5_INCDIR/QtCore/$QT5_VERSION/QtCore -I$QT5_INCDIR/QtGui/$QT5_VERSION" + QT5_MOC=`$PKG_CONFIG --variable=host_bins Qt5Core`/moc + QT5_IM_MODULEDIR=$QT5_LIBDIR/qt5/plugins/platforminputcontexts + AC_SUBST(QT5_MOC) + AC_SUBST(QT5_IM_MODULEDIR) + AC_SUBST(QT5_PREFIX) + AC_SUBST(QT5_LIBDIR) + + tmp_CPPFLAGS="$CPPFLAGS" + CPPFLAGS="$QT5_CFLAGS -fPIC" + AC_LANG_PUSH([C++]) + AC_CHECK_HEADERS([QtGui/qpa/qplatforminputcontext.h], + [SCIM_HAS_QT5_PRIVATE=yes], + [AC_MSG_ERROR([QT5 platform development headers are needed. In Debian based OS, install qtbase5-private-dev package])]) + CPPFLAGS="$tmp_CPPFLAGS" + AC_LANG_POP +fi + # Check if we should build scim-bridge-clutter-immodule PKG_CHECK_MODULES(CLUTTER, clutter-1.0, [SCIM_HAS_CLUTTER=yes], @@ -371,6 +400,11 @@ AC_ARG_WITH([qt4-moc], [Select QT4 moc program (default to QT4_PREFIX/bin/moc)])], [QT4_MOC=$with_qt4_moc]) +AC_ARG_WITH([qt5-moc], + [AS_HELP_STRING([--with-qt5-moc=file], + [Select QT5 moc program (default to QT5_PREFIX/bin/moc)])], + [QT5_MOC=$with_qt5_moc]) + AC_ARG_WITH([qt3-im-module-dir], [AS_HELP_STRING([--with-qt3-im-module-dir=dir], [Select QT3 immodule dir])], @@ -381,6 +415,11 @@ AC_ARG_WITH([qt4-im-module-dir], [Select QT4 immodule dir])], [QT4_IM_MODULEDIR=$with_qt4_im_module_dir]) +AC_ARG_WITH([qt5-im-module-dir], + [AS_HELP_STRING([--with-qt5-im-module-dir=dir], + [Select QT5 immodule dir])], + [QT5_IM_MODULEDIR=$with_qt5_im_module_dir]) + AC_ARG_WITH([clutter-im-module-dir], [AS_HELP_STRING([--with-clutter-im-module-dir=dir], [Select clutter immodule dir])], @@ -518,6 +557,12 @@ AC_ARG_ENABLE([qt4-immodule], [], [enable_qt4_immodule=yes]) +AC_ARG_ENABLE([qt5-immodule], + [AS_HELP_STRING([--disable-qt5-immodule], + [Do not build QT5 IMModule])], + [], + [enable_qt5_immodule=yes]) + AC_ARG_ENABLE([clutter-immodule], [AS_HELP_STRING([--enable-clutter-immodule], [Do not build CLUTTER IMModule])], @@ -722,6 +767,17 @@ else enable_qt4_immodule=no fi +if test "$enable_qt5_immodule" = "yes" -a "$SCIM_HAS_QT5" = "yes"; then + SCIM_BUILD_QT5_IMMODULE=1 + SCIM_BUILD_IMMODULE=1 + enable_immodule=yes + SCIM_BUILD_IM_AGENT=1 + enable_im_agent=yes +else + SCIM_BUILD_QT5_IMMODULE=0 + enable_qt5_immodule=no +fi + if test "$enable_clutter_immodule" = "yes" -a \ "$SCIM_HAS_CLUTTER" = "yes" -a \ "$SCIM_HAS_CLUTTERIMCONTEXT" = "yes" ; then @@ -888,6 +944,9 @@ AM_CONDITIONAL(SCIM_BUILD_QT3_IMMODULE, AM_CONDITIONAL(SCIM_BUILD_QT4_IMMODULE, [test "$enable_qt4_immodule" = "yes"]) +AM_CONDITIONAL(SCIM_BUILD_QT5_IMMODULE, + [test "$enable_qt5_immodule" = "yes"]) + AM_CONDITIONAL(SCIM_BUILD_CLUTTER_IMMODULE, [test "$enable_clutter_immodule" = "yes"]) @@ -935,6 +994,7 @@ AC_SUBST(SCIM_BUILD_GTK3_IMMODULE) AC_SUBST(SCIM_BUILD_GTK4_IMMODULE) AC_SUBST(SCIM_BUILD_QT3_IMMODULE) AC_SUBST(SCIM_BUILD_QT4_IMMODULE) +AC_SUBST(SCIM_BUILD_QT5_IMMODULE) AC_SUBST(SCIM_BUILD_CLUTTER_IMMODULE) AC_SUBST(SCIM_BUILD_IMMODULE) @@ -996,6 +1056,9 @@ AC_CONFIG_FILES([Makefile extras/immodules/client-gtk/gtk2/Makefile extras/immodules/client-gtk/gtk3/Makefile extras/immodules/client-gtk/gtk4/Makefile + extras/immodules/client-qt/qt3/Makefile + extras/immodules/client-qt/qt4/Makefile + extras/immodules/client-qt/qt5/Makefile extras/immodules/client-clutter/Makefile extras/immodules/doc/Makefile tests/Makefile @@ -1045,10 +1108,12 @@ Module options: GTK4 IMModule dir $GTK4_IM_MODULEDIR QT3 IMModule dir $QT3_IM_MODULEDIR QT4 IMModule dir $QT4_IM_MODULEDIR + QT5 IMModule dir $QT5_IM_MODULEDIR Clutter IMModule dir $CLUTTER_IM_MODULEDIR QT3 moc program $QT3_MOC QT4 moc program $QT4_MOC + QT5 moc program $QT5_MOC Original GTK2 IMModule $enable_orig_gtk2_immodule Original GTK3 IMModule $enable_orig_gtk3_immodule @@ -1059,5 +1124,6 @@ Module options: GTK4 IMModule $enable_gtk4_immodule QT3 IMModule $enable_qt3_immodule QT4 IMModule $enable_qt4_immodule + QT5 IMModule $enable_qt5_immodule CLUTTER IMModule $enable_clutter_immodule ]) diff --git a/extras/immodules/Makefile.am b/extras/immodules/Makefile.am index 8fceaa8..607a926 100644 --- a/extras/immodules/Makefile.am +++ b/extras/immodules/Makefile.am @@ -37,4 +37,4 @@ MAINTAINERCLEANFILES = Makefile.in CLEANFILES = *.bak -SUBDIRS = common client-common client-gtk/gtk2 client-gtk/gtk3 client-gtk/gtk4 client-clutter agent doc +SUBDIRS = common client-common client-gtk/gtk2 client-gtk/gtk3 client-gtk/gtk4 client-qt/qt3 client-qt/qt4 client-qt/qt5 client-clutter agent doc diff --git a/extras/immodules/client-qt/im-scim-bridge-qt.cpp b/extras/immodules/client-qt/im-scim-bridge-qt.cpp index ddf1df6..523e0cb 100644 --- a/extras/immodules/client-qt/im-scim-bridge-qt.cpp +++ b/extras/immodules/client-qt/im-scim-bridge-qt.cpp @@ -19,54 +19,18 @@ #include <cassert> -#include <Qt> -#include <qpa/qplatforminputcontextplugin_p.h> - -using namespace Qt; - #include "scim-bridge.h" #include "scim-bridge-client-common-qt.h" -#include "scim-bridge-client-imcontext-qt.h" #include "scim-bridge-client-qt.h" +#include "im-scim-bridge-qt.h" + +#if QT_VERSION >= 0x040000 +using namespace Qt; +#endif /* Static Variables */ static ScimBridgeClientQt *client = NULL; -/* The class Definition */ -class ScimBridgeInputContextPlugin: public QPlatformInputContextPlugin -{ - Q_OBJECT - Q_PLUGIN_METADATA(IID QPlatformInputContextFactoryInterface_iid FILE "scim.json") - - private: - - /** - * The language list for SCIM. - */ - static QStringList scim_languages; - - public: - - ScimBridgeInputContextPlugin (); - - ~ScimBridgeInputContextPlugin (); - - QStringList keys () const; - - QStringList languages (const QString &key); - - QString description (const QString &key); - - ScimBridgeClientIMContext *create (const QString &key, const QStringList ¶m) Q_DECL_OVERRIDE; - - QString displayName (const QString &key); - -}; - - -/* Implementations */ -QStringList ScimBridgeInputContextPlugin::scim_languages; - ScimBridgeInputContextPlugin::ScimBridgeInputContextPlugin () { } @@ -78,6 +42,12 @@ ScimBridgeInputContextPlugin::~ScimBridgeInputContextPlugin () client = NULL; } +#if QT_VERSION < 0x050000 + +/* Implementations */ +QStringList ScimBridgeInputContextPlugin::scim_languages; + + QStringList ScimBridgeInputContextPlugin::keys () const { QStringList identifiers; identifiers.push_back (SCIM_BRIDGE_IDENTIFIER_NAME); @@ -104,10 +74,24 @@ QString ScimBridgeInputContextPlugin::description (const QString &key) } -ScimBridgeClientIMContext *ScimBridgeInputContextPlugin::create (const QString &key, const QStringList ¶m) +QString ScimBridgeInputContextPlugin::displayName (const QString &key) { - Q_UNUSED(param); + return key; +} + +#endif + +#if QT_VERSION >= 0x050000 +QInputContext *ScimBridgeInputContextPlugin::create (const QString &key, const QStringList ¶mList) +#else +QInputContext *ScimBridgeInputContextPlugin::create (const QString &key) +#endif +{ +#if QT_VERSION >= 0x040000 if (key.toLower () != SCIM_BRIDGE_IDENTIFIER_NAME) { +#else + if (key.lower () != SCIM_BRIDGE_IDENTIFIER_NAME) { +#endif return NULL; } else { if (client == NULL) client = new ScimBridgeClientQt (); @@ -115,10 +99,8 @@ ScimBridgeClientIMContext *ScimBridgeInputContextPlugin::create (const QString & } } - -QString ScimBridgeInputContextPlugin::displayName (const QString &key) -{ - return key; -} - -#include "im-scim-bridge-qt.moc" +#if QT_VERSION < 0x040000 +Q_EXPORT_PLUGIN (ScimBridgeInputContextPlugin) +#elif QT_VERSION < 0x050000 +Q_EXPORT_PLUGIN2 (ScimBridgeInputContextPlugin, ScimBridgeInputContextPlugin) +#endif diff --git a/extras/immodules/client-qt/im-scim-bridge-qt.h b/extras/immodules/client-qt/im-scim-bridge-qt.h new file mode 100644 index 0000000..41fa1a7 --- /dev/null +++ b/extras/immodules/client-qt/im-scim-bridge-qt.h @@ -0,0 +1,57 @@ +#include <QtGlobal> +#if QT_VERSION >= 0x050000 +#include <QObject> +#include <QtCore/QStringList> +#include <QtGui/qpa/qplatforminputcontextplugin_p.h> +#include <QtGui/qpa/qplatforminputcontext.h> +#elif QT_VERSION >= 0x040000 +#include <Qt> +#include <QInputContextPlugin> +#else +#include <qinputcontextplugin.h> +#endif + +#if QT_VERSION >= 0x050000 +typedef QPlatformInputContext QInputContext; +typedef QPlatformInputContextPlugin QInputContextPlugin; +#elif QT_VERSION >= 0x040000 +using namespace Qt; +#endif + +/* The class Definition */ +class ScimBridgeInputContextPlugin: public QInputContextPlugin +{ +#if QT_VERSION >= 0x050000 + Q_OBJECT + + Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QPlatformInputContextFactoryInterface.5.1" FILE "scim.json") +#endif + + public: + + ScimBridgeInputContextPlugin (); + + ~ScimBridgeInputContextPlugin (); + +#if QT_VERSION >= 0x050000 + QInputContext *create(const QString &key, const QStringList ¶mList); +#else + private: + + /** + * The language list for SCIM. + */ + static QStringList scim_languages; + + public: + QStringList keys () const; + + QStringList languages (const QString &key); + + QString description (const QString &key); + + QString displayName (const QString &key); + + QInputContext *create (const QString &key); +#endif +}; diff --git a/extras/immodules/client-qt/qt3/Makefile.am b/extras/immodules/client-qt/qt3/Makefile.am new file mode 100644 index 0000000..e5ac16d --- /dev/null +++ b/extras/immodules/client-qt/qt3/Makefile.am @@ -0,0 +1,72 @@ +## Makefile.am -- Process this file with automake to produce Makefile.in +## +## Copyright (C) 2006 Ryo Dairiki +## +## +## This library is free software; you can redistribute it and/or +## modify it under the terms of the GNU Lesser General Public +## License as published by the Free Software Foundation and +## appearing in the file LICENSE.LGPL included in the package of this file. +## You can also redistribute it and/or modify it under the terms of +## the GNU General Public License as published by the Free Software Foundation and +## appearing in the file LICENSE.GPL included in the package of this file. +## +## This library is distributed in the hope that it will be useful, +## but WITHOUT ANY WARRANTY; without even the implied warranty of +## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + +if SCIM_BUILD_QT3_IMMODULE + +AM_CPPFLAGS = -I$(top_builddir) \ + -I$(top_srcdir) \ + -I$(top_srcdir)/extras/immodules/common \ + -I$(top_srcdir)/extras/immodules/client-common + +noinst_HEADERS = ../scim-bridge-client-qt.h ../scim-bridge-client-imcontext-qt.h ../scim-bridge-client-key-event-utility-qt.h ../scim-bridge-client-common-qt.h ../im-scim-bridge-qt.h + +moduledir = @QT3_IM_MODULEDIR@ +module_LTLIBRARIES = im-scim.la + +im_scim_la_SOURCES = ../im-scim-bridge-qt.cpp \ + ../scim-bridge-client-qt.cpp \ + ../scim-bridge-client-imcontext-qt.cpp \ + ../scim-bridge-client-key-event-utility-qt.cpp \ + moc_scim-bridge-client-qt.cpp + +im_scim_la_CXXFLAGS=@QT3_CFLAGS@ -DQT_IMMODULE -fPIC -Wl,-z,defs +im_scim_la_CFLAGS =@QT3_CFLAGS@ -DQT_IMMODULE -fPIC -Wl,-z,defs + +im_scim_la_LDFLAGS = -rpath $(moduledir) \ + -avoid-version -no-undefined \ + -module \ + @QT3_LIBS@ + +im_scim_la_LIBADD = $(top_builddir)/extras/immodules/common/libscimbridgecommon.la \ + $(top_builddir)/extras/immodules/client-common/libscimbridgeclientcommon.la + +MOC = @QT3_MOC@ + +moc_scim-bridge-client-qt.cpp: ../scim-bridge-client-qt.h + $(MOC) $< -o $@ + +moc_im-scim-bridge-qt.cpp: ../im-scim-bridge-qt.h + $(MOC) $< -o $@ + +else + +moc_scim-bridge-client-qt.cpp: + touch $@ + +moc_im-scim-bridge-qt.cpp: + touch $@ + +endif + +dist-hook: + -rm -f $(distdir)/moc_scim-bridge-client-qt.cpp \ + $(distdir)/moc_im-scim-bridge-qt.cpp + +MAINTAINERCLEANFILES = Makefile.in +CLEANFILES = moc_scim-bridge-client-qt.cpp \ + moc_im-scim-bridge-qt.cpp + diff --git a/extras/immodules/client-qt/qt4/Makefile.am b/extras/immodules/client-qt/qt4/Makefile.am new file mode 100644 index 0000000..8bcaded --- /dev/null +++ b/extras/immodules/client-qt/qt4/Makefile.am @@ -0,0 +1,73 @@ +## Makefile.am -- Process this file with automake to produce Makefile.in +## +## Copyright (C) 2006 Ryo Dairiki +## +## +## This library is free software; you can redistribute it and/or +## modify it under the terms of the GNU Lesser General Public +## License as published by the Free Software Foundation and +## appearing in the file LICENSE.LGPL included in the package of this file. +## You can also redistribute it and/or modify it under the terms of +## the GNU General Public License as published by the Free Software Foundation and +## appearing in the file LICENSE.GPL included in the package of this file. +## +## This library is distributed in the hope that it will be useful, +## but WITHOUT ANY WARRANTY; without even the implied warranty of +## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + +if SCIM_BUILD_QT4_IMMODULE + +AM_CPPFLAGS = -I$(top_builddir) \ + -I$(top_srcdir) \ + -I$(top_srcdir)/extras/immodules/common \ + -I$(top_srcdir)/extras/immodules/client-common + +noinst_HEADERS = ../scim-bridge-client-qt.h ../scim-bridge-client-imcontext-qt.h ../scim-bridge-client-key-event-utility-qt.h ../scim-bridge-client-common-qt.h ../im-scim-bridge-qt.h + +moduledir = @QT4_IM_MODULEDIR@ +module_LTLIBRARIES = im-scim.la + +im_scim_la_SOURCES = ../im-scim-bridge-qt.cpp \ + ../scim-bridge-client-qt.cpp \ + ../scim-bridge-client-imcontext-qt.cpp \ + ../scim-bridge-client-key-event-utility-qt.cpp \ + moc_scim-bridge-client-qt.cpp \ + moc_im-scim-bridge-qt.cpp + +im_scim_la_CXXFLAGS=@QT4_CFLAGS@ -DQT_IMMODULE -DQT4 -fPIC -Wl,-z,defs +im_scim_la_CFLAGS =@QT4_CFLAGS@ -DQT_IMMODULE -DQT4 -fPIC -Wl,-z,defs + +im_scim_la_LDFLAGS = -rpath $(moduledir) \ + -avoid-version -no-undefined \ + -module \ + @QT4_LIBS@ + +im_scim_la_LIBADD = $(top_builddir)/extras/immodules/common/libscimbridgecommon.la \ + $(top_builddir)/extras/immodules/client-common/libscimbridgeclientcommon.la + +MOC = @QT4_MOC@ + +moc_scim-bridge-client-qt.cpp: ../scim-bridge-client-qt.h + $(MOC) $< -o $@ + +moc_im-scim-bridge-qt.cpp: ../im-scim-bridge-qt.h + $(MOC) $< -o $@ + +else + +moc_scim-bridge-client-qt.cpp: + touch $@ + +moc_im-scim-bridge-qt.cpp: + touch $@ + +endif + +dist-hook: + -rm -f $(distdir)/moc_scim-bridge-client-qt.cpp \ + $(distdir)/moc_im-scim-bridge-qt.cpp + +MAINTAINERCLEANFILES = Makefile.in +CLEANFILES = moc_scim-bridge-client-qt.cpp \ + moc_im-scim-bridge-qt.cpp + diff --git a/extras/immodules/client-qt/qt5/Makefile.am b/extras/immodules/client-qt/qt5/Makefile.am new file mode 100644 index 0000000..48596de --- /dev/null +++ b/extras/immodules/client-qt/qt5/Makefile.am @@ -0,0 +1,72 @@ +## Makefile.am -- Process this file with automake to produce Makefile.in +## +## Copyright (C) 2006 Ryo Dairiki +## +## +## This library is free software; you can redistribute it and/or +## modify it under the terms of the GNU Lesser General Public +## License as published by the Free Software Foundation and +## appearing in the file LICENSE.LGPL included in the package of this file. +## You can also redistribute it and/or modify it under the terms of +## the GNU General Public License as published by the Free Software Foundation and +## appearing in the file LICENSE.GPL included in the package of this file. +## +## This library is distributed in the hope that it will be useful, +## but WITHOUT ANY WARRANTY; without even the implied warranty of +## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + +if SCIM_BUILD_QT5_IMMODULE + +AM_CPPFLAGS = -I$(top_builddir) \ + -I$(top_srcdir) \ + -I$(top_srcdir)/extras/immodules/common \ + -I$(top_srcdir)/extras/immodules/client-common + +noinst_HEADERS = ../scim-bridge-client-qt.h ../scim-bridge-client-imcontext-qt.h ../scim-bridge-client-key-event-utility-qt.h ../scim-bridge-client-common-qt.h ../im-scim-bridge-qt.h + +moduledir = @QT5_IM_MODULEDIR@ +module_LTLIBRARIES = libscimplatforminputcontextplugin.la + +libscimplatforminputcontextplugin_la_SOURCES = ../im-scim-bridge-qt.cpp \ + ../scim-bridge-client-qt.cpp \ + ../scim-bridge-client-imcontext-qt.cpp \ + ../scim-bridge-client-key-event-utility-qt.cpp \ + moc_scim-bridge-client-qt.cpp \ + moc_im-scim-bridge-qt.cpp + +libscimplatforminputcontextplugin_la_CXXFLAGS=@QT5_CFLAGS@ -DQT_IMMODULE -DQT5 -fPIC +libscimplatforminputcontextplugin_la_CFLAGS =@QT5_CFLAGS@ -DQT_IMMODULE -DQT5 -fPIC +libscimplatforminputcontextplugin_la_LDFLAGS = -rpath $(moduledir) \ + -avoid-version -no-undefined \ + -module \ + @QT5_LIBS@ + +libscimplatforminputcontextplugin_la_LIBADD = $(top_builddir)/extras/immodules/common/libscimbridgecommon.la \ + $(top_builddir)/extras/immodules/client-common/libscimbridgeclientcommon.la + +MOC = @QT5_MOC@ + +moc_scim-bridge-client-qt.cpp: ../scim-bridge-client-qt.h + $(MOC) $< -DQT_VERSION=0x050000 -o $@ + +moc_im-scim-bridge-qt.cpp: ../im-scim-bridge-qt.h + $(MOC) $< -DQT_VERSION=0x050000 -o $@ + +else + +moc_im-scim-bridge-qt.cpp: + touch $@ + +moc_scim-bridge-client-qt.cpp: + touch $@ + +endif + +dist-hook: + -rm -f $(distdir)/moc_scim-bridge-client-qt.cpp \ + $(distdir)/moc_im-scim-bridge-qt.cpp + +MAINTAINERCLEANFILES = Makefile.in +CLEANFILES = moc_scim-bridge-client-qt.cpp \ + moc_im-scim-bridge-qt.cpp + diff --git a/extras/immodules/client-qt/scim-bridge-client-common-qt.h b/extras/immodules/client-qt/scim-bridge-client-common-qt.h index 6fcac17..c19782d 100644 --- a/extras/immodules/client-qt/scim-bridge-client-common-qt.h +++ b/extras/immodules/client-qt/scim-bridge-client-common-qt.h @@ -27,8 +27,14 @@ #ifndef SCIMBRIDGECOMMONQT_H_ #define SCIMBRIDGECOMMONQT_H_ +#include <QtGlobal> +#if QT_VERSION >= 0x040000 #include <QString> #include <QStringList> +#else +#include <qstring.h> +#include <qstringlist.h> +#endif #include "scim-bridge.h" diff --git a/extras/immodules/client-qt/scim-bridge-client-imcontext-qt.cpp b/extras/immodules/client-qt/scim-bridge-client-imcontext-qt.cpp index 26c0027..865b8d4 100644 --- a/extras/immodules/client-qt/scim-bridge-client-imcontext-qt.cpp +++ b/extras/immodules/client-qt/scim-bridge-client-imcontext-qt.cpp @@ -20,12 +20,20 @@ #include <cassert> #include <string> +#include <QtGlobal> +#if QT_VERSION >= 0x050000 +#include <QInputMethodEvent> +#include <QTextCharFormat> +#include <QAbstractNativeEventFilter> +#elif QT_VERSION >= 0x040000 #include <QColor> #include <QInputMethodEvent> #include <QPalette> #include <QTextCharFormat> - +#endif +#if defined(Q_WS_X11) || (QT_VERSION >= 0x050000) #include <QX11Info> +#endif #include "scim-bridge-output.h" #include "scim-bridge-string.h" @@ -35,11 +43,20 @@ #include "scim-bridge-client-imcontext-qt.h" #include "scim-bridge-client-key-event-utility-qt.h" +#if QT_VERSION >= 0x040000 using namespace std; using namespace Qt; typedef QInputMethodEvent::Attribute QAttribute; +#endif + +#if QT_VERSION < 0x050000 +namespace Qt { + typedef QFlags<InputMethodQuery> InputMethodQueries; +} +class QAbstractNativeEventFilter {}; +#endif /* Static variables */ class ScimBridgeClientIMContextImpl; @@ -49,7 +66,7 @@ static ScimBridgeClientIMContextImpl *focused_imcontext = NULL; static bool key_event_forwarded = false; /* Class Definition */ -class ScimBridgeClientIMContextImpl: public _ScimBridgeClientIMContext +class ScimBridgeClientIMContextImpl: public _ScimBridgeClientIMContext, private QAbstractNativeEventFilter { public: @@ -57,19 +74,58 @@ class ScimBridgeClientIMContextImpl: public _ScimBridgeClientIMContext ScimBridgeClientIMContextImpl (); ~ScimBridgeClientIMContextImpl (); +#ifdef Q_WS_X11 bool x11FilterEvent (QWidget *widget, XEvent *event); - bool filterEvent (const QEvent *event); +#endif + +#if QT_VERSION >= 0x050000 + bool nativeEventFilter(const QByteArray &eventType, void *message, long *result); +#endif + +#if QT_VERSION >= 0x050000 + bool isValid() const; + //bool hasCapability(Capability capability) const; + + //void invokeAction(QInputMethod::Action, int cursorPosition); + //QRectF keyboardRect() const; + + void showInputPanel(); + void hideInputPanel(); + bool isInputPanelVisible() const; + // + //QLocale locale() const; + //Qt::LayoutDirection inputDirection() const; + + void update(Qt::InputMethodQueries queries=Qt::ImMicroFocus); + + void setFocusObject(QObject *object); - void update (); + // helper function to abstract behaviours between Qt4 and Qt5 + void sendEvent(QInputMethodEvent &event); + QWidget *focusWidget() const; + +#elif QT_VERSION >= 0x040000 + void update () { updateMicroFocus(); } QString identifierName (); QString language (); - bool isValid() const Q_DECL_OVERRIDE; - void setFocusObject (QObject *object) Q_DECL_OVERRIDE; void widgetDestroyed (QWidget *widget); - bool isComposing () const; void mouseHandler (int offset, QMouseEvent *event); +#else + // since this function can't handling caps lock correctly (QEvent lack of information), + // I move it here to not be included in Qt >= 4.0 + bool filterEvent (const QEvent *event); + void setFocus (); + void unsetFocus (); + void setMicroFocus (int x, int y, int w, int h, QFont *font = 0); + void mouseHandler (int offset, QEvent::Type type, ButtonState button, ButtonState state); +#endif + +#if QT_VERSION >= 0x040000 + bool isComposing () const { return preedit_string.size () > 0; } + void updateMicroFocus (); +#endif void reset (); @@ -91,9 +147,11 @@ class ScimBridgeClientIMContextImpl: public _ScimBridgeClientIMContext scim_bridge_imcontext_id_t get_id () const; void set_id (scim_bridge_imcontext_id_t new_id); +#if QT_VERSION >= 0x040000 bool get_surrounding_text (unsigned int before_max, unsigned int after_max, char **string, int *cursor_position); bool delete_surrounding_text (int offset, int length); bool replace_surrounding_text (const char *text, int cursor_position); +#endif private: @@ -103,7 +161,16 @@ class ScimBridgeClientIMContextImpl: public _ScimBridgeClientIMContext QString preedit_string; +#if QT_VERSION >= 0x040000 QList<QAttribute> preedit_attributes; +#else + int preedit_selected_offset; + int preedit_selected_length; +#endif + +#if QT_VERSION >= 0x050000 + QObject *focused_object; +#endif int preedit_cursor_position; @@ -142,11 +209,19 @@ _ScimBridgeClientIMContext *_ScimBridgeClientIMContext::alloc () } -ScimBridgeClientIMContextImpl::ScimBridgeClientIMContextImpl (): id (-1), preedit_shown (false) +ScimBridgeClientIMContextImpl::ScimBridgeClientIMContextImpl (): id (-1), preedit_shown (false), preedit_cursor_position(0) { scim_bridge_pdebugln (5, "ScimBridgeClientIMContextImpl::ScimBridgeClientIMContextImpl ()"); +#if QT_VERSION >= 0x040000 preedit_attributes.push_back (QAttribute (QInputMethodEvent::Cursor, preedit_cursor_position, true, 0)); +#else + preedit_selected_offset = 0; + preedit_selected_length = 0; +#endif +#if QT_VERSION >= 0x050000 + focused_object = NULL; +#endif if (!scim_bridge_client_is_messenger_opened ()) { scim_bridge_perrorln ("The messenger is now down"); @@ -155,6 +230,10 @@ ScimBridgeClientIMContextImpl::ScimBridgeClientIMContextImpl (): id (-1), preedi } else { scim_bridge_pdebugln (1, "IMContext registered: id = %d", id); } + +#if QT_VERSION >= 0x050000 + qApp->installNativeEventFilter(this); +#endif } @@ -162,6 +241,10 @@ ScimBridgeClientIMContextImpl::~ScimBridgeClientIMContextImpl () { scim_bridge_pdebugln (5, "ScimBridgeClientIMContextImpl::~ScimBridgeClientIMContextImpl ()"); +#if QT_VERSION >= 0x050000 + qApp->removeNativeEventFilter(this); +#endif + if (this == focused_imcontext) focus_out (); if (!scim_bridge_client_is_messenger_opened ()) { @@ -173,6 +256,100 @@ ScimBridgeClientIMContextImpl::~ScimBridgeClientIMContextImpl () } } + +#if QT_VERSION >= 0x050000 + +void ScimBridgeClientIMContextImpl::update(Qt::InputMethodQueries queries) +{ + scim_bridge_pdebugln (4, "ScimBridgeClientIMContextImpl::update (0x%lx)", queries); + + if(queries & Qt::ImMicroFocus) { + updateMicroFocus(); + } +} + +bool ScimBridgeClientIMContextImpl::isValid() const +{ + scim_bridge_pdebugln (5, "ScimBridgeClientIMContextImpl::isValid ()"); + return scim_bridge_client_is_initialized(); +} + +void ScimBridgeClientIMContextImpl::showInputPanel() +{ + if(scim_bridge_client_is_messenger_opened ()) return; + + scim_bridge_pdebugln (5, "ScimBridgeClientIMContextImpl::showInputPanel ()"); + + focus_in(); +} + +void ScimBridgeClientIMContextImpl::hideInputPanel() +{ + if(!scim_bridge_client_is_messenger_opened ()) return; + + scim_bridge_pdebugln (5, "ScimBridgeClientIMContextImpl::hideInputPanel ()"); + + focus_out(); +} + +bool ScimBridgeClientIMContextImpl::isInputPanelVisible() const +{ + scim_bridge_pdebugln (5, "ScimBridgeClientIMContextImpl::isInputPanelVisible ()"); + return scim_bridge_client_is_messenger_opened (); +} + +void ScimBridgeClientIMContextImpl::setFocusObject(QObject *object) +{ + scim_bridge_pdebugln (5, "ScimBridgeClientIMContextImpl::setFocusObject"); + + focused_object = object; +} + +void ScimBridgeClientIMContextImpl::sendEvent(QInputMethodEvent &event) +{ + if(focused_object) { + qApp->sendEvent(focused_object, &event); + } +} + +QWidget *ScimBridgeClientIMContextImpl::focusWidget() const +{ + return qobject_cast<QWidget *>(focused_object); +} + +bool ScimBridgeClientIMContextImpl::nativeEventFilter(const QByteArray &eventType, void *message, long *result) +{ + bool isXcb = eventType.startsWith("xcb"); + if (!isXcb && !focused_object) return false; + + xcb_generic_event_t *event = static_cast<xcb_generic_event_t*>(message); + uint8_t event_type = event->response_type & ~0x80; + if (key_event_forwarded || (event_type != XCB_KEY_PRESS && event_type != XCB_KEY_RELEASE)) return false; + + scim_bridge_pdebugln (5, "ScimBridgeClientIMContextImpl::nativeEventFilter"); + + if (focused_imcontext != this) focus_in (); + + if (scim_bridge_client_is_messenger_opened ()) { + ScimBridgeKeyEvent *bridge_key_event = scim_bridge_key_event_xcb_to_bridge (event, QX11Info::connection()); + + boolean consumed = FALSE; + const retval_t retval_error = scim_bridge_client_handle_key_event (this, bridge_key_event, &consumed); + + scim_bridge_free_key_event (bridge_key_event); + + if (retval_error) { + scim_bridge_perrorln ("An IOException at x11FilterEvent ()"); + } else { + return consumed; + } + } + + return false; +} + +#elif QT_VERSION >= 0x040000 + QString ScimBridgeClientIMContextImpl::identifierName () { return SCIM_BRIDGE_IDENTIFIER_NAME; @@ -190,28 +367,79 @@ void ScimBridgeClientIMContextImpl::widgetDestroyed (QWidget *widget) update (); } -bool ScimBridgeClientIMContextImpl::isValid() const +void ScimBridgeClientIMContextImpl::mouseHandler (int offset, QMouseEvent *mevent) { - return true; } -void ScimBridgeClientIMContextImpl::setFocusObject (QObject *object) +#else + +void ScimBridgeClientIMContextImpl::setFocus () { - scim_bridge_pdebugln (4, "ScimBridgeClientIMContextImpl::setFocusObject ()"); - QPlatformInputContext::setFocusObject (object); - if (object == NULL) { - focus_out (); - } else { - focus_in (); - } - update (); + scim_bridge_pdebugln (4, "ScimBridgeClientIMContextImpl::setFocus ()"); + + focus_in (); } -void ScimBridgeClientIMContextImpl::update () + +void ScimBridgeClientIMContextImpl::unsetFocus () { - scim_bridge_pdebugln (4, "ScimBridgeClientIMContextImpl::update ()"); + scim_bridge_pdebugln (4, "ScimBridgeClientIMContextImpl::unsetFocus ()"); + + focus_out (); +} - QWidget *focused_widget = qApp->focusWidget (); + +void ScimBridgeClientIMContextImpl::setMicroFocus (int x, int y, int w, int h, QFont *qfont) +{ + scim_bridge_pdebugln (4, "ScimBridgeClientIMContextImpl::setMicroFocus ()"); + + QPoint new_cursor_location (x, y + h); + set_cursor_location (new_cursor_location); +} + +void ScimBridgeClientIMContextImpl::mouseHandler (int offset, QEvent::Type type, ButtonState button, ButtonState state) +{ +} + +bool ScimBridgeClientIMContextImpl::filterEvent (const QEvent *qevent) +{ + scim_bridge_pdebugln (5, "ScimBridgeClientIMContextImpl::filterEvent ()"); + +#ifndef Q_WS_X11 + if (key_event_forwarded || (qevent->type () != QEvent::KeyPress && qevent->type () != QEvent::KeyRelease)) return false; + + if (focused_imcontext != this) focus_in (); + + if (scim_bridge_client_is_messenger_opened ()) { + const QKeyEvent *key_event = static_cast<const QKeyEvent*> (qevent); + ScimBridgeKeyEvent *bridge_key_event = scim_bridge_key_event_qt_to_bridge (key_event); + + if (scim_bridge_key_event_get_code (bridge_key_event) == SCIM_BRIDGE_KEY_CODE_NullKey) + return false; + + boolean consumed = FALSE; + const retval_t retval_error = scim_bridge_client_handle_key_event (this, bridge_key_event, &consumed); + + scim_bridge_free_key_event (bridge_key_event); + + if (retval_error) { + scim_bridge_perrorln ("An IOException at filterEvent ()"); + } else { + return consumed; + } + } +#endif + + return false; +} + +#endif + +#if QT_VERSION >= 0x040000 + +void ScimBridgeClientIMContextImpl::updateMicroFocus () +{ + QWidget *focused_widget = focusWidget (); if (focused_widget != NULL) { if (focused_imcontext == NULL) focus_in (); @@ -223,16 +451,6 @@ void ScimBridgeClientIMContextImpl::update () } } -bool ScimBridgeClientIMContextImpl::isComposing () const -{ - scim_bridge_pdebugln (4, "ScimBridgeClientIMContextImpl::isComposing ()"); - return preedit_string.size () > 0; -} - -void ScimBridgeClientIMContextImpl::mouseHandler (int offset, QMouseEvent *mevent) -{ -} - bool ScimBridgeClientIMContextImpl::get_surrounding_text (unsigned int before_max, unsigned int after_max, char **text, int *cursor_position) { scim_bridge_pdebugln (6, "ScimBridgeClientIMContextImpl::get_surrounding_text ()"); @@ -254,6 +472,10 @@ bool ScimBridgeClientIMContextImpl::replace_surrounding_text (const char *text, return false; } +#endif + +#ifdef Q_WS_X11 + bool ScimBridgeClientIMContextImpl::x11FilterEvent (QWidget *widget, XEvent *xevent) { scim_bridge_pdebugln (5, "ScimBridgeClientIMContextImpl::x11FilterEvent ()"); @@ -280,44 +502,20 @@ bool ScimBridgeClientIMContextImpl::x11FilterEvent (QWidget *widget, XEvent *xev return false; } -bool ScimBridgeClientIMContextImpl::filterEvent (const QEvent *qevent) -{ - scim_bridge_pdebugln (5, "ScimBridgeClientIMContextImpl::filterEvent ()"); - - if (key_event_forwarded || (qevent->type () != QEvent::KeyPress && qevent->type () != QEvent::KeyRelease)) return false; - - if (focused_imcontext != this) focus_in (); - - if (scim_bridge_client_is_messenger_opened ()) { - const QKeyEvent *key_event = static_cast<const QKeyEvent*> (qevent); - ScimBridgeKeyEvent *bridge_key_event = scim_bridge_key_event_qt_to_bridge (key_event); - - if (scim_bridge_key_event_get_code (bridge_key_event) == SCIM_BRIDGE_KEY_CODE_NullKey) - return false; - - boolean consumed = FALSE; - const retval_t retval_error = scim_bridge_client_handle_key_event (this, bridge_key_event, &consumed); - - scim_bridge_free_key_event (bridge_key_event); - - if (retval_error) { - scim_bridge_perrorln ("An IOException at filterEvent ()"); - } else { - return consumed; - } - } - - return false; -} - +#endif void ScimBridgeClientIMContextImpl::reset () { scim_bridge_pdebugln (5, "ScimBridgeClientIMContextImpl::reset ()"); preedit_cursor_position = 0; +#if QT_VERSION >= 0x040000 preedit_attributes.clear (); preedit_attributes.push_back (QAttribute (QInputMethodEvent::Cursor, preedit_cursor_position, true, 0)); +#else + preedit_selected_offset = 0; + preedit_selected_length = 0; +#endif preedit_string = ""; if (scim_bridge_client_is_messenger_opened ()) { @@ -325,6 +523,10 @@ void ScimBridgeClientIMContextImpl::reset () scim_bridge_perrorln ("An IOException at filterEvent ()"); } } + +#if QT_VERSION < 0x040000 + QInputContext::reset (); +#endif } @@ -398,19 +600,26 @@ void ScimBridgeClientIMContextImpl::set_commit_string (const char *new_string) void ScimBridgeClientIMContextImpl::commit () { - scim_bridge_pdebugln (5, "ScimBridgeClientIMContextImpl::commit ()"); - if (commit_string.length () <= 0) return; - scim_bridge_pdebugln (9, "commit string: %s", commit_string.toUtf8 ().data ()); - QObject *input = qApp->focusObject(); - if (!input) return; + scim_bridge_pdebugln (5, "ScimBridgeClientIMContextImpl::commit (): '%s', %d", commit_string.toUtf8().constData(), commit_string.length()); + +#if QT_VERSION >= 0x040000 + scim_bridge_pdebugln (9, "commit string: %s", commit_string.toUtf8 ().constData ()); +#endif const bool is_composing = isComposing (); +#if QT_VERSION >= 0x040000 QInputMethodEvent commit_event; commit_event.setCommitString (commit_string); - QCoreApplication::sendEvent (input, &commit_event); + sendEvent (commit_event); +#else + if (!is_composing) sendIMEvent (QEvent::IMStart); + sendIMEvent (QEvent::IMEnd, commit_string); +#endif + + commit_string.resize(0); if (is_composing) update_preedit (); } @@ -423,9 +632,21 @@ void ScimBridgeClientIMContextImpl::forward_key_event (const ScimBridgeKeyEvent QWidget *focused_widget = qApp->focusWidget (); if (focused_widget != NULL) { key_event_forwarded = true; +#ifdef Q_WS_X11 + const WId window_id = focused_widget->winId (); +#if QT_VERSION >= 0x040000 + Display *x11_display = QX11Info::display(); +#else + Display *x11_display = qt_xdisplay (); +#endif + XEvent *x_event = scim_bridge_key_event_bridge_to_x11 (key_event, x11_display, window_id); + qApp->x11ProcessEvent (x_event); + free (x_event); +#else QKeyEvent *forwarded_key_event = scim_bridge_key_event_bridge_to_qt (key_event); QApplication::sendEvent (focused_widget, forwarded_key_event); delete forwarded_key_event; +#endif key_event_forwarded = false; } else { scim_bridge_pdebugln (4, "No widget is focused"); @@ -441,8 +662,13 @@ void ScimBridgeClientIMContextImpl::set_preedit_shown (bool shown) if (!preedit_shown) { preedit_string = ""; preedit_cursor_position = 0; +#if QT_VERSION >= 0x040000 preedit_attributes.clear (); preedit_attributes.push_back (QAttribute (QInputMethodEvent::Cursor, preedit_cursor_position, true, 0)); +#else + preedit_selected_offset = 0; + preedit_selected_length = 0; +#endif } } @@ -465,8 +691,13 @@ void ScimBridgeClientIMContextImpl::set_preedit_attributes (ScimBridgeAttribute* { scim_bridge_pdebugln (5, "ScimBridgeClientIMContextImpl::set_preedit_attribute ()"); +#if QT_VERSION >= 0x040000 preedit_attributes.clear (); preedit_attributes.push_back (QAttribute (QInputMethodEvent::Cursor, preedit_cursor_position, true, 0)); +#else + preedit_selected_offset = 0; + preedit_selected_length = 0; +#endif for (int i = 0; i < attribute_count; ++i) { const ScimBridgeAttribute *attribute = attributes[i]; @@ -476,9 +707,13 @@ void ScimBridgeClientIMContextImpl::set_preedit_attributes (ScimBridgeAttribute* const scim_bridge_attribute_type_t attribute_type = scim_bridge_attribute_get_type (attribute); const scim_bridge_attribute_value_t attribute_value = scim_bridge_attribute_get_value (attribute); +#if QT_VERSION >= 0x040000 const size_t attribute_length = attribute_end - attribute_begin; const QWidget *focused_widget = qApp->focusWidget (); + if(!focused_widget) { + break; + } const QPalette &palette = focused_widget->palette (); const QBrush &reversed_foreground = palette.base (); @@ -542,6 +777,13 @@ void ScimBridgeClientIMContextImpl::set_preedit_attributes (ScimBridgeAttribute* default: break; } +#else + if (attribute_type == ATTRIBUTE_DECORATE && (attribute_value == SCIM_BRIDGE_ATTRIBUTE_DECORATE_HIGHLIGHT || attribute_value == SCIM_BRIDGE_ATTRIBUTE_DECORATE_REVERSE)) { + preedit_selected_offset = attribute_begin; + preedit_selected_length = attribute_end - attribute_begin; + break; + } +#endif } } @@ -550,13 +792,26 @@ void ScimBridgeClientIMContextImpl::update_preedit () { scim_bridge_pdebugln (5, "ScimBridgeClientIMContextImpl::update_preedit ()"); - QObject *input = qApp->focusObject(); - if (!input) return; - +#if QT_VERSION >= 0x040000 preedit_attributes[0] = QAttribute (QInputMethodEvent::Cursor, preedit_cursor_position, true, 0); QInputMethodEvent im_event (preedit_string, preedit_attributes); - QCoreApplication::sendEvent(input, &im_event); + sendEvent (im_event); update (); +#else + if (preedit_shown) { + if (!isComposing ()) sendIMEvent (QEvent::IMStart); + const size_t preedit_length = preedit_string.length (); + + size_t cursor_position = preedit_cursor_position; + if (cursor_position > preedit_length) cursor_position = preedit_length; + + size_t selected_length = preedit_selected_length; + if (cursor_position + selected_length > preedit_length) selected_length = preedit_length - cursor_position; + sendIMEvent (QEvent::IMCompose, preedit_string, cursor_position, selected_length); + } else { + if (isComposing ()) sendIMEvent (QEvent::IMEnd); + } +#endif } @@ -665,22 +920,37 @@ void scim_bridge_client_imcontext_update_preedit (ScimBridgeClientIMContext *imc boolean scim_bridge_client_imcontext_get_surrounding_text (ScimBridgeClientIMContext *imcontext, int before_max, int after_max, char **string, int *cursor_position) { +#if QT_VERSION >= 0x040000 ScimBridgeClientIMContextImpl *imcontext_impl = static_cast<ScimBridgeClientIMContextImpl*> (imcontext); return imcontext_impl->get_surrounding_text (before_max, after_max, string, cursor_position); +#else + scim_bridge_perrorln ("FIXME: scim_bridge_client_imcontext_get_surrounding_text () is not yet implemented."); + return FALSE; +#endif } boolean scim_bridge_client_imcontext_delete_surrounding_text (ScimBridgeClientIMContext *imcontext, int offset, int length) { +#if QT_VERSION >= 0x040000 ScimBridgeClientIMContextImpl *imcontext_impl = static_cast<ScimBridgeClientIMContextImpl*> (imcontext); return imcontext_impl->delete_surrounding_text (offset, length); +#else + scim_bridge_perrorln ("FIXME: scim_bridge_client_imcontext_delete_surrounding_text () is not yet implemented."); + return FALSE; +#endif } boolean scim_bridge_client_imcontext_replace_surrounding_text (ScimBridgeClientIMContext *imcontext, int cursor_position, const char *string) { +#if QT_VERSION >= 0x040000 ScimBridgeClientIMContextImpl *imcontext_impl = static_cast<ScimBridgeClientIMContextImpl*> (imcontext); return imcontext_impl->replace_surrounding_text (string, cursor_position); +#else + scim_bridge_perrorln ("FIXME: scim_bridge_client_imcontext_replace_surrounding_text () is not yet implemented."); + return FALSE; +#endif } diff --git a/extras/immodules/client-qt/scim-bridge-client-imcontext-qt.h b/extras/immodules/client-qt/scim-bridge-client-imcontext-qt.h index 4bec2f7..7530acd 100644 --- a/extras/immodules/client-qt/scim-bridge-client-imcontext-qt.h +++ b/extras/immodules/client-qt/scim-bridge-client-imcontext-qt.h @@ -26,14 +26,30 @@ #ifndef SCIMBRIDGECLIENTIMCONTEXTQT_H_ #define SCIMBRIDGECLIENTIMCONTEXTQT_H_ +#include <QtGlobal> +#if QT_VERSION >= 0x040000 #include <QApplication> #include <QEvent> #include <QFont> -#include <qpa/qplatforminputcontext.h> -#include <QInputMethodEvent> #include <QObject> #include <QPoint> #include <QWidget> +#else +#include <qapplication.h> +#include <qevent.h> +#include <qfont.h> +#include <qinputcontext.h> +#include <qobject.h> +#include <qptrlist.h> +#include <qpoint.h> +#include <qwidget.h> +#endif +#if QT_VERSION >= 0x050000 +#include <QtGui/qpa/qplatforminputcontext.h> +#elif QT_VERSION >= 0x040000 +#include <QInputContext> +#include <QInputMethodEvent> +#endif #include "scim-bridge.h" #include "scim-bridge-attribute.h" @@ -42,10 +58,14 @@ #include "scim-bridge-client-common-qt.h" +#if QT_VERSION >= 0x050000 +typedef QPlatformInputContext QInputContext; +#endif + /** * IMContext class for qt client. */ -struct _ScimBridgeClientIMContext: public QPlatformInputContext +struct _ScimBridgeClientIMContext: public QInputContext { public: @@ -82,6 +102,50 @@ struct _ScimBridgeClientIMContext: public QPlatformInputContext */ virtual ~_ScimBridgeClientIMContext () {} +#ifdef Q_WS_X11 + /** + * Filter a event from X11. + * + * @param widget The widget. + * @param A event from X11. + * @return If this event is consumed or not. + */ + virtual bool x11FilterEvent (QWidget *widget, XEvent *event) = 0; +#endif + +#if QT_VERSION < 0x040000 + + /** + * Focus an IMContext. + */ + virtual void setFocus () = 0; + + /** + * Unfocus an IMContext. + */ + virtual void unsetFocus () = 0; + + /** + * Set the focused area in the display. + * + * @param x The X loation of the focused area. + * @param y The Y loation of the focused area. + * @param w The width of the focused area. + * @param h The height of the focused area. + * @param font The font. + */ + virtual void setMicroFocus (int x, int y, int w, int h, QFont *font = 0) = 0; + + /** + * Filter a mouse event. + * + * @param offset The cursor offset in the preedit string. + * @param type The type of the event. + * @param button The button of this event. + * @param state The state of the button. + */ + virtual void mouseHandler (int offset, QEvent::Type type, ButtonState button, ButtonState state) = 0; + /** * Filter a key event. * @@ -90,6 +154,8 @@ struct _ScimBridgeClientIMContext: public QPlatformInputContext */ virtual bool filterEvent (const QEvent *event) = 0; +#elif QT_VERSION < 0x050000 + /** * The focus has been changed. */ @@ -124,6 +190,8 @@ struct _ScimBridgeClientIMContext: public QPlatformInputContext */ virtual void widgetDestroyed (QWidget *widget) = 0; +#endif + /** * Reset the current IME. */ diff --git a/extras/immodules/client-qt/scim-bridge-client-key-event-utility-qt.cpp b/extras/immodules/client-qt/scim-bridge-client-key-event-utility-qt.cpp index 5d52ea3..f83d550 100644 --- a/extras/immodules/client-qt/scim-bridge-client-key-event-utility-qt.cpp +++ b/extras/immodules/client-qt/scim-bridge-client-key-event-utility-qt.cpp @@ -22,10 +22,16 @@ #include <cstdlib> #include <map> +#include <QtGlobal> +#if QT_VERSION >= 0x040000 #include <QApplication> #include <QChar> #include <QEvent> #include <QKeyEvent> +#else +#include <qapplication.h> +#include <qkeycode.h> +#endif #include "scim-bridge-output.h" #include "scim-bridge-client-key-event-utility-qt.h" @@ -43,7 +49,7 @@ static map<scim_bridge_key_code_t, int> bridge_to_qt_key_map; static void register_key (int qt_key_code, scim_bridge_key_code_t bridge_key_code) { qt_to_bridge_key_map[qt_key_code] = bridge_key_code; - qt_to_bridge_key_map[bridge_key_code] = qt_key_code; + bridge_to_qt_key_map[bridge_key_code] = qt_key_code; } @@ -77,8 +83,13 @@ static void static_initialize () register_key (Qt::Key_Up, SCIM_BRIDGE_KEY_CODE_Up); register_key (Qt::Key_Right, SCIM_BRIDGE_KEY_CODE_Right); register_key (Qt::Key_Down, SCIM_BRIDGE_KEY_CODE_Down); +#if QT_VERSION >= 0x040000 register_key (Qt::Key_PageUp, SCIM_BRIDGE_KEY_CODE_Prior); - register_key (Qt::Key_PageDown, SCIM_BRIDGE_KEY_CODE_Next); + register_key (Qt::Key_PageUp, SCIM_BRIDGE_KEY_CODE_Next); +#else + register_key (Qt::Key_Prior, SCIM_BRIDGE_KEY_CODE_Prior); + register_key (Qt::Key_Next, SCIM_BRIDGE_KEY_CODE_Next); +#endif register_key (Qt::Key_CapsLock, SCIM_BRIDGE_KEY_CODE_Caps_Lock); register_key (Qt::Key_NumLock, SCIM_BRIDGE_KEY_CODE_Num_Lock); register_key (Qt::Key_ScrollLock, SCIM_BRIDGE_KEY_CODE_Scroll_Lock); @@ -174,17 +185,36 @@ QKeyEvent *scim_bridge_key_event_bridge_to_qt (const ScimBridgeKeyEvent *bridge_ if (bridge_key_code < 0x1000) { if (bridge_key_code >= SCIM_BRIDGE_KEY_CODE_a && bridge_key_code <= SCIM_BRIDGE_KEY_CODE_z) { ascii_code = bridge_key_code; +#if QT_VERSION >= 0x050000 qt_key_code = QChar (ascii_code).toUpper ().toLatin1 (); +#elif QT_VERSION >= 0x040000 + qt_key_code = QChar (ascii_code).toUpper ().toAscii (); +#else + qt_key_code = QChar (ascii_code).upper (); +#endif } else { ascii_code = bridge_key_code; qt_key_code = bridge_key_code; } } else if (bridge_key_code < 0x3000) { +#ifdef Q_WS_WIN qt_key_code = bridge_key_code; } else { - qt_key_code = Qt::Key_unknown; + qt_key_code = Key_unknown; + } +#else + qt_key_code = bridge_key_code | Qt::UNICODE_ACCEL; + } else { + map<scim_bridge_key_code_t, int>::iterator iter = bridge_to_qt_key_map.find (bridge_key_code); + if (iter != bridge_to_qt_key_map.end ()) { + qt_key_code = iter->second; + } else { + qt_key_code = Qt::Key_unknown; + } } +#endif +#if QT_VERSION >= 0x040000 Qt::KeyboardModifiers modifiers = Qt::NoModifier; if (scim_bridge_key_event_is_alt_down (bridge_key_event)) modifiers |= Qt::AltModifier; @@ -193,6 +223,16 @@ QKeyEvent *scim_bridge_key_event_bridge_to_qt (const ScimBridgeKeyEvent *bridge_ if (scim_bridge_key_event_is_meta_down (bridge_key_event)) modifiers |= Qt::MetaModifier; return new QKeyEvent (type, qt_key_code, modifiers); +#else + unsigned int modifiers = 0; + + if (scim_bridge_key_event_is_alt_down (bridge_key_event)) modifiers |= Qt::AltButton; + if (scim_bridge_key_event_is_shift_down (bridge_key_event)) modifiers |= Qt::ShiftButton; + if (scim_bridge_key_event_is_control_down (bridge_key_event)) modifiers |= Qt::ControlButton; + if (scim_bridge_key_event_is_meta_down (bridge_key_event)) modifiers |= Qt::MetaButton; + + return new QKeyEvent (type, qt_key_code, ascii_code, modifiers); +#endif } @@ -202,6 +242,7 @@ ScimBridgeKeyEvent *scim_bridge_key_event_qt_to_bridge (const QKeyEvent *key_eve ScimBridgeKeyEvent *bridge_key_event = scim_bridge_alloc_key_event (); +#if QT_VERSION >= 0x040000 const Qt::KeyboardModifiers modifiers = key_event->modifiers (); if (modifiers & Qt::ShiftModifier) { @@ -216,6 +257,22 @@ ScimBridgeKeyEvent *scim_bridge_key_event_qt_to_bridge (const QKeyEvent *key_eve if (modifiers & Qt::MetaModifier) { scim_bridge_key_event_set_meta_down (bridge_key_event, TRUE); } +#else + const int modifiers = key_event->state (); + + if (modifiers & Qt::ShiftButton) { + scim_bridge_key_event_set_shift_down (bridge_key_event, TRUE); + } + if (modifiers & Qt::ControlButton) { + scim_bridge_key_event_set_control_down (bridge_key_event, TRUE); + } + if (modifiers & Qt::AltButton) { + scim_bridge_key_event_set_alt_down (bridge_key_event, TRUE); + } + if (modifiers & Qt::MetaButton) { + scim_bridge_key_event_set_meta_down (bridge_key_event, TRUE); + } +#endif const int qt_key_code = key_event->key (); int bridge_key_code; @@ -240,9 +297,17 @@ ScimBridgeKeyEvent *scim_bridge_key_event_qt_to_bridge (const QKeyEvent *key_eve } if (!scim_bridge_key_event_is_caps_lock_down (bridge_key_event) ^ scim_bridge_key_event_is_shift_down (bridge_key_event)) { +#if QT_VERSION >= 0x040000 bridge_key_code = QChar (qt_key_code).toLower ().unicode (); +#else + bridge_key_code = QChar (qt_key_code).lower ().unicode (); +#endif } else { +#if QT_VERSION >= 0x040000 bridge_key_code = QChar (qt_key_code).toUpper ().unicode (); +#else + bridge_key_code = QChar (qt_key_code).upper ().unicode (); +#endif } } else { map<int, scim_bridge_key_code_t>::iterator iter = qt_to_bridge_key_map.find (qt_key_code); @@ -262,6 +327,7 @@ ScimBridgeKeyEvent *scim_bridge_key_event_qt_to_bridge (const QKeyEvent *key_eve } +#ifdef Q_WS_X11 XEvent *scim_bridge_key_event_bridge_to_x11 (const ScimBridgeKeyEvent *bridge_key_event, Display *display, WId window_id) { XEvent *x_event = static_cast<XEvent*> (malloc (sizeof (XEvent))); @@ -349,3 +415,59 @@ ScimBridgeKeyEvent* scim_bridge_key_event_x11_to_bridge (const XEvent *x_event) return bridge_key_event; } + +#endif + +#if QT_VERSION >= 0x050000 +ScimBridgeKeyEvent* scim_bridge_key_event_xcb_to_bridge (xcb_generic_event_t *xcb_event, xcb_connection_t *xcb_connection) +{ + xcb_key_press_event_t *key_event = (xcb_key_press_event_t *) xcb_event; + + ScimBridgeKeyEvent *bridge_key_event = scim_bridge_alloc_key_event (); + + uint8_t event_type = key_event->response_type & ~0x80; + scim_bridge_key_event_set_pressed (bridge_key_event, event_type == XCB_KEY_PRESS); + + xcb_key_symbols_t *key_symbols = xcb_key_symbols_alloc(xcb_connection); + if(key_symbols == NULL) { + return bridge_key_event; + } + + xcb_keysym_t keysym = (event_type == XCB_KEY_PRESS) + ? xcb_key_press_lookup_keysym(key_symbols, key_event, 0) + : xcb_key_release_lookup_keysym(key_symbols, key_event, 0); + scim_bridge_key_event_set_code (bridge_key_event, keysym); + xcb_key_symbols_free(key_symbols); + + if (key_event->state & XCB_MOD_MASK_SHIFT || (event_type == XCB_KEY_PRESS && (keysym == XK_Shift_L || keysym == XK_Shift_R))) { + scim_bridge_key_event_set_shift_down (bridge_key_event, TRUE); + } + if (key_event->state & XCB_MOD_MASK_CONTROL || (event_type == XCB_KEY_PRESS && (keysym == XK_Control_L || keysym == XK_Control_R))) { + scim_bridge_key_event_set_control_down (bridge_key_event, TRUE); + } + if (key_event->state & XCB_MOD_MASK_LOCK || (event_type == XCB_KEY_PRESS && (keysym == XK_Caps_Lock))) { + scim_bridge_key_event_set_caps_lock_down (bridge_key_event, TRUE); + } + if (key_event->state & XCB_MOD_MASK_1 || (event_type == XCB_KEY_PRESS && (keysym == XK_Alt_L || keysym == XK_Alt_R))) { + scim_bridge_key_event_set_alt_down (bridge_key_event, TRUE); + } + // super or window key + if (key_event->state & XCB_MOD_MASK_4 || (event_type == XCB_KEY_PRESS && (keysym == XK_Meta_L || keysym == XK_Meta_R))) { + scim_bridge_key_event_set_meta_down (bridge_key_event, TRUE); + } + + if (scim_bridge_key_event_get_code (bridge_key_event) == SCIM_BRIDGE_KEY_CODE_backslash) { + boolean kana_ro = FALSE; + int keysym_size = 0; + xcb_key_symbols_t *key_symbols = xcb_key_symbols_alloc(xcb_connection); + if(key_symbols != NULL) { + kana_ro = (xcb_key_symbols_get_keysym(key_symbols, key_event->detail, 0) == XK_backslash + && xcb_key_symbols_get_keysym(key_symbols, key_event->detail, 1) == XK_underscore); + xcb_key_symbols_free(key_symbols); + } + scim_bridge_key_event_set_quirk_enabled (bridge_key_event, SCIM_BRIDGE_KEY_QUIRK_KANA_RO, kana_ro); + } + + return bridge_key_event; +} +#endif diff --git a/extras/immodules/client-qt/scim-bridge-client-key-event-utility-qt.h b/extras/immodules/client-qt/scim-bridge-client-key-event-utility-qt.h index 09f2f5d..dcefd96 100644 --- a/extras/immodules/client-qt/scim-bridge-client-key-event-utility-qt.h +++ b/extras/immodules/client-qt/scim-bridge-client-key-event-utility-qt.h @@ -32,13 +32,22 @@ #include "scim-bridge-client-common-qt.h" +#ifdef Q_WS_X11 #include <X11/Xlib.h> #include <X11/keysym.h> #include <X11/Xutil.h> +#elif QT_VERSION >= 0x050000 +#include <xcb/xcb.h> +#include <xcb/xcb_keysyms.h> +#include <X11/keysym.h> +#endif + +#ifdef Q_WS_X11 static const int XKeyPress = KeyPress; static const int XKeyRelease = KeyRelease; #undef KeyPress #undef KeyRelease +#endif class QKeyEvent; @@ -58,6 +67,7 @@ QKeyEvent *scim_bridge_key_event_bridge_to_qt (const ScimBridgeKeyEvent *bridge_ */ ScimBridgeKeyEvent *scim_bridge_key_event_qt_to_bridge (const QKeyEvent *qt_key_event); +#ifdef Q_WS_X11 /** * Translate a key event from scim-bridge into X11. * @@ -76,5 +86,23 @@ XEvent *scim_bridge_key_event_bridge_to_x11 (const ScimBridgeKeyEvent *bridge_ke * @return The key event from scim-bridge. */ ScimBridgeKeyEvent* scim_bridge_key_event_x11_to_bridge (const XEvent *x11_event); +#endif +#if QT_VERSION >= 0x050000 +/** + * Translate a key event from scim-bridge into xcb. + * + * @param bridge_key_event The key event from scim-bridge. + * @return The key event for xcb. + */ +xcb_generic_event_t *scim_bridge_key_event_bridge_to_xcb (const ScimBridgeKeyEvent *bridge_key_event); + +/** + * Translate a key event from xcb into scim-bridge. + * + * @param xcb_event The event from xcb. + * @return The key event from scim-bridge. + */ +ScimBridgeKeyEvent* scim_bridge_key_event_xcb_to_bridge (xcb_generic_event_t *xcb_event, xcb_connection_t *xcb_connection); +#endif #endif /*SCIMBRIDGECLIENTKEYEVENTUTILITYQT_H_*/ diff --git a/extras/immodules/client-qt/scim-bridge-client-qt.cpp b/extras/immodules/client-qt/scim-bridge-client-qt.cpp index 7495ca6..8926d1b 100644 --- a/extras/immodules/client-qt/scim-bridge-client-qt.cpp +++ b/extras/immodules/client-qt/scim-bridge-client-qt.cpp @@ -23,7 +23,9 @@ #include "scim-bridge-client-qt.h" +#if QT_VERSION >= 0x040000 using namespace Qt; +#endif /* Static variables */ static ScimBridgeClientQt *client = NULL; diff --git a/extras/immodules/client-qt/scim-bridge-client-qt.h b/extras/immodules/client-qt/scim-bridge-client-qt.h index 65ad450..408d2e4 100644 --- a/extras/immodules/client-qt/scim-bridge-client-qt.h +++ b/extras/immodules/client-qt/scim-bridge-client-qt.h @@ -26,8 +26,13 @@ #ifndef SCIMBRIDGECLIENTQT_H_ #define SCIMBRIDGECLIENTQT_H_ +#if QT_VERSION >= 0x040000 #include <QObject> #include <QSocketNotifier> +#else +#include <qobject.h> +#include <qsocketnotifier.h> +#endif #include "scim-bridge.h" #include "scim-bridge-client-imcontext-qt.h" diff --git a/extras/immodules/configure.ac b/extras/immodules/configure.ac index 4959dac..790c1f4 100644 --- a/extras/immodules/configure.ac +++ b/extras/immodules/configure.ac @@ -136,6 +136,17 @@ if test "$SCIM_BRIDGE_HAS_QT4" = "yes"; then AC_SUBST(QT4_PREFIX) fi +PKG_CHECK_MODULES(QT5, [Qt5Gui >= 5.0, Qt5Core >= 5.0], + [SCIM_BRIDGE_HAS_QT5=yes], + [SCIM_BRIDGE_HAS_QT5=no]) + +if test "$SCIM_BRIDGE_HAS_QT5" = "yes"; then + if test -z "$QT5_PREFIX"; then + QT5_PREFIX=`$PKG_CONFIG --variable=prefix Qt5Core` + fi + AC_SUBST(QT5_PREFIX) +fi + # Check if we should build scim-bridge-clutter-immodule PKG_CHECK_MODULES(CLUTTER, clutter-0.9 clutter-imcontext-0.1, [SCIM_BRIDGE_HAS_CLUTTER=yes], @@ -189,6 +200,10 @@ AC_ARG_ENABLE(qt4-immodule, [AS_HELP_STRING([--enable-qt4-immodule], [build Qt4 IM module])], , enable_qt4_immodule=yes) +AC_ARG_ENABLE(qt5-immodule, + [AS_HELP_STRING([--enable-qt5-immodule], [build Qt5 IM module])], , + enable_qt5_immodule=yes) + AC_ARG_ENABLE(clutter-immodule, [AS_HELP_STRING([--enable-clutter-immodule], [build CLUTTER IM module])], , ) @@ -270,6 +285,15 @@ else enable_qt4_immodule=no fi +if test "$enable_qt5_immodule" = "yes" -a "$SCIM_BRIDGE_HAS_QT5" = "yes"; then + SCIM_BRIDGE_BUILD_QT5_IMMODULE=1 + SCIM_BRIDGE_BUILD_IMMODULE=1 + enable_immodule=yes +else + SCIM_BRIDGE_BUILD_QT5_IMMODULE=0 + enable_qt5_immodule=no +fi + if test "$enable_clutter_immodule" = "yes"; then SCIM_BRIDGE_BUILD_CLUTTER_IMMODULE=1 SCIM_BRIDGE_BUILD_IMMODULE=1 @@ -306,6 +330,9 @@ AM_CONDITIONAL(SCIM_BRIDGE_BUILD_QT3_IMMODULE, AM_CONDITIONAL(SCIM_BRIDGE_BUILD_QT4_IMMODULE, [test "$enable_qt4_immodule" = "yes"]) +AM_CONDITIONAL(SCIM_BRIDGE_BUILD_QT5_IMMODULE, + [test "$enable_qt5_immodule" = "yes"]) + AM_CONDITIONAL(SCIM_BRIDGE_BUILD_CLUTTER_IMMODULE, [test "$enable_clutter_immodule" = "yes"]) @@ -319,6 +346,7 @@ AC_SUBST(SCIM_BRIDGE_BUILD_GTK3_IMMODULE) AC_SUBST(SCIM_BRIDGE_BUILD_GTK4_IMMODULE) AC_SUBST(SCIM_BRIDGE_BUILD_QT3_IMMODULE) AC_SUBST(SCIM_BRIDGE_BUILD_QT4_IMMODULE) +AC_SUBST(SCIM_BRIDGE_BUILD_QT5_IMMODULE) AC_SUBST(SCIM_BRIDGE_BUILD_CLUTTER_IMMODULE) AC_SUBST(SCIM_BRIDGE_BUILD_IMMODULE) @@ -357,7 +385,7 @@ AC_SUBST(SCIM_LOCALDIR) ## Output files. ## ########################################################### AC_SUBST(ac_aux_dir) -AC_CONFIG_FILES([Makefile common/Makefile agent/Makefile client-common/Makefile client-gtk/gtk2/Makefile client-gtk/gtk3/Makefile client-qt/qt3/Makefile client-qt/qt4/Makefile client-clutter/Makefile tests/Makefile doc/Makefile]) +AC_CONFIG_FILES([Makefile common/Makefile agent/Makefile client-common/Makefile client-gtk/gtk2/Makefile client-gtk/gtk3/Makefile client-qt/qt3/Makefile client-qt/qt4/Makefile client-qt/qt5/Makefile client-clutter/Makefile tests/Makefile doc/Makefile]) AC_OUTPUT @@ -378,6 +406,7 @@ Module options: Build GTK4 IMModule $enable_gtk4_immodule Build QT3 IMModule $enable_qt3_immodule Build QT4 IMModule $enable_qt4_immodule + Build QT5 IMModule $enable_qt5_immodule Build CLUTTER IMModule $enable_clutter_immodule ]) diff --git a/utils/Makefile.am b/utils/Makefile.am index c77ea65..e835ecb 100644 --- a/utils/Makefile.am +++ b/utils/Makefile.am @@ -55,7 +55,8 @@ libscim_gtkutils@SCIM_EPOCH@_la_LDFLAGS= -version-info $(SCIM_CURRENT):$(SCIM_RE -export-dynamic \ @LIBTOOL_EXPORT_OPTIONS@ \ @LTLIBINTL@ \ - @GTK_LIBS@ + @GTK_LIBS@ \ + @X_LIBS@ libscim_gtkutils@SCIM_EPOCH@_la_LIBADD= $(top_builddir)/src/libscim@SCIM_EPOCH@.la $(X11_UTILS) -- 2.37.3