Input method menu patch

Yukihiro Nakai <[email protected]> Thu, 11 Mar 2004 19:41:58 +0900
Newsgroups gmane.comp.graphics.sodipodi
Organization Red Hat North Asia
Message-ID <[email protected]>
Hi,

Users can change input methods (GTK+ immodules) with the right click menu in the normal
GTK+ editable widgets, and this feature is very useful when you want to switch to another
input method or input other languages on an application.

The attached patch brings you a happy switching of input methods.
I've put a screenshot:
http://bonobo.gnome.gr.jp/~nakai/tmp/immenu.png

Thank you.
--
Nakai
sodipodi-CVS-immenu.diff (application/octet-stream, 9.2 KB)
Index: ChangeLog
===================================================================
RCS file: /cvs/gnome/sodipodi/ChangeLog,v
retrieving revision 1.753
diff -u -r1.753 ChangeLog
--- ChangeLog	29 Feb 2004 18:10:19 -0000	1.753
+++ ChangeLog	11 Mar 2004 10:28:18 -0000
@@ -1,3 +1,9 @@
+2004-03-11  Yukihiro Nakai  <[email protected]>
+
+	* src/desktop.h,src/desktop.c,src/interface.c,src/text-context.h,
+	src/text-context.c: Move GtkIMContext to desktop.h to add
+	input method menus to right click menu.
+
 2004-02-29  Lauris Kaplinski  <[email protected]>
 
 	* src/sp-item.c (sp_item_set): Parse visibility
Index: src/desktop.c
===================================================================
RCS file: /cvs/gnome/sodipodi/src/desktop.c,v
retrieving revision 1.124
diff -u -r1.124 desktop.c
--- src/desktop.c	29 Feb 2004 18:10:20 -0000	1.124
+++ src/desktop.c	11 Mar 2004 10:28:18 -0000
@@ -180,6 +180,7 @@
 	nr_matrix_d_set_scale (NR_MATRIX_D_FROM_DOUBLE (desktop->doc2dt), 0.8, -0.8);
 
 	desktop->guides_active = FALSE;
+	desktop->imc = gtk_im_multicontext_new();
 }
 
 static void
@@ -210,6 +211,8 @@
 		dt->selection = NULL;
 	}
 
+	g_object_unref (dt->imc);
+
 	G_OBJECT_CLASS (parent_class)->dispose (object);
 }
 
Index: src/desktop.h
===================================================================
RCS file: /cvs/gnome/sodipodi/src/desktop.h,v
retrieving revision 1.50
diff -u -r1.50 desktop.h
--- src/desktop.h	29 Feb 2004 18:10:21 -0000	1.50
+++ src/desktop.h	11 Mar 2004 10:28:18 -0000
@@ -28,6 +28,7 @@
 #include "helper/units.h"
 #include "forward.h"
 #include "view.h"
+#include <gtk/gtkimcontext.h>
 
 struct _SPDesktop {
 	SPView view;
@@ -62,6 +63,9 @@
 	gdouble guidesnap;
 	/* fixme: This has to be implemented in different way */
 	guint guides_active : 1;
+
+	/* Input Methods */
+	GtkIMContext *imc;
 };
 
 struct _SPDesktopClass {
Index: src/interface.c
===================================================================
RCS file: /cvs/gnome/sodipodi/src/interface.c,v
retrieving revision 1.75
diff -u -r1.75 interface.c
--- src/interface.c	29 Feb 2004 18:10:21 -0000	1.75
+++ src/interface.c	11 Mar 2004 10:28:19 -0000
@@ -482,6 +482,15 @@
 	sp_ui_menu_append (menu, verbs, FALSE);
 }
 
+static void
+sp_ui_inputmethod_menu (GtkMenu *menu, SPDocument *doc)
+{
+	static const unsigned int verbs[] = {
+		SP_VERB_LAST
+	};
+	sp_ui_menu_append (menu, verbs, FALSE);
+}
+
 /* Menus */
 
 static void
@@ -617,6 +626,13 @@
 	sp_ui_dialog_menu (GTK_MENU (sm), NULL);
 	gtk_widget_show (sm);
 	gtk_menu_item_set_submenu (GTK_MENU_ITEM (i), sm);
