Back to index

im-sdk  12.3.91
popupIM.c
Go to the documentation of this file.
00001 /*
00002 Copyright 1990-2001 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 #ifdef HAVE_CONFIG_H
00043 #include <config.h>
00044 #endif
00045 
00046 #include <stdio.h>
00047 #include "xiiimp.h"
00048 #include "popupIM.h"
00049 #include "iiimpIM.h"
00050 #include "guiIMSts.h"
00051 #include "Xlcint.h"
00052 #include "composeIM.h"
00053 
00054 #include "status.h"
00055 #include "codeinput.h"
00056 #include "tableinput.h"
00057 #include "xfactory.h"
00058 
00059 static Bool isLanguageSupported(XicCommon , char *);
00060 static char *getDisplayLanguageFromState(XimCommon im, char *localename);
00061  
00062 static void CallSwitchIMNotifyCallback(XicCommon ic,
00063                                    XIMUnicodeCharacterSubset *aSubset);
00064 #define xMargin 4
00065 #define yMargin 5
00066 #define cMargin 0
00067 
00068 Bool
00069 SwitchRemoteIMState(XicCommon ic, char *localename) {
00070   if (!isLanguageSupported(ic, localename)) {
00071      return False;
00072   }    
00073   XIC_GUI((XIC)ic, change_lookup)((XIC)ic, LOOKUP_DONE,
00074                                   (XPointer)NULL);
00075   XIC_GUI((XIC)ic, change_preedit)((XIC)ic, PREEDIT_DONE,
00076                                    (XPointer)NULL);
00077   XIC_GUI((XIC)ic, change_status)((XIC)ic, STATUS_DONE,
00078                                   (XPointer)NULL);
00079   IMTriggerNotify(ic, CONV_OFF);
00080   SetConversionMode(ic, False);
00081   IMSetPrimaryLocale(ic, localename);
00082   IMTriggerNotify(ic, CONV_ON);
00083   SetConversionMode(ic, True);
00084   return True;
00085 }
00086 
00087 static XFontSet
00088 status_window_fontset(XicCommon ic) {
00089   XFontSet fs = 0;
00090   fs = ic->core.status_attr.fontset;
00091   if (!fs) {
00092     StatusWin status;
00093     SetStatusFont((XicCommon)ic, 0);      /* call_data can be 0 */
00094     status = (StatusWin)ic->gui_icpart->status;
00095     if (status)
00096       fs = status->fontset;
00097   }
00098   return fs;
00099 }
00100 
00101 static unsigned int
00102 status_window_height(XicCommon ic) {
00103   unsigned int height = ic->core.status_attr.area.height;
00104   if (height == 0) {
00105     XFontSet fs;
00106     if ((fs = status_window_fontset(ic))) {
00107       XFontSetExtents *fse;
00108       fse = XExtentsOfFontSet(fs);
00109       height = fse->max_logical_extent.height;
00110       height += (fse->max_ink_extent.height + fse->max_ink_extent.y);
00111     }
00112   }
00113   if (height == 0) height = 19;    /* may not work */
00114   return height;
00115 }
00116 
00117 static Bool
00118 status_window_fg_and_bg(XicCommon ic, unsigned long *fg,
00119                      unsigned long *bg) {
00120   Display *display = ic->core.im->core.display;
00121   Bool ret_val = True;
00122 
00123   if (XIMP_CHK_STSFGMASK(ic) && XIMP_CHK_STSBGMASK(ic)) {
00124     *fg = ic->core.status_attr.foreground;
00125     *bg = ic->core.status_attr.background;
00126   } else {
00127     *fg = BlackPixel(display, DefaultScreen(display));
00128     *bg = WhitePixel(display, DefaultScreen(display));
00129     ret_val = False;
00130   }
00131   return ret_val;
00132 }
00133 
00134 static int
00135 getChoiceIndex(XicCommon ic, XEvent *event) {
00136   int x = event->xbutton.x;
00137   int y = event->xbutton.y;
00138   int h;
00139   int index;
00140 
00141   x += XIC_POPUP(ic, menu_offset_x);
00142   y += XIC_POPUP(ic, menu_offset_y);
00143 
00144   x = (x < xMargin ? 0: x - xMargin);
00145   y = (y < yMargin ? 0: y - yMargin);
00146 
00147   index = 0;
00148   h = status_window_height(ic);
00149   while (h < y) {
00150     h += status_window_height(ic);
00151     index++;
00152   }
00153   if (index != XIC_POPUP(ic, menu_index)) {
00154     if (-1 != XIC_POPUP(ic, menu_index_pre)) {
00155       XIC_POPUP(ic, menu_index_pre) = XIC_POPUP(ic, menu_index);
00156     }
00157     XIC_POPUP(ic, menu_index) = index;
00158   }
00159   return index;
00160 }
00161 
00162 
00163 typedef struct _lang_pair {
00164   char *input_language;
00165   char *display_language;
00166 } lang_pair;
00167 
00168 static lang_pair displayLanguage[] = {
00169   {"ja", "[ Japanese ]"},
00170   {"ko", "[ Korean ]"},
00171   {"zh_CN", "[ S-Chinese ]"},
00172   {"zh_TW", "[ T-Chinese ]"}
00173 };
00174 
00175 static void
00176 DrawText(XicCommon ic, XFontSet fs, GC gc, int x, int y,
00177         char *utf8_text)
00178 {
00179   size_t len;
00180 
00181   len = strlen(utf8_text);
00182   if (XIM_USE_UNICODE(ic->core.im)) {
00183     size_t native_len = 64; /* enough */
00184     char buffer[64], *pbuffer;
00185     memset(&buffer, 0, 64);
00186     pbuffer = buffer;
00187     if (IMConvertFromUTF8(utf8_text, len,
00188                        (char**)&pbuffer, &native_len) != -1) {
00189       XmbDrawImageString(ic->core.im->core.display,
00190                       XIM_POPUP(ic->core.im, window),
00191                       fs, gc,
00192                       x, y, buffer, 64 - native_len);
00193       return;
00194     }
00195   }
00196   XmbDrawImageString(ic->core.im->core.display,
00197                    XIM_POPUP(ic->core.im, window),
00198                    fs, gc,
00199                    x, y, utf8_text, len);
00200 }
00201 
00202 static unsigned int
00203 TextEscapement(XicCommon ic, XFontSet fs, char *utf8_text)
00204 {
00205   size_t len;
00206   len = strlen(utf8_text);
00207   if (XIM_USE_UNICODE(ic->core.im)) {
00208     size_t native_len = 64; /* enough */
00209     char buffer[64], *pbuffer;
00210     memset(&buffer, 0, 64);
00211     pbuffer = buffer;
00212     if (IMConvertFromUTF8(utf8_text, len,
00213                        (char**)&pbuffer, &native_len) != -1) {
00214       return XmbTextEscapement(fs, buffer, 64 - native_len);
00215     }
00216   }
00217   return XmbTextEscapement(fs, utf8_text, len);
00218 }
00219 
00220 static char*
00221 convertToDisplayLanguage(char *src) {
00222   size_t num = sizeof(displayLanguage)/sizeof(displayLanguage[0]);
00223   lang_pair *p;
00224   for (p = displayLanguage; p < &displayLanguage[num]; p++) {
00225     if (!strcmp(p->input_language, src))
00226       return p->display_language;
00227   }
00228   return (char*)src;
00229 }
00230 static void
00231 update_menu(XicCommon ic) {
00232   int y, n;
00233   XFontSet fs = status_window_fontset(ic);
00234   if (!fs) return;
00235 
00236   y = 0;
00237   n = 1;
00238   if (XIM_IS_COMPOSE(ic->core.im)) {
00239     XIMComposeIM lim = ((XimCommon)ic->core.im)->local_impart;
00240     LocalIMState *state = lim->top_state;
00241 
00242     while (state) {
00243       if (state->type == RemoteIMState) {
00244        state = state->next;
00245        continue;
00246       }
00247       y += status_window_height(ic);
00248       if (n == XIC_POPUP(ic, menu_index)) {
00249        DrawText(ic, fs, XIM_POPUP(ic->core.im, rgc),
00250                xMargin, y, state->name);
00251       } else if ((-1 == XIC_POPUP(ic, menu_index_pre)) ||
00252                (n == XIC_POPUP(ic, menu_index_pre))) {
00253        DrawText(ic, fs, XIM_POPUP(ic->core.im, gc),
00254                xMargin, y, state->name);
00255       }
00256       n++;
00257       state = state->next;
00258     }
00259   }
00260   if (XIM_IS_IIIMP(ic->core.im)) {
00261     XIMText *language_list = XIM_IIIMP(ic->core.im, supported_languages);
00262     int number = XIM_IIIMP(ic->core.im, count_languages);
00263     if (language_list) {
00264       XIMText *p;
00265       for (p = language_list; p < &language_list[number]; p++) {
00266         char *display_lang =
00267          getDisplayLanguageFromState((XimCommon)ic->core.im,
00268                                   p->string.multi_byte);
00269        if (!display_lang) {
00270           display_lang = convertToDisplayLanguage(p->string.multi_byte);
00271        } 
00272         y += status_window_height(ic);
00273         if (n == XIC_POPUP(ic, menu_index)) {
00274          DrawText(ic, fs, XIM_POPUP(ic->core.im, rgc),
00275                  xMargin, y, display_lang);
00276         } else if ((-1 == XIC_POPUP(ic, menu_index_pre)) ||
00277                    (n == XIC_POPUP(ic, menu_index_pre))) {
00278          DrawText(ic, fs, XIM_POPUP(ic->core.im, gc),
00279                  xMargin, y, display_lang);
00280         }
00281         n++;
00282       }
00283     }
00284   }
00285   return;
00286 }
00287 
00288 static Bool
00289 repaint_menu(Display *d, Window w, XEvent *ev,
00290             XPointer client_data) {
00291   update_menu((XicCommon)client_data);
00292   return True;
00293 }
00294 
00295 static Bool
00296 motion_menu(Display *d, Window w, XEvent *ev,
00297             XPointer client_data) {
00298   XicCommon ic = (XicCommon)client_data;
00299   if (getChoiceIndex(ic, ev) == -1) return True;
00300   update_menu(ic);
00301   return True;
00302 }
00303 
00304 static void
00305 get_menu_size(XicCommon ic, unsigned int *w, unsigned int *h) {
00306   unsigned int width, height, temp;
00307   XFontSet fs = status_window_fontset(ic);
00308 
00309   if (!fs) return;
00310 
00311   width = 0;
00312   height = 0;
00313   if (XIM_IS_COMPOSE(ic->core.im)) {
00314     XIMComposeIM lim = ((XimCommon)ic->core.im)->local_impart;
00315     LocalIMState *state = lim->top_state;
00316     while (state) {
00317       size_t len;    
00318       if (state->type == RemoteIMState) {
00319            state = state->next;
00320            continue;
00321       }
00322       len = strlen(state->name);
00323       temp = TextEscapement(ic, fs, state->name);
00324       width = (temp > width) ? temp : width;
00325       height += status_window_height(ic);
00326       state = state->next;
00327     }
00328   }
00329   if (XIM_IS_IIIMP(ic->core.im)) {
00330     XIMText *language_list = XIM_IIIMP(ic->core.im, supported_languages);
00331     int number = XIM_IIIMP(ic->core.im, count_languages);
00332     if (language_list) {
00333       XIMText *p;
00334       size_t len;    
00335       for (p = language_list; p < &language_list[number]; p++) {
00336         char *display_lang =
00337           getDisplayLanguageFromState((XimCommon)ic->core.im,
00338                                    p->string.multi_byte);
00339        if (!display_lang) {
00340           display_lang = convertToDisplayLanguage(p->string.multi_byte);
00341         }
00342         len = strlen(display_lang);
00343         temp = TextEscapement(ic, fs, display_lang);
00344         width = (temp > width) ? temp : width;
00345         height += status_window_height(ic);
00346       }
00347     }
00348   }
00349   if (width != 0) *w = width + xMargin * 2;
00350   if (height != 0) *h = height + yMargin;
00351 }
00352 
00353 static Bool
00354 map_notify_filter(Display *d, Window w, XEvent *ev,
00355                 XPointer client_data) {
00356   XicCommon ic = (XicCommon)client_data;
00357   if (-2 == XIC_POPUP(ic, menu_index_pre)) {
00358          XUnmapWindow(d, w);
00359   }
00360   return True;
00361 }
00362 
00363 static Bool
00364 unmap_notify_filter(Display *d, Window w, XEvent *ev,
00365                 XPointer client_data) {
00366   _XUnregisterFilter(d, w, repaint_menu, client_data);
00367   _XUnregisterFilter(d, w, map_notify_filter, client_data);
00368   _XUnregisterFilter(d, w, unmap_notify_filter, client_data);
00369 
00370   return True;
00371 }
00372 
00373 static void
00374 popup_menu(XicCommon ic, int x, int y, Window status_window, XEvent *ev) {
00375   XSizeHints hints;
00376   unsigned int width;
00377   unsigned int height;
00378   unsigned long val_mask;
00379   XGCValues gcval;
00380   int  new_x;
00381   int  new_y;
00382   XIMPopup popup_impart = 0;
00383   unsigned long bg, fg;
00384   Bool use_client_color;
00385   Display *display = ic->core.im->core.display;
00386   XIM im = ic->core.im;
00387 
00388   if (!display) return;
00389 
00390   if (!ic->popup_icpart) {
00391     ic->popup_icpart = Xmalloc(sizeof(XICPopupRec));
00392     if (!ic->popup_icpart) return;
00393     memset(ic->popup_icpart, 0, sizeof(XICPopupRec));
00394   }
00395   XIC_POPUP(ic, menu_index) = -1;
00396   XIC_POPUP(ic, menu_index_pre) = -1;
00397   XIC_POPUP(ic, menu_offset_x) = 0;
00398   XIC_POPUP(ic, menu_offset_y) = 0;
00399 
00400   popup_impart = ((XimCommon)im)->popup_impart;
00401   if (!popup_impart) {
00402 
00403     popup_impart = (XIMPopup)Xmalloc(sizeof(XIMPopupRec));
00404     if (!popup_impart) {
00405       return;
00406     }
00407     memset(popup_impart, 0, sizeof(XIMPopupRec));
00408     ((XimCommon)ic->core.im)->popup_impart = popup_impart;
00409   }
00410 
00411   use_client_color = status_window_fg_and_bg(ic, &fg, &bg);
00412   if (!XIM_POPUP(im, window)) {
00413     if (use_client_color) {
00414        XIM_POPUP(im, window) = XCreateSimpleWindow(display,
00415                                           ic->core.client_window,
00416                                           0, 0, 1, 1, 0, 0, bg);
00417        if (XIM_POPUP(im, window)) {
00418          XReparentWindow(display, XIM_POPUP(im, window),
00419                             DefaultRootWindow(display), 0, 0);
00420        }             
00421     } else {
00422        XIM_POPUP(im, window) = XCreateSimpleWindow(display,
00423                                           DefaultRootWindow(display),
00424                                           0, 0, 1, 1, 0, 0, bg);
00425     }
00426   }
00427   if (!XIM_POPUP(im, window)) {
00428     XFree(popup_impart);
00429     return;
00430   }
00431   val_mask = GCForeground | GCBackground;
00432   gcval.foreground = fg;
00433   gcval.background = bg;
00434 
00435   if (XIM_POPUP(im, gc)) XFreeGC(display, XIM_POPUP(im, gc));
00436   if (XIM_POPUP(im, rgc)) XFreeGC(display, XIM_POPUP(im, rgc));
00437 
00438   XIM_POPUP(im, gc) = XCreateGC(display,
00439                             XIM_POPUP(im, window), val_mask, &gcval);
00440   gcval.foreground = bg;
00441   gcval.background = fg;
00442 
00443   XIM_POPUP(im, rgc) = XCreateGC(display,
00444                              XIM_POPUP(im, window), val_mask, &gcval);
00445 
00446 #ifdef override_redirect
00447   attr.override_redirect = True;
00448   XChangeWindowAttributes(display, XIM_POPUP(im, window),
00449                        CWOverrideRedirect, &attr);
00450 #endif
00451   XFactoryRemoveDecoration(display, XIM_POPUP(im, window));
00452   XSelectInput(display, XIM_POPUP(im, window),
00453               KeyPressMask|ExposureMask|ButtonPressMask|ButtonReleaseMask|
00454               StructureNotifyMask|
00455               PointerMotionMask);
00456   _XRegisterFilterByType(display, XIM_POPUP(im, window),
00457                       Expose, Expose, repaint_menu, (XPointer)ic);
00458   _XRegisterFilterByType(display, XIM_POPUP(im, window),
00459                       MapNotify, MapNotify,
00460                       map_notify_filter, (XPointer)ic);
00461   _XRegisterFilterByType(display, XIM_POPUP(im, window),
00462                       UnmapNotify, UnmapNotify,
00463                       unmap_notify_filter, (XPointer)ic);
00464   width = 100;
00465   height = 200;
00466 
00467   get_menu_size(ic, &width, &height);
00468 
00469   XFactoryAdjustPlacementInsideScreen(display, XIM_POPUP(im, window),
00470                                   x, y, width, height,
00471                                   &new_x, &new_y);
00472   XIC_POPUP(ic, menu_offset_x) = x - new_x;
00473   XIC_POPUP(ic, menu_offset_y) = y - new_y;
00474 
00475   hints.flags = PPosition|PSize;
00476   hints.x = new_x;
00477   hints.y = new_y;
00478   hints.width = width;
00479   hints.height = height;
00480   XSetWMNormalHints(display, XIM_POPUP(im, window), &hints);
00481   XMoveResizeWindow(display, XIM_POPUP(im, window),
00482                   new_x, new_y, width, height);
00483   XIM_POPUP(im, x) = new_x; XIM_POPUP(im, y) = new_y;
00484   XIM_POPUP(im, width) = width; XIM_POPUP(im, height) = height;
00485 
00486   XMapWindow(display, XIM_POPUP(im, window));
00487   update_menu(ic);
00488 }
00489 
00490 static void
00491 popdown_menu(XicCommon ic) {
00492   XIC_POPUP(ic, menu_index_pre) = -2;
00493   XUnmapWindow(ic->core.im->core.display,
00494               XIM_POPUP(ic->core.im, window));
00495 }
00496 
00497 static int
00498 select_menu(XicCommon ic, int aIndex) {
00499   int index;
00500   int n_index = 1;
00501   XimCommon im = (XimCommon)ic->core.im;
00502 
00503   index = aIndex;
00504 
00505   if (index == 0 ||
00506       (im->unicode_char_subsets &&
00507        index > im->unicode_char_subsets->count_subsets))
00508     return False;
00509 
00510   if (XIM_IS_COMPOSE(ic->core.im)) {
00511     XIMComposeIM lim = ((XimCommon)ic->core.im)->local_impart;
00512     LocalIMState *state = lim->top_state;
00513 
00514     if (state) {                   /* using with localIM */
00515       while (state && --index > 0) {
00516        if (state->type == RemoteIMState) 
00517           n_index++;
00518        state = state->next;
00519       }
00520       if (index == 0) {
00521        if (ic->local_icpart->imstate == state &&
00522            state->type != LookupState && aIndex != 1) {
00523          /* same state, don't need to update, but if it is LookupState,
00524             we will get back to initial char-set choice mode */
00525          return False;
00526        }
00527        if (state->type == RemoteIMState) {
00528           /* Can ignore the return value */
00529 #ifdef USE_KEY_SWITCH
00530           SwitchRemoteIMState(ic, state->language);
00531 #else
00532           index = n_index;
00533           goto RemoteIMLabel;
00534 #endif
00535        }
00536        if (ic->local_icpart->imstate->type == CodeInputState) {
00537          /* previous state is CodeInput */
00538          Ximp_Local_Preedit_Done(ic);
00539        }
00540        if (ic->local_icpart->imstate->type == LookupState) {
00541          /* previous state is LookupInput */
00542          Ximp_Local_Table_Done(ic);
00543        }
00544 
00545        if (state->type != RemoteIMState) {
00546            ic->local_icpart->imstate = state;
00547            ic->local_icpart->context = ic->local_icpart->imstate->parser;
00548            Ximp_Local_Status_Set(ic);
00549            Ximp_Local_Status_Draw(ic);
00550            /* initialize internal state for next key sequence */
00551            ic->local_icpart->context = ic->local_icpart->imstate->parser;
00552         } else {
00553            ic->local_icpart->imstate = lim->top_state;
00554            ic->local_icpart->context = ic->local_icpart->imstate->parser;
00555        } 
00556        if (state->type == LookupState) {
00557          Ximp_Local_Table_Start(ic);
00558        }
00559       }
00560       if (XIM_IS_IIIMP(ic->core.im) && (index == 0)) {
00561        if (state->type != RemoteIMState) {
00562           IMTriggerNotify(ic, CONV_OFF);
00563           SetConversionMode(ic, False);
00564           /* IMSetFocus(ic);       */
00565           return True;
00566        }
00567       } else
00568        return False;
00569 RemoteIMLabel:
00570       if (index > 0) {
00571        /* select one from remote IM */
00572        XIMText *language_list = (XIMText*)0;
00573        int number;
00574 
00575        if (XIM_IS_IIIMP(ic->core.im)) {
00576          language_list = XIM_IIIMP(ic->core.im, supported_languages);
00577          number = XIM_IIIMP(ic->core.im, count_languages);
00578 
00579          if (!language_list) return False;
00580 
00581          if (index <= number) {
00582            XIC_GUI((XIC)ic, change_lookup)((XIC)ic, LOOKUP_DONE,
00583                                        (XPointer)NULL);
00584            XIC_GUI((XIC)ic, change_preedit)((XIC)ic, PREEDIT_DONE,
00585                                         (XPointer)NULL);
00586            XIC_GUI((XIC)ic, change_status)((XIC)ic, STATUS_DONE,
00587                                        (XPointer)NULL);
00588            IMTriggerNotify(ic, CONV_OFF);
00589            SetConversionMode(ic, False);
00590            /* IMSetFocus(ic);      */
00591          }
00592          if (index <= number) {
00593            XIMText *p = &language_list[index - 1];
00594            IMSetPrimaryLocale(ic, p->string.multi_byte);
00595            IMTriggerNotify(ic, CONV_ON); /* make converison on */
00596            SetConversionMode(ic, True);
00597 
00598            if (ic->local_icpart->imstate->type == CodeInputState) {
00599              /* previous state is CodeInput */
00600              Ximp_Local_Preedit_Done(ic);
00601            }
00602            if (ic->local_icpart->imstate->type == LookupState) {
00603              /* previous state is LookupInput */
00604              Ximp_Local_Table_Done(ic);
00605            }
00606            /* return to top_state */
00607            ic->local_icpart->imstate = lim->top_state;
00608            ic->local_icpart->context = ic->local_icpart->imstate->parser;
00609            /* initialize internal state for next key sequence */
00610            ic->local_icpart->context = ic->local_icpart->imstate->parser;
00611            return True;
00612          }
00613        }
00614       }
00615     }
00616   } else {                  /* not using ComposeIM */
00617     if (index > 0) {
00618       /* select one from remote IM */
00619       XIMText *language_list = (XIMText*)0;
00620       int number;
00621       if (XIM_IS_IIIMP(ic->core.im)) {
00622        language_list = XIM_IIIMP(ic->core.im, supported_languages);
00623        number = XIM_IIIMP(ic->core.im, count_languages);
00624        if (!language_list) return False;
00625 
00626        if (index <= number) {
00627          XIMText *p = &language_list[index - 1];
00628          IMSetPrimaryLocale(ic, p->string.multi_byte);
00629          IMTriggerNotify(ic, CONV_OFF);
00630          SetConversionMode(ic, False);
00631          XIC_GUI((XIC)ic, change_lookup)((XIC)ic, LOOKUP_DONE,
00632                                      (XPointer)NULL);
00633          XIC_GUI((XIC)ic, change_preedit)((XIC)ic, PREEDIT_DONE,
00634                                       (XPointer)NULL);
00635          XIC_GUI((XIC)ic, change_status)((XIC)ic, STATUS_DONE,
00636                                      (XPointer)NULL);
00637          return True;
00638        }
00639       }
00640     }
00641   }
00642   return False;
00643 }
00644 
00645 Bool
00646 popup_button_press(Display *d, Window w, XEvent *ev,
00647                  XPointer client_data) {
00648   XicCommon ic = (XicCommon)client_data;
00649 
00650   switch (ev->type) {
00651   case ButtonPress:
00652     if (ev->xbutton.button != Button1) return True;
00653     {
00654       Window child;
00655       int new_x = 0, new_y = 0;
00656       XTranslateCoordinates(d, w, DefaultRootWindow(d),
00657                          ev->xbutton.x, ev->xbutton.y,
00658                          &new_x, &new_y, &child);
00659       popup_menu(ic, new_x, new_y, w, ev);
00660     }
00661     _XRegisterFilterByType(d, w,
00662                         MotionNotify, MotionNotify, motion_menu,
00663                         (XPointer)ic);
00664     break;
00665   case ButtonRelease:
00666     if (ev->xbutton.button != Button1) return True;
00667     popdown_menu(ic);
00668     _XUnregisterFilter(d, w, motion_menu, (XPointer)ic);
00669     {
00670       XimCommon im = (XimCommon)ic->core.im;
00671       Window child;
00672       int new_x = 0, new_y = 0;
00673       XTranslateCoordinates(d, w, DefaultRootWindow(d),
00674                          ev->xbutton.x, ev->xbutton.y,
00675                          &new_x, &new_y, &child);
00676       if (XIM_POPUP(im, x) <= new_x &&
00677          new_x <= XIM_POPUP(im, x) + XIM_POPUP(im, width)) {
00678        XIMUnicodeCharacterSubset *subset;
00679        int menu_index = XIC_POPUP(ic, menu_index);
00680        if (select_menu(ic, menu_index)) {
00681          if (im->unicode_char_subsets) {
00682            subset = &im->unicode_char_subsets->supported_subsets[menu_index - 1];
00683            CallSwitchIMNotifyCallback(ic, subset);
00684          }
00685        }
00686       }
00687     }
00688     break;
00689   }
00690   return True;
00691 }
00692 
00693 void
00694 ClosePopupIM(XimCommon im) {
00695   if (im && im->popup_impart && im->core.display) {
00696     if (XIM_POPUP(im, gc)) XFreeGC(im->core.display, XIM_POPUP(im, gc));
00697     if (XIM_POPUP(im, rgc)) XFreeGC(im->core.display, XIM_POPUP(im, rgc));
00698     if (XIM_POPUP(im, window)) {
00699       XDestroyWindow(im->core.display, XIM_POPUP(im, window));
00700     }
00701     Xfree(im->popup_impart);
00702     im->popup_impart = 0;
00703   }
00704   return;
00705 }
00706 
00707 static Bool
00708 isLanguageSupported(XicCommon ic, char *localename) {
00709     Bool support_status = False;
00710     XIMText *p;
00711     XIMText *language_list = (XIMText *)0;
00712     int number;
00713     if (!XIM_IS_IIIMP(ic->core.im))
00714        return False;
00715     language_list = XIM_IIIMP(ic->core.im, supported_languages);
00716     number = XIM_IIIMP(ic->core.im, count_languages);
00717     if (!language_list)
00718        return support_status;
00719     for (p = language_list; p < &language_list[number]; p++) {
00720        if (!strcmp(p->string.multi_byte, localename)) {
00721          support_status = True;
00722          break;
00723        }
00724     }
00725     return support_status;
00726 }             
00727 
00728 static char *
00729 getDisplayLanguageFromState(XimCommon im, char *localename) {
00730   XIMComposeIM lim = im->local_impart;
00731   LocalIMState *state;
00732 
00733   if (!lim) return (char*)0;
00734 
00735   state = lim->top_state;
00736 
00737   while (state) {
00738     if ((state->type == RemoteIMState) && 
00739        (!strcmp(state->language, localename))) {
00740       break;
00741     }
00742     state = state->next;
00743   }
00744   if (state)
00745     return state->name;
00746   else
00747     return (char *)0;
00748 }
00749 
00750 /* for Multilingual Input */
00751 static void
00752 CallSwitchIMNotifyCallback(XicCommon ic,
00753                         XIMUnicodeCharacterSubset *aSubset) {
00754   XimCommon im = (XimCommon)ic->core.im;
00755   XIMCallback *cb;
00756 
00757   cb = &ic->switchim_notify_callback;
00758 
00759   if (cb && cb->callback) {
00760     XIMSwitchIMNotifyCallbackStruct call_data;
00761 
00762     memset(&call_data, 0, sizeof(XIMSwitchIMNotifyCallbackStruct));
00763 
00764     /* remember selected subset for this XIC */
00765     call_data.from = &im->unicode_char_subsets->supported_subsets[ic->subset_id];
00766     call_data.to = aSubset;
00767     (*cb->callback)((XIM)ic, cb->client_data, (XPointer)&call_data);
00768     ic->subset_id = aSubset->index;
00769   }
00770 }
00771 
00772 int
00773 SelectCharacterSubset(XicCommon ic, XIMUnicodeCharacterSubset *aSubset) {
00774   XimCommon im = (XimCommon)ic->core.im;
00775   int menu_index;
00776 
00777   if (!im->unicode_char_subsets) return False;
00778 
00779   menu_index = aSubset->index + 1;
00780 
00781   if (select_menu(ic, menu_index))
00782     CallSwitchIMNotifyCallback(ic, aSubset);
00783 
00784   return True;
00785 }
00786 
00787 void
00788 UpdateIMCharacterSubset(XimCommon xim) {
00789   XIMUnicodeCharacterSubsets *im_sub_sets;
00790   unsigned short n;
00791   unsigned short count = 0;
00792 
00793   /* already set */
00794   if (xim->unicode_char_subsets) return;
00795 
00796   if (XIM_IS_COMPOSE(xim)) {
00797     XIMComposeIM lim = xim->local_impart;
00798     LocalIMState *state = lim->top_state;
00799 
00800     while (state) {
00801       if (state->type == RemoteIMState) {
00802        state = state->next;
00803        continue;
00804       }
00805       count++;
00806       state = state->next;
00807     }
00808   }
00809   if (XIM_IS_IIIMP(xim)) {
00810     count += XIM_IIIMP(xim, count_languages);
00811   }
00812 
00813   if ((im_sub_sets = (XIMUnicodeCharacterSubsets*)
00814        Xmalloc(sizeof(XIMUnicodeCharacterSubsets) +
00815               sizeof(XIMUnicodeCharacterSubset) * count)) == NULL) {
00816     return;
00817   }
00818   im_sub_sets->count_subsets = count;
00819   im_sub_sets->supported_subsets =
00820     (XIMUnicodeCharacterSubset*)(&im_sub_sets[1]);
00821 
00822   n = 0;
00823   if (XIM_IS_COMPOSE(xim)) {
00824     XIMComposeIM lim = xim->local_impart;
00825     LocalIMState *state = lim->top_state;
00826 
00827     while (state) {
00828       if (state->type == RemoteIMState) {
00829        state = state->next;
00830        continue;
00831       }
00832       im_sub_sets->supported_subsets[n].index = n;
00833       im_sub_sets->supported_subsets[n].subset_id = 0; /* not yet */
00834       im_sub_sets->supported_subsets[n].name = state->name;
00835       im_sub_sets->supported_subsets[n].is_active = True;
00836       n++;
00837       state = state->next;
00838     }
00839   }
00840   if (XIM_IS_IIIMP(xim)) {
00841     XIMText *language_list = XIM_IIIMP(xim, supported_languages);
00842     int number = XIM_IIIMP(xim, count_languages);
00843     if (language_list) {
00844       XIMText *p;
00845       for (p = language_list; p < &language_list[number]; p++) {
00846         char *display_lang =
00847          getDisplayLanguageFromState(xim,
00848                                   p->string.multi_byte);
00849        if (!display_lang) {
00850          display_lang = convertToDisplayLanguage(p->string.multi_byte);
00851        }
00852        im_sub_sets->supported_subsets[n].index = n;
00853        im_sub_sets->supported_subsets[n].subset_id = 0; /* not yet */
00854        im_sub_sets->supported_subsets[n].name = display_lang;
00855        im_sub_sets->supported_subsets[n].is_active = True;
00856        n++;
00857       }
00858     }
00859   }
00860   xim->unicode_char_subsets = im_sub_sets;
00861 
00862   return;
00863 }
00864