Blame gtk/gtkimmodule.c

Packit Service fb6fa5
/* GTK - The GIMP Toolkit
Packit Service fb6fa5
 * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
Packit Service fb6fa5
 *
Packit Service fb6fa5
 * This library is free software; you can redistribute it and/or
Packit Service fb6fa5
 * modify it under the terms of the GNU Lesser General Public
Packit Service fb6fa5
 * License as published by the Free Software Foundation; either
Packit Service fb6fa5
 * version 2 of the License, or (at your option) any later version.
Packit Service fb6fa5
 *
Packit Service fb6fa5
 * This library is distributed in the hope that it will be useful,
Packit Service fb6fa5
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit Service fb6fa5
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.	 See the GNU
Packit Service fb6fa5
 * Lesser General Public License for more details.
Packit Service fb6fa5
 *
Packit Service fb6fa5
 * You should have received a copy of the GNU Lesser General Public
Packit Service fb6fa5
 * License along with this library; if not, write to the Free
Packit Service fb6fa5
 * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
Packit Service fb6fa5
 */
Packit Service fb6fa5
Packit Service fb6fa5
/*
Packit Service fb6fa5
 * Modified by the GTK+ Team and others 1997-2000.  See the AUTHORS
Packit Service fb6fa5
 * file for a list of people on the GTK+ Team.  See the ChangeLog
Packit Service fb6fa5
 * files for a list of changes.  These files are distributed with
Packit Service fb6fa5
 * GTK+ at ftp://ftp.gtk.org/pub/gtk/. 
Packit Service fb6fa5
 */
Packit Service fb6fa5
Packit Service fb6fa5
#include "config.h"
Packit Service fb6fa5
Packit Service fb6fa5
#include <errno.h>
Packit Service fb6fa5
#include <stdio.h>
Packit Service fb6fa5
#include <stdlib.h>
Packit Service fb6fa5
#include <string.h>
Packit Service fb6fa5
Packit Service fb6fa5
#include <glib/gstdio.h>
Packit Service fb6fa5
#include <gmodule.h>
Packit Service fb6fa5
#include "gtkimmodule.h"
Packit Service fb6fa5
#include "gtkimcontextsimple.h"
Packit Service fb6fa5
#include "gtksettings.h"
Packit Service fb6fa5
#include "gtkmain.h"
Packit Service fb6fa5
#include "gtkrc.h"
Packit Service fb6fa5
#include "gtkintl.h"
Packit Service fb6fa5
#include "gtkalias.h"
Packit Service fb6fa5
Packit Service fb6fa5
/* Do *not* include "gtkprivate.h" in this file. If you do, the
Packit Service fb6fa5
 * correct_libdir_prefix() and correct_localedir_prefix() functions
Packit Service fb6fa5
 * below will have to move somewhere else.
Packit Service fb6fa5
 */
Packit Service fb6fa5
Packit Service fb6fa5
#ifdef __GTK_PRIVATE_H__
Packit Service fb6fa5
#error gtkprivate.h should not be included in this file
Packit Service fb6fa5
#endif
Packit Service fb6fa5
Packit Service fb6fa5
#define SIMPLE_ID "gtk-im-context-simple"
Packit Service fb6fa5
Packit Service fb6fa5
/**
Packit Service fb6fa5
 * GtkIMContextInfo:
Packit Service fb6fa5
 * @context_id: The unique identification string of the input method.
Packit Service fb6fa5
 * @context_name: The human-readable name of the input method.
Packit Service fb6fa5
 * @domain: Translation domain to be used with dgettext()
Packit Service fb6fa5
 * @domain_dirname: Name of locale directory for use with bindtextdomain()
Packit Service fb6fa5
 * @default_locales: A colon-separated list of locales where this input method
Packit Service fb6fa5
 *   should be the default. The asterisk "*" sets the default for all locales.
Packit Service fb6fa5
 *
Packit Service fb6fa5
 * Bookkeeping information about a loadable input method.
Packit Service fb6fa5
 */
