diff options
author | Huang Peng <shawn.p.huang@gmail.com> | 2008-08-16 12:51:47 +0800 |
---|---|---|
committer | Huang Peng <shawn.p.huang@gmail.com> | 2008-08-16 12:51:47 +0800 |
commit | 931f116d5fee25f22a48cf50b13323f3bd89180b (patch) | |
tree | 3bea5f8278717fd9552b008ffa21b01ef698da2f | |
parent | 6a820938ed75a8c87ba223e248cba0d552bcb8b1 (diff) | |
download | ibus-931f116d5fee25f22a48cf50b13323f3bd89180b.tar.gz ibus-931f116d5fee25f22a48cf50b13323f3bd89180b.tar.xz ibus-931f116d5fee25f22a48cf50b13323f3bd89180b.zip |
WIP.
-rw-r--r-- | Makefile.am | 5 | ||||
-rw-r--r-- | client/Makefile.am | 26 | ||||
-rw-r--r-- | client/gtk2/Makefile.am | 50 | ||||
-rw-r--r-- | client/gtk2/ibusim.c (renamed from gtk2/ibusim.c) | 4 | ||||
-rw-r--r-- | client/gtk2/ibusimclient.c (renamed from gtk2/ibusimclient.c) | 22 | ||||
-rw-r--r-- | client/gtk2/ibusimclient.h (renamed from gtk2/ibusimclient.h) | 6 | ||||
-rw-r--r-- | client/gtk2/ibusimcontext.c (renamed from gtk2/ibusimcontext.c) | 0 | ||||
-rw-r--r-- | client/gtk2/ibusimcontext.h (renamed from gtk2/ibusimcontext.h) | 0 | ||||
-rw-r--r-- | client/gtk2/ibusmarshalers.list (renamed from gtk2/ibusmarshalers.list) | 0 | ||||
-rw-r--r-- | client/qt4/.gitignore (renamed from qt4/.gitignore) | 0 | ||||
-rw-r--r-- | client/qt4/Makefile.am (renamed from qt4/Makefile.am) | 0 | ||||
-rw-r--r-- | client/qt4/ibus-client.cpp (renamed from qt4/ibus-client.cpp) | 0 | ||||
-rw-r--r-- | client/qt4/ibus-client.h (renamed from qt4/ibus-client.h) | 0 | ||||
-rw-r--r-- | client/qt4/ibus-input-context.cpp (renamed from qt4/ibus-input-context.cpp) | 0 | ||||
-rw-r--r-- | client/qt4/ibus-input-context.h (renamed from qt4/ibus-input-context.h) | 0 | ||||
-rw-r--r-- | client/qt4/ibus.pro (renamed from qt4/ibus.pro) | 0 | ||||
-rw-r--r-- | client/qt4/im-ibus-qt.cpp (renamed from qt4/im-ibus-qt.cpp) | 0 | ||||
-rw-r--r-- | client/x11/IMdkit/FrameMgr.c (renamed from x11/IMdkit/FrameMgr.c) | 0 | ||||
-rw-r--r-- | client/x11/IMdkit/FrameMgr.h (renamed from x11/IMdkit/FrameMgr.h) | 0 | ||||
-rw-r--r-- | client/x11/IMdkit/IMConn.c (renamed from x11/IMdkit/IMConn.c) | 0 | ||||
-rw-r--r-- | client/x11/IMdkit/IMMethod.c (renamed from x11/IMdkit/IMMethod.c) | 0 | ||||
-rw-r--r-- | client/x11/IMdkit/IMValues.c (renamed from x11/IMdkit/IMValues.c) | 0 | ||||
-rw-r--r-- | client/x11/IMdkit/IMdkit.h (renamed from x11/IMdkit/IMdkit.h) | 0 | ||||
-rw-r--r-- | client/x11/IMdkit/Makefile.am (renamed from x11/IMdkit/Makefile.am) | 0 | ||||
-rw-r--r-- | client/x11/IMdkit/Xi18n.h (renamed from x11/IMdkit/Xi18n.h) | 0 | ||||
-rw-r--r-- | client/x11/IMdkit/Xi18nX.h (renamed from x11/IMdkit/Xi18nX.h) | 0 | ||||
-rw-r--r-- | client/x11/IMdkit/XimFunc.h (renamed from x11/IMdkit/XimFunc.h) | 0 | ||||
-rw-r--r-- | client/x11/IMdkit/XimProto.h (renamed from x11/IMdkit/XimProto.h) | 0 | ||||
-rw-r--r-- | client/x11/IMdkit/Xtrans.h (renamed from x11/IMdkit/Xtrans.h) | 0 | ||||
-rw-r--r-- | client/x11/IMdkit/i18nAttr.c (renamed from x11/IMdkit/i18nAttr.c) | 0 | ||||
-rw-r--r-- | client/x11/IMdkit/i18nClbk.c (renamed from x11/IMdkit/i18nClbk.c) | 0 | ||||
-rw-r--r-- | client/x11/IMdkit/i18nIMProto.c (renamed from x11/IMdkit/i18nIMProto.c) | 0 | ||||
-rw-r--r-- | client/x11/IMdkit/i18nIc.c (renamed from x11/IMdkit/i18nIc.c) | 0 | ||||
-rw-r--r-- | client/x11/IMdkit/i18nMethod.c (renamed from x11/IMdkit/i18nMethod.c) | 0 | ||||
-rw-r--r-- | client/x11/IMdkit/i18nPtHdr.c (renamed from x11/IMdkit/i18nPtHdr.c) | 0 | ||||
-rw-r--r-- | client/x11/IMdkit/i18nUtil.c (renamed from x11/IMdkit/i18nUtil.c) | 0 | ||||
-rw-r--r-- | client/x11/IMdkit/i18nX.c (renamed from x11/IMdkit/i18nX.c) | 0 | ||||
-rw-r--r-- | client/x11/Makefile.am (renamed from x11/Makefile.am) | 0 | ||||
-rw-r--r-- | client/x11/gdk-private.c (renamed from x11/gdk-private.c) | 0 | ||||
-rw-r--r-- | client/x11/gdk-private.h (renamed from x11/gdk-private.h) | 0 | ||||
-rw-r--r-- | client/x11/main.c (renamed from x11/main.c) | 0 | ||||
-rw-r--r-- | configure.ac | 11 | ||||
-rw-r--r-- | lib/Makefile.am | 24 | ||||
-rw-r--r-- | lib/gtk2/Makefile.am (renamed from gtk2/Makefile.am) | 31 | ||||
-rw-r--r-- | lib/gtk2/ibusimclient.c | 1308 | ||||
-rw-r--r-- | lib/gtk2/ibusimclient.h | 125 | ||||
-rw-r--r-- | lib/gtk2/ibusmarshalers.list | 5 |
47 files changed, 1559 insertions, 58 deletions
diff --git a/Makefile.am b/Makefile.am index bff6e8f..977d057 100644 --- a/Makefile.am +++ b/Makefile.am @@ -26,10 +26,9 @@ SUBDIRS = \ launcher \ panel \ engine \ - gtk2 \ - qt4 \ + lib \ + client \ setup \ - x11 \ icons \ m4 \ po \ diff --git a/client/Makefile.am b/client/Makefile.am new file mode 100644 index 0000000..c7bd313 --- /dev/null +++ b/client/Makefile.am @@ -0,0 +1,26 @@ +# vim:set noet ts=4: +# +# ibus - The Input Bus +# +# Copyright (c) 2007-2008 Huang Peng <shawn.p.huang@gmail.com> +# +# 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; either +# version 2 of the License, or (at your option) any later version. +# +# 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. See the +# GNU Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this program; if not, write to the +# Free Software Foundation, Inc., 59 Temple Place, Suite 330, +# Boston, MA 02111-1307 USA + +SUBDIRS = \ + gtk2 \ + qt4 \ + x11 \ + $(NULL) diff --git a/client/gtk2/Makefile.am b/client/gtk2/Makefile.am new file mode 100644 index 0000000..465e0ce --- /dev/null +++ b/client/gtk2/Makefile.am @@ -0,0 +1,50 @@ +# vim:set noet ts=4: +# +# ibus - The Input Bus +# +# Copyright (c) 2007-2008 Huang Peng <shawn.p.huang@gmail.com> +# +# 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; either +# version 2 of the License, or (at your option) any later version. +# +# 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. See the +# GNU Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this program; if not, write to the +# Free Software Foundation, Inc., 59 Temple Place, Suite 330, +# Boston, MA 02111-1307 USA + +INCLUDES = \ + -I$(top_srcdir)/lib/gtk2 \ + $(NULL) + +immoduledir = @GTK_IM_MODULEDIR@ +# $(libdir)/gtk-2.0/immodules +immodule_LTLIBRARIES = im-ibus.la +im_ibus_la_DEPENDENCIES = libibus-gtk.la +im_ibus_la_SOURCES = \ + ibusim.c \ + $(NULL) +im_ibus_la_CFLAGS = \ + @GTK2_CFLAGS@ \ + @DBUS_CFLAGS@ \ + -DG_LOG_DOMAIN=\"IBUS\" \ + $(NULL) +im_ibus_la_LDFLAGS = \ + @GTK2_LIBS@ \ + @DBUS_LIBS@ \ + $(builddir)/libibus-gtk.la \ + -avoid-version \ + -module \ + $(NULL) + +EXTRA_DIST = \ + $(NULL) + +test: all + GTK_IM_MODULE=ibus gedit diff --git a/gtk2/ibusim.c b/client/gtk2/ibusim.c index d0a5773..e87c9f6 100644 --- a/gtk2/ibusim.c +++ b/client/gtk2/ibusim.c @@ -59,9 +59,9 @@ GtkIMContext * im_module_create (const gchar *context_id) { if (strcmp (context_id, "ibus") == 0) { - gchar *ic; + const gchar *ic; IBusIMContext *context; - ic = ibus_im_client_create_im_context (_client); + ic = ibus_im_client_create_input_context (_client); return GTK_IM_CONTEXT(context); } return NULL; diff --git a/gtk2/ibusimclient.c b/client/gtk2/ibusimclient.c index d2576d1..c1535b7 100644 --- a/gtk2/ibusimclient.c +++ b/client/gtk2/ibusimclient.c @@ -83,13 +83,6 @@ static void ibus_im_client_class_init (IBusIMClientClass *klass); static void ibus_im_client_init (IBusIMClient *client); static void ibus_im_client_finalize (GObject *obj); - -static void ibus_im_client_connected (IBusIMClient *client); -static void ibus_im_client_disconnected (IBusIMClient *client); - -static const gchar * - _ibus_im_client_create_input_context - (IBusIMClient *client); static void _ibus_im_client_ibus_open (IBusIMClient *client); static void _ibus_im_client_ibus_close (IBusIMClient *client); @@ -410,19 +403,10 @@ _ibus_im_client_ibus_close (IBusIMClient *client) } /* - * create an im context - */ -const char * -ibus_im_client_create_im_context (IBusIMClient *client) -{ - return _ibus_im_client_create_input_context (client); -} - -/* * create a ibus input context */ -static const gchar * -_ibus_im_client_create_input_context (IBusIMClient *client) +const gchar * +ibus_im_client_create_input_context (IBusIMClient *client) { IBusIMClientPrivate *priv = client->priv; @@ -1290,7 +1274,7 @@ ibus_im_client_set_use_preedit (IBusIMClient *client, const gchar *ic, gboolean } void -ibus_im_client_release_im_context (IBusIMClient *client, const gchar *ic) +ibus_im_client_release_input_context (IBusIMClient *client, const gchar *ic) { g_return_if_fail (IBUS_IS_IM_CLIENT(client)); g_return_if_fail (ic != NULL); diff --git a/gtk2/ibusimclient.h b/client/gtk2/ibusimclient.h index 4e51fb8..a0e4f75 100644 --- a/gtk2/ibusimclient.h +++ b/client/gtk2/ibusimclient.h @@ -93,7 +93,8 @@ extern IBusIMClient *_client; GType ibus_im_client_get_type (void); void ibus_im_client_register_type (GTypeModule *type_module); IBusIMClient *ibus_im_client_new (void); -const gchar *ibus_im_client_create_im_context (IBusIMClient *client); +const gchar *ibus_im_client_create_input_context + (IBusIMClient *client); void ibus_im_client_shutdown (void); void ibus_im_client_focus_in (IBusIMClient *client, const gchar *ic); @@ -112,7 +113,8 @@ void ibus_im_client_set_use_preedit (IBusIMClient *client, const gchar *ic, gboolean use_preedit); gboolean ibus_im_client_is_enabled (IBusIMClient *client); -void ibus_im_client_release_im_context(IBusIMClient *client, +void ibus_im_client_release_input_context + (IBusIMClient *client, const gchar *ic); void ibus_im_client_kill_daemon (IBusIMClient *client); gboolean ibus_im_client_get_connected (IBusIMClient *client); diff --git a/gtk2/ibusimcontext.c b/client/gtk2/ibusimcontext.c index 1a14564..1a14564 100644 --- a/gtk2/ibusimcontext.c +++ b/client/gtk2/ibusimcontext.c diff --git a/gtk2/ibusimcontext.h b/client/gtk2/ibusimcontext.h index 934a022..934a022 100644 --- a/gtk2/ibusimcontext.h +++ b/client/gtk2/ibusimcontext.h diff --git a/gtk2/ibusmarshalers.list b/client/gtk2/ibusmarshalers.list index 89c4f76..89c4f76 100644 --- a/gtk2/ibusmarshalers.list +++ b/client/gtk2/ibusmarshalers.list diff --git a/qt4/.gitignore b/client/qt4/.gitignore index 52bae9b..52bae9b 100644 --- a/qt4/.gitignore +++ b/client/qt4/.gitignore diff --git a/qt4/Makefile.am b/client/qt4/Makefile.am index 012a6b0..012a6b0 100644 --- a/qt4/Makefile.am +++ b/client/qt4/Makefile.am diff --git a/qt4/ibus-client.cpp b/client/qt4/ibus-client.cpp index cb37b1b..cb37b1b 100644 --- a/qt4/ibus-client.cpp +++ b/client/qt4/ibus-client.cpp diff --git a/qt4/ibus-client.h b/client/qt4/ibus-client.h index 285d633..285d633 100644 --- a/qt4/ibus-client.h +++ b/client/qt4/ibus-client.h diff --git a/qt4/ibus-input-context.cpp b/client/qt4/ibus-input-context.cpp index 692fecb..692fecb 100644 --- a/qt4/ibus-input-context.cpp +++ b/client/qt4/ibus-input-context.cpp diff --git a/qt4/ibus-input-context.h b/client/qt4/ibus-input-context.h index 317c876..317c876 100644 --- a/qt4/ibus-input-context.h +++ b/client/qt4/ibus-input-context.h diff --git a/qt4/ibus.pro b/client/qt4/ibus.pro index 1c308a2..1c308a2 100644 --- a/qt4/ibus.pro +++ b/client/qt4/ibus.pro diff --git a/qt4/im-ibus-qt.cpp b/client/qt4/im-ibus-qt.cpp index 0d6944b..0d6944b 100644 --- a/qt4/im-ibus-qt.cpp +++ b/client/qt4/im-ibus-qt.cpp diff --git a/x11/IMdkit/FrameMgr.c b/client/x11/IMdkit/FrameMgr.c index 9b49794..9b49794 100644 --- a/x11/IMdkit/FrameMgr.c +++ b/client/x11/IMdkit/FrameMgr.c diff --git a/x11/IMdkit/FrameMgr.h b/client/x11/IMdkit/FrameMgr.h index ce7ed50..ce7ed50 100644 --- a/x11/IMdkit/FrameMgr.h +++ b/client/x11/IMdkit/FrameMgr.h diff --git a/x11/IMdkit/IMConn.c b/client/x11/IMdkit/IMConn.c index 6d36589..6d36589 100644 --- a/x11/IMdkit/IMConn.c +++ b/client/x11/IMdkit/IMConn.c diff --git a/x11/IMdkit/IMMethod.c b/client/x11/IMdkit/IMMethod.c index 5a33878..5a33878 100644 --- a/x11/IMdkit/IMMethod.c +++ b/client/x11/IMdkit/IMMethod.c diff --git a/x11/IMdkit/IMValues.c b/client/x11/IMdkit/IMValues.c index 687014a..687014a 100644 --- a/x11/IMdkit/IMValues.c +++ b/client/x11/IMdkit/IMValues.c diff --git a/x11/IMdkit/IMdkit.h b/client/x11/IMdkit/IMdkit.h index 6f8d673..6f8d673 100644 --- a/x11/IMdkit/IMdkit.h +++ b/client/x11/IMdkit/IMdkit.h diff --git a/x11/IMdkit/Makefile.am b/client/x11/IMdkit/Makefile.am index b567d9d..b567d9d 100644 --- a/x11/IMdkit/Makefile.am +++ b/client/x11/IMdkit/Makefile.am diff --git a/x11/IMdkit/Xi18n.h b/client/x11/IMdkit/Xi18n.h index aaf7768..aaf7768 100644 --- a/x11/IMdkit/Xi18n.h +++ b/client/x11/IMdkit/Xi18n.h diff --git a/x11/IMdkit/Xi18nX.h b/client/x11/IMdkit/Xi18nX.h index ff91b1a..ff91b1a 100644 --- a/x11/IMdkit/Xi18nX.h +++ b/client/x11/IMdkit/Xi18nX.h diff --git a/x11/IMdkit/XimFunc.h b/client/x11/IMdkit/XimFunc.h index a9f4a04..a9f4a04 100644 --- a/x11/IMdkit/XimFunc.h +++ b/client/x11/IMdkit/XimFunc.h diff --git a/x11/IMdkit/XimProto.h b/client/x11/IMdkit/XimProto.h index e3ed168..e3ed168 100644 --- a/x11/IMdkit/XimProto.h +++ b/client/x11/IMdkit/XimProto.h diff --git a/x11/IMdkit/Xtrans.h b/client/x11/IMdkit/Xtrans.h index cae691c..cae691c 100644 --- a/x11/IMdkit/Xtrans.h +++ b/client/x11/IMdkit/Xtrans.h diff --git a/x11/IMdkit/i18nAttr.c b/client/x11/IMdkit/i18nAttr.c index a52370b..a52370b 100644 --- a/x11/IMdkit/i18nAttr.c +++ b/client/x11/IMdkit/i18nAttr.c diff --git a/x11/IMdkit/i18nClbk.c b/client/x11/IMdkit/i18nClbk.c index b3edf3a..b3edf3a 100644 --- a/x11/IMdkit/i18nClbk.c +++ b/client/x11/IMdkit/i18nClbk.c diff --git a/x11/IMdkit/i18nIMProto.c b/client/x11/IMdkit/i18nIMProto.c index 618da9d..618da9d 100644 --- a/x11/IMdkit/i18nIMProto.c +++ b/client/x11/IMdkit/i18nIMProto.c diff --git a/x11/IMdkit/i18nIc.c b/client/x11/IMdkit/i18nIc.c index 61b576f..61b576f 100644 --- a/x11/IMdkit/i18nIc.c +++ b/client/x11/IMdkit/i18nIc.c diff --git a/x11/IMdkit/i18nMethod.c b/client/x11/IMdkit/i18nMethod.c index 203f831..203f831 100644 --- a/x11/IMdkit/i18nMethod.c +++ b/client/x11/IMdkit/i18nMethod.c diff --git a/x11/IMdkit/i18nPtHdr.c b/client/x11/IMdkit/i18nPtHdr.c index d350354..d350354 100644 --- a/x11/IMdkit/i18nPtHdr.c +++ b/client/x11/IMdkit/i18nPtHdr.c diff --git a/x11/IMdkit/i18nUtil.c b/client/x11/IMdkit/i18nUtil.c index 22a2376..22a2376 100644 --- a/x11/IMdkit/i18nUtil.c +++ b/client/x11/IMdkit/i18nUtil.c diff --git a/x11/IMdkit/i18nX.c b/client/x11/IMdkit/i18nX.c index a5ba080..a5ba080 100644 --- a/x11/IMdkit/i18nX.c +++ b/client/x11/IMdkit/i18nX.c diff --git a/x11/Makefile.am b/client/x11/Makefile.am index 25517cb..25517cb 100644 --- a/x11/Makefile.am +++ b/client/x11/Makefile.am diff --git a/x11/gdk-private.c b/client/x11/gdk-private.c index e3d5522..e3d5522 100644 --- a/x11/gdk-private.c +++ b/client/x11/gdk-private.c diff --git a/x11/gdk-private.h b/client/x11/gdk-private.h index bd918ab..bd918ab 100644 --- a/x11/gdk-private.h +++ b/client/x11/gdk-private.h diff --git a/x11/main.c b/client/x11/main.c index cb361a2..cb361a2 100644 --- a/x11/main.c +++ b/client/x11/main.c diff --git a/configure.ac b/configure.ac index 2c04a25..ac94eb3 100644 --- a/configure.ac +++ b/configure.ac @@ -175,10 +175,13 @@ panel/ibus-panel gconf/Makefile gconf/ibus-gconf engine/Makefile -gtk2/Makefile -qt4/Makefile -x11/Makefile -x11/IMdkit/Makefile +lib/Makefile +lib/gtk2/Makefile +client/Makefile +client/gtk2/Makefile +client/qt4/Makefile +client/x11/Makefile +client/x11/IMdkit/Makefile setup/Makefile setup/ibus-setup setup/ibus-setup.desktop diff --git a/lib/Makefile.am b/lib/Makefile.am new file mode 100644 index 0000000..19d7bc3 --- /dev/null +++ b/lib/Makefile.am @@ -0,0 +1,24 @@ +# vim:set noet ts=4: +# +# ibus - The Input Bus +# +# Copyright (c) 2007-2008 Huang Peng <shawn.p.huang@gmail.com> +# +# 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; either +# version 2 of the License, or (at your option) any later version. +# +# 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. See the +# GNU Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this program; if not, write to the +# Free Software Foundation, Inc., 59 Temple Place, Suite 330, +# Boston, MA 02111-1307 USA + +SUBDIRS = \ + gtk2 \ + $(NULL) diff --git a/gtk2/Makefile.am b/lib/gtk2/Makefile.am index 399544a..4f86420 100644 --- a/gtk2/Makefile.am +++ b/lib/gtk2/Makefile.am @@ -25,12 +25,10 @@ INCLUDES = \ lib_LTLIBRARIES = libibus-gtk.la libibus_gtk_la_SOURCES = \ - ibusimcontext.c \ - ibusimcontext.h \ - ibusimclient.c \ - ibusimclient.h \ - ibusmarshalers.c \ ibusmarshalers.h \ + ibusmarshalers.c \ + ibusimclient.h \ + ibusimclient.c \ $(NULL) libibus_gtk_la_CFLAGS = \ @GTK2_CFLAGS@ \ @@ -42,27 +40,6 @@ libibus_gtk_la_LDFLAGS = \ @DBUS_LIBS@ \ $(NULL) -immoduledir = @GTK_IM_MODULEDIR@ -# $(libdir)/gtk-2.0/immodules -immodule_LTLIBRARIES = im-ibus.la -im_ibus_la_DEPENDENCIES = libibus-gtk.la -im_ibus_la_SOURCES = \ - ibusim.c \ - $(NULL) -im_ibus_la_CFLAGS = \ - @GTK2_CFLAGS@ \ - @DBUS_CFLAGS@ \ - -DG_LOG_DOMAIN=\"IBUS\" \ - $(NULL) -im_ibus_la_LDFLAGS = \ - @GTK2_LIBS@ \ - @DBUS_LIBS@ \ - $(builddir)/libibus-gtk.la \ - -avoid-version \ - -module \ - $(NULL) - - # gen marshal ibusmarshalers.h: stamp-ibusmarshalers.h @true @@ -82,5 +59,3 @@ EXTRA_DIST = \ ibusmarshalers.list \ $(NULL) -test: all - GTK_IM_MODULE=ibus gedit diff --git a/lib/gtk2/ibusimclient.c b/lib/gtk2/ibusimclient.c new file mode 100644 index 0000000..c1535b7 --- /dev/null +++ b/lib/gtk2/ibusimclient.c @@ -0,0 +1,1308 @@ +/* vim:set et ts=4: */ +/* IBus - The Input Bus + * Copyright (C) 2008-2009 Huang Peng <shawn.p.huang@gmail.com> + * + * 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; either + * version 2 of the License, or (at your option) any later version. + * + * 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. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ +#include <config.h> +#include <unistd.h> +#include <sys/types.h> +#include <sys/socket.h> +#include <sys/time.h> +#include <sys/un.h> +#include <string.h> +#include <stdarg.h> +#include <glib/gstdio.h> +#include <gdk/gdkkeysyms.h> +#include <gdk/gdkx.h> +#include <dbus/dbus.h> +#include <dbus/dbus-glib.h> +#include <dbus/dbus-glib-lowlevel.h> + +#ifdef HAVE_SYS_INOTIFY_H +#define HAVE_INOTIFY +# include <sys/inotify.h> +#endif +#include "ibusmarshalers.h" +#include "ibusimclient.h" + +enum { + CONNECTED, + DISCONNECTED, + FORWARD_EVENT, + COMMIT_STRING, + UPDATE_PREEDIT, + SHOW_PREEDIT, + HIDE_PREEDIT, + ENABLED, + DISABLED, + LAST_SIGNAL, +}; + +#define IBUS_NAME "org.freedesktop.IBus" +#define IBUS_IFACE "org.freedesktop.IBus" +#define IBUS_PATH "/org/freedesktop/IBus" + +#define I_(string) g_intern_static_string (string) + +/* IBusIMClientPriv */ +struct _IBusIMClientPrivate { +#if USE_DBUS_SESSION_BUS + DBusConnection *dbus; +#endif + +#ifdef HAVE_INOTIFY + /* inotify */ + gint inotify_wd; + GIOChannel *inotify_channel; + guint inotify_source; +#endif + + DBusConnection *ibus; + +}; + +/* variables */ +static guint client_signals[LAST_SIGNAL] = { 0 }; + +/* functions prototype */ +static void ibus_im_client_class_init (IBusIMClientClass *klass); +static void ibus_im_client_init (IBusIMClient *client); +static void ibus_im_client_finalize (GObject *obj); + +static void _ibus_im_client_ibus_open (IBusIMClient *client); +static void _ibus_im_client_ibus_close (IBusIMClient *client); + +static gboolean _ibus_call_with_reply_and_block + (DBusConnection *connection, + const gchar *method, + int first_arg_type, + ...); +static gboolean _ibus_call_with_reply (DBusConnection *connection, + const gchar *method, + DBusPendingCallNotifyFunction + function, + void *data, + DBusFreeFunction free_function, + int first_arg_type, + ...); +static gboolean _dbus_call_with_reply_and_block + (DBusConnection *connection, + const gchar *dest, + const gchar *path, + const gchar *iface, + const char *method, + int first_arg_type, + ...); + +/* callback functions */ +static DBusHandlerResult + _ibus_im_client_message_filter_cb + (DBusConnection *connection, + DBusMessage *message, + void *user_data); + +static GType ibus_type_im_client = 0; +static GtkObjectClass *parent_class = NULL; + + +GType +ibus_im_client_get_type (void) +{ + if (ibus_type_im_client == 0) { + ibus_im_client_register_type (NULL); + } + + g_assert (ibus_type_im_client != 0); + return ibus_type_im_client; +} + +void +ibus_im_client_register_type (GTypeModule *type_module) +{ + static const GTypeInfo ibus_im_client_info = { + sizeof (IBusIMClientClass), + (GBaseInitFunc) NULL, + (GBaseFinalizeFunc) NULL, + (GClassInitFunc) ibus_im_client_class_init, + NULL, /* class finialize */ + NULL, /* class data */ + sizeof (IBusIMClient), + 0, + (GInstanceInitFunc) ibus_im_client_init, + }; + + if (! ibus_type_im_client ) { + if (type_module) { + ibus_type_im_client = + g_type_module_register_type (type_module, + GTK_TYPE_OBJECT, + "IBusIMClient", + &ibus_im_client_info, + (GTypeFlags)0); + } + else { + ibus_type_im_client = + g_type_register_static (GTK_TYPE_OBJECT, + "IBusIMClient", + &ibus_im_client_info, + (GTypeFlags)0); + } + } +} + +IBusIMClient * +ibus_im_client_new (void) +{ + IBusIMClient *client; + + client = IBUS_IM_CLIENT(g_object_new (IBUS_TYPE_IM_CLIENT, NULL)); + + return client; +} + +static void +ibus_im_client_class_init (IBusIMClientClass *klass) +{ + /* GtkObjectClass *object_class = GTK_OBJECT_CLASS (klass); */ + GObjectClass *gobject_class = G_OBJECT_CLASS (klass); + + parent_class = (GtkObjectClass *) g_type_class_peek_parent (klass); + + g_type_class_add_private (klass, sizeof (IBusIMClientPrivate)); + + gobject_class->finalize = ibus_im_client_finalize; + + client_signals[CONNECTED] = + g_signal_new (I_("connected"), + G_TYPE_FROM_CLASS (gobject_class), + G_SIGNAL_RUN_FIRST, + G_STRUCT_OFFSET (IBusIMClientClass, connected), + NULL, NULL, + ibus_marshal_VOID__VOID, + G_TYPE_NONE, 0); + + client_signals[DISCONNECTED] = + g_signal_new (I_("disconnected"), + G_TYPE_FROM_CLASS (gobject_class), + G_SIGNAL_RUN_FIRST, + G_STRUCT_OFFSET (IBusIMClientClass, disconnected), + NULL, NULL, + ibus_marshal_VOID__VOID, + G_TYPE_NONE, 0); + + client_signals[FORWARD_EVENT] = + g_signal_new (I_("forward-event"), + G_TYPE_FROM_CLASS (gobject_class), + G_SIGNAL_RUN_FIRST, + G_STRUCT_OFFSET (IBusIMClientClass, commit_string), + NULL, NULL, + ibus_marshal_VOID__STRING_POINTER, + G_TYPE_NONE, 2, + G_TYPE_STRING, + G_TYPE_POINTER); + + + client_signals[COMMIT_STRING] = + g_signal_new (I_("commit-string"), + G_TYPE_FROM_CLASS (gobject_class), + G_SIGNAL_RUN_FIRST, + G_STRUCT_OFFSET (IBusIMClientClass, commit_string), + NULL, NULL, + ibus_marshal_VOID__STRING_STRING, + G_TYPE_NONE, 2, + G_TYPE_STRING, + G_TYPE_STRING); + + client_signals[UPDATE_PREEDIT] = + g_signal_new (I_("update-preedit"), + G_TYPE_FROM_CLASS (gobject_class), + G_SIGNAL_RUN_FIRST, + G_STRUCT_OFFSET (IBusIMClientClass, update_preedit), + NULL, NULL, + ibus_marshal_VOID__STRING_STRING_POINTER_INT_BOOLEAN, + G_TYPE_NONE, 5, + G_TYPE_STRING, + G_TYPE_STRING, + G_TYPE_POINTER, + G_TYPE_INT, + G_TYPE_BOOLEAN + ); + + client_signals[SHOW_PREEDIT] = + g_signal_new (I_("show-preedit"), + G_TYPE_FROM_CLASS (gobject_class), + G_SIGNAL_RUN_FIRST, + G_STRUCT_OFFSET (IBusIMClientClass, show_preedit), + NULL, NULL, + ibus_marshal_VOID__STRING, + G_TYPE_NONE, 1, + G_TYPE_STRING); + + client_signals[HIDE_PREEDIT] = + g_signal_new (I_("hide-preedit"), + G_TYPE_FROM_CLASS (gobject_class), + G_SIGNAL_RUN_FIRST, + G_STRUCT_OFFSET (IBusIMClientClass, hide_preedit), + NULL, NULL, + ibus_marshal_VOID__STRING, + G_TYPE_NONE, 1, + G_TYPE_STRING); + + client_signals[ENABLED] = + g_signal_new (I_("enabled"), + G_TYPE_FROM_CLASS (gobject_class), + G_SIGNAL_RUN_FIRST, + G_STRUCT_OFFSET (IBusIMClientClass, enabled), + NULL, NULL, + ibus_marshal_VOID__STRING, + G_TYPE_NONE, 1, + G_TYPE_STRING); + + client_signals[DISABLED] = + g_signal_new (I_("disabled"), + G_TYPE_FROM_CLASS (gobject_class), + G_SIGNAL_RUN_FIRST, + G_STRUCT_OFFSET (IBusIMClientClass, disabled), + NULL, NULL, + ibus_marshal_VOID__STRING, + G_TYPE_NONE, 1, + G_TYPE_STRING); + +} + +/* + * open ibus connection + */ +static void +_ibus_im_client_ibus_open (IBusIMClient *client) +{ + gchar *ibus_addr = NULL; + DBusError error; + + IBusIMClientPrivate *priv = client->priv; + + if (priv->ibus != NULL) + return; + +#if USE_DBUS_SESSION_BUS + dbus_connection_setup_with_g_main (priv->dbus, NULL); + if (!_dbus_call_with_reply_and_block (priv->dbus, + IBUS_NAME, IBUS_PATH, IBUS_IFACE, + "GetIBusAddress", + DBUS_TYPE_INVALID, + DBUS_TYPE_STRING, &ibus_addr, + DBUS_TYPE_INVALID + )) { + g_warning ("Can not get ibus address"); + return; + } +#endif + if (ibus_addr == NULL) { + gchar *display; + gchar *hostname = ""; + gchar *displaynumber = "0"; + gchar *screennumber = "0"; + gchar *username = NULL; + gchar *p; + + display = g_strdup (g_getenv ("DISPLAY")); + if (display == NULL) { + g_warning ("DISPLAY is empty! We use default DISPLAY (:0.0)"); + } + else { + p = display; + hostname = display; + for (; *p != ':' && *p != '\0'; p++); + + if (*p == ':') { + *p = '\0'; + p++; + displaynumber = p; + } + + for (; *p != '.' && *p != '\0'; p++); + + if (*p == '.') { + *p = '\0'; + p++; + screennumber = p; + } + } + + username = g_strdup (getlogin()); + if (username == NULL) + username = g_strdup (g_getenv("LOGNAME")); + if (username == NULL) + username = g_strdup (g_getenv("USER")); + if (username == NULL) + username = g_strdup (g_getenv("LNAME")); + if (username == NULL) + username = g_strdup (g_getenv("USERNAME")); + + ibus_addr = g_strdup_printf ( + "unix:path=/tmp/ibus-%s/ibus-%s-%s.%s", + username, hostname, displaynumber, screennumber); + + g_free (display); + g_free (username); + } + + /* + * Init ibus and proxy object + */ + dbus_error_init (&error); + priv->ibus = dbus_connection_open_private (ibus_addr, &error); + g_free (ibus_addr); + if (priv->ibus == NULL) { + g_warning ("Error: %s", error.message); + dbus_error_free (&error); + return; + } + + if (!dbus_connection_add_filter (priv->ibus, + _ibus_im_client_message_filter_cb, + client, NULL)) { + g_warning ("Out of memory"); + return; + } + + dbus_connection_setup_with_g_main (priv->ibus, NULL); + + g_signal_emit (client, client_signals[CONNECTED], 0); + +} + +/* + * close ibus connection + */ +static void +_ibus_im_client_ibus_close (IBusIMClient *client) +{ + IBusIMClientPrivate *priv = client->priv; + + if (priv->ibus) { + dbus_connection_close (priv->ibus); + dbus_connection_unref (priv->ibus); + priv->ibus = NULL; + g_signal_emit (client, client_signals[DISCONNECTED], 0); + } +} + +/* + * create a ibus input context + */ +const gchar * +ibus_im_client_create_input_context (IBusIMClient *client) +{ + IBusIMClientPrivate *priv = client->priv; + + if (priv->ibus == NULL) + return NULL; + + const gchar *app_name = g_get_application_name (); + gchar *ic = NULL; + _ibus_call_with_reply_and_block (priv->ibus, "CreateInputContext", + DBUS_TYPE_STRING, &app_name, + DBUS_TYPE_INVALID, + DBUS_TYPE_STRING, &ic, + DBUS_TYPE_INVALID); + return ic; +} + +#ifdef HAVE_INOTIFY +static gboolean +_ibus_im_client_inotify_cb (GIOChannel *source, GIOCondition condition, IBusIMClient *client) +{ + struct inotify_event *p = NULL; + gchar *name; + gsize n; + + if ((condition & G_IO_IN) == 0) + return TRUE; + + p = g_malloc0 (sizeof (struct inotify_event) + 1024); + + g_io_channel_read_chars (source, (gchar *) p, sizeof (struct inotify_event), &n, NULL); + g_io_channel_read_chars (source, ((gchar *)p) + sizeof (struct inotify_event), p->len, &n, NULL); + + name = g_strdup_printf ("ibus-%s", g_getenv ("DISPLAY")); + for (n = 0; name[n] != 0; n++) { + if (name[n] != ':') + continue; + name[n] = '-'; + break; + } + + if (g_strcmp0 (p->name, name) == 0) { + if (p->mask & IN_CREATE) { + g_usleep (1000); + _ibus_im_client_ibus_open (client); + } + } + g_free (name); + g_free (p); + + return TRUE; +} +#endif + +static void +ibus_im_client_init (IBusIMClient *obj) +{ + DEBUG_FUNCTION_IN; + + IBusIMClient *client = IBUS_IM_CLIENT (obj); + IBusIMClientPrivate *priv; + + gchar *watch_path; + struct stat stat_buf; + +#ifdef HAVE_INOTIFY + gint inotify_fd = inotify_init (); +#endif + + priv = G_TYPE_INSTANCE_GET_PRIVATE (client, IBUS_TYPE_IM_CLIENT, IBusIMClientPrivate); + client->priv = priv; + + watch_path = g_strdup_printf ("/tmp/ibus-%s", g_get_user_name ()); + + if (g_stat (watch_path, &stat_buf) != 0) { + g_mkdir (watch_path, 0750); + } + +#ifdef HAVE_INOTIFY + /* init inotify */ + priv->inotify_wd = inotify_add_watch (inotify_fd, watch_path, IN_CREATE | IN_DELETE); + priv->inotify_channel = g_io_channel_unix_new (inotify_fd); + g_io_channel_set_close_on_unref (priv->inotify_channel, TRUE); + priv->inotify_source = g_io_add_watch (priv->inotify_channel, + G_IO_IN, + (GIOFunc)_ibus_im_client_inotify_cb, + (gpointer)client); +#endif + g_free (watch_path); + +#if USE_DBUS_SESSION_BUS + /* + * Init dbus + */ + dbus_error_init (&error); + priv->dbus = dbus_bus_get (DBUS_BUS_SESSION, &error); + if (priv->dbus == NULL) { + g_warning ("Error: %s", error.message); + dbus_error_free (&error); + return; + } +#endif + + _ibus_im_client_ibus_open (client); + +#if USE_DBUS_SESSION_BUS + if (!dbus_connection_add_filter (priv->dbus, + _ibus_im_client_message_filter_cb, + client, NULL)) { + g_warning ("Out of memory"); + return; + } + + gchar *rule = + "type='signal'," + "sender='" DBUS_SERVICE_DBUS "'," + "interface='" DBUS_INTERFACE_DBUS "'," + "member='NameOwnerChanged'," + "path='" DBUS_PATH_DBUS "'," + "arg0='" IBUS_NAME "'"; + + if (!_dbus_call_with_reply_and_block (priv->dbus, + DBUS_SERVICE_DBUS, DBUS_PATH_DBUS, DBUS_INTERFACE_DBUS, + "AddMatch", + DBUS_TYPE_STRING, &rule, + DBUS_TYPE_INVALID, + DBUS_TYPE_INVALID + )) { + g_warning ("Can not get ibus address"); + return; + } +#endif +#if 0 + /* get dbus proxy */ + priv->dbus = dbus_g_proxy_new_for_name (priv->ibus, + DBUS_SERVICE_DBUS, + DBUS_PATH_DBUS, + DBUS_INTERFACE_DBUS); + g_assert (priv->dbus != NULL); + + /* connect NameOwnerChanged signal */ + dbus_g_proxy_add_signal (priv->dbus, "NameOwnerChanged", + G_TYPE_STRING, + G_TYPE_STRING, + G_TYPE_STRING, + G_TYPE_INVALID); + + dbus_g_proxy_connect_signal (priv->dbus, "NameOwnerChanged", + G_CALLBACK (_dbus_name_owner_changed_cb), + (gpointer)client, NULL); + dbus_bus_add_match ((DBusConnection *)dbus_g_connection_get_connection (priv->ibus), + "type='signal'," + "sender='" DBUS_SERVICE_DBUS + "',interface='" DBUS_INTERFACE_DBUS + "',path='" DBUS_PATH_DBUS + "',member='NameOwnerChanged'," + "arg0='" IBUS_DBUS_SERVICE "'", + &dbus_error); + + _ibus_im_client_reinit_imm (client); +#endif + +} + + +static void +ibus_im_client_finalize (GObject *obj) +{ + DEBUG_FUNCTION_IN; + + IBusIMClient *client = IBUS_IM_CLIENT (obj); + IBusIMClientPrivate *priv = client->priv; + + g_assert (client == _client); + +#ifdef HAVE_INOTIFY + g_source_remove (priv->inotify_source); + g_io_channel_unref (priv->inotify_channel); +#endif + +#if USE_DBUS_SESSION_BUS + if (priv->dbus) { + dbus_connection_unref (priv->dbus); + } +#endif + _ibus_im_client_ibus_close (client); + + G_OBJECT_CLASS(parent_class)->finalize (obj); + + _client = NULL; +} + +static void +_ibus_signal_commit_string_handler (DBusConnection *connection, DBusMessage *message, IBusIMClient *client) +{ + /* Handle CommitString signal */ + DBusError error = {0}; + gchar *ic = NULL; + gchar *string = NULL; + + if (!dbus_message_get_args (message, &error, + DBUS_TYPE_STRING, &ic, + DBUS_TYPE_STRING, &string, + DBUS_TYPE_INVALID)) { + g_warning ("%s", error.message); + dbus_error_free (&error); + } + else { + g_signal_emit (client, client_signals[COMMIT_STRING], 0, ic, string); + } +} + +static void +_ibus_signal_update_preedit_handler (DBusConnection *connection, DBusMessage *message, IBusIMClient *client) +{ + /* Handle UpdatePreedit signal */ + DBusMessageIter iter, sub_iter; + int type, sub_type; + + gchar *ic = NULL; + gchar *string = NULL; + PangoAttrList *attrs = NULL; + int cursor = 0; + gboolean visible = False; + + if (!dbus_message_iter_init (message, &iter)) { + g_warning ("The UpdatePreedit signal does have args!"); + return; + } + + type = dbus_message_iter_get_arg_type (&iter); + if (type != DBUS_TYPE_STRING) { + g_warning ("The 1st argument of UpdatePreedit signal must be a String"); + return; + } + dbus_message_iter_get_basic (&iter, &ic); + dbus_message_iter_next (&iter); + + type = dbus_message_iter_get_arg_type (&iter); + if (type != DBUS_TYPE_STRING) { + g_warning ("The 2nd argument of UpdatePreedit signal must be a String"); + return; + } + dbus_message_iter_get_basic (&iter, &string); + dbus_message_iter_next (&iter); + + + type = dbus_message_iter_get_arg_type (&iter); + if (type != DBUS_TYPE_ARRAY) { + g_warning ("The 3rd argument of UpdatePreedit signal must be a Struct Array"); + return; + } + + dbus_message_iter_recurse (&iter, &sub_iter); + + if (dbus_message_iter_get_arg_type (&sub_iter) != DBUS_TYPE_INVALID) { + if (dbus_message_iter_get_arg_type (&sub_iter) != DBUS_TYPE_ARRAY || + dbus_message_iter_get_element_type (&sub_iter) != DBUS_TYPE_UINT32 ) { + g_warning ("The 3rd argument of UpdatePreedit signal must be a Struct Array"); + return; + } + + attrs = pango_attr_list_new (); + + while ((sub_type = dbus_message_iter_get_arg_type (&sub_iter) != DBUS_TYPE_INVALID)) { + PangoAttribute *attr; + DBusMessageIter sub_sub_iter; + guint *values = NULL; + gint length = 0; + dbus_message_iter_recurse (&sub_iter, &sub_sub_iter); + dbus_message_iter_get_fixed_array (&sub_sub_iter, &values, &length); + + if (length <= 0) { + g_warning ("The element of the 3rd argument of UpdatePreedit should not be a empty array"); + continue; + } + + switch (values[0]) { + case 1: /* Underline */ + attr = pango_attr_underline_new (values[1]); + attr->start_index = g_utf8_offset_to_pointer (string, values[2]) - string; + attr->end_index = g_utf8_offset_to_pointer (string, values[3]) - string; + pango_attr_list_insert (attrs, attr); + break; + + case 2: /* Foreground Color */ + attr = pango_attr_foreground_new ( + (values[1] & 0xff0000) >> 8, + (values[1] & 0x00ff00), + (values[1] & 0x0000ff) << 8 + ); + attr->start_index = g_utf8_offset_to_pointer (string, values[2]) - string; + attr->end_index = g_utf8_offset_to_pointer (string, values[3]) - string; + pango_attr_list_insert (attrs, attr); + break; + case 3: /* Background Color */ + attr = pango_attr_background_new ( + (values[1] & 0xff0000) >> 8, + (values[1] & 0x00ff00), + (values[1] & 0x0000ff) << 8 + ); + attr->start_index = g_utf8_offset_to_pointer (string, values[2]) - string; + attr->end_index = g_utf8_offset_to_pointer (string, values[3]) - string; + pango_attr_list_insert (attrs, attr); + break; + default: + g_warning ("Unkown type attribute type = %d", values[0]); + + } + + dbus_message_iter_next (&sub_iter); + + } + } + dbus_message_iter_next (&iter); + + type = dbus_message_iter_get_arg_type (&iter); + if (type != DBUS_TYPE_INT32) { + g_warning ("The 4th argument of UpdatePreedit signal must be an Int32 %c", type); + pango_attr_list_unref (attrs); + return; + } + dbus_message_iter_get_basic (&iter, &cursor); + dbus_message_iter_next (&iter); + + type = dbus_message_iter_get_arg_type (&iter); + if (type != DBUS_TYPE_BOOLEAN) { + g_warning ("The 4th argument of UpdatePreedit signal must be an Int32 %c", type); + pango_attr_list_unref (attrs); + return; + } + dbus_message_iter_get_basic (&iter, &visible); + dbus_message_iter_next (&iter); + + { + g_signal_emit (client, client_signals[UPDATE_PREEDIT], 0, + ic, string, attrs, cursor, visible); + } + pango_attr_list_unref (attrs); + +} + +static void +_ibus_signal_show_preedit_handler (DBusConnection *connection, DBusMessage *message, IBusIMClient *client) +{ + /* Handle CommitString signal */ + DBusError error = {0}; + gchar *ic = NULL; + + if (!dbus_message_get_args (message, &error, + DBUS_TYPE_STRING, &ic, + DBUS_TYPE_INVALID)) { + g_warning ("%s", error.message); + dbus_error_free (&error); + } + else { + g_signal_emit (client, client_signals[SHOW_PREEDIT], 0, ic); + } +} + +static void +_ibus_signal_hide_preedit_handler (DBusConnection *connection, DBusMessage *message, IBusIMClient *client) +{ + /* Handle CommitString signal */ + DBusError error = {0}; + gchar *ic = NULL; + + if (!dbus_message_get_args (message, &error, + DBUS_TYPE_STRING, &ic, + DBUS_TYPE_INVALID)) { + g_warning ("%s", error.message); + dbus_error_free (&error); + } + else { + g_signal_emit (client, client_signals[HIDE_PREEDIT], 0, ic); + } +} + +#ifdef USE_DBUS_SESSION_BUS +static void +_ibus_signal_name_owner_changed_handler (DBusConnection *connection, DBusMessage *message, IBusIMClient *client) +{ + gchar *name = NULL; + gchar *old_name = NULL; + gchar *new_name = NULL; + DBusError error = {0}; + + if (!dbus_message_get_args (message, &error, + DBUS_TYPE_STRING, &name, + DBUS_TYPE_STRING, &old_name, + DBUS_TYPE_STRING, &new_name, + DBUS_TYPE_INVALID)) { + g_warning ("%s", error.message); + dbus_error_free (&error); + } + + g_return_if_fail (strcmp (name, IBUS_NAME) == 0); + + if (g_strcmp0 (new_name, "") == 0) { + _ibus_im_client_ibus_close (client); + priv->enable = FALSE; + } + else { + _ibus_im_client_ibus_open (client); + priv->enable = TRUE; + } +} +#endif + +static void +_ibus_signal_disconnected_handler (DBusConnection *connection, DBusMessage *message, IBusIMClient *client) +{ + _ibus_im_client_ibus_close (client); +} + +static void +_ibus_signal_enabled_handler (DBusConnection *connection, DBusMessage *message, IBusIMClient *client) +{ + DEBUG_FUNCTION_IN; + /* Handle CommitString signal */ + DBusError error = {0}; + gchar *ic = NULL; + + if (!dbus_message_get_args (message, &error, + DBUS_TYPE_STRING, &ic, + DBUS_TYPE_INVALID)) { + g_warning ("%s", error.message); + dbus_error_free (&error); + } + else { + g_signal_emit (client, client_signals[ENABLED], 0, ic); + } +} + + +static void +_ibus_signal_disabled_handler (DBusConnection *connection, DBusMessage *message, IBusIMClient *client) +{ + DEBUG_FUNCTION_IN; + /* Handle CommitString signal */ + DBusError error = {0}; + gchar *ic = NULL; + + if (!dbus_message_get_args (message, &error, + DBUS_TYPE_STRING, &ic, + DBUS_TYPE_INVALID)) { + g_warning ("%s", error.message); + dbus_error_free (&error); + } + else { + g_signal_emit (client, client_signals[DISABLED], 0, ic); + } +} + + +static DBusHandlerResult +_ibus_im_client_message_filter_cb (DBusConnection *connection, DBusMessage *message, void *user_data) +{ + IBusIMClient *client = (IBusIMClient *) user_data; + + static struct SIGNAL_HANDLER { + const gchar *iface; + const gchar *name; + void (* handler) (DBusConnection *, DBusMessage *, IBusIMClient *); + } handlers[] = { +#ifdef USE_DBUS_SESSION_BUS + { DBUS_INTERFACE_DBUS, "NameOwnerChanged", _ibus_signal_name_owner_changed_handler }, +#endif + { DBUS_INTERFACE_LOCAL, "Disconnected", _ibus_signal_disconnected_handler }, + { IBUS_IFACE, "CommitString", _ibus_signal_commit_string_handler }, + { IBUS_IFACE, "UpdatePreedit", _ibus_signal_update_preedit_handler }, + { IBUS_IFACE, "ShowPreedit", _ibus_signal_show_preedit_handler }, + { IBUS_IFACE, "HidePreedit", _ibus_signal_hide_preedit_handler }, + { IBUS_IFACE, "Enabled", _ibus_signal_enabled_handler }, + { IBUS_IFACE, "Disabled", _ibus_signal_disabled_handler }, + {0}, + }; + + gint i; + for (i = 0; handlers[i].iface != NULL; i++) { + if (dbus_message_is_signal (message, handlers[i].iface, handlers[i].name)) { + handlers[i].handler (connection, message, client); + return DBUS_HANDLER_RESULT_HANDLED; + } + } + g_debug ("Unknown message %s", dbus_message_get_member (message)); + return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; +} + +inline static gboolean +_dbus_call_with_reply_and_block_valist (DBusConnection *connection, + const gchar *dest, const gchar *path, const gchar* iface, const char *method, + int first_arg_type, va_list args) +{ + + DBusMessage *message, *reply; + DBusError error = {0}; + int type; + va_list tmp; + + if (connection == NULL) + return FALSE; + + message = dbus_message_new_method_call (dest, + path, iface, method); + if (!message) { + g_warning ("Out of memory!"); + return FALSE; + } + + va_copy (tmp, args); + if (!dbus_message_append_args_valist (message, first_arg_type, tmp)) { + dbus_message_unref (message); + g_warning ("Can not create call message"); + return FALSE; + } + + reply = dbus_connection_send_with_reply_and_block (connection, + message, -1, &error); + + dbus_message_unref (message); + + if (!reply) { + g_warning ("%s", error.message); + dbus_error_free (&error); + return FALSE; + } + + type = first_arg_type; + while (type != DBUS_TYPE_INVALID) { + if (type == DBUS_TYPE_ARRAY) { + va_arg (args, int); + va_arg (args, void *); + va_arg (args, int); + } + else { + va_arg (args, void *); + } + type = va_arg (args, int); + } + + type = va_arg (args, int); + if (!dbus_message_get_args_valist (reply, &error, type, args)) { + g_warning ("%s", error.message); + dbus_error_free (&error); + dbus_message_unref (reply); + return FALSE; + } + dbus_message_unref (reply); + + return TRUE; + +} + +inline static gboolean +_dbus_call_with_reply_and_block (DBusConnection *connection, + const gchar *dest, const gchar *path, const gchar* iface, const char *method, + gint first_arg_type, ...) +{ + va_list args; + gboolean retval; + + if (connection == NULL) + return FALSE; + + va_start (args, first_arg_type); + retval = _dbus_call_with_reply_and_block_valist (connection, + dest, path, iface, method, first_arg_type, args); + va_end (args); + + return TRUE; + +} + +static gboolean +_ibus_call_with_reply_and_block (DBusConnection *connection, const gchar *method, int first_arg_type, ...) +{ + va_list args; + gboolean retval; + + if (connection == NULL) + return FALSE; + + va_start (args, first_arg_type); + retval = _dbus_call_with_reply_and_block_valist (connection, + IBUS_NAME, IBUS_PATH, IBUS_IFACE, method, first_arg_type, args); + va_end (args); + + return retval; + +} + + +inline static gboolean +_dbus_call_with_reply_valist (DBusConnection *connection, + const gchar *dest, const gchar *path, const gchar* iface, const char *method, + DBusPendingCallNotifyFunction notify_function, + void *user_data, DBusFreeFunction free_function, + gint first_arg_type, va_list args) +{ + DBusMessage *message = NULL; + DBusPendingCall *pendingcall = NULL; + + if (connection == NULL) { + goto error; + } + + message = dbus_message_new_method_call (dest, + path, iface, method); + if (!message) { + g_warning ("Out of memory!"); + goto error; + } + + if (!dbus_message_append_args_valist (message, first_arg_type, args)) { + g_warning ("Can not create call message"); + goto error; + } + + if (!dbus_connection_send_with_reply (connection, + message, &pendingcall, -1)) { + g_warning ("Out of memory!"); + goto error; + } + + if (!dbus_pending_call_set_notify (pendingcall, notify_function, + user_data, free_function)) { + g_warning ("Out of memory!"); + goto error; + } + + dbus_message_unref (message); + return TRUE; + +error: + if (message) + dbus_message_unref (message); + if (pendingcall) + dbus_pending_call_cancel (pendingcall); + if (user_data && free_function) + free_function (user_data); + return False; +} + +inline static gboolean +_dbus_call_with_reply (DBusConnection *connection, + const gchar *dest, const gchar *path, const gchar* iface, const char *method, + DBusPendingCallNotifyFunction notify_function, + void *user_data, DBusFreeFunction free_function, + gint first_arg_type, ...) +{ + va_list args; + gboolean retval; + + if (connection == NULL) + return FALSE; + + va_start (args, first_arg_type); + retval = _dbus_call_with_reply_valist (connection, + dest, path, iface, method, + notify_function, + user_data, free_function, + first_arg_type, args); + va_end (args); + + return TRUE; + +} + + + +static gboolean +_ibus_call_with_reply (DBusConnection *connection, const gchar *method, + DBusPendingCallNotifyFunction notify_function, + void *user_data, DBusFreeFunction free_function, + int first_arg_type, ...) +{ + va_list args; + gboolean retval; + + if (connection == NULL) + return FALSE; + + va_start (args, first_arg_type); + retval = _dbus_call_with_reply_valist (connection, + IBUS_NAME, IBUS_PATH, IBUS_IFACE, + method, notify_function, + user_data, free_function, + first_arg_type, args); + va_end (args); + + return retval; +} + +typedef struct { + IBusIMClient *client; + gchar *ic; + GdkEvent event; +}KeyPressCallData; + +static KeyPressCallData * +_key_press_call_data_new (IBusIMClient *client, const gchar *ic, GdkEvent *event) +{ + KeyPressCallData *p = g_new (KeyPressCallData, 1); + p->client = g_object_ref (client); + p->ic = g_strdup (ic); + p->event = *event; + return p; +} + +static void +_key_press_call_data_free (KeyPressCallData *p) +{ + if (p) { + g_object_unref (p->client); + g_free (p->ic); + } + g_free (p); +} + +static void +_ibus_filter_keypress_reply_cb (DBusPendingCall *pending, void *user_data) +{ + DBusMessage *reply; + DBusError error = {0}; + KeyPressCallData *call_data = (KeyPressCallData *) user_data; + gboolean retval; + + + reply = dbus_pending_call_steal_reply (pending); + dbus_pending_call_unref (pending); + + if (dbus_set_error_from_message (&error, reply)) { + g_warning ("%s", error.message); + dbus_error_free (&error); + retval = FALSE; + } + else { + if (!dbus_message_get_args (reply, &error, + DBUS_TYPE_BOOLEAN, &retval, DBUS_TYPE_INVALID)) { + g_warning ("%s", error.message); + dbus_error_free (&error); + retval = FALSE; + } + } + + if (!retval) { + g_signal_emit (call_data->client, client_signals[FORWARD_EVENT], 0, + call_data->ic, &(call_data->event)); + } +} + +gboolean +ibus_im_client_filter_keypress (IBusIMClient *client, const gchar *ic, GdkEventKey *event) +{ + g_return_val_if_fail (IBUS_IS_IM_CLIENT(client), FALSE); + g_return_val_if_fail (ic != NULL, FALSE); + g_return_val_if_fail (event != NULL, FALSE); + + IBusIMClientPrivate *priv = client->priv; + + guint state = event->state & GDK_MODIFIER_MASK; + gboolean is_press = event->type == GDK_KEY_PRESS; + + if (event->send_event) { + return FALSE; + } + + /* Call IBus ProcessKeyEvent method */ + if (!_ibus_call_with_reply (priv->ibus, + "ProcessKeyEvent", + _ibus_filter_keypress_reply_cb, + _key_press_call_data_new (client, ic, (GdkEvent *)event), + (DBusFreeFunction)_key_press_call_data_free, + DBUS_TYPE_STRING, &ic, + DBUS_TYPE_UINT32, &event->keyval, + DBUS_TYPE_BOOLEAN, &is_press, + DBUS_TYPE_UINT32, &state, + DBUS_TYPE_INVALID)) + return FALSE; + + return TRUE; +} + + +void +ibus_im_client_focus_in (IBusIMClient *client, const gchar *ic) +{ + g_return_if_fail (IBUS_IS_IM_CLIENT(client)); + g_return_if_fail (ic != NULL); + + IBusIMClientPrivate *priv = client->priv; + + /* Call IBus FocusIn method */ + _ibus_call_with_reply_and_block (priv->ibus, + "FocusIn", + DBUS_TYPE_STRING, &ic, + DBUS_TYPE_INVALID, + DBUS_TYPE_INVALID); +} + +void +ibus_im_client_focus_out (IBusIMClient *client, const gchar *ic) +{ + g_return_if_fail (IBUS_IS_IM_CLIENT(client)); + g_return_if_fail (ic != NULL); + + IBusIMClientPrivate *priv = client->priv; + + /* Call IBus FocusOut method */ + _ibus_call_with_reply_and_block (priv->ibus, + "FocusOut", + DBUS_TYPE_STRING, &ic, + DBUS_TYPE_INVALID, + DBUS_TYPE_INVALID); + +} + +void +ibus_im_client_reset (IBusIMClient *client, const gchar *ic) +{ + g_return_if_fail (IBUS_IS_IM_CLIENT(client)); + g_return_if_fail (ic != NULL); + + IBusIMClientPrivate *priv = client->priv; + + /* Call IBus Reset method */ + _ibus_call_with_reply_and_block (priv->ibus, + "Reset", + DBUS_TYPE_STRING, &ic, + DBUS_TYPE_INVALID, + DBUS_TYPE_INVALID); + +} + +void +ibus_im_client_set_cursor_location (IBusIMClient *client, const gchar *ic, GdkRectangle *area) +{ + g_return_if_fail (IBUS_IS_IM_CLIENT(client)); + g_return_if_fail (ic != NULL); + g_return_if_fail (area != NULL); + + _ibus_call_with_reply_and_block (client->priv->ibus, + "SetCursorLocation", + DBUS_TYPE_STRING, &ic, + DBUS_TYPE_INT32, &area->x, + DBUS_TYPE_INT32, &area->y, + DBUS_TYPE_INT32, &area->width, + DBUS_TYPE_INT32, &area->height, + DBUS_TYPE_INVALID, + DBUS_TYPE_INVALID); +} + +void +ibus_im_client_set_use_preedit (IBusIMClient *client, const gchar *ic, gboolean use_preedit) +{ + g_return_if_fail (IBUS_IS_IM_CLIENT(client)); + g_return_if_fail (ic != NULL); + + _ibus_call_with_reply_and_block (client->priv->ibus, + "SetCapabilities", + DBUS_TYPE_STRING, &ic, + DBUS_TYPE_INT32, &use_preedit, + DBUS_TYPE_INVALID, + DBUS_TYPE_INVALID); +} + +void +ibus_im_client_release_input_context (IBusIMClient *client, const gchar *ic) +{ + g_return_if_fail (IBUS_IS_IM_CLIENT(client)); + g_return_if_fail (ic != NULL); + + IBusIMClientPrivate *priv = client->priv; + + _ibus_call_with_reply_and_block (priv->ibus, "ReleaseInputContext", + DBUS_TYPE_STRING, &ic, + DBUS_TYPE_INVALID, + DBUS_TYPE_INVALID); + +} + +void +ibus_im_client_kill_daemon (IBusIMClient *client) +{ + IBusIMClientPrivate *priv = client->priv; + _ibus_call_with_reply_and_block (priv->ibus, "Kill", + DBUS_TYPE_INVALID, + DBUS_TYPE_INVALID); +} + + +gboolean +ibus_im_client_get_connected (IBusIMClient *client) +{ + IBusIMClientPrivate *priv = client->priv; + if (priv->ibus == NULL) + return FALSE; + return dbus_connection_get_is_connected (priv->ibus); +} diff --git a/lib/gtk2/ibusimclient.h b/lib/gtk2/ibusimclient.h new file mode 100644 index 0000000..a0e4f75 --- /dev/null +++ b/lib/gtk2/ibusimclient.h @@ -0,0 +1,125 @@ +/* vim:set et ts=4: */ +/* IBus - The Input Bus + * Copyright (C) 2008-2009 Huang Peng <shawn.p.huang@gmail.com> + * + * 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; either + * version 2 of the License, or (at your option) any later version. + * + * 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. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ +#ifndef __IBUS_IM_CLIENT_H_ +#define __IBUS_IM_CLIENT_H_ + +#include <gtk/gtk.h> +/* + * Type macros. + */ + +/* define GOBJECT macros */ +#define IBUS_TYPE_IM_CLIENT \ + (ibus_im_client_get_type ()) +#define IBUS_IM_CLIENT(obj) \ + (GTK_CHECK_CAST ((obj), IBUS_TYPE_IM_CLIENT, IBusIMClient)) +#define IBUS_IM_CLIENT_CLASS(klass) \ + (GTK_CHECK_CLASS_CAST ((klass), IBUS_TYPE_IM_CLIENT, IBusIMClientClass)) +#define IBUS_IS_IM_CLIENT(obj) \ + (GTK_CHECK_TYPE ((obj), IBUS_TYPE_IM_CLIENT)) +#define IBUS_IS_IM_CLIENT_CLASS(klass) \ + (GTK_CHECK_CLASS_TYPE ((klass), IBUS_TYPE_IM_CLIENT)) +#define IBUS_IM_CLIENT_GET_CLASS(obj) \ + (GTK_CHECK_GET_CLASS ((obj), IBUS_TYPE_IM_CLIENT, IBusIMClientClass)) + +#if 0 +#define DEBUG_FUNCTION_IN g_debug("%s IN", __FUNCTION__); +#define DEBUG_FUNCTION_OUT g_debug("%s OUT", __FUNCTION__); +#else +#define DEBUG_FUNCTION_IN +#define DEBUG_FUNCTION_OUT +#endif + + + +#define IBUS_DBUS_SERVICE "org.freedesktop.ibus" +#define IBUS_DBUS_INTERFACE "org.freedesktop.ibus.Manager" +#define IBUS_DBUS_PATH "/org/freedesktop/ibus/Manager" + +G_BEGIN_DECLS +typedef struct _IBusIMClient IBusIMClient; +typedef struct _IBusIMClientClass IBusIMClientClass; +typedef struct _IBusIMClientPrivate IBusIMClientPrivate; + +struct _IBusIMClient { + GtkObject parent; + /* instance members */ + IBusIMClientPrivate *priv; +}; + +struct _IBusIMClientClass { + GtkObjectClass parent; + /* class members */ + void (* connected) (IBusIMClient *client); + void (* disconnected) (IBusIMClient *client); + void (* commit_string) (IBusIMClient *client, + const gchar *ic, + const gchar *text); + void (* update_preedit) (IBusIMClient *client, + const gchar *ic, + const gchar *text, + gpointer *attrs, + gint cursor_pos, + gboolean visible); + void (* show_preedit) (IBusIMClient *client, + const gchar *ic); + void (* hide_preedit) (IBusIMClient *client, + const gchar *ic); + void (* enabled) (IBusIMClient *client, + const gchar *ic); + void (* disabled) (IBusIMClient *client, + const gchar *ic); +}; + +extern IBusIMClient *_client; + +GType ibus_im_client_get_type (void); +void ibus_im_client_register_type (GTypeModule *type_module); +IBusIMClient *ibus_im_client_new (void); +const gchar *ibus_im_client_create_input_context + (IBusIMClient *client); +void ibus_im_client_shutdown (void); +void ibus_im_client_focus_in (IBusIMClient *client, + const gchar *ic); +void ibus_im_client_focus_out (IBusIMClient *client, + const gchar *ic); +void ibus_im_client_reset (IBusIMClient *client, + const gchar *ic); +gboolean ibus_im_client_filter_keypress (IBusIMClient *client, + const gchar *ic, + GdkEventKey *key); +void ibus_im_client_set_cursor_location + (IBusIMClient *client, + const gchar *ic, + GdkRectangle *area); +void ibus_im_client_set_use_preedit (IBusIMClient *client, + const gchar *ic, + gboolean use_preedit); +gboolean ibus_im_client_is_enabled (IBusIMClient *client); +void ibus_im_client_release_input_context + (IBusIMClient *client, + const gchar *ic); +void ibus_im_client_kill_daemon (IBusIMClient *client); +gboolean ibus_im_client_get_connected (IBusIMClient *client); + + +G_END_DECLS +#endif + diff --git a/lib/gtk2/ibusmarshalers.list b/lib/gtk2/ibusmarshalers.list new file mode 100644 index 0000000..89c4f76 --- /dev/null +++ b/lib/gtk2/ibusmarshalers.list @@ -0,0 +1,5 @@ +NONE:NONE +NONE:STRING +NONE:STRING,STRING +NONE:STRING,POINTER +NONE:STRING,STRING,POINTER,INT,BOOL |