Back to index

im-sdk  12.3.91
aux_so.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 
00043 #include <stddef.h>
00044 #include <stdlib.h>
00045 #include <stdio.h>
00046 #include <sys/types.h>
00047 #include <unistd.h>
00048 #include <limits.h>
00049 
00050 #include <X11/Xmd.h>
00051 #include <X11/Xlib.h>
00052 #include <X11/Xatom.h>
00053 
00054 #include "iiimpAux.h"
00055 #include "trace_message.h"
00056 
00057 #define HASH_SIZE 137
00058 #define ME                  "aux_so"
00059 #define       AUX_EXT                     "/usr/lib/im/locale/zh_CN/newpy/aux_win"
00060 
00061 typedef struct _aux_icid {
00062         aux_t *                 aux;
00063         int                     icid;
00064         struct _aux_icid *      prev;
00065         struct _aux_icid *      next;
00066 } aux_icid_t;
00067 
00068 static Bool   panel_Create(aux_t *);
00069 static Bool   panel_Start(aux_t *, const unsigned char *, int);
00070 static Bool   panel_Draw(aux_t *, const unsigned char *, int);
00071 static Bool   panel_Done(aux_t *, const unsigned char *, int);
00072 static Bool   panel_Switched(aux_t *, int, int);
00073 static Bool   panel_Destroy(aux_t *);
00074 
00075 /*
00076  * com.sun.iiim.sample.newpy.NewPYPanel
00077 */
00078 
00079 static CARD16 aux_name_panel_name[] = {
00080        0x0063, 0x006f, 0x006d, 0x002e,
00081        0x0073, 0x0075, 0x006e, 0x002e,
00082        0x0069, 0x0069, 0x0069, 0x006d,
00083        0x002e, 0x0073, 0x0061, 0x006d,
00084        0x0070, 0x006c, 0x0065, 0x002e,
00085        0x006e, 0x0065, 0x0077, 0x0070,
00086        0x0079, 0x002e, 0x004e, 0x0065, 
00087        0x0077, 0x0050, 0x0059, 0x0050,
00088        0x0061, 0x006e, 0x0065, 0x006c,
00089 };
00090 
00091 static aux_method_t  aux_method_panel = {
00092        panel_Create,
00093        panel_Start,
00094        panel_Draw,
00095        panel_Done,
00096        panel_Switched,
00097        panel_Destroy
00098 };
00099 
00100 aux_dir_t     aux_dir[] = {
00101        {{sizeof (aux_name_panel_name),
00102          aux_name_panel_name},
00103         &aux_method_panel},
00104 
00105        {{0, NULL}, NULL}
00106 };
00107 
00108 #define HTT_PANEL_EXT_NAME  "htt_panel_sample_ext"
00109 #define HTT_PANEL_SO_NAME   "htt_panel_sample_so"
00110 #define HTT_PANEL_PROP_NAME "htt_panel_sample_prop"
00111 #define HTT_PANEL_PROP1_NAME       "htt_panel_sample_prop1"
00112 
00113 static void   panel_ext_send(aux_t *, const unsigned char *, int);
00114 static void   panel_process_property_notify(Display *, Window);
00115 static void   panel_process_client_message(Display *, Window, XEvent *);
00116 static Bool   panel_event_filter(Display *, Window, XEvent *, XPointer);
00117 
00118 static Bool   panel_init(aux_t *);
00119 
00120 static void          panel_icid_init(void);
00121 static void          panel_icid_finish(void);
00122 static aux_icid_t *  panel_icid_get(int);
00123 static void          panel_icid_delete(int);
00124 
00125 static int           panel_initialized = 0;
00126 static aux_icid_t    panel_icid[HASH_SIZE];
00127 
00128 static Atom   panel_so_atom;
00129 static Atom   panel_ext_atom;
00130 static Atom   panel_prop_atom;
00131 static Atom   panel_prop1_atom;
00132 
00133 static Window panel_window;
00134 
00135 static void
00136 panel_ext_send(aux_t * aux, const unsigned char * p, int len)
00137 {
00138        Display *     display;
00139        Window        w_ext;
00140 
00141        TRACE_MESSAGE('S', (ME ":panel_ext_send: \"%.*s\" len=%d\n", len - 4, p + 4, len));
00142        
00143        display = aux->service->display(aux);
00144 
00145        if (None == (w_ext = XGetSelectionOwner(display, panel_ext_atom))) {
00146               TRACE_MESSAGE('s', (ME ":panel_ext_send: no owner of %08x (display=%08x)\n",
00147                                 panel_ext_atom, display));
00148 
00149               XChangeProperty(display, panel_window, panel_prop1_atom, XA_STRING,
00150                             8, PropModeReplace, (unsigned char *)p, len);
00151 
00152               return;
00153        }
00154 
00155        TRACE_MESSAGE('s', (ME ":panel_ext_send: owner %08x\n", w_ext));
00156 
00157        XChangeProperty(display, w_ext, panel_prop_atom, XA_STRING,
00158                      8, PropModeReplace, (unsigned char *)p, len);
00159 
00160        return;
00161 }
00162 
00163 
00164 static void
00165 panel_process_property_notify(Display * display, Window window)
00166 {
00167        long          long_length;
00168        Atom          actual_type_return;
00169        int           actual_format_return;
00170        unsigned long nitem_return;
00171        unsigned long bytes_after_return;
00172        unsigned char *      prop_return;
00173        int           r;
00174        int           imid;
00175        int           icid;
00176        aux_icid_t *  ic;
00177        int           size;
00178        aux_data_t *  aux_data;
00179        unsigned char *      p;
00180        unsigned char buf[1024];
00181        const char *  inbuf;
00182        size_t        inbytesleft;
00183        char *        outbuf;
00184        size_t        outbytesleft;
00185 
00186        TRACE_MESSAGE('P', (ME ":panel_process_property_notify: %08x %08x %08x\n",
00187                          display, window, panel_prop_atom));
00188 
00189        r = XGetWindowProperty(display, window,
00190                             panel_prop_atom, 0, INT_MAX, False,
00191                             AnyPropertyType, &actual_type_return,
00192                             &actual_format_return, &nitem_return,
00193                             &bytes_after_return, &prop_return);
00194        if (Success != r) {
00195               return;
00196        }
00197 
00198        imid = ((*(prop_return + 0) << 8) +
00199               (*(prop_return + 1) << 0));
00200        icid = ((*(prop_return + 2) << 8) +
00201               (*(prop_return + 3) << 0));
00202 
00203        TRACE_MESSAGE('P', (ME ":panel_process_property_notify: imid=%d icid=%d \"%s\"\n",
00204                          imid, icid, prop_return + 4));
00205 
00206        ic = panel_icid_get(icid);
00207 
00208        if (NULL == ic->aux) {
00209               XFree(prop_return);
00210               return;
00211        }
00212 
00213        aux_data = (aux_data_t *)malloc(sizeof (aux_data_t));
00214        aux_data->type = AUX_DATA_SETVALUE;
00215        aux_data->im = imid;
00216        aux_data->ic = icid;
00217        aux_data->aux_index = 0;
00218        aux_data->aux_name = (unsigned char *)aux_name_panel_name;
00219        aux_data->aux_name_length = (sizeof (aux_name_panel_name));
00220 
00221        aux_data->integer_count = 2;
00222        aux_data->integer_list = (int *)malloc(2 * (sizeof (int)));
00223        *(aux_data->integer_list + 0) = aux_data->im;
00224        *(aux_data->integer_list + 1) = aux_data->ic;
00225 
00226        aux_data->string_count = 2;
00227        aux_data->string_list =
00228               (aux_string_t *)malloc(2 * (sizeof (aux_string_t)));
00229 
00230        inbuf = (const char *)(prop_return + 4);
00231        inbytesleft = (nitem_return - 4);
00232        outbuf = (char *)buf;
00233        outbytesleft = (sizeof (buf));
00234        ic->aux->service->mb_utf16(&inbuf, &inbytesleft,
00235                                &outbuf, &outbytesleft);
00236 
00237        (aux_data->string_list + 0)->ptr = buf;
00238        (aux_data->string_list + 0)->length = ((sizeof (buf)) - outbytesleft);
00239 
00240        (aux_data->string_list + 1)->ptr = buf;
00241        (aux_data->string_list + 1)->length = ((sizeof (buf)) - outbytesleft);
00242 
00243 #if 0
00244        (aux_data->string_list + 1)->ptr = (prop_return + 4);
00245        (aux_data->string_list + 1)->length = (nitem_return - 4);
00246 #endif /* 0 */
00247 
00248        aux_data->string_ptr = NULL;
00249 
00250        p = ic->aux->service->compose(aux_data, &size);
00251 
00252 #if defined(ENABLE_TRACE)
00253        if (TRACE_P('p')) {
00254               int    i;
00255               int    j;
00256               int    k;
00257               TRACE_MESSAGE('p', ("panel_process_property_notify: len=%d\n", size));
00258               for (i = 0, k = 0; i < size; i += 4) {
00259                      for (j = 0; j < 4; j++) {
00260                             TRACE_MESSAGE('p', ("%02x", *(p + i + j)));
00261                      }
00262                      if (7 == k) {
00263                             TRACE_MESSAGE('p', ("\n"));
00264                             k = 0;
00265                      } else {
00266                             TRACE_MESSAGE('p', (" "));
00267                             k += 1;
00268                      }
00269               }
00270               TRACE_MESSAGE('p', ("\n"));
00271        }
00272 #endif /* ENABLE_TRACE */
00273 
00274        ic->aux->service->aux_setvalue(ic->aux, p, size);
00275 
00276        free(p);
00277        free(aux_data->string_list);
00278        free(aux_data->integer_list);
00279        free(aux_data);
00280        XFree(prop_return);
00281 
00282        return;
00283 }
00284 
00285 
00286 static void
00287 panel_process_client_message(Display * display, Window window, XEvent * event)
00288 {
00289        XClientMessageEvent *       message;
00290        int                  imid;
00291        int                  icid;
00292 
00293        message = (XClientMessageEvent *)event;
00294 
00295        imid = ((*(message->data.b + 0) << 8) +
00296               (*(message->data.b + 1) << 0));
00297        icid = ((*(message->data.b + 2) << 8) +
00298               (*(message->data.b + 3) << 0));
00299 
00300        if (message->message_type == panel_so_atom) {
00301               TRACE_MESSAGE('M',
00302                            (ME ":process_client_message: %08x %08x %d\n",
00303                             display, window, message->data.l[0]));
00304               TRACE_MESSAGE('M',
00305                            (ME ":process_client_message: exiting...\n"));
00306               exit(0);
00307        }
00308               
00309        switch (message->message_type) {
00310        case XA_INTEGER:
00311               TRACE_MESSAGE('M',
00312                            (ME ":panel_process_client_message: %08x %08x %d\n",
00313                             display, window, message->data.l[0]));
00314               break;
00315        case XA_STRING:
00316               TRACE_MESSAGE('M',
00317                            (ME ":panel_process_client_message: d=%08x w=%08x im=%d ic=%d %s\n",
00318                             display, window, imid, icid, message->data.b + 4));
00319               break;
00320        }
00321 
00322        return;
00323 }
00324 
00325 
00326 static Bool
00327 panel_event_filter(
00328        Display *     display,
00329        Window        window,
00330        XEvent *      event,
00331        XPointer      pointer)
00332 {
00333        switch (event->type) {
00334        case PropertyNotify:
00335               if (panel_prop_atom != ((XPropertyEvent *)event)->atom) {
00336                      return False;
00337               }
00338               panel_process_property_notify(display, window);
00339               return True;
00340               break;
00341        case ClientMessage:
00342               panel_process_client_message(display, window, event);
00343               return True;
00344               break;
00345        }
00346        return False;
00347 }
00348 
00349 
00350 static Bool
00351 panel_init(aux_t * aux)
00352 {
00353        Display *     display;
00354 
00355        TRACE_MESSAGE('I', (ME ":panel_init: display = %08x\n", display));
00356 
00357        display = aux->service->display(aux);
00358 
00359        panel_ext_atom = XInternAtom(display, HTT_PANEL_EXT_NAME, False);
00360        panel_so_atom = XInternAtom(display, HTT_PANEL_SO_NAME, False);
00361        panel_prop_atom = XInternAtom(display, HTT_PANEL_PROP_NAME, False);
00362        panel_prop1_atom = XInternAtom(display, HTT_PANEL_PROP1_NAME, False);
00363 
00364        if (None != XGetSelectionOwner(display, panel_so_atom)) {
00365               TRACE_MESSAGE('I', (ME ":panel_init: panel_so already exists\n"));
00366               return False;
00367        }
00368        panel_window = XCreateSimpleWindow(display, RootWindow(display, 0),
00369                                  0, 0, 1, 1, 0, 0, 0);
00370 
00371        TRACE_MESSAGE('I', (ME ":panel_init: window = %08x\n", panel_window));
00372 
00373        if (None != XGetSelectionOwner(display, panel_so_atom)) {
00374               TRACE_MESSAGE('I', (ME ":panel_init: panel_so already exists (0)\n"));
00375               return False;
00376        }
00377        XSetSelectionOwner(display, panel_so_atom, panel_window, CurrentTime);
00378        if (panel_window != XGetSelectionOwner(display, panel_so_atom)) {
00379               TRACE_MESSAGE('I', (ME ":panel_init: panel_so already exists (1)\n"));
00380               return False;
00381        }
00382 
00383        XSelectInput(display, panel_window, PropertyChangeMask);
00384 
00385        aux->service->register_X_filter(display, panel_window,
00386                                    PropertyNotify, PropertyNotify,
00387                                    panel_event_filter, NULL);
00388 
00389        aux->service->register_X_filter(display, panel_window,
00390                                    ClientMessage, ClientMessage,
00391                                    panel_event_filter, NULL);
00392 }
00393 
00394 
00395 static void
00396 panel_icid_init(void)
00397 {
00398        int    i;
00399 
00400        for (i = 0; i < HASH_SIZE; i++) {
00401               panel_icid[i].icid = (-1);
00402        }
00403 }
00404 
00405 
00406 static void
00407 panel_icid_finish(void)
00408 {
00409        int           i;
00410        aux_icid_t *  p0;
00411        aux_icid_t *  p1;
00412 
00413        for (i = 0; i < HASH_SIZE; i++) {
00414               p0 = panel_icid[i].next;
00415 
00416               for (; NULL != p0; p0 = p1) {
00417                      free(p0);
00418                      p1 = p0->next;
00419               }
00420        }
00421 }
00422 
00423 
00424 static aux_icid_t *
00425 panel_icid_get(int icID)
00426 {
00427        int           hash_value;
00428        aux_icid_t *  p;
00429 
00430        hash_value = (icID % HASH_SIZE);
00431 
00432        p = &(panel_icid[hash_value]);
00433 
00434        if ((-1) == p->icid) {
00435               p->icid = icID;
00436               return p;
00437        }
00438 
00439        for (; NULL != p; p = p->next) {
00440               if (icID == p->icid) {
00441                      return p;
00442               }
00443               if (NULL == p->next) {
00444                      p->next = malloc(sizeof (aux_icid_t));
00445                      if (NULL == p->next) {
00446                             return NULL;
00447                      }
00448                      memset(p->next, 0, (sizeof (aux_icid_t)));
00449                      p->next->prev = p;
00450                      return p->next;
00451               }
00452        }
00453        return NULL;  /* never comes here */
00454 }
00455 
00456 
00457 static void
00458 panel_icid_delete(int icID)
00459 {
00460        aux_icid_t *  p;
00461 
00462        p = panel_icid_get(icID);
00463        if (NULL == p) {
00464               return;
00465        }
00466        if (NULL != p->prev) {
00467               p->prev->next = p->next;
00468               free(p);
00469        }
00470 }
00471 
00472 
00473 static Bool
00474 panel_Create(aux_t * aux)
00475 {
00476        int           i;
00477        pid_t         pid;
00478        aux_icid_t *  aux_icid;
00479 
00480        TRACE_MESSAGE_INIT("TRACE_AUX_SO");
00481 
00482        TRACE_MESSAGE('X', (ME ":panel_Create\n"));
00483 
00484        if (0 == panel_initialized) {
00485               panel_icid_init();
00486        }
00487 
00488        if (NULL == (aux_icid = panel_icid_get(aux->service->ic_id(aux)))) {
00489               return False;
00490        }
00491        aux_icid->aux = aux;
00492        if (0 == panel_initialized) {
00493               panel_init(aux);
00494        }
00495 
00496        panel_initialized = 1;
00497 
00498 #if 0
00499        aux->service->data_set(aux, im_id,(void *)aux_icid);
00500 #endif /* 0 */
00501 
00502 #ifdef HAVE_FORK1
00503        pid = fork1();
00504 #else
00505        pid = fork();
00506 #endif
00507        if ((pid_t)(-1) == pid) {
00508               return False;
00509        } else if (0 == pid) {
00510               execl(AUX_EXT, "panel", "-name", "panel", NULL);
00511               _exit(1);
00512        } else {
00513               return True;
00514        }
00515 }
00516 
00517 
00518 static Bool
00519 panel_Start(aux_t * aux, const unsigned char * p, int size)
00520 {
00521        TRACE_MESSAGE('X', (ME ":panel_Start: size = %d\n", size));
00522        return True;
00523 }
00524 
00525 
00526 static Bool
00527 panel_Draw(aux_t * aux, const unsigned char * p, int size)
00528 {
00529        aux_data_t *  aux_data;
00530        char *        string_ptr;
00531        char          string_buf[1024];
00532        int           string_len;
00533        Window        w;
00534        XPoint        point;
00535 
00536        TRACE_MESSAGE('X', (ME ":panel_Draw: im=%d ic=%d size = %d\n",
00537                          aux->service->im_id(aux),
00538                          aux->service->ic_id(aux),
00539                          size));
00540 
00541        *((CARD16 *)(string_buf + 0)) = aux->service->im_id(aux);
00542        *((CARD16 *)(string_buf + 2)) = aux->service->ic_id(aux);
00543        string_ptr = (string_buf + 4);
00544        string_len = 4;
00545 
00546        w = aux->service->window(aux);
00547        aux->service->point(aux, &point);
00548 
00549        TRACE_MESSAGE('D', (ME ":panel_Draw: w=%08x x=%d y=%d\n", w, point.x, point.y));
00550 
00551        aux_data = aux->service->decompose(AUX_DATA_DRAW, p);
00552 
00553 #if defined(ENABLE_TRACE)
00554        if (TRACE_P('D')) {
00555               char          aux_name;
00556               const char *  inbuf;
00557               size_t        inbytesleft;
00558               char *        outbuf;
00559               size_t        outbytesleft;
00560               char          buf[1024];
00561 
00562               TRACE_MESSAGE('D', (ME ":panel_Draw: aux_index = %d\n",
00563                                 aux_data->aux_index));
00564               inbuf = (char *)(aux_data->aux_name);
00565               inbytesleft = aux_data->aux_name_length;
00566               outbuf = buf;
00567               outbytesleft = (sizeof (buf));
00568               aux->service->utf16_mb(&inbuf, &inbytesleft,
00569                                    &outbuf, &outbytesleft);
00570               TRACE_MESSAGE('D', (ME ":panel_Draw: aux_name = \"%.*s\"\n",
00571                                 (sizeof (buf)) - outbytesleft, buf));
00572        }
00573 #endif /* ENABLE_TRACE */
00574 
00575        if (0 < aux_data->integer_count) {
00576               int    i;
00577               TRACE_MESSAGE('D', (ME ":panel_Draw: integer_list[%d] =",
00578                                 aux_data->integer_count));
00579               for (i = 0; i < aux_data->integer_count; i++) {
00580                      TRACE_MESSAGE('D',
00581                                   (" %d", *(aux_data->integer_list + i)));
00582               }
00583               TRACE_MESSAGE('D', ("\n"));
00584        } else {
00585               TRACE_MESSAGE('D',
00586                            (ME ":panel_Draw: integer_count = 0\n"));
00587        }
00588        if (0 < aux_data->string_count) {
00589               int    i;
00590               for (i = 0; i < aux_data->string_count; i++) {
00591                      const char *  inbuf;
00592                      size_t        inbytesleft;
00593                      char *        outbuf;
00594                      size_t        outbytesleft;
00595                      int           j;
00596 
00597                      inbuf = (char *)((aux_data->string_list + i)->ptr);
00598                      inbytesleft = (aux_data->string_list + i)->length;
00599                      outbuf = string_ptr;
00600                      outbytesleft = ((sizeof (string_buf)) - string_len);
00601 
00602                      aux->service->utf16_mb(&inbuf, &inbytesleft,
00603                                           &outbuf, &outbytesleft);
00604 #if defined(ENABLE_TRACE)
00605                      j = (((sizeof (string_buf)) - string_len) - outbytesleft);
00606                      TRACE_MESSAGE('D',
00607                                   (ME ":panel_Draw: "
00608                                    "*(string_list + %d) = \"%.*s\" len=%d\n",
00609                                    i, j, string_ptr, j));
00610 #endif /* ENABLE_TRACE */
00611                      string_len = ((sizeof (string_buf)) - outbytesleft);
00612                      string_ptr = (string_buf + string_len);
00613                      switch (*(string_ptr - 1)) {
00614                      case '\0':
00615                             *(string_ptr - 1) = ' ';
00616                             break;
00617                      case ' ':
00618                             break;
00619                      default:
00620                             *string_ptr = ' ';
00621                             string_ptr += 1;
00622                             string_len += 1;
00623                             break;
00624                      }
00625               }
00626        } else {
00627               TRACE_MESSAGE('D',
00628                            (ME ":panel_Draw: string_count = 0\n"));
00629        }
00630 
00631        if (0 < string_len) {
00632               panel_ext_send(aux, (unsigned char *)string_buf, string_len);
00633        }
00634 
00635        aux->service->decompose_free(aux_data);
00636 
00637        return True;
00638 }
00639 
00640 
00641 static Bool
00642 panel_Done(aux_t * aux, const unsigned char * p, int size)
00643 {
00644        TRACE_MESSAGE('X', (ME ":panel_Done: size = %d\n", size));
00645        return True;
00646 }
00647 
00648 
00649 static Bool
00650 panel_Switched(aux_t * aux, int im_id, int on_off)
00651 {
00652        TRACE_MESSAGE('X', (ME ":panel_Switched im_id = %d %s\n",
00653                          im_id, ((1 == on_off) ? "on" : "off")));
00654 
00655        return True;
00656 }
00657 
00658 
00659 static Bool
00660 panel_Destroy(aux_t * aux)
00661 {
00662        TRACE_MESSAGE('X', (ME ":panel_Destroy\n"));
00663 
00664        return True;
00665 }