Packit Service fb6fa5
Packit Service fb6fa5
typedef struct _GtkIMModule      GtkIMModule;
Packit Service fb6fa5
typedef struct _GtkIMModuleClass GtkIMModuleClass;
Packit Service fb6fa5
Packit Service fb6fa5
#define GTK_TYPE_IM_MODULE          (gtk_im_module_get_type ())
Packit Service fb6fa5
#define GTK_IM_MODULE(im_module)    (G_TYPE_CHECK_INSTANCE_CAST ((im_module), GTK_TYPE_IM_MODULE, GtkIMModule))
Packit Service fb6fa5
#define GTK_IS_IM_MODULE(im_module) (G_TYPE_CHECK_INSTANCE_TYPE ((im_module), GTK_TYPE_IM_MODULE))
Packit Service fb6fa5
Packit Service fb6fa5
struct _GtkIMModule
Packit Service fb6fa5
{
Packit Service fb6fa5
  GTypeModule parent_instance;
Packit Service fb6fa5
  
Packit Service fb6fa5
  gboolean builtin;
Packit Service fb6fa5
Packit Service fb6fa5
  GModule *library;
Packit Service fb6fa5
Packit Service fb6fa5
  void          (*list)   (const GtkIMContextInfo ***contexts,
Packit Service fb6fa5
 		           guint                    *n_contexts);
Packit Service fb6fa5
  void          (*init)   (GTypeModule              *module);
Packit Service fb6fa5
  void          (*exit)   (void);
Packit Service fb6fa5
  GtkIMContext *(*create) (const gchar              *context_id);
Packit Service fb6fa5
Packit Service fb6fa5
  GtkIMContextInfo **contexts;
Packit Service fb6fa5
  guint n_contexts;
Packit Service fb6fa5
Packit Service fb6fa5
  gchar *path;
Packit Service fb6fa5
};
Packit Service fb6fa5
Packit Service fb6fa5
struct _GtkIMModuleClass 
Packit Service fb6fa5
{
Packit Service fb6fa5
  GTypeModuleClass parent_class;
Packit Service fb6fa5
};
Packit Service fb6fa5
Packit Service fb6fa5
static GType gtk_im_module_get_type (void);
Packit Service fb6fa5
Packit Service fb6fa5
static gint n_loaded_contexts = 0;
Packit Service fb6fa5
static GHashTable *contexts_hash = NULL;
Packit Service fb6fa5
static GSList *modules_list = NULL;
Packit Service fb6fa5
Packit Service fb6fa5
static GObjectClass *parent_class = NULL;
Packit Service fb6fa5
Packit Service fb6fa5
static gboolean
Packit Service fb6fa5
gtk_im_module_load (GTypeModule *module)
Packit Service fb6fa5
{
Packit Service fb6fa5
  GtkIMModule *im_module = GTK_IM_MODULE (module);
Packit Service fb6fa5
  
Packit Service fb6fa5
  if (!im_module->builtin)
Packit Service fb6fa5
    {
Packit Service fb6fa5
      im_module->library = g_module_open (im_module->path, G_MODULE_BIND_LAZY | G_MODULE_BIND_LOCAL);
Packit Service fb6fa5
      if (!im_module->library)
Packit Service fb6fa5
	{
Packit Service fb6fa5
	  g_warning ("%s", g_module_error());
Packit Service fb6fa5
	  return FALSE;
Packit Service fb6fa5
	}
Packit Service fb6fa5
  
Packit Service fb6fa5
      /* extract symbols from the lib */
Packit Service fb6fa5
      if (!g_module_symbol (im_module->library, "im_module_init",
Packit Service fb6fa5
			    (gpointer *)&im_module->init) ||
Packit Service fb6fa5
	  !g_module_symbol (im_module->library, "im_module_exit", 
Packit Service fb6fa5
			    (gpointer *)&im_module->exit) ||
Packit Service fb6fa5
	  !g_module_symbol (im_module->library, "im_module_list", 
Packit Service fb6fa5
			    (gpointer *)&im_module->list) ||
Packit Service fb6fa5
	  !g_module_symbol (im_module->library, "im_module_create", 
Packit Service fb6fa5
			    (gpointer *)&im_module->create))
Packit Service fb6fa5
	{
Packit Service fb6fa5
	  g_warning ("%s", g_module_error());
Packit Service fb6fa5
	  g_module_close (im_module->library);
Packit Service fb6fa5
	  
Packit Service fb6fa5
	  return FALSE;
Packit Service fb6fa5
	}
Packit Service fb6fa5
    }
Packit Service fb6fa5
	    
Packit Service fb6fa5
  /* call the module's init function to let it */
Packit Service fb6fa5
  /* setup anything it needs to set up. */
Packit Service fb6fa5
  im_module->init (module);
Packit Service fb6fa5
Packit Service fb6fa5
  return TRUE;
Packit Service fb6fa5
}
Packit Service fb6fa5
Packit Service fb6fa5
static void
Packit Service fb6fa5
gtk_im_module_unload (GTypeModule *module)
Packit Service fb6fa5
{
Packit Service fb6fa5
  GtkIMModule *im_module = GTK_IM_MODULE (module);
Packit Service fb6fa5
  
Packit Service fb6fa5
  im_module->exit();
Packit Service fb6fa5
Packit Service fb6fa5
  if (!im_module->builtin)
Packit Service fb6fa5
    {
Packit Service fb6fa5
      g_module_close (im_module->library);
Packit Service fb6fa5
      im_module->library = NULL;
Packit Service fb6fa5
Packit Service fb6fa5
      im_module->init = NULL;
Packit Service fb6fa5
      im_module->exit = NULL;
Packit Service fb6fa5
      im_module->list = NULL;
Packit Service fb6fa5
      im_module->create = NULL;
Packit Service fb6fa5
    }
Packit Service fb6fa5
}
Packit Service fb6fa5
Packit Service fb6fa5
/* This only will ever be called if an error occurs during
Packit Service fb6fa5
 * initialization
Packit Service fb6fa5
 */
