Back to index

im-sdk  12.3.91
guiIMPre.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 #include "xiiimp.h"
00043 #include "iiimpIM.h"
00044 #include "iiimpColor.h"
00045 #include "guiIMPre.h"
00046 #include "XimpIm.h"
00047 #include "xfactory.h"
00048 #include "trace_message.h"
00049 
00050 static void UpdatePreedit(XicCommon, int, int);
00051 
00052 static void
00053 DrawPreeditString(XicCommon ic,
00054                 Display *display, Window win, XFontSet fontset,
00055                 GC gc, GC rgc, int x, int y, XIMFeedback *feedback,
00056                 IMFeedbackList *feedback_list,
00057                 wchar_t *wstr, int offset, int len) {
00058   if (fontset == NULL) return;
00059 
00060   wstr += offset;
00061   if (feedback != NULL) {
00062     XIMFeedback *start = (XIMFeedback*)feedback + offset;
00063     XIMFeedback *current;
00064     IMFeedbackList *start_flist = 0;
00065     IMFeedbackList *current_flist;
00066     int left = len;
00067     int nchars;
00068     wchar_t *wcstr = wstr;
00069     int under_line = y + 1;
00070     int pos_x = x;
00071     int width;
00072 
00073     if (feedback_list) {
00074       start_flist = &feedback_list[offset];
00075     }
00076     while (0 < left) {
00077       current = start;
00078       current_flist = start_flist;
00079       nchars = 0;
00080 
00081       while (*current == *start &&
00082             SameIMFeedbackList(current_flist, start_flist)) {
00083        nchars++;
00084        left--;
00085        if (left == 0) break;
00086        current++;
00087        current_flist++;
00088       }
00089       /* set colors */
00090       SetIMColors(ic, display, win, gc, rgc, start_flist, *start);
00091 
00092       if (*start & XIMReverse) {
00093        XwcDrawImageString(display, win, fontset, rgc, 
00094                         pos_x, y, wcstr, nchars);
00095       } else {
00096        XwcDrawImageString(display, win, fontset, gc, 
00097                         pos_x, y, wcstr, nchars);
00098       }
00099       width = XwcTextEscapement(fontset, wcstr, nchars);
00100       if (*start & XIMUnderline) {
00101        if (*start & XIMReverse)
00102          XDrawLine(display, win, rgc, 
00103                   pos_x, under_line, pos_x + width, under_line);
00104        else
00105          XDrawLine(display, win, gc, 
00106                   pos_x, under_line, pos_x + width, under_line);
00107       }
00108       wcstr += nchars;
00109       pos_x += width;
00110       start = current;
00111       start_flist = current_flist;
00112     }
00113   } else {
00114     XwcDrawString(display, win, fontset, gc, x, y, wstr, len);
00115   }
00116 }
00117 
00118 Bool
00119 FilterConfigureNotify(Display *d, Window w, XEvent *ev, XPointer client_data) {
00120   XicCommon ic = (XicCommon)client_data;
00121 
00122   if (!ic->gui_icpart || NULL == XIC_GUI(ic, preedit)) {
00123     /* perhaps the ic has been destroyed already */
00124     return False;
00125   }
00126   if (NULL != ev) {
00127     if (ConfigureNotify == ev->type) {
00128       if (((XConfigureEvent *)ev)->window == ic->core.focus_window) {
00129        XIC_GUI(ic, preedit)->client_window_width =
00130               ((XConfigureEvent *)ev)->width;
00131        XIC_GUI(ic, preedit)->client_window_height =
00132               ((XConfigureEvent *)ev)->height;
00133        XIC_GUI(ic, change_preedit)((XIC)ic, PREEDIT_WIN, NULL);
00134        UpdatePreedit(ic, 0, 0);
00135       }
00136     }
00137   } else {
00138     if (w == ic->core.focus_window) {
00139       XWindowAttributes attr;
00140       if (XGetWindowAttributes(d, w, &attr)) {
00141        XIC_GUI(ic, preedit)->client_window_width = attr.width;
00142        XIC_GUI(ic, preedit)->client_window_height = attr.height;
00143       }
00144     }
00145   }
00146 
00147   return False;
00148 }
00149 
00150 static Bool
00151 FilterKeyPress(Display *d, Window w, XEvent *ev, XPointer client_data) {
00152   XicCommon ic = (XicCommon)client_data;
00153   IMForwardEvent(ic, ev);
00154   PutBackXKeyEvent(ic);
00155   return True;
00156 }
00157 
00158 static Bool
00159 RepaintPreedit(Display *d, Window w, XEvent *ev, XPointer client_data) {
00160   XicCommon ic = (XicCommon)client_data;
00161   PreeditWin preedit = NULL;
00162 
00163   if (!ic->gui_icpart) return True;
00164   preedit = (PreeditWin)ic->gui_icpart->preedit;
00165   
00166   if (!preedit) return True;
00167 
00168   if (True == XIC_GUI(ic, preedit)->discard_expose_event) {
00169     /*
00170      * when preedit window is created or reconfigured, expose
00171      * event will be delivered.  xiiimp.so always updates
00172      * contents of the window before receiving expose event,
00173      * there is no need to update the contents here.
00174      */
00175     XIC_GUI(ic, preedit)->discard_expose_event = False;
00176     return True;
00177   }
00178 
00179   /* multiple expose event */
00180   if (0 != ((XExposeEvent *)ev)->count) return True;
00181 
00182   UpdatePreedit(ic, 0, 0);
00183   return True;
00184 }
00185 
00186 static void
00187 UpdatePreeditAll(XicCommon ic) {
00188   PreeditWin preedit = (PreeditWin)(ic->gui_icpart->preedit);
00189   PreeditArea preedit_area = preedit->preedit_areas;
00190   PreeditChars preedit_chars = (PreeditChars)&(preedit->preedit_chars);
00191   int i;
00192 
00193   if (preedit_chars->wchar == 0) return;
00194 
00195   /* Draw All Preedit Text */
00196   for (i = 0; i < preedit->active_areas; i++) {
00197     if (ic->core.input_style & XIMPreeditArea) {
00198       XClearArea(ic->core.im->core.display,
00199                preedit_area[i].window, 0, 0, 0, 0, False);
00200     }
00201     if (preedit_area[i].active_lines == 0) {
00202       DrawPreeditString(ic,
00203                      ic->core.im->core.display,
00204                      preedit_area[i].window,
00205                      preedit->fontset,
00206                      preedit->gc, preedit->rgc,
00207                      preedit_area[i].x,
00208                      preedit_area[i].y,
00209                      preedit_chars->feedback,
00210                      preedit_chars->feedback_list,
00211                      preedit_chars->wchar,
00212                      preedit_area[i].char_offset,
00213                      preedit_area[i].char_len);
00214     } else {
00215       int j;
00216       PreeditLine line = (PreeditLine)preedit_area[i].lines;
00217       for (j = 0; j < preedit_area[i].active_lines; j++) {
00218        DrawPreeditString(ic,
00219                        ic->core.im->core.display,
00220                        preedit_area[i].window,
00221                        preedit->fontset,
00222                        preedit->gc, preedit->rgc,
00223                        line[j].x,
00224                        line[j].y,
00225                        preedit_chars->feedback,
00226                        preedit_chars->feedback_list,
00227                        preedit_chars->wchar,
00228                        line[j].char_offset,
00229                        line[j].char_len);
00230       }
00231     }
00232   }
00233 }
00234 
00235 static void
00236 preedit_window_fg_and_bg(XicCommon ic, unsigned long *fg,
00237                       unsigned long *bg) {
00238   Display *display = ic->core.im->core.display;
00239 
00240   if (XIMP_CHK_PREFGMASK(ic) && XIMP_CHK_PREBGMASK(ic)) {
00241     *fg = ic->core.preedit_attr.foreground;
00242     *bg = ic->core.preedit_attr.background;
00243   } else {
00244     *fg = BlackPixel(display, DefaultScreen(display));
00245     *bg = WhitePixel(display, DefaultScreen(display));
00246   }
00247   return;
00248 }
00249 
00250 static void
00251 create_preedit_gc(Display *display, Window win,
00252                 PreeditWin preedit,
00253                 unsigned long fg, unsigned long bg) {
00254   unsigned long val_mask;
00255   XGCValues gcval;
00256 
00257   val_mask = GCForeground | GCBackground;
00258   gcval.foreground = fg;
00259   gcval.background = bg;
00260   preedit->gc = XCreateGC(display, win, val_mask, &gcval);
00261   gcval.foreground = bg;
00262   gcval.background = fg;
00263   preedit->rgc = XCreateGC(display, win, val_mask, &gcval);
00264 }
00265                       
00266 void
00267 UnmapPreeditWindow(XicCommon ic, PreeditArea preedit_area) {
00268   if (False == preedit_area->mapped) {
00269     return;
00270   }
00271 
00272   XUnmapWindow(ic->core.im->core.display, preedit_area->window);
00273   preedit_area->mapped = False;
00274   preedit_area->win_config.x = -1;
00275   preedit_area->win_config.y = -1;
00276   preedit_area->win_config.height = -1;
00277   preedit_area->win_config.width = -1;
00278 
00279   return;
00280 }
00281 
00282 static void
00283 UpdatePreedit(XicCommon ic, int start, int len) {
00284   PreeditWin preedit = (PreeditWin)(ic->gui_icpart->preedit);
00285   PreeditArea preedit_area = preedit->preedit_areas;
00286   PreeditChars preedit_chars;
00287   int i;
00288 
00289   if (!preedit) return;
00290 
00291   if (!preedit->preedit_areas) {
00292     XIC_GUI(ic, change_preedit)((XIC)ic, PREEDIT_CREATE, NULL);
00293     if (!preedit->preedit_areas)
00294       return;
00295   }
00296   preedit_area = preedit->preedit_areas;
00297   preedit_chars = (PreeditChars)&(preedit->preedit_chars);
00298 
00299   if (preedit_chars->wchar_len == 0) {
00300     for (i = 0; i < preedit->active_areas; i++) {
00301       UnmapPreeditWindow(ic, preedit_area + i);
00302     }
00303     return;
00304   }
00305   if (preedit->gc == 0 || preedit->rgc == 0) {
00306     unsigned long fg, bg;
00307     preedit_window_fg_and_bg(ic, &fg, &bg);
00308     create_preedit_gc(ic->core.im->core.display,
00309                     preedit_area[0].window, preedit,
00310                     fg, bg);
00311   }
00312 
00313   if (!preedit->fontset) {
00314     SetPreeditFont(ic, NULL);
00315   }
00316   for (i = 0; i < preedit->active_areas; i++) {
00317     if (preedit_area[i].char_len == 0) {
00318       UnmapPreeditWindow(ic, preedit_area + i);
00319       continue;
00320     }
00321     if (False == preedit_area[i].mapped) {
00322       XMapWindow(ic->core.im->core.display, preedit_area[i].window);
00323       preedit_area[i].mapped = True;
00324     }
00325   }
00326   for (i = preedit->active_areas; i < preedit->alloc_areas; i++) {
00327     UnmapPreeditWindow(ic, preedit_area + i);
00328   }
00329   if (preedit_chars->wchar_len == 0) {
00330     for (i = 0; i < preedit->active_areas; i++) {
00331       XClearArea(ic->core.im->core.display,
00332                preedit_area[i].window, 0, 0, 0, 0, False);
00333     }
00334   }
00335   if (start == 0 && len == 0) {
00336     UpdatePreeditAll(ic);
00337   } else if (ic->core.input_style & XIMPreeditArea &&
00338             (preedit_area[0].configured == True ||
00339              preedit_area[0].char_len !=
00340              preedit_area[0].char_len_backup)) {
00341     UpdatePreeditAll(ic);
00342   } else if (len > 0) {
00343     int x;
00344     unsigned int width;
00345     wchar_t *wcstr = preedit_chars->wchar;
00346 
00347     for (i = preedit->active_areas - 1; i >= 0; i--) {
00348       if (preedit_area[i].active_lines == 0) {
00349        int char_offset = preedit_area[i].char_offset;
00350        int char_len = preedit_area[i].char_len;
00351        int start_clear;
00352        int end_clear;
00353 
00354        if (True == preedit_area[i].configured) {
00355          start_clear = char_offset;
00356          end_clear = start_clear + char_len;
00357          width = XwcTextEscapement(preedit->fontset,
00358                                 wcstr + start_clear, char_len);
00359          x = 0;
00360          preedit_area[i].configured = False;
00361 
00362        } else {
00363          if (char_offset + char_len < start) continue;
00364          if (char_offset > start + len) continue;
00365 
00366          start_clear = start > char_offset ? start : char_offset;
00367          if ((True == XIC_GUI(ic, preedit)->discard_expose_event) &&
00368              ((start + len) <= (char_offset + char_len))) {
00369            end_clear = (char_offset + char_len);
00370          } else {
00371            end_clear = (((start + len) < (char_offset + char_len)) ?
00372                       (start + len) : (char_offset + char_len));
00373          }
00374 
00375          if ((start + len) < (char_offset + char_len)) {
00376            width = XwcTextEscapement(preedit->fontset, wcstr + start_clear,
00377                                   end_clear - start_clear);
00378          } else {
00379            width = 0;
00380          }
00381          if (0 < (start_clear - char_offset)) {
00382            x = XwcTextEscapement(preedit->fontset, wcstr + char_offset,
00383                               start_clear - char_offset);
00384          } else {
00385            x = 0;
00386          }
00387        }
00388 
00389        TRACE_MESSAGE('p', ("UpdatePreedit: "
00390                          "len=%d start=%d end=%d "
00391                          "char_offset=%d char_len=%d x=%d width=%d "
00392                          "area[%d].x=%d, area[%d].y=%d "
00393                          "\n",
00394                          len, start_clear, end_clear,
00395                          char_offset, char_len, x, width,
00396                          i, preedit_area[i].x, i, preedit_area[i].y));
00397        if ((preedit_chars->wchar[0]) && (0 < (end_clear - start_clear))) {
00398          XClearArea(ic->core.im->core.display,
00399                    preedit_area[i].window,
00400                    preedit_area[i].x + x, preedit_area[i].y,
00401                    width, 0, False);
00402          DrawPreeditString(ic,
00403                          ic->core.im->core.display,
00404                          preedit_area[i].window,
00405                          preedit->fontset,
00406                          preedit->gc, preedit->rgc,
00407                          preedit_area[i].x + x, preedit_area[i].y,
00408                          preedit_chars->feedback,
00409                          preedit_chars->feedback_list,
00410                          preedit_chars->wchar,
00411                          start_clear, end_clear - start_clear);
00412        }
00413       } else {
00414        PreeditLine line = (PreeditLine)preedit_area[i].lines;
00415        int j;
00416        XClearArea(ic->core.im->core.display,
00417                  preedit_area[i].window, 0, 0, 0, 0, False);
00418        for (j = 0; j < preedit_area[i].active_lines; j++) {    
00419          DrawPreeditString(ic,
00420                          ic->core.im->core.display,
00421                          preedit_area[i].window,
00422                          preedit->fontset,
00423                          preedit->gc, preedit->rgc,
00424                          line[j].x,
00425                          line[j].y,
00426                          preedit_chars->feedback,
00427                          preedit_chars->feedback_list,
00428                          preedit_chars->wchar,
00429                          line[j].char_offset,
00430                          line[j].char_len);
00431        }
00432       }
00433     }
00434   }
00435 }
00436 
00437 /* Public Methods */
00438 Bool
00439 SetupPreeditExt(XicCommon ic) {
00440   PreeditWin preedit = (PreeditWin)Xmalloc(sizeof(PreeditWinRec));
00441 
00442   if (!preedit) return False;
00443   memset((char *)preedit, 0, sizeof(PreeditWinRec));
00444 
00445   preedit->alloc_areas = 0;
00446   preedit->active_areas = 0;
00447   preedit->need_free_fontset = False;
00448 
00449   ic->gui_icpart->preedit = (void *)preedit;
00450   return True;
00451 }
00452 
00453 Bool
00454 NewPreeditWindow(XicCommon ic) {
00455   PreeditWin preedit = (PreeditWin)(ic->gui_icpart->preedit);
00456   Window win;
00457   int x, y;
00458   unsigned int width, height;
00459   unsigned long fg, bg;
00460   Display *display = ic->core.im->core.display;
00461   PreeditArea preedit_area = (PreeditArea)NULL;
00462   int n;
00463   int nn;
00464   int mask;
00465   XIMFilterRec filters[2];
00466   XClassHint class_hint;
00467 
00468   if (!preedit) return False;
00469 
00470   if (XIMP_CHK_PREAREAMASK(ic)) {
00471     x = ic->core.preedit_attr.area.x;
00472     y = ic->core.preedit_attr.area.y;
00473     width   = ic->core.preedit_attr.area.width;
00474     height  = ic->core.preedit_attr.area.height;
00475   } else if (XIMP_CHK_PRESPOTLMASK(ic)) {
00476     x = ic->core.preedit_attr.spot_location.x;
00477     y = ic->core.preedit_attr.spot_location.y;
00478     width = height = 1;
00479   } else {
00480     x  = y = 0;
00481     width = height = 1;
00482   }
00483 
00484   if (preedit->alloc_areas == 0 || !preedit->preedit_areas) {
00485     preedit->alloc_areas = 1;
00486     preedit->active_areas = 1;
00487     preedit->preedit_areas = (PreeditArea)Xmalloc(sizeof(PreeditAreaRec));
00488     if (!preedit->preedit_areas) {
00489       return False;
00490     }
00491     memset((char *)preedit->preedit_areas, 0, sizeof(PreeditAreaRec));
00492   } else {
00493     preedit->alloc_areas++;
00494     preedit->active_areas++;
00495     preedit->preedit_areas = (PreeditArea)
00496       Xrealloc(preedit->preedit_areas, sizeof(PreeditAreaRec) *
00497               preedit->alloc_areas);
00498     if (!preedit->preedit_areas) {
00499       return False;
00500     }
00501   }
00502   preedit_area = preedit->preedit_areas;
00503   n = preedit->alloc_areas;
00504 
00505   preedit_window_fg_and_bg(ic, &fg, &bg);
00506 
00507   mask = None;
00508   nn = 0;
00509   filters[nn].type = KeyPress;
00510   filters[nn].filter = FilterKeyPress;
00511   filters[nn].client_data = (XPointer)ic;
00512   mask |= KeyPressMask;
00513   nn++;
00514   filters[nn].type = Expose;
00515   filters[nn].filter = RepaintPreedit;
00516   filters[nn].client_data = (XPointer)ic;
00517   nn++;
00518   mask |= ExposureMask;
00519 
00520   width = height = 1;
00521   win = XFactoryCreateIMWindow(display, preedit->parent,
00522                             ic->core.client_window,
00523                             x, y, width, height, bg,
00524                             mask, filters, nn);
00525   if (!win) return False;
00526 
00527   if (ic->core.input_style & XIMPreeditArea ||
00528       ic->core.input_style & XIMPreeditPosition) {
00529     /* set override-redirect to true */
00530     XSetWindowAttributes attributes;
00531     int cmask = 0;
00532     cmask |= CWOverrideRedirect;
00533     attributes.override_redirect = True;
00534     XChangeWindowAttributes(ic->core.im->core.display, win,
00535                          cmask, &attributes);
00536   }
00537 
00538   XStoreName(display, win, "iiimx IM Preedit");
00539 
00540   class_hint.res_name = "iiimx-im-preedit";
00541   class_hint.res_class = "IiimxImPreedit";
00542   XSetClassHint(display, win, &class_hint);
00543 
00544   if (!(ic->core.input_style & XIMPreeditNothing)) {
00545     /* bug fix:
00546           4295973: preedit text is invisible in XIMPreeditNothing
00547        We don't know why backing store with XIMPreeditNothing causes
00548        4295973, but having the codes commented out will fix it.
00549     */
00550     XSetWindowAttributes attributes;
00551     mask = 0;
00552     attributes.bit_gravity = NorthWestGravity;
00553     mask |= CWBitGravity;
00554     attributes.backing_store = WhenMapped;
00555     mask |= CWBackingStore;
00556     XChangeWindowAttributes(display, win, mask, &attributes);
00557   }
00558 #if 0
00559   if (XIMP_CHK_PREFGMASK(ic) && XIMP_CHK_PREBGMASK(ic)) {
00560     create_preedit_gc(display, win, preedit,
00561                     ic->core.preedit_attr.foreground,
00562                     ic->core.preedit_attr.background);
00563   }
00564 #endif
00565 
00566   preedit_area[n-1].window = win;
00567   preedit_area[n-1].char_offset = 0;
00568   preedit_area[n-1].char_len = 0;
00569   preedit_area[n-1].char_offset_backup = 0;
00570   preedit_area[n-1].char_len_backup = 0;
00571   preedit_area[n-1].active_lines = 0;
00572   preedit_area[n-1].alloc_lines = 0;
00573   preedit_area[n-1].mapped = False;
00574   preedit_area[n-1].win_config.x = x;
00575   preedit_area[n-1].win_config.y = y;
00576   preedit_area[n-1].win_config.width = width;
00577   preedit_area[n-1].win_config.height = height;
00578 
00579 
00580   return True;
00581 }
00582 
00583 Bool
00584 SetupPreeditWindow(XicCommon ic, Window parent) {
00585   PreeditWin preedit = (PreeditWin)(ic->gui_icpart->preedit);
00586   int x, y;
00587   Display *display = ic->core.im->core.display;
00588   PreeditArea preedit_area = (PreeditArea)NULL;
00589   XWindowAttributes cwin_att;
00590   int i;
00591 
00592   if (!preedit) return False;
00593 
00594   /* A new parent window is the same as the previous, nothing to do. */
00595   if (preedit->preedit_areas) {
00596     if (parent == 0 || preedit->parent == parent)
00597       return False;
00598 
00599     /* on Linux, sometimes parent window is invalid */
00600     if (preedit->parent && !IMCheckIMWindow(ic, preedit->parent)) {
00601       preedit->alloc_areas=0;
00602     }
00603   }
00604 
00605   preedit->parent = parent;
00606 
00607   if (XIMP_CHK_PREAREAMASK(ic)) {
00608     x = ic->core.preedit_attr.area.x;
00609     y = ic->core.preedit_attr.area.y;
00610   } else if (XIMP_CHK_PRESPOTLMASK(ic)) {
00611     x = ic->core.preedit_attr.spot_location.x;
00612     y = ic->core.preedit_attr.spot_location.y;
00613   } else {
00614     x  = y = 0;
00615   }
00616 
00617   if (preedit->alloc_areas > 0) {
00618     preedit_area = preedit->preedit_areas;
00619     for (i = 0; i < preedit->alloc_areas; i++) {
00620       if (preedit_area[i].window) {
00621        /* Make sure the window gets unmapped */
00622         preedit_area[i].mapped = True;
00623        UnmapPreeditWindow(ic, preedit_area + i);
00624        XReparentWindow(display, preedit_area[i].window,
00625                      preedit->parent,
00626                      x, y);
00627       }
00628     }
00629     XIC_GUI(ic, change_preedit)((XIC)ic, PREEDIT_MOVE, NULL);
00630     /* redraw if any text in preedit windows */
00631     UpdatePreedit(ic, 0, 0);
00632     return True;
00633   } else {
00634     if (XGetWindowAttributes(ic->core.im->core.display, 
00635               ic->core.client_window, &cwin_att) && 
00636               (cwin_att.map_state == IsViewable))
00637       return NewPreeditWindow(ic);
00638     else 
00639       return False;
00640   }
00641 }
00642 
00643 void
00644 SetPreeditForeground(XicCommon ic, XPointer call_data) {
00645   PreeditWin preedit = (PreeditWin)(ic->gui_icpart->preedit);
00646   CacheRec *preedit_cache;
00647 
00648   if (!preedit) return;  /* Let's do it later */
00649 
00650   preedit_cache = (CacheRec*)&(preedit->preedit_cache);
00651 
00652   if (preedit_cache->foreground == ic->core.preedit_attr.foreground) {
00653     return;
00654   }
00655 #if 0
00656   if (preedit->gc) {
00657     XGCValues val;
00658     unsigned long mask;
00659     val.foreground = ic->core.preedit_attr.foreground;
00660     mask = GCForeground;
00661     XChangeGC(ic->core.im->core.display,
00662              preedit->gc,
00663              mask,
00664              &val);
00665   }
00666 
00667   if (preedit->rgc) {
00668     XGCValues val;
00669     unsigned long mask;
00670     val.background = ic->core.preedit_attr.foreground;
00671     mask = GCBackground;
00672     XChangeGC(ic->core.im->core.display,
00673              preedit->rgc,
00674              mask,
00675              &val);
00676   }
00677 #endif
00678   preedit_cache->foreground = ic->core.preedit_attr.foreground;
00679   return;
00680 }
00681 
00682 void
00683 SetPreeditBackground(XicCommon ic, XPointer call_data) {
00684   PreeditWin preedit = (PreeditWin)(ic->gui_icpart->preedit);
00685   CacheRec *preedit_cache;
00686   int i;
00687 
00688   if (!preedit) return;  /* Let's do it later */
00689 
00690   preedit_cache = (CacheRec*)&(preedit->preedit_cache);
00691 
00692   TRACE_MESSAGE('p', ("SetPreeditBackground: %d %d\n",
00693                     preedit_cache->background,
00694                     ic->core.preedit_attr.background));
00695 
00696   if (preedit_cache->background == ic->core.preedit_attr.background) {
00697     return;
00698   }
00699 
00700   for (i = 0; i < preedit->alloc_areas; i++) {
00701     if (preedit->preedit_areas[i].window) {
00702       XSetWindowBackground(ic->core.im->core.display,
00703                         preedit->preedit_areas[i].window,
00704                         ic->core.preedit_attr.background);
00705     }
00706   }
00707 #if 0
00708   if (preedit->gc) {
00709     XGCValues val;
00710     unsigned long mask;
00711     val.background = ic->core.preedit_attr.background;
00712     mask = GCBackground;
00713     XChangeGC(ic->core.im->core.display,
00714              preedit->gc,
00715              mask,
00716              &val);
00717   }
00718   if (preedit->rgc) {
00719     XGCValues val;
00720     unsigned long mask;
00721     val.foreground = ic->core.preedit_attr.background;
00722     mask = GCForeground;
00723     XChangeGC(ic->core.im->core.display,
00724              preedit->rgc,
00725              mask,
00726              &val);
00727   }
00728 #endif
00729   preedit_cache->background = ic->core.preedit_attr.background;
00730   return;
00731 }
00732 
00733 static void
00734 UpdatePreeditWidth(XicCommon ic) {
00735   PreeditWin preedit = (PreeditWin)(ic->gui_icpart->preedit);
00736   PreeditChars preedit_chars;
00737   int i;
00738   int text_length;
00739   wchar_t *wc_p;
00740 
00741   preedit_chars = &(preedit->preedit_chars);
00742   text_length = preedit_chars->wchar_len;
00743 
00744   for (wc_p = preedit_chars->wchar, i = 0; i < text_length; i++) {
00745     *(preedit_chars->wchar_width + i) =
00746       XwcTextEscapement(preedit->fontset, wc_p + i, 1);
00747   }
00748   UpdatePreedit(ic, 0, text_length);
00749 }
00750 
00751 void
00752 SetPreeditFont(XicCommon ic, XPointer call_data) {
00753   PreeditWin preedit = (PreeditWin)(ic->gui_icpart->preedit);
00754 
00755   if (!preedit) {
00756     XIC_GUI(ic, change_preedit)((XIC)ic, PREEDIT_CREATE, NULL);
00757     preedit = (PreeditWin)ic->gui_icpart->preedit;
00758     if (!preedit) return;
00759   }
00760   if (ic->core.preedit_attr.fontset) {
00761     if (preedit->fontset && preedit->need_free_fontset) {
00762       XFactoryFreeDefaultFontSet (ic->core.im->core.display);
00763       preedit->need_free_fontset = False;
00764     }
00765     preedit->fontset = ic->core.preedit_attr.fontset;
00766   } else if (preedit->fontset == NULL) {
00767     preedit->fontset = XFactoryCreateDefaultFontSet(ic->core.im->core.display,
00768                                               XIM_IIIMP(ic->core.im, default_font_name));
00769     preedit->need_free_fontset = True;
00770   }
00771   preedit->fse = XExtentsOfFontSet(preedit->fontset);
00772 
00773   XIC_GUI(ic, change_preedit)((XIC)ic, PREEDIT_WIN, NULL);
00774   UpdatePreeditWidth(ic);
00775   XIC_GUI(ic, change_preedit)((XIC)ic, PREEDIT_MOVE, NULL);
00776   return;
00777 }
00778 
00779 static void
00780 PreeditReplaceString(XicCommon ic, PreeditWin preedit,
00781                    int *change_first, int *change_length,
00782                    XIMText *text, IMFeedbackList *feedback_list) {
00783   int  first_real;
00784   int  length_real;
00785   int  first_orig;
00786   int  length_orig;
00787   int  i = 0;
00788   int  j;
00789   int  m;
00790   int  text_length;
00791   PreeditChars preedit_chars;
00792   PreeditChars preedit_chars_backup;
00793   wchar_t *cur_char;
00794   wchar_t *chg_char;
00795   wchar_t wc_buf[1024];
00796   wchar_t *wc_p;
00797   wchar_t *wc_p_free;
00798   IMFeedbackList *src_fbl;
00799   IMFeedbackList *dst_fbl;
00800   IMFeedbackList *cur_fbl;
00801   IMFeedbackList *chg_fbl;
00802   XIMFeedback *cur_xfb;
00803   XIMFeedback *chg_xfb;
00804   IMFeedback  *cur_fb;
00805   IMFeedback  *chg_fb;
00806 
00807   preedit_chars = &(preedit->preedit_chars);
00808 
00809   if (preedit_chars->wchar_len < *change_first) {
00810     first_orig  = preedit_chars->wchar_len;
00811     length_orig = 0;
00812   } else if (preedit_chars->wchar_len < (*change_first + *change_length)) {
00813     first_orig  = *change_first;
00814     length_orig = (preedit_chars->wchar_len - *change_first);
00815   } else {
00816     first_orig  = *change_first;
00817     length_orig = *change_length;
00818   }
00819   first_real = first_orig;
00820   length_real = length_orig;
00821 
00822   wc_p_free = NULL;
00823 
00824   /*
00825    * dtermine the real change
00826    */
00827   if (NULL == text) {
00828     wc_p = NULL;
00829     text_length = 0;
00830     *change_first = first_real;
00831     *change_length = length_real;
00832   } else {
00833     text_length = text->length;
00834     if (text->encoding_is_wchar) {
00835       wc_p = text->string.wide_char;
00836     } else {
00837       wc_p = wc_buf;
00838       if (((sizeof (wc_buf)) / (sizeof (wchar_t))) < text_length) {
00839        wc_p = Xmalloc((sizeof (wchar_t)) * text_length);
00840        if (NULL == wc_p) return;
00841        wc_p_free = wc_p;
00842       }
00843       IIimpMbstoWcs((XimCommon)ic->core.im,
00844                   text->string.multi_byte, strlen(text->string.multi_byte),
00845                   wc_p, text_length, NULL);
00846     }
00847 
00848     cur_char = (preedit_chars->wchar + first_real);
00849     cur_fbl = (preedit_chars->feedback_list + first_real);
00850     cur_xfb = (preedit_chars->feedback + first_real);
00851     chg_char = wc_p;
00852     chg_fbl = feedback_list;
00853     chg_xfb = text->feedback;
00854 
00855     /*
00856      * calculate first_real
00857      */
00858     for (i = 0; i < length_real; i++) {
00859       if (*(cur_char + i) != *(chg_char + i)) {
00860        break;
00861       }
00862 
00863       cur_fb = cur_fbl[i].feedbacks;
00864       if (NULL == chg_fbl) {
00865        for (j = 0; j < cur_fbl[i].count_feedbacks; j++) {
00866          if ((IM_DECORATION_FEEDBACK != (cur_fb + j)->type) ||
00867              (0 != (cur_fb + j)->value)) {
00868            break;
00869          }
00870        }
00871        if (j != cur_fbl[i].count_feedbacks) {
00872          break;
00873        }
00874       } else {
00875        if (cur_fbl[i].count_feedbacks != chg_fbl[i].count_feedbacks) {
00876          break;
00877        }
00878        chg_fb = chg_fbl[i].feedbacks;
00879        for (j = 0; j < cur_fbl[i].count_feedbacks; j++) {
00880          if (((cur_fb + j)->type  != (chg_fb + j)->type) ||
00881              ((cur_fb + j)->value != (chg_fb + j)->value)) {
00882            break;
00883          }
00884        }
00885        if (j != cur_fbl[i].count_feedbacks) {
00886          break;
00887        }
00888       }
00889 
00890       if (NULL == chg_xfb) {
00891        if (*(cur_xfb + i) != 0) {
00892          break;
00893        }
00894       } else {
00895        if (*(cur_xfb + i) != *(chg_xfb + i)) {
00896          break;
00897        }
00898       }
00899     }
00900     first_real += i;
00901 
00902     cur_char = (preedit_chars->wchar + *change_first + *change_length - 1);
00903     cur_fbl = ((NULL == preedit_chars->feedback_list) ? NULL :
00904               (preedit_chars->feedback_list +
00905               *change_first + *change_length - 1));
00906     cur_xfb = ((NULL == preedit_chars->feedback) ? NULL :
00907               (preedit_chars->feedback + *change_first + *change_length - 1));
00908     chg_char = (wc_p + text_length - 1);
00909     chg_fbl = ((NULL == feedback_list) ? NULL :
00910               (feedback_list + text_length - 1));
00911     chg_xfb = ((NULL == text->feedback) ? NULL :
00912               (text->feedback + text_length - 1));
00913 
00914     /*
00915      * calculate length_real
00916      */
00917     if (0 == *change_length) {
00918       m = 0;
00919     } else {
00920       m = ((text_length < *change_length) ? *change_length : text_length);
00921     }
00922     for (i = 0; i < m; i++) {
00923       if (*(cur_char - i) != *(chg_char - i)) {
00924        break;
00925       }
00926 
00927       cur_fb = (cur_fbl->feedbacks - i);
00928       if (NULL == chg_fbl) {
00929        for (j = 0; j < cur_fbl->count_feedbacks; j++) {
00930          if ((IM_DECORATION_FEEDBACK != (cur_fb + j)->type) ||
00931              (0 != (cur_fb + j)->value)) {
00932            break;
00933          }
00934        }
00935        if (j != cur_fbl->count_feedbacks) {
00936          break;
00937        }
00938       } else {
00939        if ((cur_fbl - i)->count_feedbacks != (chg_fbl - i)->count_feedbacks) {
00940          break;
00941        }
00942        chg_fb = (chg_fbl->feedbacks - i);
00943        for (j = 0; j < cur_fbl->count_feedbacks; j++) {
00944          if (((cur_fb + j)->type  != (chg_fb + j)->type) ||
00945              ((cur_fb + j)->value != (chg_fb + j)->value)) {
00946            break;
00947          }
00948        }
00949        if (j != cur_fbl->count_feedbacks) {
00950          break;
00951        }
00952       }
00953 
00954       if (NULL == chg_xfb) {
00955        if (*(cur_xfb - i) != 0) {
00956          break;
00957        }
00958       } else {
00959        if (*(cur_xfb - i) != *(chg_xfb - i)) {
00960          break;
00961        }
00962       }
00963     }
00964     length_real -= i;
00965 
00966     *change_first = first_real;
00967     if (*change_length == text_length) {
00968       *change_length = length_real;
00969     } else {
00970       *change_length = (preedit_chars->wchar_len
00971                      - first_real - *change_length + text_length);
00972     }
00973   }
00974 
00975   /*
00976    * free preedit_chars_backup
00977    */
00978   preedit_chars_backup = &(preedit->preedit_chars_backup);
00979 
00980   Xfree((char*)preedit_chars_backup->feedback);
00981   Xfree((char*)preedit_chars_backup->wchar);
00982   Xfree((char*)preedit_chars_backup->wchar_width);
00983   FreeFeedbackList(preedit_chars_backup->feedback_list, 
00984                  preedit_chars_backup->alloc_len);
00985 
00986   /*
00987    * backup current preedit_chars
00988    */
00989   preedit_chars_backup->feedback_list = preedit_chars->feedback_list;
00990   preedit_chars_backup->feedback = preedit_chars->feedback;
00991   preedit_chars_backup->wchar = preedit_chars->wchar;
00992   preedit_chars_backup->wchar_width = preedit_chars->wchar_width;
00993   preedit_chars_backup->wchar_len = preedit_chars->wchar_len;
00994   preedit_chars_backup->alloc_len = preedit_chars->alloc_len;
00995 
00996   /*
00997    * allocate new preedit_chars areas
00998    */
00999   preedit_chars->wchar_len = (preedit_chars_backup->wchar_len - length_orig
01000                            + text_length);
01001   preedit_chars->alloc_len = (preedit_chars->wchar_len + 1);
01002   preedit_chars->wchar = Xmalloc(preedit_chars->alloc_len * (sizeof (wchar_t)));
01003   preedit_chars->wchar_width = Xmalloc(preedit_chars->alloc_len *
01004                                    (sizeof (unsigned short)));
01005   memset(preedit_chars->wchar_width, 0,
01006         preedit_chars->alloc_len * (sizeof (unsigned short)));
01007   preedit_chars->feedback =
01008          Xmalloc(preedit_chars->alloc_len * (sizeof (XIMFeedback)));
01009   memset(preedit_chars->feedback, 0,
01010         preedit_chars->alloc_len * (sizeof (XIMFeedback)));
01011   preedit_chars->feedback_list =
01012          Xmalloc(preedit_chars->alloc_len * (sizeof (IMFeedbackList)));
01013   memset(preedit_chars->feedback_list, 0,
01014         preedit_chars->alloc_len * (sizeof (IMFeedbackList)));  
01015 
01016   /*
01017    * update wchar
01018    */
01019   if (0 != first_orig) {
01020     memcpy(preedit_chars->wchar, preedit_chars_backup->wchar,
01021           (sizeof (wchar_t)) * first_orig);
01022   }
01023   if (0 != text_length) {
01024     memcpy(preedit_chars->wchar + first_orig, wc_p,
01025           (sizeof (wchar_t)) * text_length);
01026   }
01027   if ((first_orig + text_length) < preedit_chars->wchar_len) {
01028     memcpy(preedit_chars->wchar + first_orig + text_length,
01029           preedit_chars_backup->wchar + first_orig + length_orig,
01030           (sizeof (wchar_t)) *
01031           (preedit_chars->wchar_len - first_orig + text_length));
01032   }
01033   *(preedit_chars->wchar + preedit_chars->wchar_len) = L'\0';
01034 
01035   /*
01036    * update width
01037    */
01038 
01039   if (0 != first_orig) {
01040     memcpy(preedit_chars->wchar_width, preedit_chars_backup->wchar_width,
01041           (sizeof (unsigned short)) * first_orig);
01042   }
01043   if (0 != text_length) {
01044     if (NULL == preedit->fontset) {
01045       SetPreeditFont(ic, NULL);
01046     }
01047     if (NULL == preedit->fontset) {
01048       *(preedit_chars->wchar_width + i) = 0;
01049     } else {
01050       for (i = 0; i < text_length; i++) {
01051        *(preedit_chars->wchar_width + first_orig + i) =
01052               XwcTextEscapement(preedit->fontset, wc_p + i, 1);
01053       }
01054     }
01055   }
01056   if ((first_orig + text_length) < preedit_chars->wchar_len) {
01057     memcpy(preedit_chars->wchar_width + first_orig + text_length,
01058           preedit_chars_backup->wchar_width + first_orig + length_orig,
01059           (sizeof (unsigned short)) *
01060           (preedit_chars->wchar_len - first_orig + text_length));
01061   }
01062 
01063   /*
01064    * update feedback
01065    */
01066   if (0 != first_orig) {
01067     memcpy(preedit_chars->feedback, preedit_chars_backup->feedback,
01068           (sizeof (XIMFeedback)) * first_orig);
01069   }
01070   if (0 != text_length) {
01071     memcpy(preedit_chars->feedback + first_orig, text->feedback,
01072           (sizeof (XIMFeedback)) * text_length);
01073   } else {
01074     memset(preedit_chars->feedback + first_orig, 0,
01075           (sizeof (XIMFeedback)) * text_length);
01076   }
01077   if ((first_orig + text_length) < preedit_chars->wchar_len) {
01078     memcpy(preedit_chars->feedback + first_orig + text_length,
01079           preedit_chars_backup->feedback + first_orig + length_orig,
01080           (sizeof (XIMFeedback)) * 
01081           (preedit_chars->wchar_len - first_orig + text_length));
01082   }
01083   *(preedit_chars->feedback + preedit_chars->wchar_len) = 0;
01084 
01085   /*
01086    * update feedback_list
01087    */
01088   for (i = 0; i < first_orig; i++) {
01089     (preedit_chars->feedback_list + i)->count_feedbacks =
01090            (preedit_chars_backup->feedback_list + i)->count_feedbacks;
01091     if (0 == (preedit_chars->feedback_list + i)->count_feedbacks) {
01092       (preedit_chars->feedback_list + i)->feedbacks = NULL;
01093     } else {
01094       (preedit_chars->feedback_list + i)->feedbacks =
01095              Xmalloc((preedit_chars->feedback_list + i)->count_feedbacks *
01096                     (sizeof (IMFeedback)));
01097     }
01098     for (j = 0; j < (preedit_chars->feedback_list + i)->count_feedbacks; j++) {
01099       ((preedit_chars->feedback_list + i)->feedbacks + j)->type =
01100              ((preedit_chars_backup->feedback_list + i)->feedbacks + j)->type;
01101       ((preedit_chars->feedback_list + i)->feedbacks + j)->value =
01102              ((preedit_chars_backup->feedback_list + i)->feedbacks + j)->value;
01103     }
01104   }
01105   if (NULL != feedback_list) {
01106     for (i = first_orig; i < (first_orig + text_length); i++) {
01107       (preedit_chars->feedback_list + i)->count_feedbacks =
01108              (feedback_list + i)->count_feedbacks;
01109       if (0 == (preedit_chars->feedback_list + i)->count_feedbacks) {
01110        (preedit_chars->feedback_list + i)->feedbacks = NULL;
01111       } else {
01112        (preedit_chars->feedback_list + i)->feedbacks =
01113               Xmalloc((preedit_chars->feedback_list + i)->count_feedbacks *
01114                      (sizeof (IMFeedback)));
01115       }
01116       for (j = 0; j < (preedit_chars->feedback_list + i)->count_feedbacks; j++) {
01117        ((preedit_chars->feedback_list + i)->feedbacks + j)->type =
01118               ((feedback_list + i)->feedbacks + j)->type;
01119        ((preedit_chars->feedback_list + i)->feedbacks + j)->value =
01120               ((feedback_list + i)->feedbacks + j)->value;
01121       }
01122     }
01123   } else {
01124     for (i = first_orig; i < (first_orig + text_length); i++) {
01125       (preedit_chars->feedback_list + i)->count_feedbacks = 0;
01126       (preedit_chars->feedback_list + i)->feedbacks = NULL;
01127     }
01128   }
01129   dst_fbl = (preedit_chars->feedback_list + first_orig + text_length);
01130   src_fbl = (preedit_chars_backup->feedback_list + first_orig + text_length);
01131   for (i = first_orig + text_length; i < preedit_chars->wchar_len; i++) {
01132     dst_fbl->count_feedbacks = src_fbl->count_feedbacks;
01133     if (0 == dst_fbl->count_feedbacks) {
01134       dst_fbl->feedbacks = NULL;
01135     } else {
01136       dst_fbl->feedbacks =
01137              Xmalloc(dst_fbl->count_feedbacks * (sizeof (IMFeedback)));
01138     }
01139     for (j = 0; j < dst_fbl->count_feedbacks; j++) {
01140       (dst_fbl->feedbacks + j)->type  = (src_fbl->feedbacks + j)->type;
01141       (dst_fbl->feedbacks + j)->value = (src_fbl->feedbacks + j)->value;
01142     }
01143     src_fbl += 1;
01144     dst_fbl += 1;
01145   }
01146   dst_fbl->count_feedbacks = 0;
01147   dst_fbl->feedbacks = NULL;
01148 
01149 
01150   Xfree(wc_p_free);
01151 
01152   return;
01153 }
01154 
01155 #if 0
01156 static void
01157 PreeditDelete(PreeditChars preedit_chars, int start, int len) {
01158 
01159   int move_len = preedit_chars->wchar_len - (start + len);
01160   IMFeedbackList *from, *to, *temp;
01161   int i;
01162 
01163   if (move_len < 0) return;
01164 
01165   if (move_len == 0) {
01166     from = &preedit_chars->feedback_list[start];
01167     for (i = 0; i < len; i++, from++) {
01168       if (from->feedbacks) {
01169        Xfree(from->feedbacks);
01170        from->feedbacks = 0;
01171       }
01172     }
01173   } else {
01174     to = &preedit_chars->feedback_list[start];
01175     from = &preedit_chars->feedback_list[start + len];
01176     for (i = 0; i < move_len; i++) {
01177       to->count_feedbacks = from->count_feedbacks;
01178       if (to->feedbacks) Xfree(to->feedbacks);
01179       to->feedbacks = from->feedbacks;
01180       temp = from;
01181       from++; to++;
01182       Xfree(temp);
01183     }
01184     (void)memmove((void *)(preedit_chars->feedback + start),
01185                 (void *)(preedit_chars->feedback + start + len),
01186                 sizeof(XIMFeedback) * move_len);
01187     (void)memmove((void *)(preedit_chars->wchar + start),
01188                 (void *)(preedit_chars->wchar + start + len),
01189                 sizeof(wchar_t) * move_len);
01190   }
01191   preedit_chars->wchar_len -= len;
01192   preedit_chars->wchar[preedit_chars->wchar_len] = (wchar_t)0;
01193   return;
01194 }
01195 
01196 static void
01197 PreeditInsert(XicCommon ic, PreeditChars preedit_chars, int start,
01198              XIMText *text, IMFeedbackList *feedback_list) {
01199   IMFeedbackList *from, *to;
01200   int i;
01201 
01202   if (!text) return;
01203 
01204   if (text->length == 0) return;
01205 
01206   if (preedit_chars->alloc_len < preedit_chars->wchar_len + text->length + 1) {
01207     /* reallocate */
01208     int prev_alloc_len=preedit_chars->alloc_len;
01209     preedit_chars->alloc_len += 16 + text->length + 1;
01210     preedit_chars->wchar = Xrealloc(preedit_chars->wchar,
01211                                 sizeof(wchar_t) *
01212                                 preedit_chars->alloc_len);
01213     preedit_chars->feedback = Xrealloc(preedit_chars->feedback,
01214                                    sizeof(XIMFeedback) *
01215                                    preedit_chars->alloc_len);
01216     preedit_chars->feedback_list = Xrealloc(preedit_chars->feedback_list,
01217                                        sizeof(IMFeedbackList) *
01218                                        preedit_chars->alloc_len);
01219     /* initialized to 0 */
01220     memset(preedit_chars->feedback_list+prev_alloc_len, 0,
01221                                    sizeof(IMFeedbackList) *
01222                                    (16 + text->length + 1));
01223   }
01224 
01225   if (preedit_chars->wchar_len > start) {
01226     /* shift the right most part first */
01227     (void)memmove((void *)(preedit_chars->wchar + start + text->length),
01228                 (void *)(preedit_chars->wchar + start),
01229                 sizeof(wchar_t) * (preedit_chars->wchar_len - start));
01230     (void)memmove((void *)(preedit_chars->feedback + start + text->length),
01231                 (void *)(preedit_chars->feedback + start),
01232                 sizeof(XIMFeedback) * (preedit_chars->wchar_len - start));
01233     from = &preedit_chars->feedback_list[start];
01234     to = &preedit_chars->feedback_list[start + text->length];
01235     for (i = 0; i < preedit_chars->wchar_len - start; i++, from++, to++) {
01236       to->count_feedbacks = from->count_feedbacks;
01237       to->feedbacks = from->feedbacks;
01238     }
01239   }
01240   /* then, copy from XIMText to preedit internal buffer */
01241   if (text->encoding_is_wchar) {
01242     (void)memmove((void *)(preedit_chars->wchar + start),
01243                 (void *)(text->string.wide_char),
01244                 sizeof(wchar_t) * text->length);
01245   } else {
01246     int len = strlen(text->string.multi_byte);
01247     XimCommon im = (XimCommon)ic->core.im;
01248     IIimpMbstoWcs(im, text->string.multi_byte, len,
01249                 preedit_chars->wchar + start, text->length, NULL);
01250   }
01251   if (text->feedback) {
01252     (void)memmove((void *)(preedit_chars->feedback + start),
01253                 (void *)(text->feedback),
01254                 sizeof(XIMFeedback) * text->length);
01255   } else {
01256     /* Let's use the previous feedback */
01257     XIMFeedback *tmp = preedit_chars->feedback + start;
01258     int i;
01259     for (i = 0; i < text->length; i++) {
01260       *tmp++ = *(preedit_chars->feedback);
01261     }
01262   }
01263   if (feedback_list) {
01264     from = feedback_list;
01265     to = &preedit_chars->feedback_list[start];
01266     for (i = 0; i < text->length; i++, from++, to++) {
01267       to->count_feedbacks = from->count_feedbacks;
01268       if (to->count_feedbacks > 0)
01269        to->feedbacks = Xmalloc(sizeof(IMFeedback) * to->count_feedbacks);
01270       if (to->feedbacks) {
01271        IMFeedback *p, *q;
01272        for (p = to->feedbacks, q = from->feedbacks;
01273             p < &to->feedbacks[to->count_feedbacks];
01274             p++, q++) {
01275          p->type = q->type;
01276          p->value = q->value;
01277        }
01278       }
01279     }
01280   } else {
01281     /* Let's use the previous feedback, so nothing to do */
01282   }
01283   preedit_chars->wchar_len += text->length;
01284   preedit_chars->wchar[preedit_chars->wchar_len] = (wchar_t)0;
01285   return;
01286 }
01287 #endif /* 0 */
01288 
01289 static void
01290 PreeditCursor(PreeditChars preedit_chars, int caret) {
01291   /* need to implement  */
01292   if (preedit_chars->caret_pos != caret) {
01293     preedit_chars->caret_pos = caret;
01294   }
01295   return;
01296 }
01297 
01298 void
01299 PreeditStart(XicCommon ic, XPointer call_data) {
01300   PreeditWin preedit = (PreeditWin)(ic->gui_icpart->preedit);
01301   PreeditChars preedit_chars;
01302 
01303   if (!preedit) {
01304     XIC_GUI(ic, change_preedit)((XIC)ic, PREEDIT_CREATE, NULL);
01305     preedit = (PreeditWin)(ic->gui_icpart->preedit);
01306     if (!preedit) return;
01307   }
01308   preedit_chars = (PreeditChars)&(preedit->preedit_chars);
01309   preedit_chars->caret_pos = 0;
01310   preedit_chars->wchar_len = 0;
01311   preedit_chars->alloc_len = 16;
01312   preedit_chars->wchar = Xmalloc(sizeof(wchar_t) *
01313                              preedit_chars->alloc_len);
01314   preedit_chars->wchar_width = Xmalloc(sizeof(unsigned short) *
01315                                    preedit_chars->alloc_len);
01316   preedit_chars->feedback = Xmalloc(sizeof(XIMFeedback) *
01317                                 preedit_chars->alloc_len);
01318   preedit_chars->feedback_list = Xmalloc(sizeof(IMFeedbackList) *
01319                                     preedit_chars->alloc_len);
01320   memset(preedit_chars->wchar, 0,
01321         sizeof(wchar_t) * preedit_chars->alloc_len);
01322   memset(preedit_chars->wchar_width, 0,
01323         sizeof(unsigned short) * preedit_chars->alloc_len);
01324   memset(preedit_chars->feedback, 0,
01325         sizeof(XIMFeedback) * preedit_chars->alloc_len);
01326   memset(preedit_chars->feedback_list, 0,
01327         sizeof(IMFeedbackList) * preedit_chars->alloc_len);
01328 
01329   FilterConfigureNotify(ic->core.im->core.display,
01330                      ic->core.focus_window,
01331                      NULL, (XPointer)ic);
01332   _XRegisterFilterByType(ic->core.im->core.display, ic->core.focus_window,
01333                       ConfigureNotify, ConfigureNotify,
01334                       FilterConfigureNotify, (XPointer)ic);
01335 
01336   return;
01337 }
01338 
01339 void
01340 PreeditDrawText(XicCommon ic, XPointer p) {
01341   PreeditWin preedit = (PreeditWin)(ic->gui_icpart->preedit);
01342   PreeditChars preedit_chars;
01343   int chg_first;
01344   int chg_length;
01345   XIMDrawTextStruct *preedit_draw = (XIMDrawTextStruct*)p;
01346   XIMPreeditDrawCallbackStruct *call_data =
01347     (XIMPreeditDrawCallbackStruct*)preedit_draw->call_data;
01348   XIMText *text = (XIMText*)call_data->text;
01349   IMFeedbackList *feedback_list = preedit_draw->feedback_list;
01350 
01351   if (!preedit) {
01352     XIC_GUI(ic, change_preedit)((XIC)ic, PREEDIT_CREATE, NULL);
01353     preedit = (PreeditWin)(ic->gui_icpart->preedit);
01354     if (!preedit) return;
01355   }
01356 
01357   preedit_chars = (PreeditChars)&(preedit->preedit_chars);
01358   if (preedit_chars->alloc_len == 0) {
01359     if (text) {
01360       /* Start drawing preedit without calling preedit_start */
01361       PreeditStart(ic, NULL);
01362     } else {
01363       return;               /* nothing to do */
01364     }
01365   }
01366 
01367 #if 0
01368   if (call_data->chg_first == preedit_chars->wchar_len) {
01369     /* append from right most position */
01370     if (text && text->length > 0) change_len = text->length;
01371   }else if ((call_data->chg_first + call_data->chg_length
01372             == preedit_chars->wchar_len) && !text) {
01373     /* delete from right most position */
01374     change_len = call_data->chg_length;
01375   } else {
01376     /* other operations */
01377     change_len = preedit_chars->wchar_len - call_data->chg_first;
01378     change_len -= call_data->chg_length;
01379     if (text && text->length > 0) change_len += text->length;
01380   }
01381 #endif /* 0 */
01382 
01383   chg_first = call_data->chg_first;
01384   chg_length = call_data->chg_length;
01385 
01386   TRACE_MESSAGE('p', ("PreeditDrawText: chg_first = %d chg_length = %d, %d %d, caret = %d\n",
01387                     call_data->chg_first, call_data->chg_length,
01388                     chg_first, chg_length, call_data->caret));
01389 
01390 #if 1
01391   PreeditReplaceString(ic, preedit,
01392                      &chg_first, &chg_length, text, feedback_list);
01393 
01394 #else /* 0 */
01395   if (call_data->chg_length) {
01396     PreeditDelete(preedit_chars,
01397                 call_data->chg_first, call_data->chg_length);
01398   }
01399   PreeditInsert(ic, preedit_chars, call_data->chg_first,
01400               text, feedback_list);
01401 #endif /* 0 */
01402   PreeditCursor(preedit_chars, call_data->caret);
01403   XIC_GUI(ic, change_preedit)((XIC)ic, PREEDIT_WIN, NULL);
01404 #if 1
01405   UpdatePreedit(ic, chg_first, chg_length);
01406 #else /* 0 */
01407   UpdatePreedit(ic, call_data->chg_first, change_len);
01408 #endif /* 0 */
01409 
01410   return;
01411 }
01412 
01413 void
01414 PreeditCaret(XicCommon ic, XPointer call_data) {
01415   /* do nothing */
01416   return;
01417 }
01418 
01419 void
01420 PreeditDone(XicCommon ic, XPointer call_data) {
01421   PreeditWin preedit = (PreeditWin)(ic->gui_icpart->preedit);
01422   PreeditArea preedit_area;
01423   PreeditChars preedit_chars;
01424   int i;
01425 
01426   if (!preedit) return;
01427 
01428   _XUnregisterFilter(ic->core.im->core.display, ic->core.focus_window,
01429                    FilterConfigureNotify, (XPointer)ic);
01430 
01431   preedit_area = (PreeditArea)(preedit->preedit_areas);
01432   preedit_chars = (PreeditChars)&(preedit->preedit_chars);
01433 
01434   if (preedit_chars->feedback) Xfree((char*)preedit_chars->feedback);
01435   if (preedit_chars->wchar) Xfree((char*)preedit_chars->wchar);
01436   if (preedit_chars->wchar_width)
01437     Xfree((char*)preedit_chars->wchar_width);
01438   FreeFeedbackList(preedit_chars->feedback_list, 
01439                  preedit_chars->alloc_len);
01440   preedit_chars->feedback_list = NULL;
01441   preedit_chars->feedback = NULL;
01442   preedit_chars->wchar = NULL;
01443   preedit_chars->wchar_width = NULL;
01444   preedit_chars->wchar_len = 0;
01445   preedit_chars->alloc_len = 0;
01446 
01447   for (i = 0; i < preedit->alloc_areas; i++) {
01448     UnmapPreeditWindow(ic, preedit_area + i);
01449   }
01450   return;
01451 }
01452 
01453 void
01454 DestroyPreedit(XicCommon ic, XPointer call_data) {
01455   PreeditWin preedit = (PreeditWin)(ic->gui_icpart->preedit);
01456   int i;
01457   PreeditArea preedit_area;
01458 
01459   if (!preedit) return;
01460 
01461   if (preedit->fontset && preedit->need_free_fontset) {
01462     XFactoryFreeDefaultFontSet (ic->core.im->core.display);
01463     preedit->need_free_fontset = False;
01464   }
01465 #if 0
01466   PreeditDone(ic, NULL);
01467 #else
01468   _XUnregisterFilter(ic->core.im->core.display, ic->core.focus_window,
01469                    FilterConfigureNotify, (XPointer)ic);
01470 #endif
01471 
01472   preedit_area = (PreeditArea)(preedit->preedit_areas);
01473   for (i = 0; i < preedit->alloc_areas; i++) {
01474     _XUnregisterFilter(ic->core.im->core.display, 
01475                      preedit_area[i].window,
01476                      RepaintPreedit, (XPointer)ic);
01477     _XUnregisterFilter(ic->core.im->core.display, 
01478                      preedit_area[i].window,
01479                      FilterKeyPress, (XPointer)ic);
01480   }
01481 
01482   if (preedit->gc) XFreeGC(ic->core.im->core.display, preedit->gc);
01483   if (preedit->rgc) XFreeGC(ic->core.im->core.display, preedit->rgc);
01484 
01485   for (i = 0; i < preedit->alloc_areas; i++) {
01486     if (ic->core.input_style & XIMPreeditNothing) {
01487       /* check the window is valid before XDestroyWindow() */
01488       if(IMCheckIMWindow(ic, preedit_area[i].window)) {
01489         XDestroyWindow(ic->core.im->core.display, preedit_area[i].window);
01490       }
01491     }
01492   }
01493   if (preedit->preedit_areas) Xfree(preedit->preedit_areas);
01494   Xfree(preedit);
01495   ic->gui_icpart->preedit = (PreeditWin)NULL;
01496   return;
01497 }
01498 
01499 void
01500 PreeditCaretAdjustLookupPlacement(XicCommon ic, XPoint * point) {
01501   PreeditWin preedit = (PreeditWin)(ic->gui_icpart->preedit);
01502   PreeditArea preedit_area;
01503   PreeditChars preedit_chars;
01504   int  escapement = 0; 
01505   int vertical = 0;
01506   int i;
01507 
01508   if (NULL == preedit) {
01509     XIC_GUI(ic, change_preedit)((XIC)ic, PREEDIT_CREATE, NULL);
01510     preedit = (PreeditWin)(ic->gui_icpart->preedit);
01511   }
01512   if (NULL != preedit) {
01513     preedit_area = (PreeditArea)(preedit->preedit_areas);
01514     preedit_chars = (PreeditChars)&(preedit->preedit_chars);
01515     for (i = 0; i < preedit->alloc_areas; i++) {
01516       if (preedit_area[i].active_lines == 0) {
01517        int char_offset = preedit_area[i].char_offset;
01518        int char_len = preedit_area[i].char_len;
01519        if ((char_offset <= preedit_chars->caret_pos) &&
01520            (preedit_chars->caret_pos <= (char_offset + char_len))) {
01521          if (char_offset != preedit_chars->caret_pos) {
01522            escapement = XwcTextEscapement(preedit->fontset,
01523                                       preedit_chars->wchar + 
01524                                       preedit_chars->caret_pos,
01525                                       preedit_chars->caret_pos -
01526                                       char_offset);
01527          }
01528          vertical = (ic->core.preedit_attr.area.height * i);
01529          point->x += escapement;
01530          point->y += vertical;
01531          TRACE_MESSAGE('p', ("caret_pos=%d escapement=%d vertical=%d\n",
01532                            preedit_chars->caret_pos, escapement, vertical));
01533          return;
01534        }
01535       }
01536     }
01537     if ((preedit_chars->caret_pos <= 0) ||
01538        (preedit_chars->wchar_len <= preedit_chars->caret_pos)) {
01539       return;
01540     }
01541     if (0 < preedit_chars->caret_pos) {
01542       escapement = XwcTextEscapement(preedit->fontset,
01543                                  preedit_chars->wchar,
01544                                  preedit_chars->caret_pos);
01545     }
01546     TRACE_MESSAGE('p', ("caret_pos=%d escapement=%d len=%d caret=%d\n",
01547                      preedit_chars->caret_pos, escapement,
01548                      preedit_chars->wchar_len, preedit_chars->caret_pos));
01549   }
01550   return;
01551 }
01552 
01553 void
01554 PreeditCaretPlacement(XicCommon ic, XPoint * point)
01555 {
01556   PreeditWin preedit = (PreeditWin)(ic->gui_icpart->preedit);
01557   PreeditArea preedit_area;
01558   PreeditChars preedit_chars;
01559   int  x = 0; 
01560   int y = 0;
01561   int i;
01562 
01563   if (NULL == preedit) {
01564     XIC_GUI(ic, change_preedit)((XIC)ic, PREEDIT_CREATE, NULL);
01565     preedit = (PreeditWin)(ic->gui_icpart->preedit);
01566   }
01567   if (NULL != preedit) {
01568     preedit_area = (PreeditArea)(preedit->preedit_areas);
01569     preedit_chars = (PreeditChars)&(preedit->preedit_chars);
01570 
01571     if (preedit_area == 0 || preedit_chars == 0 ||
01572        preedit_chars->wchar == 0) {
01573       return;
01574     }
01575     for (i = 0; i < preedit->alloc_areas; i++) {
01576       int char_offset = preedit_area[i].char_offset;
01577       int char_len = preedit_area[i].char_len;
01578 
01579       if (preedit_area[i].active_lines == 0) {
01580        if ((char_offset <= preedit_chars->caret_pos) &&
01581            (preedit_chars->caret_pos <= (char_offset + char_len))) {
01582 
01583          XFontSetExtents *fse = 0;
01584          if (!preedit->fontset) {
01585            SetPreeditFont(ic, NULL);
01586          }
01587          fse = XExtentsOfFontSet(preedit->fontset);
01588 
01589          if (char_offset != preedit_chars->caret_pos) {
01590            x = XwcTextEscapement(preedit->fontset,
01591                               preedit_chars->wchar + 
01592                               char_offset,
01593                               preedit_chars->caret_pos -
01594                               char_offset);
01595          } else {
01596            x = 0;
01597          }
01598          y = (-fse->max_ink_extent.y);
01599          XFactoryGetLocationOnScreen(ic->core.im->core.display,
01600                                   preedit_area[i].window,
01601                                   x, y, point);
01602          TRACE_MESSAGE('p', ("caret_pos=%d escapement=%d vertical=%d\n",
01603                            preedit_chars->caret_pos, x, y));
01604          return;
01605 
01606        }
01607       } else {
01608        PreeditLine line = (PreeditLine)preedit_area[i].lines;
01609        int j;
01610 
01611        for (j = 0; j < preedit_area[i].active_lines; j++) {
01612          if ((line[j].char_offset <= preedit_chars->caret_pos) &&
01613              (preedit_chars->caret_pos < (line[j].char_offset + line[j].char_len))) {
01614            XFontSetExtents *fse = 0;
01615            if (!preedit->fontset) {
01616              SetPreeditFont(ic, NULL);
01617            }
01618            fse = XExtentsOfFontSet(preedit->fontset);
01619            if (line[j].char_offset != preedit_chars->caret_pos) {
01620              x = XwcTextEscapement(preedit->fontset,
01621                                 preedit_chars->wchar + 
01622                                 line[j].char_offset,
01623                                 preedit_chars->caret_pos -
01624                                 line[j].char_offset);
01625            } else {
01626              x = 0;
01627            }
01628            y = ((fse->max_logical_extent.height * j) +
01629                (-fse->max_ink_extent.y));
01630            XFactoryGetLocationOnScreen(ic->core.im->core.display,
01631                                    preedit_area[i].window,
01632                                    x, y, point);
01633            TRACE_MESSAGE('p', ("caret_pos=%d escapement=%d vertical=%d\n",
01634                             preedit_chars->caret_pos, x, y));
01635            return;
01636          }
01637        }
01638       }
01639     }
01640   }
01641   return;
01642 }
01643 
01644 void
01645 PreeditCaretPlacementRelative(XicCommon ic, XPoint * point)
01646 {
01647   PreeditWin preedit = (PreeditWin)(ic->gui_icpart->preedit);
01648   PreeditArea preedit_area;
01649   PreeditChars preedit_chars;
01650   int  x = 0; 
01651   int y = 0;
01652   int i;
01653   int new_x;
01654   int new_y;
01655   Window child;
01656 
01657 
01658   if (NULL == preedit) {
01659     XIC_GUI(ic, change_preedit)((XIC)ic, PREEDIT_CREATE, NULL);
01660     preedit = (PreeditWin)(ic->gui_icpart->preedit);
01661   }
01662   if (NULL != preedit) {
01663     preedit_area = (PreeditArea)(preedit->preedit_areas);
01664     preedit_chars = (PreeditChars)&(preedit->preedit_chars);
01665 
01666     for (i = 0; i < preedit->alloc_areas; i++) {
01667       int char_offset = preedit_area[i].char_offset;
01668       int char_len = preedit_area[i].char_len;
01669 
01670       if (preedit_area[i].active_lines == 0) {
01671        if ((char_offset <= preedit_chars->caret_pos) &&
01672            (preedit_chars->caret_pos <= (char_offset + char_len))) {
01673          XFontSetExtents *fse = 0;
01674          if (0 == preedit_chars->wchar_len) {
01675            if (XIMP_CHK_PREAREAMASK(ic)) {
01676              x = ic->core.preedit_attr.area.x;
01677              y = ic->core.preedit_attr.area.y;
01678            } else if (XIMP_CHK_PRESPOTLMASK(ic)) {
01679              x = ic->core.preedit_attr.spot_location.x;
01680              y = ic->core.preedit_attr.spot_location.y;
01681            } else {
01682              x  = y = 0;
01683            }
01684            return;
01685          }
01686          if (!preedit->fontset) {
01687            SetPreeditFont(ic, NULL);
01688          }
01689          fse = XExtentsOfFontSet(preedit->fontset);
01690 
01691          if (char_offset != preedit_chars->caret_pos) {
01692            x = XwcTextEscapement(preedit->fontset,
01693                               preedit_chars->wchar + 
01694                               char_offset,
01695                               preedit_chars->caret_pos -
01696                               char_offset);
01697          } else {
01698            x = 0;
01699          }
01700          y = fse->max_logical_extent.height;
01701          y += (fse->max_ink_extent.height + fse->max_ink_extent.y);
01702 
01703          XTranslateCoordinates(ic->core.im->core.display,
01704                             preedit_area[i].window,
01705                             ic->core.focus_window,
01706                             x, y, &new_x, &new_y, &child);
01707          point->x = new_x;
01708          point->y = new_y;
01709 
01710          TRACE_MESSAGE('p', ("caret_pos=%d escapement=%d vertical=%d\n",
01711                            preedit_chars->caret_pos, x, y));
01712          return;
01713 
01714        }
01715       } else {
01716        PreeditLine line = (PreeditLine)preedit_area[i].lines;
01717        int j;
01718 
01719        for (j = 0; j < preedit_area[i].active_lines; j++) {
01720          if ((line[j].char_offset <= preedit_chars->caret_pos) &&
01721              (preedit_chars->caret_pos < (line[j].char_offset + line[j].char_len))) {
01722            XFontSetExtents *fse = 0;
01723            if (0 == preedit_chars->wchar_len) {
01724              if (XIMP_CHK_PREAREAMASK(ic)) {
01725               x = ic->core.preedit_attr.area.x;
01726               y = ic->core.preedit_attr.area.y;
01727              } else if (XIMP_CHK_PRESPOTLMASK(ic)) {
01728               x = ic->core.preedit_attr.spot_location.x;
01729               y = ic->core.preedit_attr.spot_location.y;
01730              } else {
01731               x  = y = 0;
01732              }
01733              return;
01734            }
01735            if (!preedit->fontset) {
01736              SetPreeditFont(ic, NULL);
01737            }
01738            fse = XExtentsOfFontSet(preedit->fontset);
01739            if (line[j].char_offset != preedit_chars->caret_pos) {
01740              x = XwcTextEscapement(preedit->fontset,
01741                                 preedit_chars->wchar + 
01742                                 line[j].char_offset,
01743                                 preedit_chars->caret_pos -
01744                                 line[j].char_offset);
01745            } else {
01746              x = 0;
01747            }
01748            y = (fse->max_logical_extent.height * (j + 1));
01749            y += (fse->max_ink_extent.height + fse->max_ink_extent.y);
01750 
01751            XTranslateCoordinates(ic->core.im->core.display,
01752                               preedit_area[i].window,
01753                               ic->core.focus_window,
01754                               x, y, &new_x, &new_y, &child);
01755            point->x = new_x;
01756            point->y = new_y;
01757 
01758            TRACE_MESSAGE('p', ("caret_pos=%d escapement=%d vertical=%d\n",
01759                             preedit_chars->caret_pos, x, y));
01760            return;
01761          }
01762        }
01763       }
01764     }
01765   }
01766   return;
01767 }