]> Pileus Git - ~andy/gtk/blobdiff - gtk/gtkimmodule.c
stylecontext: Do invalidation on first resize container
[~andy/gtk] / gtk / gtkimmodule.c
index 042c9024ca8b93cd8d8322bd51a6a9db05114514..e6372f2edb6763b233b81164d2618e952e98033a 100644 (file)
@@ -1,8 +1,6 @@
 /* GTK - The GIMP Toolkit
  * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
  *
- * Themes added by The Rasterman <raster@redhat.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
@@ -14,8 +12,7 @@
  * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ * License along with this library. If not, see <http://www.gnu.org/licenses/>.Free
  */
 
 /*
  * files for a list of changes.  These files are distributed with
  * GTK+ at ftp://ftp.gtk.org/pub/gtk/. 
  */
+
+#include "config.h"
+
 #include <errno.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
 
+#include <glib/gstdio.h>
 #include <gmodule.h>
-#include <pango/pango-utils.h>
-#include "gtkimmodule.h"
+#include "gtkimmoduleprivate.h"
 #include "gtkimcontextsimple.h"
-#include "gtkrc.h"
-#include "config.h"
+#include "gtksettings.h"
+#include "gtkprivate.h"
 #include "gtkintl.h"
 
-/* Do *not* include "gtkprivate.h" in this file. If you do, the
- * correct_libdir_prefix() function below will have to move somewhere
- * else.
- */
+#undef GDK_DEPRECATED
+#undef GDK_DEPRECATED_FOR
+#define GDK_DEPRECATED
+#define GDK_DEPRECATED_FOR(f)
+
+#include "deprecated/gtkrc.h"
 
 #define SIMPLE_ID "gtk-im-context-simple"
 
+/**
+ * GtkIMContextInfo:
+ * @context_id: The unique identification string of the input method.
+ * @context_name: The human-readable name of the input method.
+ * @domain: Translation domain to be used with dgettext()
+ * @domain_dirname: Name of locale directory for use with bindtextdomain()
+ * @default_locales: A colon-separated list of locales where this input method
+ *   should be the default. The asterisk "*" sets the default for all locales.
+ *
+ * Bookkeeping information about a loadable input method.
+ */
+
 typedef struct _GtkIMModule      GtkIMModule;
 typedef struct _GtkIMModuleClass GtkIMModuleClass;
 