Packit Service fb6fa5
static void
Packit Service fb6fa5
gtk_im_module_finalize (GObject *object)
Packit Service fb6fa5
{
Packit Service fb6fa5
  GtkIMModule *module = GTK_IM_MODULE (object);
Packit Service fb6fa5
Packit Service fb6fa5
  g_free (module->path);
Packit Service fb6fa5
Packit Service fb6fa5
  parent_class->finalize (object);
Packit Service fb6fa5
}
Packit Service fb6fa5
Packit Service fb6fa5
G_DEFINE_TYPE (GtkIMModule, gtk_im_module, G_TYPE_TYPE_MODULE)
Packit Service fb6fa5
Packit Service fb6fa5
static void
Packit Service fb6fa5
gtk_im_module_class_init (GtkIMModuleClass *class)
Packit Service fb6fa5
{
Packit Service fb6fa5
  GTypeModuleClass *module_class = G_TYPE_MODULE_CLASS (class);
Packit Service fb6fa5
  GObjectClass *gobject_class = G_OBJECT_CLASS (class);
Packit Service fb6fa5
Packit Service fb6fa5
  parent_class = G_OBJECT_CLASS (g_type_class_peek_parent (class));
Packit Service fb6fa5
  
Packit Service fb6fa5
  module_class->load = gtk_im_module_load;
Packit Service fb6fa5
  module_class->unload = gtk_im_module_unload;
Packit Service fb6fa5
Packit Service fb6fa5
  gobject_class->finalize = gtk_im_module_finalize;
Packit Service fb6fa5
}
Packit Service fb6fa5
Packit Service fb6fa5
static void 
Packit Service fb6fa5
gtk_im_module_init (GtkIMModule* object)
Packit Service fb6fa5
{
Packit Service fb6fa5
}
Packit Service fb6fa5
Packit Service fb6fa5
static void
Packit Service fb6fa5
free_info (GtkIMContextInfo *info)
Packit Service fb6fa5
{
Packit Service fb6fa5
  g_free ((char *)info->context_id);
Packit Service fb6fa5
  g_free ((char *)info->context_name);
Packit Service fb6fa5
  g_free ((char *)info->domain);
Packit Service fb6fa5
  g_free ((char *)info->domain_dirname);
Packit Service fb6fa5
  g_free ((char *)info->default_locales);
Packit Service fb6fa5
  g_free (info);
Packit Service fb6fa5
}
Packit Service fb6fa5
Packit Service fb6fa5
static void
Packit Service fb6fa5
add_module (GtkIMModule *module, GSList *infos)
Packit Service fb6fa5
{
Packit Service fb6fa5
  GSList *tmp_list = infos;
Packit Service fb6fa5
  gint i = 0;
Packit Service fb6fa5
  gint n = g_slist_length (infos);
Packit Service fb6fa5
  module->contexts = g_new (GtkIMContextInfo *, n);
Packit Service fb6fa5
Packit Service fb6fa5
  while (tmp_list)
Packit Service fb6fa5
    {
Packit Service fb6fa5
      GtkIMContextInfo *info = tmp_list->data;
Packit Service fb6fa5
  
Packit Service fb6fa5
      if (g_hash_table_lookup (contexts_hash, info->context_id))
Packit Service fb6fa5
	{
Packit Service fb6fa5
	  free_info (info);	/* Duplicate */
Packit Service fb6fa5
	}
Packit Service fb6fa5
      else
Packit Service fb6fa5
	{
Packit Service fb6fa5
	  g_hash_table_insert (contexts_hash, (char *)info->context_id, module);
Packit Service fb6fa5
	  module->contexts[i++] = tmp_list->data;
Packit Service fb6fa5
	  n_loaded_contexts++;
Packit Service fb6fa5
	}
Packit Service fb6fa5
      
Packit Service fb6fa5
      tmp_list = tmp_list->next;
Packit Service fb6fa5
    }
Packit Service fb6fa5
  g_slist_free (infos);
Packit Service fb6fa5
  module->n_contexts = i;
Packit Service fb6fa5
Packit Service fb6fa5
  modules_list = g_slist_prepend (modules_list, module);
Packit Service fb6fa5
}
Packit Service fb6fa5
Packit Service fb6fa5
#ifdef G_OS_WIN32
Packit Service fb6fa5
Packit Service fb6fa5
static void
Packit Service fb6fa5
correct_libdir_prefix (gchar **path)
Packit Service fb6fa5
{
Packit Service fb6fa5
  /* GTK_LIBDIR here is supposed to still have the definition from
Packit Service fb6fa5
   * Makefile.am, i.e. the build-time value. Do *not* include gtkprivate.h
Packit Service fb6fa5
   * in this file.
Packit Service fb6fa5
   */
Packit Service fb6fa5
  if (strncmp (*path, GTK_LIBDIR, strlen (GTK_LIBDIR)) == 0)
Packit Service fb6fa5
    {
Packit Service fb6fa5
      /* This is an entry put there by make install on the
Packit Service fb6fa5
       * packager's system. On Windows a prebuilt GTK+
Packit Service fb6fa5
       * package can be installed in a random
Packit Service fb6fa5
       * location. The immodules.cache file distributed in
Packit Service fb6fa5
       * such a package contains paths from the package
Packit Service fb6fa5
       * builder's machine. Replace the path with the real
Packit Service fb6fa5
       * one on this machine.
Packit Service fb6fa5
       */
Packit Service fb6fa5
      extern const gchar *_gtk_get_libdir ();
Packit Service fb6fa5
      gchar *tem = *path;
Packit Service fb6fa5
      *path = g_strconcat (_gtk_get_libdir (), tem + strlen (GTK_LIBDIR), NULL);
Packit Service fb6fa5
      g_free (tem);
Packit Service fb6fa5
    }
Packit Service fb6fa5
}
Packit Service fb6fa5
Packit Service fb6fa5
static void
Packit Service fb6fa5
correct_localedir_prefix (gchar **path)
Packit Service fb6fa5
{
Packit Service fb6fa5
  /* As above, but for GTK_LOCALEDIR. Use separate function in case
Packit Service fb6fa5
   * GTK_LOCALEDIR isn't a subfolder of GTK_LIBDIR.
Packit Service fb6fa5
   */
Packit Service fb6fa5
  if (strncmp (*path, GTK_LOCALEDIR, strlen (GTK_LOCALEDIR)) == 0)
Packit Service fb6fa5
    {
Packit Service fb6fa5
      extern const gchar *_gtk_get_localedir ();
Packit Service fb6fa5
      gchar *tem = *path;
Packit Service fb6fa5
      *path = g_strconcat (_gtk_get_localedir (), tem + strlen (GTK_LOCALEDIR), NULL);
Packit Service fb6fa5
      g_free (tem);
Packit Service fb6fa5
    }
Packit Service fb6fa5
}
Packit Service fb6fa5
#endif
Packit Service fb6fa5
Packit Service fb6fa5
Packit Service fb6fa5
G_GNUC_UNUSED static GtkIMModule *
Packit Service fb6fa5
add_builtin_module (const gchar             *module_name,
Packit Service fb6fa5
		    const GtkIMContextInfo **contexts,
Packit Service fb6fa5
		    int                      n_contexts)
