diff -Nur gtk+-bak/gdk/win32/gdkproperty-win32.c gtk+/gdk/win32/gdkproperty-win32.c --- gtk+-bak/gdk/win32/gdkproperty-win32.c 2004-07-07 09:10:03.000000000 +0900 +++ gtk+/gdk/win32/gdkproperty-win32.c 2004-08-12 16:21:56.000000000 +0900 @@ -515,6 +515,7 @@ { "Gtk/KeyThemeName", "gtk-key-theme-name" }, { "Gtk/ToolbarStyle", "gtk-toolbar-style" }, { "Gtk/ToolbarIconSize", "gtk-toolbar-icon-size" }, + { "Gtk/IMModule", "gtk-im-module" }, { "Gtk/IMPreeditStyle", "gtk-im-preedit-style" }, { "Gtk/IMStatusStyle", "gtk-im-status-style" }, { "Net/CursorBlink", "gtk-cursor-blink" }, diff -Nur gtk+-bak/gdk/x11/gdkevents-x11.c gtk+/gdk/x11/gdkevents-x11.c --- gtk+-bak/gdk/x11/gdkevents-x11.c 2004-08-10 05:14:43.000000000 +0900 +++ gtk+/gdk/x11/gdkevents-x11.c 2004-08-12 21:08:16.000000000 +0900 @@ -2708,6 +2708,7 @@ { "Gtk/KeyThemeName", "gtk-key-theme-name" }, { "Gtk/ToolbarStyle", "gtk-toolbar-style" }, { "Gtk/ToolbarIconSize", "gtk-toolbar-icon-size" }, + { "Gtk/IMModule", "gtk-im-module" }, { "Gtk/IMPreeditStyle", "gtk-im-preedit-style" }, { "Gtk/IMStatusStyle", "gtk-im-status-style" }, { "Gtk/FileChooserBackend", "gtk-file-chooser-backend" }, diff -Nur gtk+-bak/gtk/gtkimmodule.c gtk+/gtk/gtkimmodule.c --- gtk+-bak/gtk/gtkimmodule.c 2004-08-10 01:59:52.000000000 +0900 +++ gtk+/gtk/gtkimmodule.c 2004-08-12 21:05:35.000000000 +0900 @@ -402,7 +402,7 @@ } /** - * _gtk_im_module_list: + * gtk_im_module_list: * @contexts: location to store an array of pointers to #GtkIMContextInfo * this array should be freed with g_free() when you are finished. * The structures it points are statically allocated and should @@ -412,8 +412,8 @@ * List all available types of input method context **/ void -_gtk_im_module_list (const GtkIMContextInfo ***contexts, - guint *n_contexts) +gtk_im_module_list (const GtkIMContextInfo ***contexts, + guint *n_contexts) { int n = 0; @@ -461,7 +461,7 @@ } /** - * _gtk_im_module_create: + * gtk_im_module_create: * @context_id: the context ID for the context type to create * * Create an IM context of a type specified by the string @@ -471,7 +471,7 @@ * if that could not be created, a newly created GtkIMContextSimple. **/ GtkIMContext * -_gtk_im_module_create (const gchar *context_id) +gtk_im_module_create (const gchar *context_id) { GtkIMModule *im_module; GtkIMContext *context = NULL; @@ -540,7 +540,7 @@ * the value is newly allocated and must be freed * with g_free(). **/ -const gchar * +gchar * _gtk_im_module_get_default_context_id (const gchar *locale) { GSList *tmp_list; @@ -548,16 +548,25 @@ gint best_goodness = 0; gint i; gchar *tmp_locale, *tmp; +#if 0 const gchar *envvar; +#endif if (!contexts_hash) gtk_im_module_init (); +#if 0 + /* + * 2004-08-12 Takuro Ashie + * * Moved into gtkimmulticontext.c because of priority issue between + * environmental variable and GtkSettings. + */ envvar = g_getenv ("GTK_IM_MODULE"); if (envvar && (strcmp (envvar, SIMPLE_ID) == 0 || g_hash_table_lookup (contexts_hash, envvar))) return g_strdup (envvar); +#endif /* Strip the locale code down to the essentials */ diff -Nur gtk+-bak/gtk/gtkimmodule.h gtk+/gtk/gtkimmodule.h --- gtk+-bak/gtk/gtkimmodule.h 2001-03-06 09:09:28.000000000 +0900 +++ gtk+/gtk/gtkimmodule.h 2004-08-12 16:20:31.000000000 +0900 @@ -39,10 +39,10 @@ /* Functions for use within GTK+ */ -void _gtk_im_module_list (const GtkIMContextInfo ***contexts, - guint *n_contexts); -GtkIMContext *_gtk_im_module_create (const gchar *context_id); -const gchar * _gtk_im_module_get_default_context_id (const gchar *lang); +void gtk_im_module_list (const GtkIMContextInfo ***contexts, + guint *n_contexts); +GtkIMContext *gtk_im_module_create (const gchar *context_id); +gchar *_gtk_im_module_get_default_context_id (const gchar *lang); /* The following entry points are exported by each input method module */ diff -Nur gtk+-bak/gtk/gtkimmulticontext.c gtk+/gtk/gtkimmulticontext.c --- gtk+-bak/gtk/gtkimmulticontext.c 2004-08-10 01:59:52.000000000 +0900 +++ gtk+/gtk/gtkimmulticontext.c 2004-08-12 21:06:11.000000000 +0900 @@ -17,6 +17,23 @@ * Boston, MA 02111-1307, USA. */ +/* + * 2004-08-12 Takuro Ashie + * + * Priority of determining default IM on start up is as follow: + * + * 1. GTK_IM_MODULE (environmetal variable) + * 2. gtk-im-module (GtkSettings) + * 3. gtk.immodules (setting file of Gtk+) + * 3.1 supported language matched with current locale + * 3.2 belower line in this file. + * + * GTK_IM_MODULE should be given the highest priority to override the setting + * when invoke the program from comamnd line for debug usage and so on. + * If the gtk-im-module value is changed after start up, the global IM will be + * changed regardless of the GTK_IM_MODULE value. + */ + #include #include @@ -27,6 +44,7 @@ #include "gtkimmodule.h" #include "gtkmain.h" #include "gtkradiomenuitem.h" +#include "gtkseparatormenuitem.h" #include "gtkintl.h" #include "gtkprivate.h" @@ -38,6 +56,12 @@ guint use_preedit : 1; guint have_cursor_location : 1; guint focus_in : 1; + + guint follow_global : 1; + GdkScreen *screen; + GtkSettings *settings; + + guint im_module_set; }; static void gtk_im_multicontext_class_init (GtkIMMulticontextClass *class); @@ -86,9 +110,10 @@ gint offset, gint n_chars, GtkIMMulticontext *multicontext); +static gchar *gtk_im_multicontext_get_default_context_id (GtkIMMulticontext *multicontext); static GtkIMContextClass *parent_class; -static const gchar *global_context_id = NULL; +static gchar *global_context_id = NULL; GType gtk_im_multicontext_get_type (void) @@ -138,17 +163,29 @@ im_context_class->get_surrounding = gtk_im_multicontext_get_surrounding; gobject_class->finalize = gtk_im_multicontext_finalize; + + gtk_settings_install_property (g_param_spec_string ("gtk-im-module", + P_("IM module"), + P_("The default IM module name to use."), + NULL, + G_PARAM_READWRITE)); } static void gtk_im_multicontext_init (GtkIMMulticontext *multicontext) { multicontext->slave = NULL; + multicontext->context_id = NULL; multicontext->priv = g_new0 (GtkIMMulticontextPrivate, 1); multicontext->priv->use_preedit = TRUE; multicontext->priv->have_cursor_location = FALSE; multicontext->priv->focus_in = FALSE; + + multicontext->priv->follow_global = TRUE; + multicontext->priv->screen = NULL; + multicontext->priv->settings = NULL; + multicontext->priv->im_module_set = 0; } /** @@ -170,7 +207,12 @@ GtkIMMulticontext *multicontext = GTK_IM_MULTICONTEXT (object); gtk_im_multicontext_set_slave (multicontext, NULL, TRUE); + + g_free ((gchar *) multicontext->context_id); + multicontext->context_id = NULL; + g_free (multicontext->priv); + multicontext->priv = NULL; G_OBJECT_CLASS (parent_class)->finalize (object); } @@ -255,32 +297,137 @@ GtkIMContext *slave; if (!global_context_id) - { - gchar *locale = _gtk_get_lc_ctype (); - global_context_id = _gtk_im_module_get_default_context_id (locale); - g_free (locale); - } - - slave = _gtk_im_module_create (global_context_id); + global_context_id + = gtk_im_multicontext_get_default_context_id (multicontext); + + g_free((gchar *) multicontext->context_id); + multicontext->context_id = g_strdup (global_context_id); + + slave = gtk_im_module_create (multicontext->context_id); gtk_im_multicontext_set_slave (multicontext, slave, FALSE); g_object_unref (slave); - - multicontext->context_id = global_context_id; } return multicontext->slave; } +static gboolean +validate_context_id (const gchar *context_id) +{ + const GtkIMContextInfo **contexts; + guint n_contexts, i; + + if (!context_id || !*context_id) + return FALSE; + + gtk_im_module_list (&contexts, &n_contexts); + + /* should we use hash table? */ + for (i = 0; i < n_contexts; i++) + { + if (strcmp (contexts[i]->context_id, context_id) == 0) + return TRUE; + } + + return FALSE; +} + +static gchar * +gtk_im_multicontext_get_default_context_id (GtkIMMulticontext *multicontext) +{ + const gchar *envvar; + gchar *context_id, *locale; + GtkSettings *settings; + + envvar = g_getenv ("GTK_IM_MODULE"); + if (envvar && *envvar && validate_context_id(envvar)) + return g_strdup(envvar); + + settings = multicontext->priv->settings; + if (!settings) + settings = gtk_settings_get_default(); + + g_object_get (settings, + "gtk-im-module", &context_id, + NULL); + if (context_id && *context_id && validate_context_id(context_id)) + return context_id; + + g_free(context_id); + + locale = _gtk_get_lc_ctype (); + context_id = _gtk_im_module_get_default_context_id (locale); + g_free (locale); + + return context_id; +} + +static void +im_module_change (GtkSettings *settings, GParamSpec *pspec, + GtkIMContext *context) +{ + GtkIMMulticontext *multicontext; + gchar *context_id; + + g_return_if_fail(GTK_IS_SETTINGS(settings)); + g_return_if_fail(GTK_IS_IM_CONTEXT(context)); + + multicontext = GTK_IM_MULTICONTEXT (context); + + g_object_get (G_OBJECT (settings), + "gtk-im-module", &context_id, + NULL); + + if (!validate_context_id (context_id)) + { + g_free(context_id); + return; + } + + if (!global_context_id || strcmp (global_context_id, context_id) != 0) + { + g_free (global_context_id); + global_context_id = context_id; + + if (multicontext->priv->follow_global) + { + gtk_im_multicontext_set_slave (multicontext, NULL, FALSE); + } + } + else + g_free (context_id); +} + static void gtk_im_multicontext_set_client_window (GtkIMContext *context, GdkWindow *window) { GtkIMMulticontext *multicontext = GTK_IM_MULTICONTEXT (context); - - GtkIMContext *slave = gtk_im_multicontext_get_slave (multicontext); + GtkIMMulticontextPrivate *priv = multicontext->priv; + GtkIMContext *slave; multicontext->priv->client_window = window; - + + if (multicontext->priv->settings && priv->im_module_set) + g_signal_handler_disconnect(G_OBJECT(priv->settings), priv->im_module_set); + + multicontext->priv->screen = NULL; + multicontext->priv->settings = NULL; + + if (priv->client_window) + { + priv->screen = gdk_drawable_get_screen (multicontext->priv->client_window); + priv->settings = gtk_settings_get_for_screen (multicontext->priv->screen); + + priv->im_module_set = g_signal_connect (priv->settings, + "notify::gtk-im-module", + G_CALLBACK (im_module_change), + multicontext); + + gtk_im_multicontext_set_slave (multicontext, NULL, FALSE); + } + + slave = gtk_im_multicontext_get_slave (multicontext); if (slave) gtk_im_context_set_client_window (slave, window); } @@ -295,7 +442,7 @@ GtkIMContext *slave = gtk_im_multicontext_get_slave (multicontext); if (slave) - gtk_im_context_get_preedit_string (slave, str, attrs, cursor_pos); + gtk_im_context_get_preedit_string (slave, str, attrs, cursor_pos); else { if (str) @@ -324,18 +471,20 @@ GtkIMMulticontext *multicontext = GTK_IM_MULTICONTEXT (context); GtkIMContext *slave; - /* If the global context type is different from the context we were - * using before, get rid of the old slave and create a new one - * for the new global context type. + /* If the global context type is different from the context we were using + * before, and the context is "global" mode, get rid of the old slave and + * create a new one for the new global context type. */ if (!multicontext->context_id || - strcmp (global_context_id, multicontext->context_id) != 0) - gtk_im_multicontext_set_slave (multicontext, NULL, FALSE); + (multicontext->priv->follow_global && + strcmp (global_context_id, multicontext->context_id) != 0)) + { + gtk_im_multicontext_set_slave (multicontext, NULL, FALSE); + } - slave = gtk_im_multicontext_get_slave (multicontext); - multicontext->priv->focus_in = TRUE; + slave = gtk_im_multicontext_get_slave (multicontext); if (slave) gtk_im_context_focus_in (slave); } @@ -480,17 +629,53 @@ } static void +apply_all_activate_cb (GtkWidget *menuitem, + GtkIMMulticontext *multicontext) +{ + gboolean is_global = GTK_CHECK_MENU_ITEM (menuitem)->active; + + multicontext->priv->follow_global = is_global; + if (is_global && + (multicontext->context_id == NULL || + strcmp (global_context_id, multicontext->context_id) != 0)) + { + /* set as default */ + gtk_im_multicontext_set_slave (multicontext, NULL, FALSE); + } +} + +static void activate_cb (GtkWidget *menuitem, GtkIMMulticontext *context) { - if (GTK_CHECK_MENU_ITEM (menuitem)->active) + GtkIMMulticontext *multicontext; + const gchar *id; + + if (!GTK_CHECK_MENU_ITEM (menuitem)->active) return; + + id = g_object_get_data (G_OBJECT (menuitem), "gtk-context-id"); + gtk_im_context_reset (GTK_IM_CONTEXT (context)); + + multicontext = GTK_IM_MULTICONTEXT (context); + + if (multicontext->priv->follow_global) + { + g_free(global_context_id); + global_context_id = g_strdup(id); + gtk_im_multicontext_set_slave (context, NULL, FALSE); + gtk_im_multicontext_get_slave (context); + } + else { - const gchar *id = g_object_get_data (G_OBJECT (menuitem), "gtk-context-id"); + GtkIMContext *slave; gtk_im_context_reset (GTK_IM_CONTEXT (context)); - - global_context_id = id; - gtk_im_multicontext_set_slave (context, NULL, FALSE); + slave = gtk_im_module_create (id); + gtk_im_multicontext_set_slave (multicontext, slave, FALSE); + g_object_unref (slave); + + g_free((gchar *) multicontext->context_id); + multicontext->context_id = g_strdup(id); } } @@ -507,15 +692,33 @@ gtk_im_multicontext_append_menuitems (GtkIMMulticontext *context, GtkMenuShell *menushell) { + GtkIMMulticontext *multicontext; const GtkIMContextInfo **contexts; guint n_contexts, i; GSList *group = NULL; + GtkWidget *menuitem; + + g_return_if_fail(GTK_IM_MULTICONTEXT(context)); + g_return_if_fail(GTK_MENU_SHELL(menushell)); + + multicontext = GTK_IM_MULTICONTEXT (context); - _gtk_im_module_list (&contexts, &n_contexts); + gtk_im_module_list (&contexts, &n_contexts); + + menuitem = gtk_check_menu_item_new_with_label ("Application Global"); + gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (menuitem), + multicontext->priv->follow_global); + g_signal_connect (menuitem, "activate", + G_CALLBACK (apply_all_activate_cb), context); + gtk_menu_shell_append (menushell, menuitem); + gtk_widget_show(menuitem); + + menuitem = gtk_separator_menu_item_new(); + gtk_menu_shell_append (menushell, menuitem); + gtk_widget_show(menuitem); for (i=0; i < n_contexts; i++) { - GtkWidget *menuitem; const gchar *translated_name; #ifdef ENABLE_NLS if (contexts[i]->domain && contexts[i]->domain_dirname && @@ -547,12 +750,17 @@ menuitem = gtk_radio_menu_item_new_with_label (group, translated_name); - if ((global_context_id == NULL && group == NULL) || - (global_context_id && - strcmp (contexts[i]->context_id, global_context_id) == 0)) + if ((multicontext->context_id && + strcmp (contexts[i]->context_id, multicontext->context_id) == 0) || + (!multicontext->context_id && + (((global_context_id == NULL && group == NULL) || + (global_context_id && + strcmp (contexts[i]->context_id, global_context_id) == 0))))) + { gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (menuitem), TRUE); - + } + group = gtk_radio_menu_item_get_group (GTK_RADIO_MENU_ITEM (menuitem)); g_object_set_data (G_OBJECT (menuitem), "gtk-context-id",