Back to index

im-sdk  12.3.91
guiIMSts.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 "guiIMSts.h"
00046 #include "XimpIm.h"
00047 #include "xfactory.h"
00048 #include <X11/Xatom.h>
00049 
00050 static void UpdateStatus(XicCommon ic, Bool);
00051 char *MergeStatus(XicCommon ic);
00052 
00053 static Bool
00054 MapStatusWindow(XicCommon ic, Window win) {
00055   Display *display = ic->core.im->core.display;
00056   XWindowAttributes win_att;
00057   XWindowAttributes cwin_att;
00058 
00059   if (!XGetWindowAttributes(display, 
00060                          ic->core.client_window,
00061                          &cwin_att)) {
00062     /* xemacs causes BadWindow of X_UnmapWindow on TL4.2 */
00063 #ifdef linux
00064     if(IMCheckIMWindow(ic, win))
00065 #endif
00066     /* client window is not ready, so unmap status */
00067     XUnmapWindow(display, win);
00068     return False;
00069   } else {
00070 
00071     if (!IsIMStatusAttached ())
00072       {
00073        XUnmapWindow(display, win);
00074        return True;
00075       }
00076 
00077     if (cwin_att.map_state == IsUnmapped) {
00078       if (ic->core.input_style & XIMStatusNothing) {
00079        return False;
00080       } else {
00081        XMapWindow(display, win);
00082        return True;
00083       }
00084     }
00085   }
00086   if (XGetWindowAttributes(display, win,
00087                         &win_att) > 0) {
00088     if (win_att.map_state == IsUnmapped) {
00089       XMapWindow(display, win);
00090     }
00091     return True;    
00092   }
00093   return False;
00094 }
00095 
00096 static void
00097 DrawStatusString(XicCommon ic,
00098                Display *display, Window win, XFontSet fontset,
00099                GC gc, int x, int y, char *str, int str_len,
00100                IMFeedbackList *feedback_list, int feedback_length) {
00101   if (fontset == NULL) return;
00102   if (feedback_list) {
00103     /* coloring */
00104     int i;
00105     wchar_t *wcstr = 0, *wcstrp = NULL;
00106     size_t wc_len = 0;
00107     IMFeedbackList *pfeedback;
00108     XimCommon im = (XimCommon)ic->core.im;
00109 
00110     /* need to get wchar string */
00111     wc_len = str_len;
00112     if (!(wcstr = Xmalloc(sizeof(wchar_t) * (wc_len + 1)))) return;
00113 
00114     if (IIimpMbstoWcs(im, str, str_len, wcstr, wc_len, NULL) == 0) {
00115       Xfree(wcstr);
00116       goto error;
00117     }
00118     wcstrp = wcstr;
00119 
00120     pfeedback = feedback_list;
00121     for (i = 0; i < feedback_length; i++, pfeedback++) {
00122       /* set colors */
00123       SetIMColors(ic, display, win, gc, (GC)0, pfeedback, (XIMFeedback)0);
00124       XwcDrawImageString(display, win, fontset, gc,
00125                       x, y, wcstrp, 1);
00126       x += XwcTextEscapement(fontset, wcstrp, 1); wcstrp++;
00127     }
00128     Xfree(wcstr);
00129     return;
00130   }
00131  error:
00132   XmbDrawString(display, win, fontset, gc, x, y, str, str_len);
00133 }
00134 
00135 #if defined(USE_FILTER_KEY_PRESS_IN_STATUS)
00136 static Bool
00137 FilterKeyPress(Display *d, Window w, XEvent *ev, XPointer client_data) {
00138   XicCommon ic = (XicCommon)client_data;
00139   if (!XIM_IS_IIIMP(ic->core.im)) return False;
00140 
00141 #if 0
00142   IMForwardEvent(ic, ev);
00143 #endif /* 0 */
00144   ev->xkey.window = ic->core.focus_window;
00145   XPutBackEvent(d, ev);
00146   return True;
00147 }
00148 #endif /* USE_FILTER_KEY_PRESS_IN_STATUS */
00149 
00150 static Bool
00151 RepaintStatus(Display *d, Window w, XEvent *ev, XPointer client_data) {
00152   XicCommon ic = (XicCommon)client_data;
00153   StatusWin status;
00154 
00155   if (!ic->gui_icpart) return True;
00156 
00157   status = (StatusWin)(ic->gui_icpart->status);
00158 
00159   if (!status) return True;
00160 
00161   UpdateStatus(ic, False);
00162 
00163   return True;
00164 }
00165 
00166 Bool
00167 SetupStatusExt(XicCommon ic) {
00168   StatusWin status = (StatusWin)Xmalloc(sizeof(StatusWinRec));
00169 
00170   if (!status) return True;
00171   memset((char *)status, 0, sizeof(StatusWinRec));
00172 
00173   memset(&status->status_cache, 0, sizeof(CacheRec));
00174 
00175   status->need_free_fontset = False;
00176 
00177   ic->gui_icpart->status = (void *)status;
00178   return True;
00179 }
00180 
00181 static void
00182 CreateGC(XicCommon ic) {
00183   StatusWin status = (StatusWin)(ic->gui_icpart->status);
00184   unsigned long fg, bg;
00185   XWindowAttributes attr;
00186   unsigned long val_mask;
00187   XGCValues gcval;
00188   Display *display = ic->core.im->core.display;
00189 
00190   if (!XIMP_CHK_STSBGMASK(ic) || !XIMP_CHK_STSFGMASK(ic)) 
00191     XGetWindowAttributes(display, 
00192                       ic->core.client_window,
00193                       &attr);
00194 
00195   if (XIMP_CHK_STSBGMASK(ic)) 
00196     bg = ic->core.status_attr.background;
00197   else if (XIMP_CHK_PREBGMASK(ic))
00198     bg = ic->core.preedit_attr.background;
00199   else
00200     bg = WhitePixel(display, XScreenNumberOfScreen(attr.screen));
00201 
00202   if (XIMP_CHK_STSFGMASK(ic))
00203     fg = ic->core.status_attr.foreground;
00204   else if (XIMP_CHK_PREFGMASK(ic))
00205     /* Motif does not set ic value for white status foreground color,
00206        so this is workaround. (#4290814)
00207     */
00208     fg = ic->core.preedit_attr.foreground;
00209   else
00210     fg = BlackPixel(display, XScreenNumberOfScreen(attr.screen));
00211 
00212   val_mask = GCForeground | GCBackground;
00213   gcval.foreground = fg;
00214   gcval.background = bg;
00215   status->gc = XCreateGC(display, status->window, val_mask, &gcval);
00216 #ifdef USE_STATUS_FEEDBACK
00217   gcval.foreground = bg;
00218   gcval.background = fg;
00219   status->rgc = XCreateGC(display, win, val_mask, &gcval);
00220 #endif
00221   return;
00222 }
00223 
00224 void
00225 UpdateStatus(XicCommon ic, Bool doCache) {
00226   StatusWin status = (StatusWin)(ic->gui_icpart->status);
00227   int len;
00228   char * status_string;
00229   status_string = MergeStatus(ic);
00230   if (NULL == status_string) return;
00231   len = strlen(status_string);
00232   if (!status->window) {
00233     if (!SetupStatusWindow(ic, ic->core.client_window)) return;
00234   }
00235 
00236   if (!status->fontset)
00237     SetStatusFont(ic, NULL);
00238   if (!status->fontset)
00239     return;
00240   if (!MapStatusWindow(ic, status->window))
00241     return;
00242 
00243   if (doCache &&
00244       len == status->len &&
00245       !strcmp(status_string, status->status_string)) {
00246     /* same string as the previous, skipped */
00247     Xfree(status_string);
00248     return;
00249   }
00250 
00251   XClearArea(ic->core.im->core.display, status->window, 0, 0, 0, 0, False);
00252 
00253   if (!status->gc) {
00254     CreateGC(ic);
00255     if (!status->gc) return;
00256   }
00257   DrawStatusString(ic, ic->core.im->core.display,
00258                  status->window,
00259                  status->fontset,
00260                  status->gc, status->x, status->y,
00261                  status_string, len,
00262                  status->feedback, status->text.length);
00263 
00264   /* status cache */
00265   status->len = len;
00266 
00267   Xfree(status->status_string);
00268   status->status_string = status_string;
00269   return;
00270 }
00271 
00272 Bool
00273 SetupStatusWindow(XicCommon ic, Window parent) {
00274   Window win;
00275   StatusWin status = (StatusWin)(ic->gui_icpart->status);
00276   int x, y;
00277   unsigned int width, height;
00278   unsigned long fg, bg;
00279   XWindowAttributes attr;
00280   Display *display = ic->core.im->core.display;
00281   XIMFilterRec filters[4];
00282   int n;
00283   unsigned int event_mask;
00284   extern Bool popup_button_press(Display *d, Window w, XEvent *ev,
00285                              XPointer client_data);
00286 
00287   if (XIMP_CHK_STSAREAMASK(ic)) {
00288     x = ic->core.status_attr.area.x;
00289     y = ic->core.status_attr.area.y;
00290     width   = ic->core.status_attr.area.width;
00291     height  = ic->core.status_attr.area.height;
00292   } else {
00293     x  = y = 0;
00294     width = height = 1;
00295   }
00296   if (width == 0 || height == 0) return False;
00297 
00298   if (!XIMP_CHK_STSBGMASK(ic) || !XIMP_CHK_STSFGMASK(ic)) 
00299     XGetWindowAttributes(display, 
00300                       ic->core.client_window,
00301                       &attr);
00302 
00303   if (XIMP_CHK_STSBGMASK(ic)) 
00304     bg = ic->core.status_attr.background;
00305   else if (XIMP_CHK_PREBGMASK(ic))
00306     bg = ic->core.preedit_attr.background;
00307   else
00308     bg = WhitePixel(display, XScreenNumberOfScreen(attr.screen));
00309 
00310   if (XIMP_CHK_STSFGMASK(ic))
00311     fg = ic->core.status_attr.foreground;
00312   else if (XIMP_CHK_PREFGMASK(ic))
00313     /* Motif does not set ic value for white status foreground color,
00314        so this is workaround. (#4290814)
00315     */
00316     fg = ic->core.preedit_attr.foreground;
00317   else
00318     fg = BlackPixel(display, XScreenNumberOfScreen(attr.screen));
00319 
00320   /* A new parent window is the same as the previous, nothing to do. */
00321   if (parent == 0 || status->parent == parent) return False;
00322 
00323   status->parent = parent;
00324 
00325   event_mask = None;
00326 
00327   n = 0;
00328 #if defined(USE_FILTER_KEY_PRESS_IN_STATUS)
00329   filters[n].type = KeyPress;
00330   filters[n].filter = FilterKeyPress;
00331   filters[n].client_data = (XPointer)ic;
00332   n++;
00333   event_mask |= KeyPressMask;
00334 #endif /* USE_FILTER_KEY_PRESS_IN_STATUS */
00335   filters[n].type = Expose;
00336   filters[n].filter = RepaintStatus;
00337   filters[n].client_data = (XPointer)ic;
00338   n++;
00339   event_mask |= ExposureMask;
00340 
00341   if (XIM_IS_SWITCH(ic->core.im) || XIM_IS_COMPOSE(ic->core.im)) {
00342     filters[n].type = ButtonPress;
00343     filters[n].filter = popup_button_press;
00344     filters[n].client_data = (XPointer)(ic);
00345     n++;
00346     event_mask |= ButtonPressMask;
00347     filters[n].type = ButtonRelease;
00348     filters[n].filter = popup_button_press;
00349     filters[n].client_data = (XPointer)(ic);
00350     n++;
00351     event_mask |= ButtonReleaseMask;
00352     event_mask |= PointerMotionMask;
00353   }
00354   if (!status->window) {
00355     XClassHint class_hint;
00356     win = XFactoryCreateIMWindow(display, parent, ic->core.client_window,
00357                              x, y, width, height, bg,
00358                              event_mask,
00359                              filters, n);
00360 
00361     if (!win) return False;
00362 
00363     /* remove all of the window decoration */
00364     XFactoryRemoveAllDecoration(display, win);
00365 
00366     if (ic->core.input_style & XIMStatusArea) {
00367       /* set override-redirect to true */
00368       XSetWindowAttributes attributes;
00369       int cmask = 0;
00370       cmask |= CWOverrideRedirect;
00371       attributes.override_redirect = True;
00372       XChangeWindowAttributes(ic->core.im->core.display, win,
00373                            cmask, &attributes);
00374     }
00375 
00376     XStoreName(display, win, "iiimx IM Status");
00377 
00378     class_hint.res_name = "iiimx-im-status";
00379     class_hint.res_class = "IiimxImStatus";
00380     XSetClassHint(display, win, &class_hint);
00381 
00382     status->window = win;
00383   }
00384 #if 0
00385  {
00386    unsigned long val_mask;
00387    XGCValues gcval;
00388    val_mask = GCForeground | GCBackground;
00389    gcval.foreground = fg;
00390    gcval.background = bg;
00391    status->gc = XCreateGC(display, win, val_mask, &gcval);
00392  }
00393 #ifdef USE_STATUS_FEEDBACK
00394   gcval.foreground = bg;
00395   gcval.background = fg;
00396   status->rgc = XCreateGC(display, win, val_mask, &gcval);
00397 #endif
00398 #endif
00399 
00400   return True;
00401 }
00402 
00403 void
00404 SetStatusForeground(XicCommon ic, XPointer call_data) {
00405   StatusWin status = (StatusWin)(ic->gui_icpart->status);
00406   CacheRec *status_cache;
00407 
00408   if (!status) return;  /* Let's do it later */
00409 
00410   status_cache = (CacheRec*)&(status->status_cache);
00411 
00412   if (status_cache->foreground == ic->core.status_attr.foreground) {
00413     return;
00414   }
00415   if (status->gc) {
00416     XGCValues val;
00417     unsigned long mask;
00418     val.foreground = ic->core.status_attr.foreground;
00419     mask = GCForeground;
00420     XChangeGC(ic->core.im->core.display,
00421              status->gc,
00422              mask,
00423              &val);
00424   }
00425 #ifdef USE_STATUS_FEEDBACK
00426   if (status->rgc) {
00427     XGCValues val;
00428     unsigned long mask;
00429     val.background = ic->core.status_attr.foreground;
00430     mask = GCBackground;
00431     XChangeGC(ic->core.im->core.display,
00432              status->rgc,
00433              mask,
00434              &val);
00435   }
00436 #endif
00437   status_cache->foreground = ic->core.status_attr.foreground;
00438   return;
00439 }
00440 
00441 void
00442 SetStatusBackground(XicCommon ic, XPointer call_data) { 
00443   StatusWin status = (StatusWin)(ic->gui_icpart->status);
00444   CacheRec *status_cache;
00445 
00446   if (!status) return;  /* Let's do it later */
00447 
00448   status_cache = (CacheRec*)&(status->status_cache);
00449 
00450   if (status_cache->background == ic->core.status_attr.background) {
00451     return;
00452   }
00453   if (status->gc) {
00454     XGCValues val;
00455     unsigned long mask;
00456     val.background = ic->core.status_attr.background;
00457     mask = GCBackground;
00458     XChangeGC(ic->core.im->core.display,
00459              status->gc,
00460              mask,
00461              &val);
00462   }
00463 #ifdef USE_STATUS_FEEDBACK
00464   if (status->rgc) {
00465     XGCValues val;
00466     unsigned long mask;
00467     val.foreground = ic->core.status_attr.background;
00468     mask = GCForeground;
00469     XChangeGC(ic->core.im->core.display,
00470              status->rgc,
00471              mask,
00472              &val);
00473   }
00474 #endif
00475   status_cache->background = ic->core.status_attr.background;
00476 
00477   if (status->window) {
00478     XSetWindowBackground(ic->core.im->core.display, status->window,
00479                       ic->core.status_attr.background);
00480   }
00481   return;
00482 }
00483 
00484 void
00485 SetStatusFont(XicCommon ic, XPointer call_data) {
00486   StatusWin status = (StatusWin)(ic->gui_icpart->status);
00487 
00488   if (!status) return;  /* Let's do it later */
00489 
00490   if (ic->core.status_attr.fontset) {
00491     if (status->fontset && status->need_free_fontset) {
00492       XFactoryFreeDefaultFontSet (ic->core.im->core.display);
00493       status->need_free_fontset = False;
00494     }
00495     /* need to clear status cache */
00496     status->fontset = ic->core.status_attr.fontset;
00497     status->len = 0;
00498     status->status_string = NULL;
00499   } else if (status->fontset == NULL) {
00500     status->fontset = XFactoryCreateDefaultFontSet(ic->core.im->core.display,
00501                                              XIM_IIIMP (ic->core.im, default_font_name));
00502     status->need_free_fontset = True;
00503   }
00504   return;
00505 }
00506 
00507 void
00508 StatusStart(XicCommon ic, XPointer call_data) {
00509   return;
00510 }
00511 
00512 void
00513 StatusDrawText(XicCommon ic, XPointer call_data) {
00514   StatusWin status = (StatusWin)(ic->gui_icpart->status);
00515   XIMDrawTextStruct *status_draw = (XIMDrawTextStruct*)call_data;
00516   XIMText *text = (XIMText*)status_draw->call_data;
00517   IMFeedbackList *feedback_list = status_draw->feedback_list;
00518 
00519   if (text == (XIMText*)NULL || text->length == 0 ||
00520       text->string.multi_byte == NULL) {
00521     /* unmap the status window if no valid status */
00522     Display *display = ic->core.im->core.display;
00523 
00524     if (status->window)
00525       XUnmapWindow(display, status->window);
00526 
00527     return;
00528   }
00529 
00530   if (!status) {
00531     XIC_GUI(ic, change_status)((XIC)ic, STATUS_CREATE, NULL);
00532     status = (StatusWin)(ic->gui_icpart->status);
00533     if (!status) return;
00534   }
00535   if (status->text.string.multi_byte) {
00536     Xfree(status->text.string.multi_byte);
00537   }
00538 
00539   if (feedback_list) {
00540     /* copy feedback_list */
00541     if (status->feedback) {
00542       IMFeedbackList *p;
00543       for (p = status->feedback; p < &status->feedback[status->text.length]; p++) {
00544        if (p->feedbacks) Xfree(p->feedbacks);
00545       }
00546       Xfree(status->feedback);
00547       status->feedback = 0;
00548     }
00549     status->feedback = Xmalloc(sizeof(IMFeedbackList) * text->length);
00550     if (status->feedback) {
00551       IMFeedbackList *from, *to;
00552       for (to = status->feedback, from = feedback_list;
00553           to < &status->feedback[text->length];
00554           to++, from++) {
00555        to->count_feedbacks = from->count_feedbacks;
00556        to->feedbacks = Xmalloc(sizeof(IMFeedback) * to->count_feedbacks);
00557        if (to->feedbacks) {
00558          IMFeedback *p, *q;
00559          for (p = to->feedbacks, q = from->feedbacks;
00560               p < &to->feedbacks[to->count_feedbacks];
00561               p++, q++) {
00562            p->type = q->type;
00563            p->value = q->value;
00564          }
00565        } else {
00566          /* error */
00567          Xfree(status->feedback);
00568          return;
00569        }
00570       }
00571     } else {
00572       /* error */
00573       return;
00574     }
00575   } else {
00576     if (NULL != status->feedback) {
00577       FreeFeedbackList(status->feedback, status->text.length);
00578       status->feedback = NULL;
00579     }
00580   }
00581   memmove(&(status->text), text, sizeof(XIMText));
00582   if (text->string.multi_byte == NULL) {
00583     status->text.string.multi_byte = NULL;
00584   } else {
00585     status->text.string.multi_byte = (char*)strdup(text->string.multi_byte);
00586   }
00587   XIC_GUI(ic, change_status)((XIC)ic, STATUS_WIN, NULL);
00588 
00589   UpdateStatus(ic, True);
00590   return;
00591 }
00592 
00593 void
00594 StatusDone(XicCommon ic, XPointer call_data) {
00595   /* do nothing */
00596   
00597 }
00598 
00599 void
00600 DestroyStatus(XicCommon ic, XPointer call_data) {
00601   StatusWin status = (StatusWin)(ic->gui_icpart->status);
00602 
00603   if (!status) return;
00604 
00605   if (status->fontset && status->need_free_fontset) {
00606     XFactoryFreeDefaultFontSet (ic->core.im->core.display);
00607     status->need_free_fontset = False;
00608   }
00609   _XUnregisterFilter(ic->core.im->core.display, status->window,
00610                    RepaintStatus, (XPointer)ic);
00611 #if defined(USE_FILTER_KEY_PRESS_IN_STATUS)
00612   _XUnregisterFilter(ic->core.im->core.display, status->window,
00613                    FilterKeyPress, (XPointer)ic);
00614 #endif /* USE_FILTER_KEY_PRESS_IN_STATUS */
00615   if (status->window) {
00616     if (IMCheckIMWindow(ic, status->window)) {
00617       XDestroyWindow(ic->core.im->core.display, status->window);
00618     }
00619     status->window = 0;
00620   }
00621 
00622   if (status->gc) XFreeGC(ic->core.im->core.display, status->gc);
00623 #ifdef USE_STATUS_FEEDBACK
00624   if (status->rgc) XFreeGC(ic->core.im->core.display, status->rgc);
00625 #endif
00626   if (status->text.string.multi_byte) {
00627     Xfree(status->text.string.multi_byte);
00628   }
00629   FreeFeedbackList(status->feedback, status->text.length);
00630   status->feedback = NULL;
00631   
00632   Xfree(status->status_string);
00633   Xfree(status);
00634   ic->gui_icpart->status = (StatusWin)NULL;
00635   return;
00636 }
00637 
00638 char *
00639 MergeStatus(XicCommon ic) {
00640   StatusWin status = (StatusWin)(ic->gui_icpart->status);
00641   int len = 0;
00642   char *status_string;
00643 
00644   if (!status) return 0;
00645   len = 0;
00646   if (NULL != status) {
00647     if (NULL != status->text.string.multi_byte) {
00648       len = strlen(status->text.string.multi_byte);
00649     }
00650   }
00651   if (len <= 0) {
00652     return NULL;
00653   }
00654 
00655   status_string = (char *)Xmalloc(len + 1);
00656   if (NULL == status_string) return NULL;
00657   if (NULL != status->text.string.multi_byte) {
00658     memcpy(status_string, status->text.string.multi_byte, len);
00659   }
00660   *(status_string + len) = '\0';
00661   return status_string;
00662 }