Packit Service fb6fa5
{
Packit Service fb6fa5
  GtkIMModule *module = g_object_new (GTK_TYPE_IM_MODULE, NULL);
Packit Service fb6fa5
  GSList *infos = NULL;
Packit Service fb6fa5
  int i;
Packit Service fb6fa5
Packit Service fb6fa5
  for (i = 0; i < n_contexts; i++)
Packit Service fb6fa5
    {
Packit Service fb6fa5
      GtkIMContextInfo *info = g_new (GtkIMContextInfo, 1);
Packit Service fb6fa5
      info->context_id = g_strdup (contexts[i]->context_id);
Packit Service fb6fa5
      info->context_name = g_strdup (contexts[i]->context_name);
Packit Service fb6fa5
      info->domain = g_strdup (contexts[i]->domain);
Packit Service fb6fa5
      info->domain_dirname = g_strdup (contexts[i]->domain_dirname);
Packit Service fb6fa5
#ifdef G_OS_WIN32
Packit Service fb6fa5
      correct_localedir_prefix ((char **) &info->domain_dirname);
Packit Service fb6fa5
#endif
Packit Service fb6fa5
      info->default_locales = g_strdup (contexts[i]->default_locales);
Packit Service fb6fa5
      infos = g_slist_prepend (infos, info);
Packit Service fb6fa5
    }
Packit Service fb6fa5
Packit Service fb6fa5
  module->builtin = TRUE;
Packit Service fb6fa5
  g_type_module_set_name (G_TYPE_MODULE (module), module_name);
Packit Service fb6fa5
  add_module (module, infos);
Packit Service fb6fa5
Packit Service fb6fa5
  return module;
Packit Service fb6fa5
}
Packit Service fb6fa5
Packit Service fb6fa5
static void
Packit Service fb6fa5
gtk_im_module_initialize (void)
Packit Service fb6fa5
{
Packit Service fb6fa5
  GString *line_buf = g_string_new (NULL);
Packit Service fb6fa5
  GString *tmp_buf = g_string_new (NULL);
Packit Service fb6fa5
  gchar *filename = gtk_rc_get_im_module_file();
Packit Service fb6fa5
  FILE *file;
Packit Service fb6fa5
  gboolean have_error = FALSE;
Packit Service fb6fa5
Packit Service fb6fa5
  GtkIMModule *module = NULL;
Packit Service fb6fa5
  GSList *infos = NULL;
Packit Service fb6fa5
Packit Service fb6fa5
  contexts_hash = g_hash_table_new (g_str_hash, g_str_equal);
Packit Service fb6fa5
Packit Service fb6fa5
#define do_builtin(m)							\
Packit Service fb6fa5
  {									\
Packit Service fb6fa5
    const GtkIMContextInfo **contexts;					\
Packit Service fb6fa5
    int n_contexts;							\
Packit Service fb6fa5
    extern void _gtk_immodule_ ## m ## _list (const GtkIMContextInfo ***contexts, \
Packit Service fb6fa5
					      guint                    *n_contexts); \
Packit Service fb6fa5
    extern void _gtk_immodule_ ## m ## _init (GTypeModule *module);	\
Packit Service fb6fa5
    extern void _gtk_immodule_ ## m ## _exit (void);			\
Packit Service fb6fa5
    extern GtkIMContext *_gtk_immodule_ ## m ## _create (const gchar *context_id); \
Packit Service fb6fa5
									\
Packit Service fb6fa5
    _gtk_immodule_ ## m ## _list (&contexts, &n_contexts);		\
Packit Service fb6fa5
    module = add_builtin_module (#m, contexts, n_contexts);		\
Packit Service fb6fa5
    module->init = _gtk_immodule_ ## m ## _init;			\
Packit Service fb6fa5
    module->exit = _gtk_immodule_ ## m ## _exit;			\
Packit Service fb6fa5
    module->create = _gtk_immodule_ ## m ## _create;			\
Packit Service fb6fa5
    module = NULL;							\
Packit Service fb6fa5
  }
Packit Service fb6fa5
Packit Service fb6fa5
#ifdef INCLUDE_IM_am_et
Packit Service fb6fa5
  do_builtin (am_et);
Packit Service fb6fa5
#endif
Packit Service fb6fa5
#ifdef INCLUDE_IM_cedilla
Packit Service fb6fa5
  do_builtin (cedilla);
Packit Service fb6fa5
#endif
Packit Service fb6fa5
#ifdef INCLUDE_IM_cyrillic_translit
Packit Service fb6fa5
  do_builtin (cyrillic_translit);
Packit Service fb6fa5
#endif
Packit Service fb6fa5
#ifdef INCLUDE_IM_ime
Packit Service fb6fa5
  do_builtin (ime);
Packit Service fb6fa5
#endif
Packit Service fb6fa5
#ifdef INCLUDE_IM_inuktitut
Packit Service fb6fa5
  do_builtin (inuktitut);
Packit Service fb6fa5
#endif
Packit Service fb6fa5
#ifdef INCLUDE_IM_ipa
Packit Service fb6fa5
  do_builtin (ipa);
Packit Service fb6fa5
#endif
Packit Service fb6fa5
#ifdef INCLUDE_IM_multipress
Packit Service fb6fa5
  do_builtin (multipress);
Packit Service fb6fa5
#endif
Packit Service fb6fa5
#ifdef INCLUDE_IM_thai
Packit Service fb6fa5
  do_builtin (thai);
Packit Service fb6fa5
#endif
Packit Service fb6fa5
#ifdef INCLUDE_IM_ti_er
Packit Service fb6fa5
  do_builtin (ti_er);
Packit Service fb6fa5
#endif
Packit Service fb6fa5
#ifdef INCLUDE_IM_ti_et
Packit Service fb6fa5
  do_builtin (ti_et);
Packit Service fb6fa5
#endif
Packit Service fb6fa5
#ifdef INCLUDE_IM_viqr
Packit Service fb6fa5
  do_builtin (viqr);
Packit Service fb6fa5
#endif
Packit Service fb6fa5
#ifdef INCLUDE_IM_xim
Packit Service fb6fa5
  do_builtin (xim);
Packit Service fb6fa5
#endif
Packit Service fb6fa5
Packit Service fb6fa5
#undef do_builtin
Packit Service fb6fa5
Packit Service fb6fa5
  file = g_fopen (filename, "r");
Packit Service fb6fa5
  if (!file)
Packit Service fb6fa5
    {
Packit Service fb6fa5
      /* In case someone wants only the default input method,
Packit Service fb6fa5
       * we allow no file at all.
Packit Service fb6fa5
       */
Packit Service fb6fa5
      g_string_free (line_buf, TRUE);
Packit Service fb6fa5
      g_string_free (tmp_buf, TRUE);
Packit Service fb6fa5
      g_free (filename);
Packit Service fb6fa5
      return;
Packit Service fb6fa5
    }
Packit Service fb6fa5
Packit Service fb6fa5
  while (!have_error && pango_read_line (file, line_buf))
Packit Service fb6fa5
    {
Packit Service fb6fa5
      const char *p;
Packit Service fb6fa5
      
Packit Service fb6fa5
      p = line_buf->str;
Packit Service fb6fa5
Packit Service fb6fa5
      if (!pango_skip_space (&p))
Packit Service fb6fa5
	{
Packit Service fb6fa5
	  /* Blank line marking the end of a module
Packit Service fb6fa5
	   */
Packit Service fb6fa5
	  if (module && *p != '#')
Packit Service fb6fa5
	    {
Packit Service fb6fa5
	      add_module (module, infos);
Packit Service fb6fa5
	      module = NULL;
Packit Service fb6fa5
	      infos = NULL;
Packit Service fb6fa5
	    }
Packit Service fb6fa5
	  
Packit Service fb6fa5
	  continue;
Packit Service fb6fa5
	}
Packit Service fb6fa5
Packit Service fb6fa5
      if (!module)
Packit Service fb6fa5
	{
Packit Service fb6fa5
	  /* Read a module location
Packit Service fb6fa5
	   */
Packit Service fb6fa5
	  module = g_object_new (GTK_TYPE_IM_MODULE, NULL);
Packit Service fb6fa5
Packit Service fb6fa5
	  if (!pango_scan_string (&p, tmp_buf) ||
Packit Service fb6fa5
	      pango_skip_space (&p))
Packit Service fb6fa5
	    {
Packit Service fb6fa5
	      g_warning ("Error parsing context info in '%s'\n  %s", 
Packit Service fb6fa5
			 filename, line_buf->str);
Packit Service fb6fa5
	      have_error = TRUE;
Packit Service fb6fa5
	    }
Packit Service fb6fa5
Packit Service fb6fa5
	  module->path = g_strdup (tmp_buf->str);
Packit Service fb6fa5
#ifdef G_OS_WIN32
Packit Service fb6fa5
	  correct_libdir_prefix (&module->path);
Packit Service fb6fa5
#endif
Packit Service fb6fa5
	  g_type_module_set_name (G_TYPE_MODULE (module), module->path);
Packit Service fb6fa5
	}
Packit Service fb6fa5
      else
Packit Service fb6fa5
	{
Packit Service fb6fa5
	  GtkIMContextInfo *info = g_new0 (GtkIMContextInfo, 1);
Packit Service fb6fa5
	  
Packit Service fb6fa5
	  /* Read information about a context type
Packit Service fb6fa5
	   */
Packit Service fb6fa5
	  if (!pango_scan_string (&p, tmp_buf))
Packit Service fb6fa5
	    goto context_error;
Packit Service fb6fa5
	  info->context_id = g_strdup (tmp_buf->str);
Packit Service fb6fa5
Packit Service fb6fa5
	  if (!pango_scan_string (&p, tmp_buf))
Packit Service fb6fa5
	    goto context_error;
Packit Service fb6fa5
	  info->context_name = g_strdup (tmp_buf->str);
Packit Service fb6fa5
Packit Service fb6fa5
	  if (!pango_scan_string (&p, tmp_buf))
Packit Service fb6fa5
	    goto context_error;
Packit Service fb6fa5
	  info->domain = g_strdup (tmp_buf->str);
Packit Service fb6fa5
Packit Service fb6fa5
	  if (!pango_scan_string (&p, tmp_buf))
Packit Service fb6fa5
	    goto context_error;
Packit Service fb6fa5
	  info->domain_dirname = g_strdup (tmp_buf->str);
Packit Service fb6fa5
#ifdef G_OS_WIN32
Packit Service fb6fa5
	  correct_localedir_prefix ((char **) &info->domain_dirname);
Packit Service fb6fa5
#endif
Packit Service fb6fa5
Packit Service fb6fa5
	  if (!pango_scan_string (&p, tmp_buf))
Packit Service fb6fa5
	    goto context_error;
Packit Service fb6fa5
	  info->default_locales = g_strdup (tmp_buf->str);
Packit Service fb6fa5
Packit Service fb6fa5
	  if (pango_skip_space (&p))
Packit Service fb6fa5
	    goto context_error;
Packit Service fb6fa5
Packit Service fb6fa5
	  infos = g_slist_prepend (infos, info);
Packit Service fb6fa5
	  continue;
Packit Service fb6fa5
Packit Service fb6fa5
	context_error:
Packit Service fb6fa5
	  g_warning ("Error parsing context info in '%s'\n  %s", 
Packit Service fb6fa5
		     filename, line_buf->str);
Packit Service fb6fa5
	  have_error = TRUE;
Packit Service fb6fa5
	}
Packit Service fb6fa5
    }
Packit Service fb6fa5
Packit Service fb6fa5
  if (have_error)
Packit Service fb6fa5
    {
Packit Service fb6fa5
      GSList *tmp_list = infos;
Packit Service fb6fa5
      while (tmp_list)
Packit Service fb6fa5
	{
Packit Service fb6fa5
	  free_info (tmp_list->data);
Packit Service fb6fa5
	  tmp_list = tmp_list->next;
Packit Service fb6fa5
	}
Packit Service fb6fa5
      g_slist_free (infos);
Packit Service fb6fa5
Packit Service fb6fa5
      g_object_unref (module);
Packit Service fb6fa5
    }
Packit Service fb6fa5
  else if (module)
Packit Service fb6fa5
    add_module (module, infos);
Packit Service fb6fa5
Packit Service fb6fa5
  fclose (file);
Packit Service fb6fa5
  g_string_free (line_buf, TRUE);
Packit Service fb6fa5
  g_string_free (tmp_buf, TRUE);
Packit Service fb6fa5
  g_free (filename);
Packit Service fb6fa5
}
Packit Service fb6fa5
Packit Service fb6fa5
static gint
Packit Service fb6fa5
compare_gtkimcontextinfo_name(const GtkIMContextInfo **a,
Packit Service fb6fa5
			      const GtkIMContextInfo **b)