+	/* Input Methods */
+	i = sp_ui_menu_append_item (GTK_MENU (m), NULL, _("Input Methods"), NULL, NULL);
+	sm = gtk_menu_new ();
+	gtk_im_multicontext_append_menuitems (GTK_IM_MULTICONTEXT (dt->imc),
+					     GTK_MENU_SHELL (sm));
+	gtk_widget_show (sm);
+	gtk_menu_item_set_submenu (GTK_MENU_ITEM (i), sm);
 	/* Modules submenu */
 	sm = sp_modules_menu_new ();
 	if (sm) {
Index: src/text-context.c
===================================================================
RCS file: /cvs/gnome/sodipodi/src/text-context.c,v
retrieving revision 1.60
diff -u -r1.60 text-context.c
--- src/text-context.c	16 Feb 2004 17:08:23 -0000	1.60
+++ src/text-context.c	11 Mar 2004 10:28:19 -0000
@@ -113,8 +113,6 @@
 	ec->hot_x = 0;
 	ec->hot_y = 0;
 
-	tc->imc = NULL;
-
 	tc->text = NULL;
 	tc->pdoc.x = 0.0;
 	tc->pdoc.y = 0.0;
@@ -128,6 +126,8 @@
 	tc->show = FALSE;
 	tc->phase = 0;
 
+	tc->sigid_commit = 0;
+	tc->sigid_preedit = 0;
 	tc->preedit_string = NULL;
 }
 
@@ -160,19 +160,20 @@
 
 	tc->timeout = gtk_timeout_add (250, (GtkFunction) sp_text_context_timeout, ec);
 
