Back to index

im-sdk  12.3.91
iiimpSwitcher.c
Go to the documentation of this file.
00001 /*
00002 Copyright 1999-2004 Sun Microsystems, Inc. All Rights Reserved.
00003 
00004 Permission is hereby granted, free of charge, to any person obtaining a
00005 copy of this software and associated documentation files (the
00006 "Software"), to deal in the Software without restriction, including
00007 without limitation the rights to use, copy, modify, merge, publish,
00008 distribute, sublicense, and/or sell copies of the Software, and to
00009 permit persons to whom the Software is furnished to do so, subject to
00010 the following conditions: The above copyright notice and this
00011 permission notice shall be included in all copies or substantial
00012 portions of the Software.
00013 
00014 
00015 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
00016 OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
00017 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
00018 IN NO EVENT SHALL THE OPEN GROUP OR SUN MICROSYSTEMS, INC. BE LIABLE
00019 FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
00020 CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH
00021 THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE EVEN IF
00022 ADVISED IN ADVANCE OF THE POSSIBILITY OF SUCH DAMAGES.
00023 
00024 
00025 Except as contained in this notice, the names of The Open Group and/or
00026 Sun Microsystems, Inc. shall not be used in advertising or otherwise to
00027 promote the sale, use or other dealings in this Software without prior
00028 written authorization from The Open Group and/or Sun Microsystems,
00029 Inc., as applicable.
00030 
00031 
00032 X Window System is a trademark of The Open Group
00033 
00034 OSF/1, OSF/Motif and Motif are registered trademarks, and OSF, the OSF
00035 logo, LBX, X Window System, and Xinerama are trademarks of the Open
00036 Group. All other trademarks and registered trademarks mentioned herein
00037 are the property of their respective owners. No right, title or
00038 interest in or to any trademark, service mark, logo or trade name of
00039 Sun Microsystems, Inc. or its licensors is granted.
00040 
00041 */
00042 
00043 /* my_stpcpy is a copy of g_stpcpy() from glib-2, hence
00044    glib-2 copyright is included here.
00045        Commentted by Hidetoshi Tajima <hidetoshi.tajima@sun.com>
00046  */
00047 
00048 /* GLIB - Library of useful routines for C programming
00049  * Copyright (C) 1995-1997  Peter Mattis, Spencer Kimball and Josh MacDonald
00050  *
00051  * This library is free software; you can redistribute it and/or
00052  * modify it under the terms of the GNU Lesser General Public
00053  * License as published by the Free Software Foundation; either
00054  * version 2 of the License, or (at your option) any later version.
00055  *
00056  * This library is distributed in the hope that it will be useful,
00057  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00058  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00059  * Lesser General Public License for more details.
00060  *
00061  * You should have received a copy of the GNU Lesser General Public
00062  * License along with this library; if not, write to the
00063  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
00064  * Boston, MA 02111-1307, USA.
00065  */
00066 
00067 /*
00068  * Modified by the GLib Team and others 1997-2000.  See the AUTHORS
00069  * file for a list of people on the GLib Team.  See the ChangeLog
00070  * files for a list of changes.  These files are distributed with
00071  * GLib at ftp://ftp.gtk.org/pub/gtk/. 
00072  */
00073 
00074 #include <string.h>
00075 #include "iiimpIM.h"
00076 #include "iiimpSwitcher.h"
00077 #include "keysyms.h"
00078 
00079 struct _SwitcherInfo
00080 {
00081   Window switcher_window;
00082   Atom  selection_atom;
00083   Atom  set_current_input_language_atom;
00084   Atom  set_current_client_atom;
00085   Atom  set_status_text_atom;
00086   Atom  set_input_language_list_atom;
00087   Atom  set_conversion_mode_atom;
00088   Atom  set_hotkey_atom;
00089 };
00090 
00091 /* A listener window for input method switcher */
00092 struct _SwitcherContext
00093 {
00094   Window invisible;
00095 };
00096 
00097 static Atom selection = None;
00098 
00111 char *
00112 my_stpcpy (char *dest, const char *src)
00113 {
00114   if (dest == NULL || src == NULL)
00115     return NULL;
00116 #ifdef HAVE_STPCPY
00117   return stpcpy (dest, src);
00118 #else
00119   register char *d = dest;
00120   register const char *s = src;
00121 
00122   do
00123     *d++ = *s;
00124   while (*s++ != '\0');
00125 
00126   return d - 1;
00127 #endif
00128 }
00129 
00130 Bool
00131 im_switcher_active (XimCommon im)
00132 {
00133   SwitcherInfo *sw_info = im->switcher_info;
00134 
00135   return (sw_info && (sw_info->switcher_window));
00136 }
00137 
00138 static Bool
00139 filter_destroy_event(Display *d, Window w, XEvent *ev,
00140                    XPointer client_data)
00141 {
00142   XimCommon im = (XimCommon)client_data;
00143   SwitcherInfo *sw_info = im->switcher_info;
00144 
00145   if (sw_info && sw_info->switcher_window == w)
00146     {
00147       sw_info->switcher_window = None;
00148       Xfree (sw_info);
00149       im->switcher_info = NULL;
00150       return True;
00151     }
00152   return False;
00153 }
00154 
00155 Bool
00156 im_switcher_new (XimCommon im)
00157 {
00158   Display *display = im->core.display;
00159   SwitcherInfo *sw_info = im->switcher_info;
00160   Window owner = None;
00161 
00162   if (sw_info == NULL)
00163     {
00164       sw_info = Xmalloc (sizeof(SwitcherInfo));
00165       if (sw_info == NULL)
00166        return False;
00167       memset(sw_info, 0, sizeof(SwitcherInfo));
00168       im->switcher_info = sw_info;
00169     }
00170 
00171   if (selection == None)
00172     selection  = XInternAtom (display, "_IIIM_SWITCHER", False);
00173 
00174   sw_info->selection_atom = selection;
00175 
00176   owner = XGetSelectionOwner (display, selection);
00177   if (owner == None)
00178     return False;
00179 
00180   sw_info->switcher_window = owner;
00181 
00182   _XRegisterFilterByType (display, owner,
00183                        DestroyNotify, DestroyNotify,
00184                        filter_destroy_event, (XPointer)im);
00185 
00186   XSelectInput (display, owner, StructureNotifyMask);
00187 
00188   sw_info->set_current_input_language_atom
00189     = XInternAtom (display, "_IIIM_SWITCHER_CURRENT_INPUT_LANGUAGE", False);
00190 
00191   sw_info->set_current_client_atom =
00192     XInternAtom (display, "_IIIM_SWITCHER_CURRENT_CLIENT", False);
00193 
00194   sw_info->set_status_text_atom =
00195     XInternAtom (display, "_IIIM_SWITCHER_STATUS_TEXT", False);
00196 
00197   sw_info->set_input_language_list_atom =
00198     XInternAtom (display, "_IIIM_SWITCHER_INPUT_LANGUAGE_LIST", False);
00199 
00200   sw_info->set_conversion_mode_atom = 
00201     XInternAtom (display, "_IIIM_SWITCHER_SET_CONVERSION_MODE", False);
00202 
00203   sw_info->set_hotkey_atom =
00204     XInternAtom (display, "_IIIM_SWITCHER_SET_HOTKEY", False);
00205 
00206   return True;
00207 }
00208 
00209 void
00210 im_switcher_shutdown (XimCommon im)
00211 {
00212   SwitcherInfo *sw_info = im->switcher_info;
00213   Display *display = im->core.display;
00214 
00215   if (sw_info && sw_info->switcher_window)
00216     _XUnregisterFilter (display, sw_info->switcher_window,
00217                      filter_destroy_event, (XPointer)im);
00218 }
00219 
00220 static Bool
00221 property_notify_switcher_window(Display *d, Window w, XEvent *ev,
00222                             XPointer client_data)
00223 {
00224   XicCommon ic = (XicCommon)client_data;
00225   XimCommon im = (XimCommon)ic->core.im;
00226   Atom type;
00227   unsigned char *data = NULL;
00228   int format;
00229   unsigned long length = 0, bytes_after;
00230   Display *display = ic->core.im->core.display;
00231   SwitcherInfo *sw_info = im->switcher_info;
00232 
00233   if (ev->xproperty.atom == sw_info->set_current_input_language_atom)
00234     {
00235       XGetWindowProperty(display, w, ev->xproperty.atom, 0L, 1000000L,
00236                       False, AnyPropertyType, &type, &format,
00237                       &length, &bytes_after, (unsigned char **)&data);
00238       ic_initialize_with_input_language (ic, data);
00239       Xfree (data);
00240       return True;
00241     }
00242   if (ev->xproperty.atom == sw_info->set_conversion_mode_atom)
00243     {
00244       XGetWindowProperty(display, w, ev->xproperty.atom, 0L, 1000000L,
00245                       False, AnyPropertyType, &type, &format,
00246                       &length, &bytes_after, (unsigned char **)&data);
00247       ic_change_conversion_mode (ic, data);
00248       Xfree (data);
00249       return True;
00250     }
00251   return False;
00252 }
00253 
00254 static Bool
00255 destroy_switcher_window(Display *d, Window window, XEvent *ev,
00256                      XPointer client_data)
00257 {
00258   XicCommon ic = (XicCommon)client_data;
00259   SwitcherContext *w = ic->switcher_context;
00260 
00261   if (!w)
00262     return False;
00263   XDestroyWindow (d, w->invisible);
00264   Xfree (w);
00265   ic->switcher_context = NULL;
00266   return False;
00267 }
00268 
00269 void
00270 ic_switcher_new (XicCommon ic)
00271 {
00272   SwitcherContext *w = Xmalloc(sizeof(SwitcherContext));
00273   XimCommon im = (XimCommon)ic->core.im;
00274   Display *display = im->core.display;
00275 
00276   if (w == NULL)
00277     return;
00278 
00279   memset(w, 0, sizeof(SwitcherContext));
00280 
00281   w->invisible = XCreateSimpleWindow(display, DefaultRootWindow(display),
00282                                  0, 0, 1, 1, 0, 0, 0);
00283   XSelectInput(display, w->invisible,
00284               PropertyChangeMask| StructureNotifyMask);
00285 
00286   _XRegisterFilterByType(display, w->invisible,
00287                       PropertyNotify, PropertyNotify,
00288                       property_notify_switcher_window, (XPointer)ic);
00289   _XRegisterFilterByType(display, w->invisible,
00290                       DestroyNotify, DestroyNotify,
00291                       destroy_switcher_window, (XPointer)ic);
00292   ic->switcher_context = w;
00293 }
00294 
00295 void
00296 ic_switcher_finalize (XicCommon ic)
00297 {
00298   SwitcherContext *w = ic->switcher_context;
00299   XimCommon im = (XimCommon)ic->core.im;
00300   Display *display = im->core.display;
00301 
00302   if (w == NULL)
00303     return;
00304 
00305   _XUnregisterFilter(display, w->invisible,
00306                    property_notify_switcher_window, (XPointer)ic);
00307   _XUnregisterFilter(display, w->invisible,
00308                    destroy_switcher_window, (XPointer)ic);
00309 
00310   XDestroyWindow (display, w->invisible);
00311 
00312   Xfree (w);
00313   ic->switcher_context = NULL;
00314   return;
00315 
00316 }
00317 
00318 void
00319 ic_switcher_set_language_list (XicCommon ic,
00320                             IIIMCF_language *lang_list,
00321                             int n_lang)
00322 {
00323   Display *display = ic->core.im->core.display;
00324   XimCommon im = (XimCommon)ic->core.im;
00325   SwitcherInfo *sw_info = im->switcher_info;
00326   char *languages;
00327   char *ptr;
00328   IIIMF_status st;
00329   char *langid;
00330   int i;
00331   size_t len;
00332   const char *separator = ";";
00333   size_t separator_len;
00334 
00335   if (sw_info == NULL)
00336     return;
00337 
00338   if (lang_list == NULL || n_lang == 0)
00339     return;
00340 
00341   if (sw_info->switcher_window == None)
00342     return;
00343 
00344   /* First part, getting length */
00345   st = iiimcf_get_language_id (lang_list[0],
00346                             (const char **) &langid);
00347   if (st != IIIMF_STATUS_SUCCESS)
00348     return;
00349 
00350   separator_len = strlen (separator);
00351   len = strlen (langid);
00352   for (i = 1; i < n_lang; i++)
00353     {
00354       st = iiimcf_get_language_id (lang_list[i],
00355                                (const char **) &langid);
00356       if (st != IIIMF_STATUS_SUCCESS)
00357        continue;
00358       len += strlen (langid);
00359     }
00360   len += separator_len * (i - 1);
00361 
00362   /* Second part, building string */
00363   languages = Xmalloc (sizeof(char) * (len + 1));
00364   if (languages == NULL)
00365     return;
00366   memset(languages, 0, sizeof(char) * (len + 1));
00367 
00368   st = iiimcf_get_language_id (lang_list[0],
00369                             (const char **) &langid);
00370   ptr = my_stpcpy (languages, langid);
00371   for (i = 1; i < n_lang; i++)
00372     {
00373       ptr = my_stpcpy (ptr, separator);
00374       st = iiimcf_get_language_id (lang_list[i],
00375                                (const char **) &langid);
00376       if (st != IIIMF_STATUS_SUCCESS)
00377        continue;
00378       ptr = my_stpcpy (ptr, langid);
00379     }
00380 
00381   XChangeProperty (display, sw_info->switcher_window,
00382                  sw_info->set_input_language_list_atom,
00383                  sw_info->set_input_language_list_atom,
00384                  8,
00385                  PropModeReplace,
00386                  (unsigned char*)languages, len);
00387   Xfree (languages);
00388 }
00389 
00390 void
00391 ic_switcher_set_status_text (XicCommon ic, char *utf8)
00392 {
00393   Display *display = ic->core.im->core.display;
00394   XimCommon im = (XimCommon)ic->core.im;
00395   SwitcherInfo *sw_info = im->switcher_info;
00396 
00397   if (sw_info == NULL || sw_info->switcher_window == None ||
00398       utf8 == NULL)
00399     return;
00400 
00401   XChangeProperty (display,
00402                  sw_info->switcher_window,
00403                  sw_info->set_status_text_atom,
00404                  sw_info->set_status_text_atom,
00405                  8,
00406                  PropModeReplace,
00407                  (unsigned char *)utf8,
00408                  strlen (utf8));
00409 }
00410 
00411 void
00412 ic_switcher_set_focus (XicCommon ic)
00413 {
00414   Display *display = ic->core.im->core.display;
00415   XimCommon im = (XimCommon)ic->core.im;
00416   SwitcherInfo *sw_info;
00417   SwitcherContext *w;
00418 
00419   if (!im_switcher_active (im))
00420     {
00421       im_switcher_new (im);
00422       if (!im_switcher_active (im))
00423        return;
00424     }
00425 
00426   if (ic->switcher_context == NULL)
00427     ic_switcher_new (ic);
00428 
00429   w = ic->switcher_context;
00430   sw_info = im->switcher_info;
00431 
00432   if (w && w->invisible)
00433     XConvertSelection (display,
00434                      sw_info->selection_atom,
00435                      sw_info->set_current_client_atom,
00436                      sw_info->set_current_client_atom,
00437                      w->invisible,
00438                      CurrentTime);
00439 }
00440 
00441 void
00442 ic_switcher_set_hotkey (XicCommon ic, char *hotkey)
00443 {
00444   Display *display = ic->core.im->core.display;
00445   XimCommon im = (XimCommon)ic->core.im;
00446   SwitcherInfo *sw_info = im->switcher_info;
00447 
00448   if (!sw_info || !hotkey) return;
00449 
00450   XChangeProperty (display,
00451                  sw_info->switcher_window,
00452                  sw_info->set_hotkey_atom,
00453                  sw_info->set_hotkey_atom,
00454                  8,
00455                  PropModeReplace,
00456                  (unsigned char *)hotkey,
00457                  strlen (hotkey));
00458 }
00459 
00460 void
00461 ic_switcher_set_input_language (XicCommon ic, char *input_lang)
00462 {
00463   Display *display = ic->core.im->core.display;
00464   XimCommon im = (XimCommon)ic->core.im;
00465   SwitcherInfo *sw_info = im->switcher_info;
00466 
00467   if (sw_info == NULL)
00468     return;
00469 
00470   if (input_lang == NULL)
00471     input_lang = ic->current_language;
00472 
00473   if (input_lang == NULL)
00474     return;
00475 
00476   XChangeProperty (display,
00477                  sw_info->switcher_window,
00478                  sw_info->set_current_input_language_atom,
00479                  sw_info->set_current_input_language_atom,
00480                  8,
00481                  PropModeReplace,
00482                  (unsigned char *)input_lang,
00483                  strlen (input_lang));
00484 }
00485 
00486 void
00487 ic_switcher_set_conversion_mode (XicCommon ic)
00488 {
00489   Display *display = ic->core.im->core.display;
00490   XimCommon im = (XimCommon)ic->core.im;
00491   SwitcherInfo *sw_info = im->switcher_info;
00492   IIIMF_status st;
00493   int conversion_mode = CONV_OFF;
00494 
00495   if (sw_info == NULL || sw_info->switcher_window == None)
00496     return;
00497 
00498   st = iiimcf_get_current_conversion_mode (XIC_IIIMP(ic, context),
00499                                       &conversion_mode);
00500   XChangeProperty (display,
00501                  sw_info->switcher_window,
00502                  sw_info->set_conversion_mode_atom,
00503                  sw_info->set_conversion_mode_atom,
00504                  32,
00505                  PropModeReplace,
00506                  (unsigned char *)&conversion_mode,
00507                  1);
00508 }
00509 
00510 static void
00511 my_strfreev (char **string)
00512 {
00513   char **p = string;
00514 
00515   if (!string) return;
00516 
00517   while (*p)
00518     {
00519       char *t = *p++;
00520       if (t) free (t);
00521     }
00522 
00523   free (string);
00524 }
00525 
00526 static int
00527 my_strv_length (char **string)
00528 {
00529   int n = 0;
00530 
00531   if (!string) return n;
00532 
00533   while (string[n]) ++n;
00534 
00535   return n;
00536 }
00537 
00538 char **
00539 my_strsplit (const char *string,
00540            const char *single_delimiter)
00541 {
00542   char *remainder;
00543   char **str_array, *s;
00544   int n = 0;
00545 
00546   remainder = string;
00547   s = strstr (remainder, single_delimiter);
00548   while (s)
00549     {
00550       remainder = s + 1;
00551       s = strstr (remainder, single_delimiter);
00552       ++n;
00553     }
00554   if (*string) ++n;
00555 
00556   str_array = (char **) malloc (sizeof(char *) * (n + 1));
00557 
00558   n = 0;
00559   remainder = string;
00560   s = strstr (remainder, single_delimiter);
00561   while (s)
00562     {
00563       int len;
00564       char *new_string;
00565 
00566       len = s - remainder;
00567       str_array[n++] = new_string = malloc (len + 1);
00568       strncpy (new_string, remainder, len);
00569       new_string[len] = 0;
00570 
00571       remainder = s + 1;
00572       s = strstr (remainder, single_delimiter);
00573     }
00574   if (*string)
00575     str_array[n++] = strdup (remainder);
00576 
00577   str_array[n] = 0;
00578   
00579   return str_array;
00580 }
00581 
00582 char *
00583 ic_switcher_get_hotkey_with_type (char *string,
00584                               char *type)
00585 {
00586   char *label_delimiter = ":";
00587   char **hotkeys = my_strsplit (string, label_delimiter);
00588   int num_hotkeys = 0, i;
00589   char *keys = NULL;
00590 
00591   num_hotkeys = my_strv_length (hotkeys) / 2;
00592 
00593   for (i = 0; i < num_hotkeys; ++i)
00594     {
00595       if (!strcasecmp (hotkeys[i * 2], type))
00596        {
00597          keys = strdup (hotkeys[i * 2 + 1]);
00598          break;
00599        }
00600     }
00601 
00602   my_strfreev (hotkeys);
00603 
00604   return keys;
00605 }
00606 
00607 char *
00608 ic_switcher_get_hotkey (XicCommon ic)
00609 {
00610   IIIMCF_context context = XIC_IIIMP (ic, context);
00611   int num_hotkey = 0, i;
00612   IIIMCF_hotkey *hotkeys = NULL;
00613   char s[512], *p = s;
00614 
00615   iiimcf_get_hotkeys (context, &num_hotkey, &hotkeys);
00616 
00617   if (num_hotkey == 0) return NULL;
00618 
00619   memset (s, 0, 512);
00620 
00621   for (i = 0; i < num_hotkey; ++i)
00622     {
00623       char label_delimiter = ':';
00624       char key_delimiter = ',';
00625       int k;
00626 
00627       strcpy (p, hotkeys[i].hotkey_label);
00628       p += strlen (hotkeys[i].hotkey_label);
00629       *p++ = label_delimiter;
00630 
00631       for (k = 0; k < hotkeys[i].nkeys; ++k)
00632        {
00633          IIIMCF_keyevent *key = hotkeys[i].keys + k;
00634          unsigned int keyval;
00635          char *keyname;
00636 
00637          if (k) *p++ = key_delimiter;
00638 
00639          if (key->modifier & IIIMF_CONTROL_MODIFIER)
00640            {
00641              strcpy (p, "Ctrl+");
00642              p += strlen ("Ctrl+");
00643            }
00644          if (key->modifier & IIIMF_SHIFT_MODIFIER)
00645            {
00646              strcpy (p, "Shift+");
00647              p += strlen ("Shift+");
00648            }
00649          if (key->modifier & IIIMF_ALT_MODIFIER)
00650            {
00651              strcpy (p, "Alt+");
00652              p += strlen ("Alt+");
00653            }
00654 
00655          keyval = i2gcode (key->keycode);
00656          keyname = x11_keyval_name (keyval);
00657 
00658          if (keyname)
00659            {
00660              strcpy (p, keyname);
00661              p += strlen (keyname);
00662            }
00663        }
00664 
00665       if (i < num_hotkey - 1) *p++ = label_delimiter;
00666     }
00667 
00668   return strdup (s);
00669 }
00670 
00671 static void
00672 change_hotkey_with_type (XicCommon ic,
00673                       char *type,
00674                       int num_keys,
00675                       IIIMCF_keyevent *keys)
00676 {
00677   IIIMCF_context context = XIC_IIIMP (ic, context);
00678   XimCommon im = (XimCommon)ic->core.im;
00679   IIIMCF_handle handle = XIM_IIIMP (im, handle);
00680   int num_hotkey = 0, i;
00681   IIIMCF_hotkey *hotkeys = NULL;
00682 
00683   iiimcf_get_hotkeys (context, &num_hotkey, &hotkeys);
00684 
00685   if (num_hotkey == 0) return;
00686 
00687   for (i = 0; i < num_hotkey; ++i)
00688     {
00689       if (!strcasecmp (type, hotkeys[i].hotkey_label))
00690        {
00691          int size = sizeof (IIIMCF_keyevent) * num_keys;
00692 
00693          if (hotkeys[i].nkeys < num_keys)
00694            {
00695              free (hotkeys[i].keys);
00696 
00697              hotkeys[i].keys = (char *)malloc (size);
00698              memset (hotkeys[i].keys, 0, size);
00699            }
00700 
00701          hotkeys[i].nkeys = num_keys;
00702          memcpy (hotkeys[i].keys, keys, size);
00703        }
00704     }
00705 
00706   /* change the onkeys and off keys if the target type is TRIGGER_KEY_LABEL */
00707   if (handle && !strcasecmp (type, TRIGGER_KEY_LABEL))
00708     {
00709       int num_on_keys = 0, num_off_keys = 0;
00710       static int initial_num_on_keys = 0, initial_num_off_keys = 0;
00711       IIIMCF_keyevent *onkeys, *offkeys;
00712 
00713       iiimcf_get_trigger_keys (handle, &num_on_keys, &onkeys,
00714                             &num_off_keys, &offkeys);
00715 
00716       if (!initial_num_on_keys && !initial_num_off_keys)
00717        {
00718          initial_num_on_keys = num_on_keys;
00719          initial_num_off_keys = num_off_keys;
00720        }
00721 
00722       num_keys = initial_num_on_keys < num_keys ? initial_num_on_keys : num_keys;
00723       memcpy (onkeys, keys, sizeof (IIIMCF_keyevent) * num_keys);
00724       memset (onkeys + num_keys, 0, sizeof (IIIMCF_keyevent) * (initial_num_on_keys - num_keys));
00725 
00726       num_keys = initial_num_off_keys < num_keys ? initial_num_off_keys : num_keys;
00727       memcpy (offkeys, keys, sizeof (IIIMCF_keyevent) * num_keys);
00728       memset (offkeys + num_keys, 0, sizeof (IIIMCF_keyevent) * (initial_num_off_keys - num_keys));
00729     }
00730 }
00731 
00732 /*
00733  * the triggerkey is set by gimlet with set_hotkey_atom, gimlet will validate
00734  * its content before change the content of atom.
00735  * Usually the format of hotkey would take "Ctrl+space,Kanji,Shift+Kanji".
00736  */
00737 static void
00738 convert_hotkey_to_IIIMCF_keyevent (char *triggerkey,
00739                                int *num_keys,
00740                                IIIMCF_keyevent **keys)
00741 {
00742   char *key_delimiter = ",";
00743   char **hotkeys = my_strsplit (triggerkey, key_delimiter);
00744   int i;
00745 
00746   if (hotkeys == NULL) return;
00747 
00748   *num_keys = my_strv_length (hotkeys);
00749 
00750   *keys = (IIIMCF_keyevent *)malloc (sizeof (IIIMCF_keyevent) * (*num_keys));
00751   memset (*keys, 0, sizeof (IIIMCF_keyevent) * (*num_keys));
00752 
00753   for (i=0; i < *num_keys; ++i)
00754     {
00755       char *key_separator = "+";
00756       char **k, **keys_text = my_strsplit (hotkeys[i], key_separator);
00757 
00758       k = keys_text;
00759       for (; *k; ++k)
00760        {
00761          if (!strcasecmp (*k, "Ctrl"))
00762            (*keys)[i].modifier |= IIIMF_CONTROL_MODIFIER;
00763          else if (!strcasecmp (*k, "Shift"))
00764            (*keys)[i].modifier |= IIIMF_SHIFT_MODIFIER;
00765          else if (!strcasecmp (*k, "Alt"))
00766            (*keys)[i].modifier |= IIIMF_ALT_MODIFIER;
00767          else
00768            {
00769              unsigned int keyval = x11_keyval_from_name (*k);
00770              int keycode = g2icode (keyval);
00771              (*keys)[i].keycode = keycode < 0 ? -keycode : keycode;
00772            }
00773        }
00774 
00775       my_strfreev (keys_text);
00776     }
00777 
00778   my_strfreev (hotkeys);
00779 }
00780 
00781 void
00782 ic_switcher_change_hotkey_with_type (XicCommon ic,
00783                                  char *type,
00784                                  char *string)
00785 {
00786   int num_keys;
00787   IIIMCF_keyevent *keys;
00788 
00789   convert_hotkey_to_IIIMCF_keyevent (string, &num_keys, &keys);
00790 
00791   change_hotkey_with_type (ic, type, num_keys, keys);
00792 
00793   free (keys);
00794 }
00795 
00796 char *
00797 ic_switcher_get_hotkey_with_atom (XicCommon ic)
00798 {
00799   Display *display = ic->core.im->core.display;
00800   XimCommon im = (XimCommon)ic->core.im;
00801   SwitcherInfo *sw_info = im->switcher_info;
00802   int format;
00803   unsigned long length, nitem;
00804   unsigned char *data = NULL;
00805   Atom type;
00806    
00807   if (!im_switcher_active (im))
00808     return NULL;
00809 
00810   XGetWindowProperty (display,
00811                     sw_info->switcher_window,
00812                     sw_info->set_hotkey_atom,
00813                     0L, 1000000L, False,
00814                     sw_info->set_hotkey_atom,
00815                     &type, &format, &nitem, &length, &data);
00816 
00817   return data;
00818 }