Packit Service fb6fa5
{
Packit Service fb6fa5
  return g_utf8_collate ((*a)->context_name, (*b)->context_name);
Packit Service fb6fa5
}
Packit Service fb6fa5
Packit Service fb6fa5
/**
Packit Service fb6fa5
 * _gtk_im_module_list:
Packit Service fb6fa5
 * @contexts: location to store an array of pointers to #GtkIMContextInfo
Packit Service fb6fa5
 *            this array should be freed with g_free() when you are finished.
Packit Service fb6fa5
 *            The structures it points are statically allocated and should
Packit Service fb6fa5
 *            not be modified or freed.
Packit Service fb6fa5
 * @n_contexts: the length of the array stored in @contexts
Packit Service fb6fa5
 * 
Packit Service fb6fa5
 * List all available types of input method context
Packit Service fb6fa5
 */
Packit Service fb6fa5
void
Packit Service fb6fa5
_gtk_im_module_list (const GtkIMContextInfo ***contexts,
Packit Service fb6fa5
		     guint                    *n_contexts)
Packit Service fb6fa5
{
Packit Service fb6fa5
  int n = 0;
Packit Service fb6fa5
Packit Service fb6fa5
  static
Packit Service fb6fa5
#ifndef G_OS_WIN32
Packit Service fb6fa5
	  const
Packit Service fb6fa5
#endif
Packit Service fb6fa5
		GtkIMContextInfo simple_context_info = {
Packit Service fb6fa5
    SIMPLE_ID,
Packit Service fb6fa5
    N_("Simple"),
Packit Service fb6fa5
    GETTEXT_PACKAGE,
Packit Service fb6fa5
#ifdef GTK_LOCALEDIR
Packit Service fb6fa5
    GTK_LOCALEDIR,
Packit Service fb6fa5
#else
Packit Service fb6fa5
    "",
Packit Service fb6fa5
#endif
Packit Service fb6fa5
    ""
Packit Service fb6fa5
  };
Packit Service fb6fa5
Packit Service fb6fa5
#ifdef G_OS_WIN32
Packit Service fb6fa5
  static gboolean beenhere = FALSE;
Packit Service fb6fa5
#endif
Packit Service fb6fa5
Packit Service fb6fa5
  if (!contexts_hash)
Packit Service fb6fa5
    gtk_im_module_initialize ();
Packit Service fb6fa5
Packit Service fb6fa5
#ifdef G_OS_WIN32
Packit Service fb6fa5
  if (!beenhere)
Packit Service fb6fa5
    {
Packit Service fb6fa5
      beenhere = TRUE;
Packit Service fb6fa5
      /* correct_localedir_prefix() requires its parameter to be a
Packit Service fb6fa5
       * malloced string
Packit Service fb6fa5
       */
Packit Service fb6fa5
      simple_context_info.domain_dirname = g_strdup (simple_context_info.domain_dirname);
Packit Service fb6fa5
      correct_localedir_prefix ((char **) &simple_context_info.domain_dirname);
Packit Service fb6fa5
    }
Packit Service fb6fa5
#endif
Packit Service fb6fa5
Packit Service fb6fa5
  if (n_contexts)
Packit Service fb6fa5
    *n_contexts = (n_loaded_contexts + 1);
Packit Service fb6fa5
Packit Service fb6fa5
  if (contexts)
Packit Service fb6fa5
    {
Packit Service fb6fa5
      GSList *tmp_list;
Packit Service fb6fa5
      int i;
Packit Service fb6fa5
      
Packit Service fb6fa5
      *contexts = g_new (const GtkIMContextInfo *, n_loaded_contexts + 1);
Packit Service fb6fa5
Packit Service fb6fa5
      (*contexts)[n++] = &simple_context_info;
Packit Service fb6fa5
Packit Service fb6fa5
      tmp_list = modules_list;
Packit Service fb6fa5
      while (tmp_list)
Packit Service fb6fa5
	{
Packit Service fb6fa5
	  GtkIMModule *module = tmp_list->data;
Packit Service fb6fa5
Packit Service fb6fa5
	  for (i=0; i<module->n_contexts; i++)
Packit Service fb6fa5
	    (*contexts)[n++] = module->contexts[i];
Packit Service fb6fa5
	  
Packit Service fb6fa5
	  tmp_list = tmp_list->next;
Packit Service fb6fa5
	}
Packit Service fb6fa5
Packit Service fb6fa5
      /* fisrt element (Default) should always be at top */
Packit Service fb6fa5
      qsort ((*contexts)+1, n-1, sizeof (GtkIMContextInfo *), (GCompareFunc)compare_gtkimcontextinfo_name);
Packit Service fb6fa5
    }
Packit Service fb6fa5
}
Packit Service fb6fa5
Packit Service fb6fa5
/**
Packit Service fb6fa5
 * _gtk_im_module_create:
Packit Service fb6fa5
 * @context_id: the context ID for the context type to create
Packit Service fb6fa5
 * 
Packit Service fb6fa5
 * Create an IM context of a type specified by the string
Packit Service fb6fa5
 * ID @context_id.
Packit Service fb6fa5
 * 
Packit Service fb6fa5
 * Return value: a newly created input context of or @context_id, or
Packit Service fb6fa5
 *     if that could not be created, a newly created GtkIMContextSimple.
Packit Service fb6fa5
 */