-	tc->imc = gtk_im_multicontext_new();
-	if (tc->imc) {
+	gtk_im_context_reset (desktop->imc);
+
+	if (desktop->imc) {
 		GtkWidget *canvas;
 
 		canvas = GTK_WIDGET (SP_DT_CANVAS (desktop));
 
-		gtk_im_context_set_use_preedit (tc->imc, TRUE);
-		gtk_im_context_set_client_window (tc->imc, canvas->window);
+		gtk_im_context_set_use_preedit (desktop->imc, TRUE);
+		gtk_im_context_set_client_window (desktop->imc, canvas->window);
 
 		g_signal_connect (G_OBJECT (canvas), "focus_in_event", G_CALLBACK (sptc_focus_in), tc);
 		g_signal_connect (G_OBJECT (canvas), "focus_out_event", G_CALLBACK (sptc_focus_out), tc);
-		g_signal_connect (G_OBJECT (tc->imc), "commit", G_CALLBACK (sptc_commit), tc);
-		g_signal_connect (G_OBJECT (tc->imc), "preedit_changed", G_CALLBACK (sptc_preedit_changed), tc);
+		tc->sigid_commit = g_signal_connect (G_OBJECT (desktop->imc), "commit", G_CALLBACK (sptc_commit), tc);
+		tc->sigid_preedit = g_signal_connect (G_OBJECT (desktop->imc), "preedit_changed", G_CALLBACK (sptc_preedit_changed), tc);
 
 		if (GTK_WIDGET_HAS_FOCUS (canvas)) {
 			sptc_focus_in (canvas, NULL, tc);
@@ -193,15 +194,23 @@
 sp_text_context_finish (SPEventContext *ec)
 {
 	SPTextContext *tc;
+	SPDesktop *desktop;
+
 	tc = SP_TEXT_CONTEXT (ec);
+	desktop = ec->desktop;
 
 	sp_text_context_forget_text (SP_TEXT_CONTEXT (ec));
 
-	if (tc->imc) {
-		g_object_unref (G_OBJECT (tc->imc));
-		tc->imc = NULL;
+	if( tc->sigid_commit > 0 ) {
+		g_signal_handler_disconnect (desktop->imc, tc->sigid_commit);
+		tc->sigid_commit = 0;
+	}
+
+	if( tc->sigid_preedit > 0 ) {
+		g_signal_handler_disconnect (desktop->imc, tc->sigid_preedit);
+		tc->sigid_preedit = 0;
 	}
-	
+
 	if (tc->timeout) {
 		gtk_timeout_remove (tc->timeout);
 		tc->timeout = 0;
@@ -305,6 +314,7 @@
 {
 	SPTextContext *tc;
 	SPStyle *style;
+	SPDesktop* desktop = ec->desktop;
 
 	tc = SP_TEXT_CONTEXT (ec);
 
@@ -329,7 +339,7 @@
 		}
 		break;
 	case GDK_KEY_PRESS:
-		if (!tc->unimode && tc->imc && gtk_im_context_filter_keypress (tc->imc, (GdkEventKey*)event)) {
+		if (!tc->unimode && desktop->imc && gtk_im_context_filter_keypress (desktop->imc, (GdkEventKey*)event)) {
 			return TRUE;
 		}
 		/* fixme: This is a quick bug fix to avoid to enter infinite loop
@@ -338,7 +348,7 @@
 		 * gtk_im_context_filter_keypress twice for single event.
 		 * The fundamental problem is at sp_desktop_new, it is bad idea to
 		 * connect sp_desktop_root_handler to acetate and main canvas (Oka) */
-		if (!tc->unimode && tc->imc &&
+		if (!tc->unimode && desktop->imc &&
 			((event->key.keyval == GDK_Shift_L) ||
 			 (event->key.keyval == GDK_Shift_R))) {
 			return TRUE;
@@ -364,8 +374,8 @@
 					tc->unimode = TRUE;
 					tc->unipos = 0;
 				}
-				if (tc->imc) {
-					gtk_im_context_reset (tc->imc);
+				if (desktop->imc) {
+					gtk_im_context_reset (desktop->imc);
 				}
 				return TRUE;
 			default:
@@ -452,7 +462,7 @@
 		}
 		break;
 	case GDK_KEY_RELEASE:
-		if (!tc->unimode && tc->imc && gtk_im_context_filter_keypress (tc->imc, (GdkEventKey*)event)) {
+		if (!tc->unimode && desktop->imc && gtk_im_context_filter_keypress (desktop->imc, (GdkEventKey*)event)) {
 			return TRUE;
 		}
 		break;
@@ -499,6 +509,7 @@
 sp_text_context_update_cursor (SPTextContext *tc)
 {
 	GdkRectangle im_cursor = { 0, 0, 1, 1 };
+	SPDesktop *desktop = SP_EVENT_CONTEXT (tc)->desktop;
 
 	if (tc->text) {
 		ArtPoint p0, p1, d0, d1;
@@ -525,8 +536,8 @@
 		tc->show = FALSE;
 	}
 
-	if (tc->imc) {
-		gtk_im_context_set_cursor_location (tc->imc, &im_cursor);
+	if (desktop->imc) {
+		gtk_im_context_set_cursor_location (desktop->imc, &im_cursor);
 	}
 }
 
@@ -568,14 +579,34 @@
 gint
 sptc_focus_in (GtkWidget *widget, GdkEventFocus *event, SPTextContext *tc)
 {
-	gtk_im_context_focus_in (tc->imc);
+	SPDesktop *desktop = SP_EVENT_CONTEXT (tc)->desktop;
+
+	if( tc->sigid_commit == 0 ) {
+		tc->sigid_commit = g_signal_connect (desktop->imc, "commit", G_CALLBACK(sptc_commit), tc);
+	}
+	if( tc->sigid_preedit == 0 ) {
+		tc->sigid_preedit = g_signal_connect (desktop->imc, "preedit_changed", G_CALLBACK(sptc_preedit_changed), tc);
+	}
+	gtk_im_context_focus_in (desktop->imc);
+
 	return FALSE;
 }
 
 gint
 sptc_focus_out (GtkWidget *widget, GdkEventFocus *event, SPTextContext *tc)
 {
-	gtk_im_context_focus_out (tc->imc);
+	SPDesktop *desktop = SP_EVENT_CONTEXT (tc)->desktop;
+
+	gtk_im_context_focus_out (desktop->imc);
+	if( tc->sigid_commit > 0 ) {
+		g_signal_handler_disconnect (desktop->imc, tc->sigid_commit);
+		tc->sigid_commit = 0;
+	}
+	if( tc->sigid_preedit > 0 ) {
+		g_signal_handler_disconnect (desktop->imc, tc->sigid_preedit);
+		tc->sigid_preedit = 0;
+	}
+
 	return FALSE;
 }
 
@@ -595,10 +626,11 @@
 sptc_preedit_changed (GtkIMContext *imc, SPTextContext *tc)
 {
 	gint cursor_pos;
+	SPDesktop *desktop = SP_EVENT_CONTEXT (tc)->desktop;
 
 	sp_text_context_preedit_reset (tc);
 
-	gtk_im_context_get_preedit_string (tc->imc,
+	gtk_im_context_get_preedit_string (desktop->imc,
 					   &tc->preedit_string, NULL,
 					   &cursor_pos);
 	if( tc->preedit_string != NULL ) {
Index: src/text-context.h
===================================================================
RCS file: /cvs/gnome/sodipodi/src/text-context.h,v
retrieving revision 1.18
diff -u -r1.18 text-context.h
--- src/text-context.h	17 Aug 2003 20:39:25 -0000	1.18
+++ src/text-context.h	11 Mar 2004 10:28:19 -0000
@@ -29,8 +29,6 @@
 struct _SPTextContext {
 	SPEventContext event_context;
 
-	GtkIMContext *imc;
-
 	SPItem *text;
 
 	/* Text item position in root coordinates */
@@ -48,6 +46,10 @@
 	guint show : 1;
 	guint phase : 1;
 
+	/* Signal Handlers for Input Methods */
+	gulong sigid_commit;
+	gulong sigid_preedit;
+
 	/* Preedit String */
 	gchar* preedit_string;
 };