@@ -55,6 +69,8 @@ struct _GtkIMModule
 {
   GTypeModule parent_instance;
   
+  gboolean builtin;
+
   GModule *library;
 
   void          (*list)   (const GtkIMContextInfo ***contexts,
@@ -74,7 +90,7 @@ struct _GtkIMModuleClass
   GTypeModuleClass parent_class;
 };
 
-GType gtk_im_module_get_type (void);
+static GType gtk_im_module_get_type (void);
 
 static gint n_loaded_contexts = 0;
 static GHashTable *contexts_hash = NULL;
@@ -87,30 +103,33 @@ gtk_im_module_load (GTypeModule *module)
 {
   GtkIMModule *im_module = GTK_IM_MODULE (module);
   
-  im_module->library = g_module_open (im_module->path, 0);
-  if (!im_module->library)
+  if (!im_module->builtin)
     {
-      g_warning (g_module_error());
-      return FALSE;
-    }
+      im_module->library = g_module_open (im_module->path, G_MODULE_BIND_LAZY | G_MODULE_BIND_LOCAL);
+      if (!im_module->library)
+       {
+         g_warning ("%s", g_module_error());
+         return FALSE;
+       }
   
-  /* extract symbols from the lib */
-  if (!g_module_symbol (im_module->library, "im_module_init",
-                       (gpointer *)&im_module->init) ||
-      !g_module_symbol (im_module->library, "im_module_exit", 
-                       (gpointer *)&im_module->exit) ||
-      !g_module_symbol (im_module->library, "im_module_list", 
-                       (gpointer *)&im_module->list) ||
-      !g_module_symbol (im_module->library, "im_module_create", 
-                       (gpointer *)&im_module->create))
-    {
-      g_warning (g_module_error());
-      g_module_close (im_module->library);
-      
-      return FALSE;
+      /* extract symbols from the lib */
+      if (!g_module_symbol (im_module->library, "im_module_init",
+                           (gpointer *)&im_module->init) ||
+         !g_module_symbol (im_module->library, "im_module_exit", 
+                           (gpointer *)&im_module->exit) ||
+         !g_module_symbol (im_module->library, "im_module_list", 
+                           (gpointer *)&im_module->list) ||
+         !g_module_symbol (im_module->library, "im_module_create", 
+                           (gpointer *)&im_module->create))
+       {
+         g_warning ("%s", g_module_error());
+         g_module_close (im_module->library);
+         
+         return FALSE;
+       }
     }
            
-  /* call the theme's init (theme_init) function to let it */
+  /* call the module's init function to let it */
   /* setup anything it needs to set up. */
   im_module->init (module);
 
@@ -124,13 +143,16 @@ gtk_im_module_unload (GTypeModule *module)
   
   im_module->exit();
 
-  g_module_close (im_module->library);
-  im_module->library = NULL;
+  if (!im_module->builtin)
+    {
+      g_module_close (im_module->library);
+      im_module->library = NULL;
 
-  im_module->init = NULL;
-  im_module->exit = NULL;
-  im_module->list = NULL;
-  im_module->create = NULL;
+      im_module->init = NULL;
+      im_module->exit = NULL;
+      im_module->list = NULL;
+      im_module->create = NULL;
+    }
 }
 
 /* This only will ever be called if an error occurs during
@@ -146,6 +168,8 @@ gtk_im_module_finalize (GObject *object)
   parent_class->finalize (object);
 }
 
+G_DEFINE_TYPE (GtkIMModule, gtk_im_module, G_TYPE_TYPE_MODULE)
+
 static void
 gtk_im_module_class_init (GtkIMModuleClass *class)
 {
@@ -160,31 +184,9 @@ gtk_im_module_class_init (GtkIMModuleClass *class)
   gobject_class->finalize = gtk_im_module_finalize;
 }
 
-GType
-gtk_im_module_get_type (void)
+static void 
+gtk_im_module_init (GtkIMModule* object)
 {
-  static GType im_module_type = 0;
-
-  if (!im_module_type)
-    {
-      static const GTypeInfo im_module_info = {
-        sizeof (GtkIMModuleClass),
-        NULL,           /* base_init */
-        NULL,           /* base_finalize */
-        (GClassInitFunc) gtk_im_module_class_init,
-        NULL,           /* class_finalize */
-        NULL,           /* class_data */
-        sizeof (GtkIMModule),
-        0,              /* n_preallocs */
-        NULL,           /* instance_init */
-      };
-
-      im_module_type =
-       g_type_register_static (G_TYPE_TYPE_MODULE, "GtkIMModule",
-                               &im_module_info, 0);
-    }
-  
-  return im_module_type;
 }
 
 static void
@@ -229,20 +231,12 @@ add_module (GtkIMModule *module, GSList *infos)
   modules_list = g_slist_prepend (modules_list, module);
 }
 
-#if defined (G_OS_WIN32) && defined (GTK_LIBDIR)
-/* This is needes on Win32, but not wanted when compiling with MSVC,
- * as the makefile.msc doesn't define any GTK_LIBDIR value.
- */
-
-#define DO_CORRECT_LIBDIR_PREFIX /* Flag to check below whether to call this */
+#ifdef G_OS_WIN32
 
 static void
 correct_libdir_prefix (gchar **path)
 {
-  /* GTK_LIBDIR here is supposed to still have the definition from
-   * Makefile.am, i.e. the build-time value. Do *not* include gtkprivate.h
-   * in this file.
-   */
+  /* GTK_LIBDIR is the build-time libdir */
   if (strncmp (*path, GTK_LIBDIR, strlen (GTK_LIBDIR)) == 0)
     {
       /* This is an entry put there by make install on the
@@ -253,17 +247,58 @@ correct_libdir_prefix (gchar **path)
        * builder's machine. Replace the path with the real
        * one on this machine.
        */
-      extern const gchar *_gtk_get_libdir ();
       gchar *tem = *path;
       *path = g_strconcat (_gtk_get_libdir (), tem + strlen (GTK_LIBDIR), NULL);
       g_free (tem);
     }
 }