Packit Service fb6fa5
GtkIMContext *
Packit Service fb6fa5
_gtk_im_module_create (const gchar *context_id)
Packit Service fb6fa5
{
Packit Service fb6fa5
  GtkIMModule *im_module;
Packit Service fb6fa5
  GtkIMContext *context = NULL;
Packit Service fb6fa5
  
Packit Service fb6fa5
  if (!contexts_hash)
Packit Service fb6fa5
    gtk_im_module_initialize ();
Packit Service fb6fa5
Packit Service fb6fa5
  if (strcmp (context_id, SIMPLE_ID) != 0)
Packit Service fb6fa5
    {
Packit Service fb6fa5
      im_module = g_hash_table_lookup (contexts_hash, context_id);
Packit Service fb6fa5
      if (!im_module)
Packit Service fb6fa5
	{
Packit Service fb6fa5
	  g_warning ("Attempt to load unknown IM context type '%s'", context_id);
Packit Service fb6fa5
	}
Packit Service fb6fa5
      else
Packit Service fb6fa5
	{
Packit Service fb6fa5
	  if (g_type_module_use (G_TYPE_MODULE (im_module)))
Packit Service fb6fa5
	    {
Packit Service fb6fa5
	      context = im_module->create (context_id);
Packit Service fb6fa5
	      g_type_module_unuse (G_TYPE_MODULE (im_module));
Packit Service fb6fa5
	    }
Packit Service fb6fa5
	  
Packit Service fb6fa5
	  if (!context)
Packit Service fb6fa5
	    g_warning ("Loading IM context type '%s' failed", context_id);
Packit Service fb6fa5
	}
Packit Service fb6fa5
    }
Packit Service fb6fa5
  
Packit Service fb6fa5
  if (!context)
Packit Service fb6fa5
     return gtk_im_context_simple_new ();
Packit Service fb6fa5
  else
Packit Service fb6fa5
    return context;
Packit Service fb6fa5
}
Packit Service fb6fa5
Packit Service fb6fa5
/* Match @locale against @against.
Packit Service fb6fa5
 * 
Packit Service fb6fa5
 * 'en_US' against 'en_US'       => 4
Packit Service fb6fa5
 * 'en_US' against 'en'          => 3
Packit Service fb6fa5
 * 'en', 'en_UK' against 'en_US' => 2
Packit Service fb6fa5
 *  all locales, against '*' 	 => 1
Packit Service fb6fa5
 */
