Back to index

im-sdk  12.3.91
XIMProtocol.cpp
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 #include <stdio.h>
00043 #include <sys/types.h>
00044 #include <netinet/in.h>            // for htonl
00045 #include "IMProtocolStruct.h"
00046 #include "XIMProtocol.hh"
00047 #include "XIMPInputContext.hh"
00048 #include "XIMProto.hh"
00049 #include "Xfactory.hh"
00050 #include <X11/Xutil.h>
00051 
00052 /* ximp input styles */
00053 static XIMStyle ximp_styles[] = {
00054   XIMPreeditCallbacks |XIMStatusCallbacks,
00055   XIMPreeditCallbacks | XIMStatusArea,
00056   XIMPreeditCallbacks | XIMStatusNothing,
00057   XIMPreeditPosition  | XIMStatusCallbacks,
00058   XIMPreeditPosition  | XIMStatusArea,
00059   XIMPreeditPosition  | XIMStatusNothing,
00060   XIMPreeditArea      | XIMStatusCallbacks,
00061   XIMPreeditArea      | XIMStatusArea,
00062   XIMPreeditArea      | XIMStatusNothing,
00063   XIMPreeditNothing   | XIMStatusCallbacks,
00064   XIMPreeditNothing   | XIMStatusArea,
00065   XIMPreeditNothing   | XIMStatusNothing,
00066   XIMPreeditCallbacks | XIMStatusNone,
00067   XIMPreeditPosition  | XIMStatusNone,
00068   XIMPreeditArea      | XIMStatusNone,
00069   XIMPreeditNothing   | XIMStatusNone,
00070   XIMPreeditNone      | XIMStatusCallbacks,
00071   XIMPreeditNone      | XIMStatusArea,
00072   XIMPreeditNone      | XIMStatusNothing,
00073   XIMPreeditNone      | XIMStatusNone
00074 };
00075 
00076 /* styles for disable_status_area */
00077 static XIMStyle ximp_styles2[] = {
00078   XIMPreeditCallbacks | XIMStatusNone,
00079   XIMPreeditPosition  | XIMStatusNone,
00080   XIMPreeditArea      | XIMStatusNone,
00081   XIMPreeditNothing   | XIMStatusNone,
00082   XIMPreeditNone      | XIMStatusNone
00083 };
00084 
00085 XIMProtocol::
00086 XIMProtocol(IMArg *args, int n) : XIMPublic(args, n) {
00087 
00088   input_context_list.disable_reordering();
00089 
00090   protocol_name = "XIMP4.0";
00091 
00092   ximp_version = "4.0";
00093   im_version = "4.0";
00094 
00095   ximp_type.num_of_types = 2;
00096   ximp_type.types = new unsigned long[2];
00097 
00098   ximp_type.types[0] = XIMP_FE_TYPE1;
00099   ximp_type.types[1] = XIMP_SYNC_BE_TYPE2;
00100 
00101   styles.count_styles = sizeof(ximp_styles)/sizeof(ximp_styles[0]);
00102   styles.supported_styles = &ximp_styles[0];
00103 
00104   atom_sequence = 0;
00105 
00106   thread = NULL;
00107 
00108 }
00109 
00110 XIMProtocol::
00111 ~XIMProtocol() {
00112   delete [] ximp_type.types;
00113 
00114   if (im_window)
00115     XDestroyWindow(display, im_window);
00116 
00117   delete start_keys.keylist;
00118   delete stop_keys.keylist;
00119   delete thread;
00120 
00121   return;
00122 }
00123 
00124 void
00125 XIMProtocol::setProps() {
00126   Atom extensions[10];
00127   int ext_number;
00128   int i;
00129 
00130   /* IMS Window Property Name */
00131   const char *COMPOUND_TEXT = "COMPOUND_TEXT";
00132   const char *XIMP_VERSION = "_XIMP_VERSION";
00133   const char *XIMP_STYLE = "_XIMP_STYLE";
00134   const char *XIMP_TYPE = "_XIMP_TYPE";
00135   const char *XIMP_SERVERNAME = "_XIMP_SERVERNAME";
00136   const char *XIMP_SERVERVERSION = "_XIMP_SERVERVERSION";
00137   const char *XIMP_VENDORNAME = "_XIMP_VENDORNAME";
00138   const char *XIMP_KEYS = "_XIMP_KEYS";
00139   const char *XIMP_SPROC_STARTED_KEYS = "_XIMP_SPROC_STARTED_KEYS";
00140   const char *XIMP_SPROC_STOPPED_KEYS = "_XIMP_SPROC_STOPPED_KEYS";
00141   const char *XIMP_EXTENSIONS = "_XIMP_EXTENSIONS";
00142   const char *XIMP_PREEDITFONT = "_XIMP_PREEDITFONT";
00143   const char *XIMP_STATUSFONT = "_XIMP_STATUSFONT";
00144 
00145   /* Client Window Property Name */
00146   const char *XIMP_FOCUS = "_XIMP_FOCUS";
00147   const char *XIMP_PREEDIT = "_XIMP_PREEDIT";
00148   const char *XIMP_STATUS = "_XIMP_STATUS";
00149 
00150   const char *XIMP_EXT_XIMP_STATUSWINDOW = "_XIMP_EXT_XIMP_STATUSWINDOW";
00151   const char *XIMP_EXT_XIMP_BACK_FRONT = "_XIMP_EXT_XIMP_BACK_FRONT";
00152   const char *XIMP_EXT_XIMP_CONVERSION = "_XIMP_EXT_XIMP_CONVERSION";
00153 
00154   const char *XIMP_PREEDIT_DRAW_DATA = "_XIMP_PREEDIT_DRAW_DATA";
00155   const char *XIMP_FEEDBACKS = "_XIMP_FEEDBACKS";
00156 
00157 #define INTERN(s) XInternAtom(display, s, False)
00158   atoms.ctext_type = INTERN(COMPOUND_TEXT);
00159   atoms.version = INTERN(XIMP_VERSION);
00160   atoms.supported_styles = INTERN(XIMP_STYLE);
00161   atoms.supported_types = INTERN(XIMP_TYPE);
00162   atoms.server_name = INTERN(XIMP_SERVERNAME);
00163   atoms.server_version = INTERN(XIMP_SERVERVERSION);
00164   atoms.vendor_name = INTERN(XIMP_VENDORNAME);
00165   atoms.keys = INTERN(XIMP_KEYS);
00166   atoms.sproc_started_keys = INTERN(XIMP_SPROC_STARTED_KEYS);
00167   atoms.sproc_stopped_keys = INTERN(XIMP_SPROC_STOPPED_KEYS);
00168   atoms.extensions = INTERN(XIMP_EXTENSIONS);
00169 
00170   atoms.focus = INTERN(XIMP_FOCUS);
00171   atoms.preedit = INTERN(XIMP_PREEDIT);
00172   atoms.status = INTERN(XIMP_STATUS);
00173   atoms.preedit_font = INTERN(XIMP_PREEDITFONT);
00174   atoms.status_font = INTERN(XIMP_STATUSFONT);
00175 
00176   atoms.ext_statuswin = INTERN(XIMP_EXT_XIMP_STATUSWINDOW);
00177   atoms.ext_backfront = INTERN(XIMP_EXT_XIMP_BACK_FRONT);
00178   atoms.ext_conversion = INTERN(XIMP_EXT_XIMP_CONVERSION);
00179 
00180   atoms.preedit_draw_data = INTERN(XIMP_PREEDIT_DRAW_DATA);
00181   atoms.feedbacks = INTERN(XIMP_FEEDBACKS);
00182 #undef INTERN
00183   /* count supported extensions */
00184   ext_number = 0;
00185 
00186   ext_flag = 0;
00187   ext_flag |= EXT_CONV;            // default
00188   if (ext_flag & EXT_STATUS)
00189     extensions[ext_number++] = atoms.ext_statuswin;
00190   if (ext_flag & EXT_BACKFRONT)
00191     extensions[ext_number++] = atoms.ext_backfront;
00192   if (ext_flag & EXT_CONV)
00193     extensions[ext_number++] = atoms.ext_conversion;
00194 
00195   IMTriggerKey keyp;
00196   XIMTriggerKey *ximp_keyp;
00197 
00198   /* start keys */
00199   start_keys.count_keys = on_keys.count();
00200   start_keys.keylist = new XIMTriggerKey[start_keys.count_keys];
00201   ximp_keyp = start_keys.keylist;
00202 
00203   for (i = 0; i < start_keys.count_keys; i++, ximp_keyp++) {
00204     keyp = on_keys.getKey(i+1);
00205     ximp_keyp->modifier = keyp.get_modifier();
00206     ximp_keyp->modifier_mask = keyp.get_modifier_mask();
00207     ximp_keyp->keysym = keyp.get_keyCode();
00208   }
00209 
00210   /* stop keys */
00211   stop_keys.count_keys = off_keys.count();
00212   stop_keys.keylist = new XIMTriggerKey[stop_keys.count_keys];
00213   ximp_keyp = stop_keys.keylist;
00214 
00215   for (i = 0; i < stop_keys.count_keys; i++, ximp_keyp++) {
00216     keyp = off_keys.getKey(i+1);
00217     ximp_keyp->modifier = keyp.get_modifier();
00218     ximp_keyp->modifier_mask = keyp.get_modifier_mask();
00219     ximp_keyp->keysym = keyp.get_keyCode();
00220   }
00221 
00222   const char *xim_name = im_name; // evil, need to be fixed in CompoundString
00223   const char *xvendor_name = vendor_name;
00224   const char *xim_version = im_version;
00225 
00226   if (disable_status_area == True){
00227     styles.count_styles = sizeof(ximp_styles2)/sizeof(ximp_styles2[0]);
00228     styles.supported_styles = &ximp_styles2[0];
00229   }
00230     
00231 #define SETPROPERTY(p, t, f, d, n) XChangeProperty(display, im_window, p, \
00232                                              t, f, PropModeReplace, \
00233                                              (unsigned char *)d, n)
00234   SETPROPERTY(atoms.version, XA_STRING, 8,
00235              ximp_version, strlen(ximp_version));
00236   SETPROPERTY(atoms.supported_styles, atoms.supported_styles, 32,
00237              styles.supported_styles, styles.count_styles);
00238   SETPROPERTY(atoms.supported_types, atoms.supported_types, 32,
00239              ximp_type.types, ximp_type.num_of_types);
00240   SETPROPERTY(atoms.server_name, XA_STRING, 8, xim_name, strlen(xim_name));
00241   SETPROPERTY(atoms.server_version, XA_STRING, 8,
00242              xim_version, strlen(xim_version));
00243   SETPROPERTY(atoms.vendor_name, XA_STRING, 8,
00244              xvendor_name, strlen(xvendor_name));
00245   SETPROPERTY(atoms.keys, atoms.keys, 32,
00246              start_keys.keylist, start_keys.count_keys * 3);
00247   SETPROPERTY(atoms.sproc_started_keys, atoms.sproc_started_keys, 32,
00248              start_keys.keylist, start_keys.count_keys * 3);
00249   SETPROPERTY(atoms.sproc_stopped_keys, atoms.sproc_stopped_keys, 32,
00250              stop_keys.keylist, stop_keys.count_keys * 3);
00251   SETPROPERTY(atoms.extensions, atoms.extensions, 32,
00252              extensions, ext_number);
00253 #undef SETPROPERTY
00254   return;
00255 }
00256 
00257 static char *
00258 NextLocaleName(char **list) {
00259   char *p;
00260     
00261   for (p = *list; **list && **list != ','; (*list)++);
00262   if (**list == ',') {
00263     **list = '\0';
00264     (*list)++;
00265   } else if (p == *list) {
00266     p = (char *)NULL;
00267   }
00268   return(p);
00269 }
00270 
00271 #if 0
00272 static Bool
00273 _XimpWaitIMProtocol(Display *dpy, Window window, XEvent *ev,
00274                   XPointer client_data) {
00275 #if 0
00276   XIMProtocol *ximp_protocol = (XIMProtocol*)client_data;
00277 #endif
00278   return True;
00279 }
00280 #endif
00281 
00282 int
00283 XIMProtocol::run() {
00284   CompoundString locale_list = input_locale;
00285   char *locale_p;
00286   Bool found;
00287   char *p, *pp, im_shortname[64], im_longname[64];
00288   Atom selection;
00289 
00290   if (display == 0) {
00291     // nothing to do
00292     fprintf(stderr, "   Error - No XDisplay connection\n");
00293     fprintf(stderr, "       XIMP40 cannot be used\n");
00294     return -1;
00295   }
00296 
00297   (void)XSetErrorHandler(XFactory::xerror_handler);
00298 #ifdef DEBUG
00299   (void)XSynchronize(display, True);
00300 #endif
00301   if (display) {
00302     screen = DefaultScreen(display);
00303     im_window = XCreateSimpleWindow(display,
00304                                 DefaultRootWindow(display),
00305                                 0, 0, 1, 1, 1, 0, 0);
00306   }
00307 
00308   (void)setProps();
00309 
00310   found = False;
00311   locale_p = locale_list;
00312   for (p = NextLocaleName((char **)&locale_p); p != NULL;
00313        p = NextLocaleName((char **)&locale_p)) {
00314     /* short selection name */
00315     if (pp = strchr(p, '.')) *pp = (char)0;
00316     sprintf(im_shortname, "_XIMP_%s", p);
00317     if (setSelectionOwner(im_window, im_shortname, &selection) == True) {
00318       found = True;
00319     }
00320     /* long selection name */
00321     const char *xim_name = im_name;
00322     sprintf(im_longname, "%s@%s.%d", im_shortname, xim_name, screen);
00323     if (setSelectionOwner(im_window, im_longname, &selection) == True) {
00324       found = True;
00325     }
00326     // fix for 4134207&4260189
00327     for (int i = 0; i < ScreenCount(display); i++) {
00328       if (screen != i) {
00329        /* long selection name */
00330        sprintf(im_longname, "%s@%s.%d", im_shortname, xim_name, i);
00331        if (setSelectionOwner(im_window, im_longname, &selection) == True) {
00332          found = True;
00333        }
00334       }
00335     }
00336   }
00337   if (!found) return -1;
00338 
00339   /* Property Name */
00340   const char *XIMP_PROTOCOL = "_XIMP_PROTOCOL";
00341 
00342   ximp_request = XInternAtom(display, XIMP_PROTOCOL, False);
00343 
00344   OpenIM();
00345 
00346   if (thread == NULL) {
00347     // start creating a thread
00348     thread = new IMThread(xevent_loop, this);
00349   }
00350   
00351   return 0;
00352 }
00353 
00354 Bool
00355 XIMProtocol::get_protocol_version(Window win, char *&prop_ret) {
00356   Atom atom_ret = (Atom)0;
00357   int format_ret = 0;
00358   unsigned long nitems_ret = (unsigned long)0;
00359   unsigned long bytes_ret = (unsigned long)0;
00360 
00361   if (XGetWindowProperty(display, win, atoms.version, 0, 10000L, True,
00362                       XA_STRING, &atom_ret, &format_ret, &nitems_ret,
00363                       &bytes_ret, (unsigned char**)&prop_ret)
00364       != Success) return False;
00365   if (atom_ret == None || atom_ret != XA_STRING) {
00366     return False;
00367   }
00368   return True;
00369 }
00370 
00371 Bool
00372 XIMProtocol::get_focus_window(Window win, Window &focus_win) {
00373   unsigned char *data;
00374   unsigned long len;
00375 
00376   if (!read_property(win, atoms.focus, XA_WINDOW, 32, &data, &len)) {
00377     return False;
00378   } else if (len != 1 && len != 2) {
00379     /* if len == 2, data[4-7] contains a event mask
00380        of the data[0-3] window. */
00381     XFree((char *)data);
00382     return False;
00383   }
00384   focus_win = *(Window *)data;
00385   XFree((char *)data);
00386   return True;
00387 }
00388 
00389 Bool
00390 XIMProtocol::get_preedit_font(Window win, char **name) {
00391   unsigned char *data;
00392   unsigned long len;
00393 
00394   if (!read_property(win, atoms.preedit_font, XA_STRING, 8,
00395                    (unsigned char **)&data, &len)) {
00396     return False;
00397   }
00398   if (*name)
00399      delete []*name;
00400   char *t_name = new char[strlen((const char *)data)+1];
00401   *name = t_name;
00402   strcpy(t_name, (const char *)data);
00403   XFree(data);
00404   return True;
00405 }
00406 
00407 Bool
00408 XIMProtocol::get_status_font(Window win, char **name) {
00409   unsigned char *data;
00410   unsigned long len;
00411 
00412   if (!read_property(win, atoms.status_font, XA_STRING, 8,
00413                    (unsigned char **)&data, &len)) {
00414     return False;
00415   }
00416   if (*name)
00417      delete []*name;
00418   char *t_name = new char[strlen((const char *)data)+1];
00419   *name = t_name;
00420   strcpy(t_name, (const char *)data);
00421   XFree(data);
00422   return True;
00423 }
00424 
00425 Bool
00426 XIMProtocol::get_preedit4(Window win,
00427                        Ximp_PreeditPropRec4 &preedit_attr) {
00428   unsigned char *data;
00429   unsigned long len;
00430 
00431   if (!read_property(win, atoms.preedit, atoms.preedit, 32,
00432                    (unsigned char **)&data, &len)) {
00433     return False;
00434   }
00435   preedit_attr = *(Ximp_PreeditPropRec4*)data;
00436   XFree((char *)data);
00437   return True;
00438 }
00439 
00440 Bool
00441 XIMProtocol::get_preedit3(Window win,
00442                        Ximp_PreeditPropRec3 &preedit_attr) {
00443   unsigned char *data;
00444   unsigned long len;
00445 
00446   if (!read_property(win, atoms.preedit, atoms.preedit, 32,
00447                    (unsigned char **)&data, &len)) {
00448     return False;
00449   }
00450   preedit_attr = *(Ximp_PreeditPropRec3*)data;
00451   XFree((char *)data);
00452   return True;
00453 }
00454 
00455 Bool
00456 XIMProtocol::get_status4(Window win,
00457                       Ximp_StatusPropRec4 &status_attr) {
00458   unsigned char *data;
00459   unsigned long len;
00460 
00461   if (!read_property(win, atoms.status, atoms.status, 32,
00462                    (unsigned char **)&data, &len)) {
00463     return False;
00464   }
00465   status_attr = *(Ximp_StatusPropRec4*)data;
00466   XFree((char *)data);
00467   return True;
00468 }
00469 
00470 Bool
00471 XIMProtocol::get_status3(Window win,
00472                       Ximp_StatusPropRec3 &status_attr) {
00473   unsigned char *data;
00474   unsigned long len;
00475 
00476   if (!read_property(win, atoms.status, atoms.status, 32,
00477                    (unsigned char **)&data, &len)) {
00478     return False;
00479   }
00480   status_attr = *(Ximp_StatusPropRec3*)data;
00481   XFree((char *)data);
00482   return True;
00483 }
00484 
00485 Bool
00486 XIMProtocol::get_server_type4(Window win, unsigned long &type) {
00487   unsigned char *data;
00488   unsigned long len;
00489 
00490   if (!read_property(win, atoms.supported_types, atoms.supported_types,
00491                    32, &data, &len)) {
00492     return False;
00493   }
00494   type = *(unsigned long*)data;
00495   XFree((char*)data);
00496   return True;
00497 }
00498 
00499 Bool
00500 XIMProtocol::set_focus_window(Window win, Window focus_win) {
00501   return write_property(win, atoms.focus,
00502                      XA_WINDOW, 32,
00503                      (unsigned char*)&focus_win, 1);
00504 }
00505 
00506 Bool
00507 XIMProtocol::set_preedit_font(Window win, char *pre_font) {
00508   return write_property(win, atoms.preedit_font,
00509                      XA_STRING, 8,
00510                      (unsigned char *)pre_font,
00511                      (CARD32)strlen(pre_font));
00512 }
00513 
00514 Bool
00515 XIMProtocol::set_status_font(Window win, char *sts_font) {
00516   return write_property(win, atoms.status_font,
00517                      XA_STRING, 8,
00518                      (unsigned char *)sts_font,
00519                      (CARD32)strlen(sts_font));
00520 }
00521 
00522 Bool
00523 XIMProtocol::set_preedit4(Window win, Ximp_PreeditPropRec4 preedit_attr) {
00524   return write_property(win, atoms.preedit,
00525                      atoms.preedit, 32,
00526                      (unsigned char *)&preedit_attr,
00527                      XIMP_PREEDIT_MAX_LONG4);
00528 }
00529 
00530 Bool
00531 XIMProtocol::set_status4(Window win, Ximp_StatusPropRec4 status_attr) {
00532   return write_property(win, atoms.status,
00533                      atoms.status, 32,
00534                      (unsigned char *)&status_attr,
00535                      XIMP_STATUS_MAX_LONG4);
00536 }
00537 
00538 Bool
00539 XIMProtocol::set_preedit3(Window win, Ximp_PreeditPropRec3 preedit_attr) {
00540   return write_property(win, atoms.preedit,
00541                      atoms.preedit, 32,
00542                      (unsigned char *)&preedit_attr,
00543                      XIMP_PREEDIT_MAX_LONG3);
00544 }
00545 
00546 Bool
00547 XIMProtocol::set_status3(Window win, Ximp_StatusPropRec3 status_attr) {
00548   return write_property(win, atoms.status,
00549                      atoms.status, 32,
00550                      (unsigned char *)&status_attr,
00551                      XIMP_STATUS_MAX_LONG3);
00552 }
00553 
00554 Bool
00555 XIMProtocol::set_server_type4(Window win, unsigned long type) {
00556   return write_property(win, atoms.supported_types,
00557                      atoms.supported_types, 32,
00558                      (unsigned char *)&type, 1);
00559 }
00560 
00561 Bool
00562 XIMProtocol::read_property(Window win, Atom prop, Atom type,
00563                         int format,
00564                         unsigned char **datapp, unsigned long *lenp) {
00565   Atom realtype;
00566   int realformat;
00567   unsigned long bytesafter;
00568 
00569   *datapp = NULL;
00570   if (XGetWindowProperty(display, win, prop, 0L, 1000000L, True, type,
00571                       &realtype, &realformat, lenp,
00572                       &bytesafter, datapp) != Success)
00573     return False;
00574   if (realtype == None) {
00575     return False;
00576   } else if (realtype != type) {
00577     return False;
00578   } else if (realformat != format) {
00579     if (*datapp != NULL) XFree((char *)*datapp);
00580     *datapp = NULL;
00581     return False;
00582   }
00583   return True;
00584 }
00585 
00586 Bool
00587 XIMProtocol::write_property(Window win, Atom prop, Atom type,
00588                          int format,
00589                          const unsigned char *datap,
00590                          const unsigned long len) {
00591   (void)XChangeProperty(display, win, prop, type, format,
00592                      PropModeReplace, datap, len);
00593   /* always return True */
00594   return True;
00595 }
00596 
00597 void*
00598 XIMProtocol::xevent_loop(void* client_data) {
00599   XIMProtocol *ximp_protocol = (XIMProtocol*)client_data;
00600 
00601   for (;;) {
00602     XEvent event;
00603     XNextEvent(ximp_protocol->display, &event);
00604     if (DestroyNotify == event.type) {
00605       ximp_protocol->destroy_window(ximp_protocol,
00606                                 event.xdestroywindow.window);
00607     }
00608     if (XFilterEvent(&event, 0) == True)
00609       continue;
00610     switch (event.type) {
00611     case KeyPress:
00612     case KeyRelease:
00613          {
00614            XIMPInputContext *ic =(XIMPInputContext *) ximp_protocol->getInputContextByFocusWindow(event.xkey.window);
00615            if (ic)
00616               ic->forward_xevent((XEvent*)&event);
00617          }
00618          break;
00619     case ClientMessage:
00620       if (event.xclient.message_type == ximp_protocol->ximp_request &&
00621          event.xclient.window == ximp_protocol->im_window &&
00622          event.xclient.format == 32) {
00623        switch ((int)event.xclient.data.l[0]) {
00624        case XIMP_KEYPRESS4:
00625        case XIMP_KEYPRESS3:
00626          ximp_protocol->key_press((XClientMessageEvent*)&event);
00627          break;
00628        case XIMP_KEYRELEASE4:
00629          ximp_protocol->key_release((XClientMessageEvent*)&event);
00630          break;
00631        case XIMP_CREATE4:
00632        case XIMP_CREATE3:
00633          ximp_protocol->create_ic((XClientMessageEvent*)&event);
00634          break;
00635        case XIMP_DESTROY4:
00636        case XIMP_DESTROY3:
00637          ximp_protocol->destroy_ic((XClientMessageEvent*)&event);
00638          break;
00639        case XIMP_REG_KEY_PRESSED4:
00640        case XIMP_BEGIN3:
00641          ximp_protocol->start((XClientMessageEvent*)&event);
00642          break;
00643        case XIMP_END3:
00644          ximp_protocol->end((XClientMessageEvent*)&event);
00645          break;
00646        case XIMP_SETFOCUS4:
00647        case XIMP_SETFOCUS3:
00648          ximp_protocol->set_focus((XClientMessageEvent*)&event);
00649          break;
00650        case XIMP_UNSETFOCUS4:
00651        case XIMP_UNSETFOCUS3:
00652          ximp_protocol->unset_focus((XClientMessageEvent*)&event);
00653          break;
00654        case XIMP_CLIENT_WINDOW4:
00655          ximp_protocol->set_clientwin((XClientMessageEvent*)&event);
00656          break;
00657        case XIMP_FOCUS_WINDOW4:
00658          ximp_protocol->set_focuswin((XClientMessageEvent*)&event);
00659          break;
00660        case XIMP_MOVE4:
00661        case XIMP_MOVE3:
00662          ximp_protocol->move((XClientMessageEvent*)&event);
00663          break;
00664        case XIMP_SETVALUE4:
00665        case XIMP_SETVALUE3:
00666          ximp_protocol->set_icvalues((XClientMessageEvent*)&event);
00667          break;
00668        case XIMP_GETVALUE4:
00669        case XIMP_GETVALUE3:
00670          ximp_protocol->get_icvalues((XClientMessageEvent*)&event);
00671          break;
00672        case XIMP_RESET4:
00673        case XIMP_RESET3:
00674          ximp_protocol->reset((XClientMessageEvent*)&event);
00675          break;
00676        case XIMP_EVENTMASK_NOTIFY4:
00677          ximp_protocol->event_mask((XClientMessageEvent*)&event);
00678          break;
00679        case XIMP_EXTENSION4:
00680        case XIMP_EXTENSION3:
00681          ximp_protocol->extension((XClientMessageEvent*)&event);
00682          break;
00683        case XIMP_PREEDITSTART_RETURN4:
00684        case XIMP_PREEDITSTART_RETURN3:
00685          ximp_protocol->preedit_start_ret((XClientMessageEvent*)&event);
00686          break;
00687        case XIMP_PREEDITCARET_RETURN4:
00688        case XIMP_PREEDITCARET_RETURN3:
00689          ximp_protocol->preedit_caret_ret((XClientMessageEvent*)&event);
00690          break;
00691        default:
00692          break;      /* unknown ximp protocol */
00693        }
00694       }
00695     default:
00696       break;
00697     }
00698   }
00699   return 0;
00700 }
00701 
00702 InputContext *
00703 XIMProtocol::getInputContextByFocusWindow(Window w) {
00704    XIMPInputContext *tmp_ic;
00705    tmp_ic = (XIMPInputContext *)&(input_context_list.getFirstItem());
00706    while (NULL != tmp_ic) {
00707      if ((NULL != tmp_ic) && (tmp_ic->focus_window() == w)) {
00708        return (InputContext *)tmp_ic;
00709      }
00710      tmp_ic = (XIMPInputContext *)&(input_context_list.getNextItem());
00711    }
00712    return NULL;
00713 }
00714 
00715 Bool
00716 XIMProtocol::key_press(XClientMessageEvent *ev) {
00717   int input_context_id = ev->data.l[1];
00718   XIMPInputContext *ic = (XIMPInputContext*)&(input_context_list.getItem(input_context_id));
00719   XEvent kev;
00720   if (!ic) return True;
00721 
00722   if (ic->checkAltKey(ev)) {
00723     if (ic->is_conv_state()) {
00724       ev->data.l[0] = XIMP_END3; // dummy
00725       end((XClientMessageEvent*)ev);
00726     } else {
00727       ev->data.l[0] = ic->is_version_40()?
00728        XIMP_REG_KEY_PRESSED4: XIMP_BEGIN3; // dummy
00729       start((XClientMessageEvent*)ev);
00730     }
00731     goto skip;
00732   }
00733 
00734   kev.xkey.type = KeyPress;
00735   kev.xkey.window = ic->focus_window();
00736   kev.xkey.display = display;
00737   kev.xkey.root = DefaultRootWindow(display);
00738   kev.xkey.x = 0;
00739   kev.xkey.y = 0;
00740   kev.xkey.x_root = 0;
00741   kev.xkey.y_root = 0;
00742   kev.xkey.keycode = ev->data.l[2];
00743   kev.xkey.state = ev->data.l[3];
00744   kev.xkey.time = (ic->is_version_40() ? ev->data.l[4] : 0);
00745   kev.xkey.same_screen = 1;
00746 
00747   if (!XFilterEvent((XEvent*)&kev, 0)) {
00748     // send back to client
00749     ic->forward_xevent((XEvent*)&kev);
00750   }
00751 
00752 skip:
00753   if (ic->is_version_40() && ic->is_sync()) {
00754     ic->set_match(ev->data.l[2], ev->data.l[3]);
00755     send_client_message(ic->focus_window(),
00756                      XIMP_KEYPRESS_RETURN4,
00757                      input_context_id,
00758                      0, 0, 0);
00759   }
00760   return True;
00761 }
00762 
00763 Bool
00764 XIMProtocol::key_release(XClientMessageEvent *ev) {
00765   int input_context_id = ev->data.l[1];
00766   XIMPInputContext *ic = (XIMPInputContext*)&(input_context_list.getItem(input_context_id));
00767   if (!ic) return True;
00768 
00769   if (ic->is_version_40() && ic->is_sync()) {
00770     ic->process_match(ev->data.l[2], ev->data.l[3]);
00771     send_client_message(ic->focus_window(),
00772                      XIMP_KEYRELEASE_RETURN4,
00773                      input_context_id,
00774                      0, 0, 0);
00775     send_client_message(ic->focus_window(),
00776                      XIMP_KEYRELEASE4,
00777                      input_context_id,
00778                      ev->data.l[2], ev->data.l[3], 0);
00779   }
00780   return True;
00781 }
00782 
00783 void
00784 XIMProtocol::create_ic(XClientMessageEvent *ev) {
00785   XIMPInputContext *ic = new XIMPInputContext(this, ev);
00786   input_context_list.addItem(ic);
00787   int input_context_id = input_context_list.getIndex(ic);
00788 
00789   send_client_message(ic->focus_window(),
00790                     (ic->is_version_40() ?
00791                      XIMP_CREATE_RETURN4:
00792                      XIMP_CREATE_RETURN3),
00793                     input_context_id,
00794                     0, 0, 0);
00795   return;
00796 }
00797 void
00798 XIMProtocol::destroy_ic(XClientMessageEvent *ev) {
00799   int input_context_id = ev->data.l[1];
00800   XIMPInputContext *ic = (XIMPInputContext*)&(input_context_list.getItem(input_context_id));
00801   if (!ic) return;
00802 
00803   ic->destroy_xic();
00804 
00805   input_context_list.remove(ic);
00806 
00807   delete ic;
00808 
00809   return;
00810 }
00811 
00812 void
00813 XIMProtocol::destroy_window(XIMProtocol *ximp_protocol,
00814                          Window destroy_win) {
00815   XIMPInputContext *ic;
00816   XClientMessageEvent xcme;
00817 
00818   ic = (XIMPInputContext *)&(ximp_protocol->input_context_list.getFirstItem());
00819   while (NULL != ic) {
00820     if (ic->client_window() == destroy_win) {
00821       /* in destroy_ic(), only data.i[1] is referred. */
00822       xcme.data.l[1] = ximp_protocol->input_context_list.getIndex(ic);
00823       ximp_protocol->destroy_ic(&xcme);
00824     }
00825     ic = (XIMPInputContext *)&(ximp_protocol->input_context_list.getNextItem());
00826   }
00827 
00828   return;
00829 }
00830 
00831 void
00832 XIMProtocol::start(XClientMessageEvent *ev) {
00833   int input_context_id = ev->data.l[1];
00834   XIMPInputContext *ic = (XIMPInputContext*)&(input_context_list.getItem(input_context_id));
00835   if (!ic) return;
00836 
00837   if (ic->is_conv_state()) return;
00838 
00839   ic->conversion_start();
00840   return;
00841 }
00842 
00843 void
00844 XIMProtocol::end(XClientMessageEvent *ev) {
00845   int input_context_id = ev->data.l[1];
00846   XIMPInputContext *ic = (XIMPInputContext*)&(input_context_list.getItem(input_context_id));
00847   if (!ic) return;
00848 
00849   if (!ic->is_conv_state()) return;
00850 
00851   ic->conversion_end();
00852   return;
00853 }
00854 
00855 void
00856 XIMProtocol::set_focus(XClientMessageEvent *ev) {
00857   int input_context_id = ev->data.l[1];
00858   XIMPInputContext *ic = (XIMPInputContext*)&(input_context_list.getItemMakeTop(input_context_id));
00859   if (!ic) return;
00860 
00861   ic->set_xicfocus();
00862 
00863   return;
00864 }
00865 
00866 void
00867 XIMProtocol::unset_focus(XClientMessageEvent *ev) {
00868   int input_context_id = ev->data.l[1];
00869   XIMPInputContext *ic = (XIMPInputContext*)&(input_context_list.getItem(input_context_id));
00870 
00871   if (!ic) return;
00872   ic->unset_xicfocus();
00873 
00874   return;
00875 }
00876 
00877 void
00878 XIMProtocol::set_clientwin(XClientMessageEvent *ev) {
00879   int input_context_id = ev->data.l[1];
00880   XIMPInputContext *ic = (XIMPInputContext*)&(input_context_list.getItem(input_context_id));
00881   if (!ic) return;
00882 
00883   ic->set_client_window(ev->data.l[2]);
00884   ic->set_fwin_select_mask(ev->data.l[3]);
00885 
00886   send_client_message(ic->focus_window(),
00887                     XIMP_CLIENT_WINDOW_RETURN4,
00888                     input_context_id,
00889                     0, 0, 0);
00890   return;
00891 }
00892 
00893 void
00894 XIMProtocol::set_focuswin(XClientMessageEvent *ev) {
00895   int input_context_id = ev->data.l[1];
00896   XIMPInputContext *ic = (XIMPInputContext*)&(input_context_list.getItemMakeTop(input_context_id));
00897   if (!ic) return;
00898 
00899   ic->set_focus_window(ev->data.l[2]);
00900   ic->set_fwin_select_mask(ev->data.l[3]);
00901 
00902   send_client_message(ic->focus_window(),
00903                     XIMP_FOCUS_WINDOW_RETURN4,
00904                     input_context_id,
00905                     0, 0, 0);
00906   return;
00907 }
00908 
00909 void
00910 XIMProtocol::move(XClientMessageEvent *ev) {
00911   int input_context_id = ev->data.l[1];
00912   XIMPInputContext *ic = (XIMPInputContext*)&(input_context_list.getItem(input_context_id));
00913   if (!ic) return;
00914 
00915   ic->set_preedit_spot_location(ev->data.l[2], ev->data.l[3]);
00916 
00917   return;
00918 }
00919 
00920 void
00921 XIMProtocol::set_icvalues(XClientMessageEvent *ev) {
00922   int input_context_id = ev->data.l[1];
00923   XIMPInputContext *ic = (XIMPInputContext*)&(input_context_list.getItem(input_context_id));
00924 
00925   if (!ic) return;
00926 
00927 #if 0
00928   XIMProtocol *ximp_protocol = ic->ximp_protocol;
00929   IMArg args[1];
00930   int n = 0;
00931   // ximp_protocol->proto_handler->SetICValues((InputContext*)ic, args, n);
00932 #endif
00933 
00934   ic->set_values(ev);
00935 
00936   return;
00937 }
00938 
00939 void
00940 XIMProtocol::get_icvalues(XClientMessageEvent *ev) {
00941   int input_context_id = ev->data.l[1];
00942   XIMPInputContext *ic = (XIMPInputContext*)&(input_context_list.getItem(input_context_id));
00943 
00944   if (!ic) return;
00945 
00946   ic->get_values(ev);
00947 
00948   send_client_message(ic->focus_window(),
00949                     (ic->is_version_40() ?
00950                      XIMP_GETVALUE_RETURN4 :
00951                      XIMP_GETVALUE_RETURN3),
00952                     input_context_id,
00953                     0, 0, 0);
00954   return;
00955 }
00956 
00957 //
00958 // reset XIC
00959 //
00960 // note: the calling order of reset_xic, conversion_end, and
00961 //      get_commit_string must not be changed so that
00962 //      implicit commit of XView applications should work well
00963 void
00964 XIMProtocol::reset(XClientMessageEvent *ev) {
00965   int input_context_id = ev->data.l[1];
00966   XIMPInputContext *ic = (XIMPInputContext*)&(input_context_list.getItem(input_context_id));
00967   if (!ic) return;
00968 
00969 #if 0
00970   XIMProtocol *ximp_protocol = ic->ximp_protocol;
00971   // IMText *text = ximp_protocol->proto_handler->ResetIC((InputContext*)ic);
00972 #endif
00973 
00974   // 
00975   // Only XIMP4.0 supports sending reset string by cmsg.
00976   //
00977   Atom atom_ret = (Atom)0;
00978   XIC_RESET_FLAG flag = RESET_NOTHING;
00979 
00980   char *ctext = ic->reset_xic(); // ctext needs to be free
00981   Bool need_ctext_free = True;
00982 
00983   ic->conversion_end();            // must be called after reset_xic()
00984 
00985   if (ctext == 0 || *ctext == 0) {
00986     ctext = ic->get_commit_string();
00987     need_ctext_free = False;
00988   } else {
00989     (void)ic->get_commit_string(); // to clear xic's being_reset flag to 0
00990   }
00991   if (ic->is_version_40()) {
00992     if (ctext == 0 || *ctext == 0) {
00993       atom_ret = 0;
00994     } else {
00995       size_t length = strlen(ctext);
00996       if (length <= 250) {
00997        commit_by_client_message(ic->focus_window(),
00998                              input_context_id,
00999                              ctext,
01000                              length);
01001        flag = RESET_BY_CMSG;
01002       } else {
01003        atom_ret = replace_prop_pool((unsigned char*)ctext, length);
01004        flag = RESET_BY_PROP;
01005       }
01006     }
01007   } else {
01008     atom_ret = 0;
01009   }
01010   if (need_ctext_free && ctext) XFree(ctext);
01011 
01012   send_client_message(ic->focus_window(),
01013                     (ic->is_version_40() ?
01014                      XIMP_RESET_RETURN4 :
01015                      XIMP_RESET_RETURN3),
01016                     input_context_id,
01017                     (CARD32)flag, (CARD32)atom_ret, 0);
01018 
01019   return;
01020 }
01021 
01022 void
01023 XIMProtocol::event_mask(XClientMessageEvent *ev) {
01024   int input_context_id = ev->data.l[1];
01025   XIMPInputContext *ic = (XIMPInputContext*)&(input_context_list.getItem(input_context_id));
01026   if (!ic) return;
01027 
01028   ic->set_fwin_select_mask(ev->data.l[2]);
01029 
01030   send_client_message(ic->focus_window(),
01031                     XIMP_EVENTMASK_NOTIFY_RETURN4,
01032                     input_context_id,
01033                     0, 0, 0);
01034   return;
01035 }
01036 
01037 void
01038 XIMProtocol::extension(XClientMessageEvent *ev) {
01039   int input_context_id = ev->data.l[1];
01040   XIMPInputContext *ic = (XIMPInputContext*)&(input_context_list.getItem(input_context_id));
01041   if (!ic) return;
01042   unsigned int extension_type = ev->data.l[2];
01043 
01044   if (extension_type == atoms.ext_statuswin) {
01045     ;
01046   }
01047   if (extension_type == atoms.ext_backfront) {
01048     ;
01049   }
01050   if (extension_type == atoms.ext_conversion) {
01051     if (ev->data.l[3]) {
01052       // set conv_state
01053       if (ev->data.l[4])    // conv state
01054        ic->conversion_start();
01055       else
01056        ic->conversion_end();
01057     } else {
01058       // get conv_state
01059       int conv_state = ic->is_conv_state();
01060       send_client_message(ic->focus_window(),
01061                        (ic->is_version_40() ?
01062                         XIMP_EXTENSION4 : XIMP_EXTENSION3),
01063                        input_context_id,
01064                        atoms.ext_conversion,
01065                        conv_state,
01066                        0);
01067     }
01068   }
01069   return;
01070 }
01071 
01072 void
01073 XIMProtocol::preedit_start_ret(XClientMessageEvent *ev) {
01074   int input_context_id = ev->data.l[1];
01075   XIMPInputContext *ic = (XIMPInputContext*)&(input_context_list.getItem(input_context_id));
01076   if (!ic) return;
01077 
01078   ic->set_preedit_maxlen(ev->data.l[2]);
01079 
01080   return;
01081 }
01082 
01083 void
01084 XIMProtocol::preedit_caret_ret(XClientMessageEvent *ev) {
01085   int input_context_id = ev->data.l[1];
01086   XIMPInputContext *ic = (XIMPInputContext*)&(input_context_list.getItem(input_context_id));
01087   if (!ic) return;
01088 
01089   ic->set_preedit_caret_position(ev->data.l[2]);
01090 
01091   return;
01092 }
01093 
01094 void
01095 XIMProtocol::commit_by_client_message(Window focus_window,
01096                                   int input_context_id,
01097                                   const char *ctext, int length) {
01098   XClientMessageEvent event;
01099   int msglen = CM_DATA_ROOM;       /* default */
01100   char *ctptr = (char*)ctext;
01101   Ximp_CommitPropRec *msg = (Ximp_CommitPropRec*)&(event.data.l[0]);
01102 
01103   event.type = ClientMessage;
01104   event.display = display;
01105   event.message_type = ximp_request;
01106   event.window = focus_window;
01107   event.format = 8;
01108 
01109   while (length > 0) {
01110     memset(msg, 0, sizeof(Ximp_CommitPropRec));
01111     msg->icid = htonl((long)input_context_id);
01112     msg->size = length;
01113     if (length < CM_DATA_ROOM) msglen = length;
01114 
01115     memmove(msg->ctext, ctptr, msglen);
01116     XSendEvent(display,
01117               focus_window,
01118               False,
01119               NoEventMask,
01120               (XEvent*)&event);
01121     length -= CM_DATA_ROOM;
01122     ctptr += CM_DATA_ROOM;
01123   }
01124   XFlush(display);
01125   return;
01126 }
01127 
01128 Atom
01129 XIMProtocol::replace_prop_pool(const unsigned char *data, int len) {
01130   char name[20];
01131   Atom type = atoms.feedbacks;
01132   Atom atom = XInternAtom(display, MakeNewAtom(name), False);
01133 
01134   XChangeProperty(display, im_window, atom, type, 32,
01135                 PropModeReplace, data, len);
01136   XFlush(display);
01137   return (atom);
01138 }
01139   
01140 Atom
01141 XIMProtocol::set_preedit_draw_data_property(const unsigned char *data ,
01142                                        int len) {
01143   char name[20];
01144   Atom atom = XInternAtom(display, MakeNewAtom(name), False);
01145   XChangeProperty(display, im_window, atom, atoms.preedit_draw_data,
01146                 32, PropModeReplace,
01147                 data, len);
01148   return atom;
01149 }
01150 
01151 Atom
01152 XIMProtocol::set_ctext_property(const unsigned char *data, int len,
01153                             int is_commit) {
01154   char name[20];
01155   Atom atom = XInternAtom(display, MakeNewAtom(name, is_commit), False);
01156   XChangeProperty(display, im_window, atom, atoms.ctext_type,
01157                 8, PropModeReplace,
01158                 data, len);
01159   return atom;
01160 }
01161 
01162 Atom
01163 XIMProtocol::set_ctext_property(const unsigned char *data, int len) {
01164   return set_ctext_property(data, len, 0);
01165 }
01166 
01167 Atom
01168 XIMProtocol::set_feedback_property(const unsigned char *data, int len) {
01169   char name[20];
01170   Atom atom = XInternAtom(display, MakeNewAtom(name), False);
01171   XChangeProperty(display, im_window, atom, atoms.feedbacks,
01172                 32, PropModeReplace,
01173                 data, len);
01174   return atom;
01175 }
01176 
01177 void
01178 XIMProtocol::send_client_message(Window focus_window, int type,
01179                              unsigned long l1, unsigned long l2,
01180                              unsigned long l3, unsigned long l4) {
01181   XEvent event;
01182 
01183   memset(&event, 0, sizeof(event));
01184   event.xclient.type = ClientMessage;
01185   event.xclient.display = display;
01186   event.xclient.window = focus_window;
01187   event.xclient.message_type = ximp_request;
01188   event.xclient.format = 32;
01189   event.xclient.data.l[0] = type;
01190   event.xclient.data.l[1] = l1;
01191   event.xclient.data.l[2] = l2;
01192   event.xclient.data.l[3] = l3;
01193   event.xclient.data.l[4] = l4;
01194 
01195   XSendEvent(display, event.xclient.window,
01196             False, NoEventMask, &event);
01197   XFlush(display);
01198 
01199 }
01200 
01201 char*
01202 XIMProtocol::MakeNewAtom(char *atomName, int is_commit) {
01203   sprintf(atomName,
01204          (is_commit ?
01205           "_XIMP_NORMALPROP_%X" :
01206           "_XIMP_CALLBACKS_%d"),
01207          (atom_sequence > 40 ? (atom_sequence = 0) : atom_sequence));
01208   atom_sequence++;
01209   return atomName;
01210 }
01211