+
+static void
+correct_localedir_prefix (gchar **path)
+{
+  /* See above */
+  if (strncmp (*path, GTK_LOCALEDIR, strlen (GTK_LOCALEDIR)) == 0)
+    {
+      gchar *tem = *path;
+      *path = g_strconcat (_gtk_get_localedir (), tem + strlen (GTK_LOCALEDIR), NULL);
+      g_free (tem);
+    }
+}
+#endif
+
+
+G_GNUC_UNUSED static GtkIMModule *
+add_builtin_module (const gchar             *module_name,
+                   const GtkIMContextInfo **contexts,
+                   int                      n_contexts)
+{
+  GtkIMModule *module = g_object_new (GTK_TYPE_IM_MODULE, NULL);
+  GSList *infos = NULL;
+  int i;
+
+  for (i = 0; i < n_contexts; i++)
+    {
+      GtkIMContextInfo *info = g_new (GtkIMContextInfo, 1);
+      info->context_id = g_strdup (contexts[i]->context_id);
+      info->context_name = g_strdup (contexts[i]->context_name);
+      info->domain = g_strdup (contexts[i]->domain);
+      info->domain_dirname = g_strdup (contexts[i]->domain_dirname);
+#ifdef G_OS_WIN32
+      correct_localedir_prefix ((char **) &info->domain_dirname);
 #endif
+      info->default_locales = g_strdup (contexts[i]->default_locales);
+      infos = g_slist_prepend (infos, info);
+    }
+
+  module->builtin = TRUE;
+  g_type_module_set_name (G_TYPE_MODULE (module), module_name);
+  add_module (module, infos);
 
+  return module;
+}
 
 static void