Packit Service fb6fa5
static gint
Packit Service fb6fa5
match_locale (const gchar *locale,
Packit Service fb6fa5
	      const gchar *against,
Packit Service fb6fa5
	      gint         against_len)
Packit Service fb6fa5
{
Packit Service fb6fa5
  if (strcmp (against, "*") == 0)
Packit Service fb6fa5
    return 1;
Packit Service fb6fa5
Packit Service fb6fa5
  if (g_ascii_strcasecmp (locale, against) == 0)
Packit Service fb6fa5
    return 4;
Packit Service fb6fa5
Packit Service fb6fa5
  if (g_ascii_strncasecmp (locale, against, 2) == 0)
Packit Service fb6fa5
    return (against_len == 2) ? 3 : 2;
Packit Service fb6fa5
Packit Service fb6fa5
  return 0;
Packit Service fb6fa5
}
Packit Service fb6fa5
Packit Service fb6fa5
static const gchar *
Packit Service fb6fa5
lookup_immodule (gchar **immodules_list)
Packit Service fb6fa5
{
Packit Service fb6fa5
  while (immodules_list && *immodules_list)
Packit Service fb6fa5
    {
Packit Service fb6fa5
      if (g_strcmp0 (*immodules_list, SIMPLE_ID) == 0)
Packit Service fb6fa5
        return SIMPLE_ID;
Packit Service fb6fa5
      else
Packit Service fb6fa5
	{
Packit Service fb6fa5
	  gboolean found;
Packit Service fb6fa5
	  gchar *context_id;
Packit Service fb6fa5
	  found = g_hash_table_lookup_extended (contexts_hash, *immodules_list,
Packit Service fb6fa5
						&context_id, NULL);
Packit Service fb6fa5
	  if (found)
Packit Service fb6fa5
	    return context_id;
Packit Service fb6fa5
	}
Packit Service fb6fa5
      immodules_list++;
Packit Service fb6fa5
    }
Packit Service fb6fa5
Packit Service fb6fa5
  return NULL;
Packit Service fb6fa5
}
Packit Service fb6fa5
Packit Service fb6fa5
/**
Packit Service fb6fa5
 * _gtk_im_module_get_default_context_id:
Packit Service fb6fa5
 * @client_window: a window
Packit Service fb6fa5
 * 
Packit Service fb6fa5
 * Return the context_id of the best IM context type 
Packit Service fb6fa5
 * for the given window.
Packit Service fb6fa5
 * 
Packit Service fb6fa5
 * Return value: the context ID (will never be %NULL)
Packit Service fb6fa5
 */