-gtk_im_module_init ()
+gtk_im_module_initialize (void)
 {
   GString *line_buf = g_string_new (NULL);
   GString *tmp_buf = g_string_new (NULL);
@@ -276,7 +311,64 @@ gtk_im_module_init ()
 
   contexts_hash = g_hash_table_new (g_str_hash, g_str_equal);
 
-  file = fopen (filename, "r");
+#define do_builtin(m)                                                  \
+  {                                                                    \
+    const GtkIMContextInfo **contexts;                                 \
+    int n_contexts;                                                    \
+    extern void _gtk_immodule_ ## m ## _list (const GtkIMContextInfo ***contexts, \
+                                             guint                    *n_contexts); \
+    extern void _gtk_immodule_ ## m ## _init (GTypeModule *module);    \
+    extern void _gtk_immodule_ ## m ## _exit (void);                   \
+    extern GtkIMContext *_gtk_immodule_ ## m ## _create (const gchar *context_id); \
+                                                                       \
+    _gtk_immodule_ ## m ## _list (&contexts, &n_contexts);             \
+    module = add_builtin_module (#m, contexts, n_contexts);            \
+    module->init = _gtk_immodule_ ## m ## _init;                       \
+    module->exit = _gtk_immodule_ ## m ## _exit;                       \
+    module->create = _gtk_immodule_ ## m ## _create;                   \
+    module = NULL;                                                     \
+  }
+
+#ifdef INCLUDE_IM_am_et
+  do_builtin (am_et);
+#endif
+#ifdef INCLUDE_IM_cedilla
+  do_builtin (cedilla);
+#endif
+#ifdef INCLUDE_IM_cyrillic_translit
+  do_builtin (cyrillic_translit);
+#endif
+#ifdef INCLUDE_IM_ime
+  do_builtin (ime);
+#endif
+#ifdef INCLUDE_IM_inuktitut
+  do_builtin (inuktitut);
+#endif
+#ifdef INCLUDE_IM_ipa
+  do_builtin (ipa);
+#endif
+#ifdef INCLUDE_IM_multipress
+  do_builtin (multipress);
+#endif
+#ifdef INCLUDE_IM_thai
+  do_builtin (thai);
+#endif
+#ifdef INCLUDE_IM_ti_er
+  do_builtin (ti_er);
+#endif
+#ifdef INCLUDE_IM_ti_et
+  do_builtin (ti_et);
+#endif
+#ifdef INCLUDE_IM_viqr
+  do_builtin (viqr);
+#endif
+#ifdef INCLUDE_IM_xim
+  do_builtin (xim);
+#endif
+
+#undef do_builtin
+
+  file = g_fopen (filename, "r");
   if (!file)
     {
       /* In case someone wants only the default input method,
@@ -323,7 +415,7 @@ gtk_im_module_init ()
            }
 
          module->path = g_strdup (tmp_buf->str);
-#ifdef DO_CORRECT_LIBDIR_PREFIX
+#ifdef G_OS_WIN32
          correct_libdir_prefix (&module->path);
 #endif
          g_type_module_set_name (G_TYPE_MODULE (module), module->path);
@@ -349,8 +441,8 @@ gtk_im_module_init ()
          if (!pango_scan_string (&p, tmp_buf))
            goto context_error;
          info->domain_dirname = g_strdup (tmp_buf->str);
-#ifdef DO_CORRECT_LIBDIR_PREFIX
-         correct_libdir_prefix (&info->domain_dirname);
+#ifdef G_OS_WIN32
+         correct_localedir_prefix ((char **) &info->domain_dirname);
 #endif
 
          if (!pango_scan_string (&p, tmp_buf))
@@ -407,23 +499,47 @@ compare_gtkimcontextinfo_name(const GtkIMContextInfo **a,
  * @n_contexts: the length of the array stored in @contexts
  * 
  * List all available types of input method context
- **/
+ */
 void
 _gtk_im_module_list (const GtkIMContextInfo ***contexts,
                     guint                    *n_contexts)
 {
   int n = 0;
 
-  static const GtkIMContextInfo simple_context_info = {
+  static
+#ifndef G_OS_WIN32
+         const
+#endif
+               GtkIMContextInfo simple_context_info = {
     SIMPLE_ID,
-    "Default",
-    "gtk+",
-    NULL,
+    N_("Simple"),
+    GETTEXT_PACKAGE,
+#ifdef GTK_LOCALEDIR
+    GTK_LOCALEDIR,
+#else
+    "",
+#endif
     ""
   };
 
+#ifdef G_OS_WIN32
+  static gboolean beenhere = FALSE;
+#endif
+
   if (!contexts_hash)
-    gtk_im_module_init ();
+    gtk_im_module_initialize ();
+
+#ifdef G_OS_WIN32
+  if (!beenhere)
+    {
+      beenhere = TRUE;
+      /* correct_localedir_prefix() requires its parameter to be a
+       * malloced string
+       */
+      simple_context_info.domain_dirname = g_strdup (simple_context_info.domain_dirname);
+      correct_localedir_prefix ((char **) &simple_context_info.domain_dirname);
+    }
+#endif
 
   if (n_contexts)
     *n_contexts = (n_loaded_contexts + 1);
@@ -461,8 +577,8 @@ _gtk_im_module_list (const GtkIMContextInfo ***contexts,
  * ID @context_id.
  * 
  * Return value: a newly created input context of or @context_id, or
- * if that could not be created, a newly created GtkIMContextSimple.
- **/
+ *     if that could not be created, a newly created GtkIMContextSimple.
+ */
 GtkIMContext *
 _gtk_im_module_create (const gchar *context_id)
 {
@@ -470,7 +586,7 @@ _gtk_im_module_create (const gchar *context_id)
   GtkIMContext *context = NULL;
   
   if (!contexts_hash)
-    gtk_im_module_init ();
+    gtk_im_module_initialize ();
 
   if (strcmp (context_id, SIMPLE_ID) != 0)
     {
@@ -513,48 +629,94 @@ match_locale (const gchar *locale,
   if (strcmp (against, "*") == 0)
     return 1;
 
-  if (strcmp (locale, against) == 0)
+  if (g_ascii_strcasecmp (locale, against) == 0)
     return 4;
 
-  if (strncmp (locale, against, 2) == 0)
+  if (g_ascii_strncasecmp (locale, against, 2) == 0)
     return (against_len == 2) ? 3 : 2;
 
   return 0;
 }
 
+static const gchar *
+lookup_immodule (gchar **immodules_list)
+{
+  while (immodules_list && *immodules_list)
+    {
+      if (g_strcmp0 (*immodules_list, SIMPLE_ID) == 0)
+        return SIMPLE_ID;
+      else
+       {
+         gboolean found;
+         gchar *context_id;
+         found = g_hash_table_lookup_extended (contexts_hash, *immodules_list,
+                                               (gpointer *) &context_id, NULL);
+         if (found)
+           return context_id;
+       }
+      immodules_list++;
+    }
+
+  return NULL;
+}
+
 /**
  * _gtk_im_module_get_default_context_id:
- * @locale: a locale id in the form 'en_US'
+ * @client_window: a window
  * 
- * Return the context_id of the best IM context type
- * for the given locale ID.
+ * Return the context_id of the best IM context type 
+ * for the given window.
  * 
  * Return value: the context ID (will never be %NULL)
- *    the value is newly allocated and must be freed
- *    with g_free().
- **/
+ */
 const gchar *
-_gtk_im_module_get_default_context_id (const gchar *locale)
+_gtk_im_module_get_default_context_id (GdkWindow *client_window)
 {
   GSList *tmp_list;
   const gchar *context_id = NULL;
   gint best_goodness = 0;
   gint i;
-  gchar *tmp_locale, *tmp;
+  gchar *tmp_locale, *tmp, **immodules;
   const gchar *envvar;
+  GdkScreen *screen;
+  GtkSettings *settings;
       
   if (!contexts_hash)
-    gtk_im_module_init ();
+    gtk_im_module_initialize ();
+
+  envvar = g_getenv("GTK_IM_MODULE");
+  if (envvar)
+    {
+        immodules = g_strsplit(envvar, ":", 0);
+        context_id = lookup_immodule(immodules);
+        g_strfreev(immodules);
 
-  envvar = g_getenv ("GTK_IM_MODULE");
-  if (envvar &&
-      (strcmp (envvar, SIMPLE_ID) == 0 ||
-       g_hash_table_lookup (contexts_hash, envvar)))
-    return g_strdup (envvar);
+        if (context_id)
+          return context_id;
+    }
+
+  /* Check if the certain immodule is set in XSETTINGS.
+   */
+  if (GDK_IS_WINDOW (client_window))
+    {
+      screen = gdk_window_get_screen (client_window);
+      settings = gtk_settings_get_for_screen (screen);
+      g_object_get (G_OBJECT (settings), "gtk-im-module", &tmp, NULL);
+      if (tmp)
+        {
+          immodules = g_strsplit(tmp, ":", 0);
+          context_id = lookup_immodule(immodules);
+          g_strfreev(immodules);
+          g_free (tmp);
+
+                 if (context_id)
+            return context_id;
+        }
+    }
 
   /* Strip the locale code down to the essentials
    */
-  tmp_locale = g_strdup (locale);
+  tmp_locale = _gtk_get_lc_ctype ();
   tmp = strchr (tmp_locale, '.');
   if (tmp)
     *tmp = '\0';
@@ -567,7 +729,7 @@ _gtk_im_module_get_default_context_id (const gchar *locale)
     {
       GtkIMModule *module = tmp_list->data;
      
-      for (i=0; i<module->n_contexts; i++)
+      for (i = 0; i < module->n_contexts; i++)
        {
          const gchar *p = module->contexts[i]->default_locales;
          while (p)
@@ -590,5 +752,5 @@ _gtk_im_module_get_default_context_id (const gchar *locale)
 
   g_free (tmp_locale);
   
-  return g_strdup (context_id ? context_id : SIMPLE_ID);
+  return context_id ? context_id : SIMPLE_ID;
 }