Packit Service fb6fa5
const gchar *
Packit Service fb6fa5
_gtk_im_module_get_default_context_id (GdkWindow *client_window)
Packit Service fb6fa5
{
Packit Service fb6fa5
  GSList *tmp_list;
Packit Service fb6fa5
  const gchar *context_id = NULL;
Packit Service fb6fa5
  gint best_goodness = 0;
Packit Service fb6fa5
  gint i;
Packit Service fb6fa5
  gchar *tmp_locale, *tmp, **immodules;
Packit Service fb6fa5
  const gchar *envvar;
Packit Service fb6fa5
  GdkScreen *screen;
Packit Service fb6fa5
  GtkSettings *settings;
Packit Service fb6fa5
      
Packit Service fb6fa5
  if (!contexts_hash)
Packit Service fb6fa5
    gtk_im_module_initialize ();
Packit Service fb6fa5
Packit Service fb6fa5
  envvar = g_getenv("GTK_IM_MODULE");
Packit Service fb6fa5
  if (envvar)
Packit Service fb6fa5
    {
Packit Service fb6fa5
        immodules = g_strsplit(envvar, ":", 0);
Packit Service fb6fa5
        context_id = lookup_immodule(immodules);
Packit Service fb6fa5
        g_strfreev(immodules);
Packit Service fb6fa5
Packit Service fb6fa5
        if (context_id)
Packit Service fb6fa5
          return context_id;
Packit Service fb6fa5
    }
Packit Service fb6fa5
Packit Service fb6fa5
  /* Check if the certain immodule is set in XSETTINGS.
Packit Service fb6fa5
   */
Packit Service fb6fa5
  if (GDK_IS_DRAWABLE (client_window))
Packit Service fb6fa5
    {
Packit Service fb6fa5
      screen = gdk_window_get_screen (client_window);
Packit Service fb6fa5
      settings = gtk_settings_get_for_screen (screen);
Packit Service fb6fa5
      g_object_get (G_OBJECT (settings), "gtk-im-module", &tmp, NULL);
Packit Service fb6fa5
      if (tmp)
Packit Service fb6fa5
        {
Packit Service fb6fa5
          immodules = g_strsplit(tmp, ":", 0);
Packit Service fb6fa5
          context_id = lookup_immodule(immodules);
Packit Service fb6fa5
          g_strfreev(immodules);
Packit Service fb6fa5
          g_free (tmp);
Packit Service fb6fa5
Packit Service fb6fa5
       	  if (context_id)
Packit Service fb6fa5
            return context_id;
Packit Service fb6fa5
        }
Packit Service fb6fa5
    }
Packit Service fb6fa5
Packit Service fb6fa5
  /* Strip the locale code down to the essentials
Packit Service fb6fa5
   */
Packit Service fb6fa5
  tmp_locale = _gtk_get_lc_ctype ();
Packit Service fb6fa5
  tmp = strchr (tmp_locale, '.');
Packit Service fb6fa5
  if (tmp)
Packit Service fb6fa5
    *tmp = '\0';
Packit Service fb6fa5
  tmp = strchr (tmp_locale, '@');
Packit Service fb6fa5
  if (tmp)
Packit Service fb6fa5
    *tmp = '\0';
Packit Service fb6fa5
  
Packit Service fb6fa5
  tmp_list = modules_list;
Packit Service fb6fa5
  while (tmp_list)
Packit Service fb6fa5
    {
Packit Service fb6fa5
      GtkIMModule *module = tmp_list->data;
Packit Service fb6fa5
     
Packit Service fb6fa5
      for (i = 0; i < module->n_contexts; i++)
Packit Service fb6fa5
	{
Packit Service fb6fa5
	  const gchar *p = module->contexts[i]->default_locales;
Packit Service fb6fa5
	  while (p)
Packit Service fb6fa5
	    {
Packit Service fb6fa5
	      const gchar *q = strchr (p, ':');
Packit Service fb6fa5
	      gint goodness = match_locale (tmp_locale, p, q ? q - p : strlen (p));
Packit Service fb6fa5
Packit Service fb6fa5
	      if (goodness > best_goodness)
Packit Service fb6fa5
		{
Packit Service fb6fa5
		  context_id = module->contexts[i]->context_id;
Packit Service fb6fa5
		  best_goodness = goodness;
Packit Service fb6fa5
		}
Packit Service fb6fa5
Packit Service fb6fa5
	      p = q ? q + 1 : NULL;
Packit Service fb6fa5
	    }
Packit Service fb6fa5
	}
Packit Service fb6fa5
      
Packit Service fb6fa5
      tmp_list = tmp_list->next;
Packit Service fb6fa5
    }
Packit Service fb6fa5
Packit Service fb6fa5
  g_free (tmp_locale);
Packit Service fb6fa5
  
Packit Service fb6fa5
  return context_id ? context_id : SIMPLE_ID;
Packit Service fb6fa5
}