Back to index

plt-scheme  4.2.1
Window.cc
Go to the documentation of this file.
00001 /*                                                      -*- C++ -*-
00002  *
00003  * Purpose: base class for all windows
00004  *
00005  * Authors: Markus Holzem and Julian Smart
00006  *
00007  * Copyright: (C) 2004-2009 PLT Scheme Inc.
00008  * Copyright: (C) 1995, AIAI, University of Edinburgh (Julian)
00009  * Copyright: (C) 1995, GNU (Markus)
00010  *
00011  * This program is free software; you can redistribute it and/or modify
00012  * it under the terms of the GNU General Public License as published by
00013  * the Free Software Foundation; either version 2 of the License, or
00014  * (at your option) any later version.
00015  *
00016  * This program is distributed in the hope that it will be useful,
00017  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00018  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00019  * GNU General Public License for more details.
00020  *
00021  * You should have received a copy of the GNU General Public License
00022  * along with this program; if not, write to the Free Software
00023  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
00024  * 02110-1301 USA.
00025  */
00026 
00027 #ifdef __GNUG__
00028 #pragma implementation "Window.h"
00029 #endif
00030 
00031 #define  Uses_XtIntrinsicP
00032 #define  Uses_wxGDI
00033 #define  Uses_wxLayout
00034 #define  Uses_wxMenu
00035 #define  Uses_wxMenuBar
00036 #define  Uses_wxTypeTree
00037 #define  Uses_wxWindow
00038 #define  Uses_wxDialogBox
00039 #define  Uses_wxItem
00040 #define  Uses_wxCanvas
00041 #define  Uses_wxApp
00042 #define  Uses_wxClipboard
00043 #include "wx.h"
00044 #define  Uses_ScrollWinWidget
00045 #define  Uses_Scrollbar
00046 #define  Uses_ShellWidget
00047 #define  Uses_SimpleWidget
00048 #define  Uses_EnforcerWidget
00049 #define  Uses_LabelWidget
00050 #define  Uses_MultiListWidget
00051 #define  Uses_ScrollbarWidget
00052 #include "widgets.h"
00053 
00054 #include "xdnd.h"
00055 
00056 #include <X11/Xatom.h>
00057 #include <X11/keysym.h> // needed for IsFunctionKey, etc.
00058 #ifdef WX_USE_XFT
00059 # include <X11/Xft/Xft.h>
00060 #endif
00061 
00062 static Atom utf8_atom = 0, net_wm_name_atom, net_wm_icon_name_atom;
00063 
00064 extern void wxSetSensitive(Widget, Bool enabled);
00065 extern int wxLocaleStringToChar(char *str, int slen);
00066 extern int wxUTF8StringToChar(char *str, int slen);
00067 extern wxWindow *wxLocationToWindow(int x, int y);
00068 
00069 static wxWindow *grabbing_panel;
00070 static Time grabbing_panel_time;
00071 static Bool grabbing_panel_regsitered;
00072 
00073 #include "xdnd.c"
00074 
00075 static int dnd_inited = 0;
00076 static DndClass dnd;
00077 
00078 Atom wx_single_instance_tag = 0;
00079 
00080 #ifndef NO_XMB_LOOKUP_STRING
00081 static XIM the_im;
00082 #endif
00083 
00084 class Accum_Single_Instance_Message {
00085 public:
00086   long src;
00087   char *accum;
00088   int len, size;
00089   Accum_Single_Instance_Message *next;
00090 };
00091 static int si_registered;
00092 static Accum_Single_Instance_Message *si_msgs;
00093 static void parse_and_drop_runtime(int len, char *s);
00094 static void decode_percent_escapes(char *s);
00095 extern void wxDrop_Runtime(char **argv, int argc);
00096 
00097 //-----------------------------------------------------------------------------
00098 // wxWindow constructor
00099 //-----------------------------------------------------------------------------
00100 
00101 #define ACTIVE_VIA_POINTER_FLAG 0x1
00102 #define DISABLED_FLAG 0x2
00103 #define SHOWN_FLAG 0x4
00104 #define NO_AUTO_SCROLL_FLAG 0x8
00105 #define FOCUS_FLAG 0x10
00106 #define REPORT_ZERO_WIDTH_FLAG 0x20
00107 #define REPORT_ZERO_HEIGHT_FLAG 0x40
00108 #define LAST_WAS_ALT_DOWN_FLAG 0x80
00109 
00110 wxWindow::wxWindow(void)
00111 { 
00112     __type = wxTYPE_WINDOW;
00113 
00114     // X representation
00115     X = new wxWindow_Xintern;
00116     X->frame = X->handle = X->scroll = NULL;
00117     X->translations_eventmask = 0;
00118     X->last_clicktime = 0;
00119     X->last_clickbutton = 0;
00120     // device context
00121     dc = NULL;
00122     // child <-> parent relationships
00123     parent   = NULL;
00124     children = DEBUG_NEW wxChildList;
00125     // layout information
00126     constraints = DEBUG_NEW wxLayoutConstraints;
00127     wxLC_MEM(constraints->left, Absolute(0));
00128     wxLC_MEM(constraints->top, Absolute(0));
00129     wxLC_MEM(constraints->width, AsIs());
00130     wxLC_MEM(constraints->height, AsIs());
00131     xoff = yoff = 0;
00132     // GDI objects
00133     cmap   = wxAPP_COLOURMAP;
00134     cursor = NULL /* wxSTANDARD_CURSOR */;
00135     font   = wxSYSTEM_FONT;
00136     // misc info
00137     allow_dclicks    = FALSE;
00138     captured         = FALSE;
00139     drag_accept      = FALSE;
00140     painting_enabled = TRUE;
00141     style            = 0;
00142     user_edit_mode   = FALSE;
00143 
00144     {
00145       wxWindow **wa;
00146       wa = (wxWindow **)MALLOC_SAFEREF();
00147       saferef = wa;
00148     }
00149     SET_SAFEREF(saferef, this);
00150     misc_flags = 0;
00151     /* except for frames, windows start out shown: */
00152     if (!wxSubType(__type, wxTYPE_FRAME))
00153       misc_flags |= SHOWN_FLAG;
00154     internal_disabled = 0;
00155 
00156     WXGC_IGNORE(this, parent);
00157 }
00158 
00159 wxWindow::~wxWindow(void)
00160 {
00161 #ifndef NO_XMB_LOOKUP_STRING
00162     if (X->ic) XDestroyIC(X->ic);
00163 #endif
00164 
00165     // destroy children
00166     DestroyChildren(); DELETE_OBJ children; children = NULL;
00167     // destroy device context
00168     if (dc) DELETE_OBJ dc; dc = NULL;
00169     // remove from parents list
00170     if (parent)      parent->RemoveChild(this); parent = NULL;
00171     // destroy widgets
00172     wxSetSensitive(X->frame, TRUE);
00173 
00174     *saferef = NULL;
00175 
00176     dndTarget = NULL; /* just in case */
00177 
00178     if (X->frame) XtDestroyWidget(X->frame); X->frame = X->handle = X->scroll = NULL;
00179     DELETE_OBJ constraints; constraints = NULL;
00180     DELETE_OBJ X; X = NULL;
00181 }
00182 
00183 //-----------------------------------------------------------------------------
00184 // child - parent relationships
00185 //-----------------------------------------------------------------------------
00186 
00187 wxWindow *wxWindow::GetGrandParent(void)
00188 {
00189     return (parent ? parent->parent : (wxWindow*)NULL);
00190 }
00191 
00192 void wxWindow::AddChild(wxWindow *child)
00193 {
00194   /* Propagate busy cursor flag */
00195   child->user_edit_mode = user_edit_mode;
00196 
00197   children->Append(child);
00198 }
00199 
00200 void wxWindow::DestroyChildren(void)
00201 {
00202   wxChildNode *node;
00203   while ( (node=children->First()) != NULL ) {
00204     wxWindow *child;
00205     child = (wxWindow*)(node->Data());
00206     if (child) {
00207       DELETE_OBJ child;
00208     }
00209   }
00210 }
00211 
00212 void wxWindow::RemoveChild(wxWindow *child)
00213 {
00214     children->DeleteObject(child);
00215 }
00216 
00217 //-----------------------------------------------------------------------------
00218 // label, name, title of wxWindow
00219 //-----------------------------------------------------------------------------
00220 
00221 char *wxWindow::GetLabel(void)
00222 {
00223   char *label = NULL;
00224 
00225   if (!X->frame) // forbid, if no widget associated
00226     return NULL;
00227   
00228   XtVaGetValues(X->frame, XtNlabel, &label, NULL);
00229   return label;
00230 }
00231 
00232 char *wxWindow::GetName(void)
00233 {
00234     if (!X->handle) // forbid, if no widget associated
00235        return NULL;
00236 
00237     return XtName(X->handle);
00238 }
00239 
00240 char *wxWindow::GetTitle(void)
00241 {
00242   char *title = NULL;
00243   
00244   if (!X->frame) // forbid, if no widget associated
00245     return NULL;
00246   
00247   XtVaGetValues(X->frame, XtNtitle, &title, NULL);
00248   return title;
00249 }
00250 
00251 void wxWindow::SetLabel(char *label)
00252 {
00253   char *oldlabel = NULL;
00254 
00255   if (!X->frame) // forbid, if no widget associated
00256     return;
00257 
00258   XtVaGetValues(X->frame, XtNlabel, &oldlabel, NULL);
00259   if (oldlabel) {
00260     label = wxGetCtlLabel(label);
00261     XtVaSetValues(X->frame, XtNlabel, label, NULL);
00262   }
00263 }
00264 
00265 void wxWindow::SetName(char *name)
00266 {
00267   // overwrite quark computed on widget creation
00268   XrmQuark q;
00269   q = XrmStringToName((name != NULL) ? name : "");
00270   X->handle->core.xrm_name = q;
00271 }
00272 
00273 void wxWindow::SetTitle(char *title)
00274 {
00275     /* Note: widget must be realized */
00276 
00277     if (!X->frame) // forbid, if no widget associated
00278        return;
00279 
00280     if (!utf8_atom) {
00281       utf8_atom = XInternAtom(XtDisplay(X->frame), "UTF8_STRING", FALSE);
00282       net_wm_name_atom = XInternAtom(XtDisplay(X->frame), "_NET_WM_NAME", FALSE);
00283       net_wm_icon_name_atom = XInternAtom(XtDisplay(X->frame), "_NET_WM_ICON_NAME", FALSE);
00284     }
00285 
00286     /* Set title and icon title as string sintead fo utf-8. If
00287        a Window manager can handle UTF-8, we expect it to use the
00288        _NET variants. */
00289     XtVaSetValues(X->frame, 
00290                 XtNtitle, title, 
00291                 XtNiconName, title, 
00292                 XtNtitleEncoding, XA_STRING,
00293                 XtNiconNameEncoding, XA_STRING,
00294                 NULL);
00295 
00296     {
00297       int i;
00298       for (i = 0; i < 2; i++) {
00299        XChangeProperty(XtDisplay(X->frame), XtWindow(X->frame),
00300                      !i ? net_wm_name_atom: net_wm_icon_name_atom,
00301                      utf8_atom,
00302                      8, PropModeReplace,
00303                      (unsigned char *)title, strlen(title));
00304       }
00305     }
00306 }
00307 
00308 //-----------------------------------------------------------------------------
00309 // set & query size and position of wxWindow
00310 //-----------------------------------------------------------------------------
00311 
00312 void wxWindow::Centre(int direction)
00313 {
00314     int x=-1,       y=-1,       width=0,      height=0,
00315        parent_x=0, parent_y=0, parent_width, parent_height;
00316 
00317     // get position and width of parent
00318     if (parent) {
00319        if ( wxSubType(__type, wxTYPE_FRAME) )
00320            parent->GetPosition(&parent_x, &parent_y);
00321        parent->GetClientSize(&parent_width, &parent_height);
00322     } else {
00323        wxDisplaySize(&parent_width, &parent_height);
00324     }
00325     // get position and size of THIS window
00326     GetPosition(&x, &y); GetSize(&width, &height);
00327 
00328     if (direction & wxCENTRE_TOPLEFT) {
00329        x = parent_x + parent_width / 2;
00330        y = parent_y + parent_height / 2;
00331     } else {
00332        // compute centered position
00333        if (direction & wxHORIZONTAL) {
00334            x = parent_x + (parent_width - width) / 2;
00335            if (x < 0)
00336              x = 0;
00337        }
00338        if (direction & wxVERTICAL) {
00339            y = parent_y + (parent_height - height) / 2;
00340            if (y < 0)
00341              y = 0;
00342        }
00343     }
00344     // move window
00345     Move(x, y);
00346 }
00347 
00348 void wxWindow::ClientToScreen(int *x, int *y)
00349 {
00350   if (!X->handle) // forbid, if no widget associated
00351     return;
00352 
00353   {
00354     Display *dpy  = XtDisplay(X->handle);
00355     Screen  *scn  = XtScreen(X->handle);
00356     Window  root  = RootWindowOfScreen(scn);
00357     Window  win   = XtWindow(X->handle);
00358     Window  child;
00359     int xx = *x;
00360     int yy = *y;
00361     XTranslateCoordinates(dpy, win, root, xx, yy, x, y, &child);
00362   }
00363 }
00364 
00365 void wxWindow::Configure(int x, int y, int width, int height, int flags)
00366 {
00367     Arg    args[4];
00368     int    i = 0;
00369     int _xoff = 0, _yoff = 0;
00370     Position cx, cy;
00371     Dimension cw, ch;
00372 
00373     if (!X->frame) // forbid, if no widget associated
00374        return;
00375 
00376     if (!wxSubType(__type, wxTYPE_FRAME) && parent) {
00377        _xoff = parent->xoff;
00378        _yoff = parent->yoff;
00379     }
00380 
00381     /* Make sure width, height != 0 */
00382     if (!width) {
00383       width = 1;
00384       misc_flags |= REPORT_ZERO_WIDTH_FLAG;
00385     } else
00386       misc_flags -= (misc_flags & REPORT_ZERO_WIDTH_FLAG);
00387 
00388     if (!height) {
00389       height = 1;
00390       misc_flags |= REPORT_ZERO_HEIGHT_FLAG;
00391     } else
00392       misc_flags -= (misc_flags & REPORT_ZERO_HEIGHT_FLAG);
00393 
00394     XtSetArg(args[0], XtNx, &cx);
00395     XtSetArg(args[1], XtNy, &cy);
00396     XtSetArg(args[2], XtNwidth, &cw);
00397     XtSetArg(args[3], XtNheight, &ch);
00398     
00399     XtGetValues(X->frame, args, 4);
00400 
00401     if (((x > -1) || ((flags & wxPOS_USE_MINUS_ONE) && (x > wxDEFAULT_POSITION)))
00402        && ((Position)(x + _xoff) != cx))
00403       { args[i].name = XtNx; args[i].value = (Position)(x+_xoff); ++i; }
00404     if (((y > -1) || ((flags & wxPOS_USE_MINUS_ONE) && (y > wxDEFAULT_POSITION)))
00405        && ((Position)(y + _yoff) != cy))
00406       { args[i].name = XtNy; args[i].value = (Position)(y+_yoff); ++i; }
00407     if ((width > -1) && ((Dimension)width != cw))
00408       { args[i].name = XtNwidth; args[i].value = (Dimension)width; ++i; }
00409     if ((height > -1) && ((Dimension)height != ch))
00410       { args[i].name = XtNheight; args[i].value = (Dimension)height; ++i; }
00411 
00412     if (i) {
00413       XtSetValues(X->frame, args, i);
00414       OnSize(width, height);
00415     }
00416 }
00417 
00418 void wxWindow::GetPosition(int *x, int *y)
00419 {
00420     int _xoff = 0, _yoff = 0;
00421     Position xx, yy;
00422 
00423     if (!X->frame) // forbid, if no widget associated
00424        return;
00425 
00426     if (!wxSubType(__type, wxTYPE_FRAME) && parent) {
00427        _xoff = parent->xoff;
00428        _yoff = parent->yoff;
00429     }
00430 
00431     XtVaGetValues(X->frame, XtNx, &xx, XtNy, &yy, NULL);
00432     *x = (int)xx - _xoff; *y = (int)yy - _yoff;
00433 }
00434 
00435 void wxWindow::GetSize(int *width, int *height)
00436 {
00437     Dimension ww, hh;
00438 
00439     if (!X->frame) // forbid, if no widget associated
00440        return;
00441 
00442     XtVaGetValues(X->frame, XtNwidth, &ww, XtNheight, &hh, NULL);
00443     *width = ww; *height = hh;
00444     
00445     if (misc_flags & REPORT_ZERO_WIDTH_FLAG)
00446       *width = 0;
00447     if (misc_flags & REPORT_ZERO_HEIGHT_FLAG)
00448       *height = 0;
00449 }
00450 
00451 /* Client size is different from size */
00452 void wxWindow::GetClientSize(int *width, int *height)
00453 {
00454     Dimension dww, dhh, fw, fh;
00455     int ww, hh;
00456 
00457     if (!X->handle) // forbid, if no widget associated
00458        return;
00459 
00460     XtVaGetValues(X->handle, XtNwidth, &dww, XtNheight, &dhh, NULL);
00461     if (X->scroll && !(misc_flags & NO_AUTO_SCROLL_FLAG)) {
00462       /* Handle window is possibly bigger than actual visible area */
00463       Dimension xs, ys;
00464       xws_get_scroll_area(X->scroll, &xs, &ys);
00465       if (wxSubType(__type, wxTYPE_LIST_BOX)) {
00466        dww = xs;
00467        dhh = ys;
00468       } else {
00469        if (xs < dww)
00470          dww = xs;
00471        if (ys < dhh)
00472          dhh = ys;
00473       }
00474     }
00475 
00476     XtVaGetValues(X->frame, XtNwidth, &fw, XtNheight, &fh, NULL);
00477 
00478     /* If frame < contained, don't believe the number! */
00479     if (fw < dww)
00480       dww = 0;
00481     if (fh < dhh)
00482       dhh = 0;
00483 
00484     ww = (int)dww;
00485     hh = (int)dhh;
00486 
00487     if (XtIsSubclass(X->handle, xfwfFrameWidgetClass)) {
00488       Dimension fw, oo, io;
00489 
00490       XtVaGetValues(X->handle, 
00491                   XtNframeWidth, &fw, 
00492                   XtNouterOffset, &oo, 
00493                   XtNinnerOffset, &io, 
00494                   NULL);
00495 
00496       ww = ww - fw - oo - io;
00497       hh = hh - fw - oo - io;
00498     }
00499 
00500     *width = ww; *height = hh;
00501 }
00502 
00503 void wxWindow::ScreenToClient(int *x, int *y)
00504 {
00505   if (!X->handle) // forbid, if no widget associated
00506     return;
00507     
00508   {
00509     Display *dpy  = XtDisplay(X->handle);
00510     Screen  *scn  = XtScreen(X->handle);
00511     Window  root  = RootWindowOfScreen(scn);
00512     Window  win   = XtWindow(X->handle);
00513     Window  child;
00514     int xx = *x;
00515     int yy = *y;
00516     XTranslateCoordinates(dpy, root, win, xx, yy, x, y, &child);
00517   }
00518 }
00519 
00520 void wxWindow::SetSize(int x, int y, int width, int height, int flags)
00521 {
00522   if ((x > -1) || ((flags & wxPOS_USE_MINUS_ONE) && (x > wxDEFAULT_POSITION)))
00523     wxLC_MEM(constraints->left, Absolute(x));
00524   if ((y > -1) || ((flags & wxPOS_USE_MINUS_ONE) && (y > wxDEFAULT_POSITION)))
00525     wxLC_MEM(constraints->top, Absolute(y));
00526 
00527   if (width > -1)
00528     wxLC_MEM(constraints->width, Absolute(width));
00529   else
00530     wxLC_MEM(constraints->width, AsIs());
00531   if (height > -1)
00532     wxLC_MEM(constraints->height, Absolute(height));
00533   else
00534     wxLC_MEM(constraints->height, AsIs());
00535 
00536   Configure(x, y, width, height, flags);
00537 }
00538 
00539 //-----------------------------------------------------------------------------
00540 // GDI objects (font, cursor)
00541 //-----------------------------------------------------------------------------
00542 
00543 wxCursor *wxWindow::SetCursor(wxCursor *new_cursor)
00544 {
00545   wxCursor *previous;
00546 
00547   if (!X->handle) // forbid, if no widget associated
00548     return NULL;
00549   
00550   previous = cursor;
00551   
00552   if (!new_cursor || (new_cursor && new_cursor->Ok())) {
00553     cursor = new_cursor;
00554     if (!user_edit_mode) { /* really indicates busy_cursor */
00555       Cursor c;
00556       c = (new_cursor ? GETCURSOR(new_cursor) : None);
00557       XtVaSetValues(X->handle, XtNcursor, c, NULL);
00558       if (__type == wxTYPE_LIST_BOX) {
00559        /* Yuck. Set cursor for total client area of listbox */
00560        XtVaSetValues(XtParent(X->handle), XtNcursor, c, NULL);
00561       }
00562       if ((__type == wxTYPE_PANEL)
00563          || (__type == wxTYPE_FRAME)
00564          || (__type == wxTYPE_DIALOG_BOX)) {
00565        /* Yuck. If the child panel has grabbed the cursor, update
00566           it. */
00567        if (grabbing_panel) {
00568          wxWindow *p = grabbing_panel;
00569          while (p) {
00570            if (p->cursor)
00571              break;
00572            if (wxSubType(p->__type, wxTYPE_FRAME)
00573               || wxSubType(p->__type, wxTYPE_DIALOG_BOX))
00574              p = NULL;
00575            else
00576              p = p->GetParent();
00577          }
00578        
00579          if (p == this) {
00580            /* Grabbing panel uses this cursor */
00581            XChangeActivePointerGrab(wxAPP_DISPLAY, 
00582                                  (ButtonPressMask | ButtonReleaseMask
00583                                   | ButtonMotionMask | PointerMotionMask | PointerMotionHintMask
00584                                   | EnterWindowMask | LeaveWindowMask),
00585                                  c, 
00586                                  grabbing_panel_time);
00587          }
00588        }
00589       }
00590     }
00591   }
00592   
00593   return previous;
00594 }
00595 
00596 //-----------------------------------------------------------------------------
00597 // layout
00598 //-----------------------------------------------------------------------------
00599 
00600 void wxWindow::SetConstraints(wxLayoutConstraints *constr)
00601 {
00602   if (constr)
00603     constraints = constr;
00604 }
00605 
00606 // void wxWindow::Layout(void)
00607 // --> wxLayout.cc
00608 
00609 //-----------------------------------------------------------------------------
00610 // Scrolling
00611 //-----------------------------------------------------------------------------
00612 
00613 void wxWindow::EnableScrolling(Bool x, Bool y)
00614 {
00615   if (X->scroll) {
00616     XtVaSetValues(X->scroll, XtNhideHScrollbar, !x, XtNhideVScrollbar, !y, NULL);
00617   }
00618 }
00619 
00620 int wxWindow::GetScrollPos(int orient)
00621 {
00622     if (!X->scroll) return 0; // window is not scrollable
00623 
00624     if (!(misc_flags & NO_AUTO_SCROLL_FLAG))
00625       return 0;
00626  
00627     if (misc_flags & NO_AUTO_SCROLL_FLAG) {
00628       return orient == wxHORIZONTAL ? hs_pos : vs_pos;
00629     } else {
00630       Position pos;
00631       XtVaGetValues(X->handle, orient == wxHORIZONTAL ? XtNx : XtNy, &pos, NULL);
00632       return -pos;
00633     }
00634 }
00635 
00636 int wxWindow::GetScrollRange(int orient)
00637 {
00638     if (!X->scroll) return 0; // window is not scrollable
00639 
00640     if (!(misc_flags & NO_AUTO_SCROLL_FLAG))
00641       return 0;
00642  
00643     return orient == wxHORIZONTAL ? hs_width : vs_width;
00644 }
00645 
00646 int wxWindow::GetScrollPage(int orient)
00647 {
00648   if (!X->scroll) return 0; // window is not scrollable
00649   
00650     if (!(misc_flags & NO_AUTO_SCROLL_FLAG))
00651       return 0;
00652  
00653   if (orient == wxHORIZONTAL) {
00654     if (!hs_width)
00655       return 0;
00656     return hs_page;
00657   } else {
00658     if (!vs_width)
00659       return 0;
00660     return vs_page;
00661   }
00662 }
00663 
00664 void wxWindow::Scroll(int x_pos, int y_pos)
00665 {
00666     if (!X->scroll)
00667        return; // don't want to scroll or window not scrollable
00668 
00669     if (misc_flags & NO_AUTO_SCROLL_FLAG) {
00670       if (x_pos >= 0) {
00671        hs_pos = x_pos;
00672        if (hs_pos > hs_width)
00673          hs_pos = hs_width;
00674       }
00675       if (y_pos >= 0) {
00676        vs_pos = y_pos;
00677        if (vs_pos > vs_width)
00678          vs_pos = vs_width;
00679       }
00680 
00681       xws_set_scroll_direct(X->scroll, hs_width, hs_page, hs_pos, vs_width, vs_page, vs_pos);
00682     } else {
00683       Position dummy; int wd, ht; Dimension gwd, ght;
00684       // size of view port
00685       XfwfCallComputeInside(X->scroll, &dummy, &dummy, &wd, &ht);
00686       // size of scrollable window
00687       XtVaGetValues(X->handle, XtNheight, &ght, XtNwidth, &gwd, NULL);
00688       // get missing position if any (x_pos <0 || y_pos < 0)
00689       if (x_pos < 0) { XtVaGetValues(X->handle, XtNx, &dummy, NULL); x_pos = -dummy; }
00690       if (y_pos < 0) { XtVaGetValues(X->handle, XtNy, &dummy, NULL); y_pos = -dummy; }
00691       // compute correct (x,y)-position - 0<=x<=gwd-wd, 0<=y<=ght-ht
00692       x_pos = min(x_pos, gwd-wd); x_pos = max(0, x_pos);
00693       y_pos = min(y_pos, ght-ht); y_pos = max(0, y_pos); 
00694       // set position
00695       XtVaSetValues(X->handle, XtNx, (Position)(-x_pos), XtNy, (Position)(-y_pos), NULL);
00696     }
00697 }
00698 
00699 void wxWindow::SetScrollArea(int gwd, int ght)
00700 {
00701     Dimension d;
00702     int wd, ht; 
00703     Position p, x, y;
00704 
00705     if ((gwd <= 0 && ght <= 0) || !X->scroll)
00706        return; // don't want to resize or window not scrollable
00707 
00708     // position of scrollable window
00709     XtVaGetValues(X->handle, XtNx, &x, XtNy, &y, NULL);
00710     // size of viewport
00711     XfwfCallComputeInside(X->scroll, &p, &p, &wd, &ht);
00712     // get missing sizes if any (gwd <0 || ght < 0)
00713     if (gwd < 0) { XtVaGetValues(X->handle, XtNwidth, &d, NULL);  gwd = d; }
00714     if (!gwd) gwd = 1;
00715     if (ght < 0) { XtVaGetValues(X->handle, XtNheight, &d, NULL); ght = d; }
00716     if (!ght) ght = 1;
00717     // compute correct (x,y)-position - 0<=x<=gwd-wd, 0<=y<=ght-ht
00718     x = min(x, gwd-wd); x = max(0, x);
00719     y = min(y, ght-ht); y = max(0, y); 
00720     // set size and reposition if necessary (x,y changed)
00721     XtVaSetValues(X->handle,
00722                 XtNx,     x,              XtNy,      y,
00723                 XtNwidth, (Dimension)gwd, XtNheight, (Dimension)ght,
00724                 NULL);
00725 }
00726 
00727 void wxWindow::SetScrollPos(int orient, int pos)
00728 {
00729   if (!(misc_flags & NO_AUTO_SCROLL_FLAG))
00730     return;
00731   
00732   if (orient == wxHORIZONTAL)      wxWindow::Scroll(pos < 0 ? 0 : pos, -1);
00733   else                       wxWindow::Scroll(-1, pos < 0 ? 0 : pos);
00734 }
00735 
00736 void wxWindow::SetScrollRange(int orient, int range)
00737 {
00738   if (!(misc_flags & NO_AUTO_SCROLL_FLAG))
00739     return;
00740 
00741   if (orient == wxHORIZONTAL) {
00742     hs_width = range;
00743     if (hs_pos > hs_width)
00744       hs_pos = hs_width;
00745   } else {
00746     vs_width = range;
00747     if (vs_pos > vs_width)
00748       vs_pos = vs_width;
00749   }
00750   
00751   xws_set_scroll_direct(X->scroll, hs_width, hs_page, hs_pos, vs_width, vs_page, vs_pos);
00752 }
00753 
00754 void wxWindow::SetScrollPage(int orient, int range)
00755 {
00756   if (!(misc_flags & NO_AUTO_SCROLL_FLAG))
00757     return;
00758   
00759   if (range <= 0)
00760     range = 1;
00761   if (orient == wxHORIZONTAL) {
00762     if (!hs_width)
00763       hs_page = 1;
00764     else
00765       hs_page = range;
00766   } else {
00767     if (!vs_width)
00768       vs_page = 1;
00769     else
00770       vs_page = range;
00771   }
00772 
00773   xws_set_scroll_direct(X->scroll, hs_width, hs_page, hs_pos, vs_width, vs_page, vs_pos);
00774 }
00775 
00776 //-----------------------------------------------------------------------------
00777 // miscellaneous
00778 //-----------------------------------------------------------------------------
00779 
00780 void wxWindow::CaptureMouse(void)
00781 {
00782     if (!X->frame) // forbid, if no widget associated
00783        return;
00784 
00785     if (!captured) {
00786        XtAddGrab(X->frame, TRUE, FALSE);
00787        captured = TRUE;
00788     }
00789 };
00790 
00791 void wxWindow::ChangeToGray(Bool gray)
00792 {
00793   if (XtIsSubclass(X->handle, xfwfLabelWidgetClass)
00794       || XtIsSubclass(X->handle, xfwfMultiListWidgetClass))
00795     XtVaSetValues(X->handle, XtNdrawgray, (Boolean)gray, NULL);
00796 
00797   if (X->scroll)
00798     XtVaSetValues(X->scroll, XtNdrawgrayScrollWin, (Boolean)gray, NULL);
00799 
00800   if (XtIsSubclass(X->frame, xfwfEnforcerWidgetClass))
00801     XtVaSetValues(X->frame, XtNdrawgray, (Boolean)gray, NULL);
00802 
00803   if (gray)
00804     ReleaseFocus();
00805 }
00806 
00807 void wxWindow::ReleaseFocus()
00808 {
00809   /* If disabling and this window has the focus, get rid of it: */
00810   if (misc_flags & FOCUS_FLAG) {
00811     wxWindow *p;
00812     p = GetParent();
00813     while (p) {
00814       if (wxSubType(p->__type, wxTYPE_FRAME)) {
00815        p->SetFocus();
00816        break;
00817       }
00818       p = p->GetParent();
00819     }
00820   }
00821 }
00822 
00823 void wxWindow::ReleaseAllFocus()
00824 {
00825   ReleaseFocus();
00826 }
00827 
00828 Bool wxWindow::IsGray(void)
00829 {
00830   return (misc_flags & DISABLED_FLAG) || internal_gray_disabled;
00831 }
00832 
00833 void wxWindow::InternalEnable(Bool enable, Bool gray)
00834 {
00835   Bool do_something;
00836   short start_igd = internal_gray_disabled;
00837   
00838   if (!X->frame || !X->handle) // forbid, if no widget associated
00839     return;
00840   
00841   if (!enable) {
00842     do_something = !internal_disabled;
00843     internal_disabled++;
00844     if (gray)
00845       internal_gray_disabled++;
00846   } else { 
00847     --internal_disabled;
00848     do_something = !internal_disabled;
00849     if (gray)
00850       --internal_gray_disabled;
00851   }
00852 
00853   if (do_something && !(misc_flags & DISABLED_FLAG))
00854     wxSetSensitive(X->frame, enable);
00855 
00856   if ((!!internal_gray_disabled != !!start_igd) && !(misc_flags & DISABLED_FLAG))
00857     ChangeToGray(!!internal_gray_disabled);
00858 }
00859 
00860 void wxWindow::Enable(Bool enable)
00861 {
00862   Bool orig_enabled = !(misc_flags & DISABLED_FLAG);
00863 
00864   if (!X->frame || !X->handle) // forbid, if no widget associated
00865     return;
00866   
00867   if (orig_enabled == !!enable)
00868     return;
00869 
00870   if (!enable)
00871     misc_flags |= DISABLED_FLAG;
00872   else
00873     misc_flags -= DISABLED_FLAG;
00874 
00875   if (!internal_disabled)
00876     wxSetSensitive(X->frame, enable);
00877 
00878   /* Doing handle sensitive makes it gray: */
00879   if (!internal_gray_disabled)
00880     ChangeToGray(!enable);
00881 }
00882 
00883 Bool wxWindow::PopupMenu(wxMenu *menu, double x, double y, Bool for_choice, int top_extra)
00884 {
00885   int dev_x = (int)x;
00886   int dev_y = (int)y;
00887   
00888   if (!X->frame || !X->handle) // forbid, if no widget associated
00889     return FALSE;
00890 
00891   ClientToScreen(&dev_x, &dev_y);
00892   menu->PopupMenu(X->frame, dev_x, dev_y, for_choice, top_extra);
00893   return TRUE;
00894 }
00895 
00896 void wxWindow::GetRefreshSize(int *w, int *h)
00897 {
00898   GetSize(w, h);
00899 }
00900 
00901 void wxWindow::Refresh(void)
00902 {
00903     XExposeEvent  dummyEvent;
00904     int           width, height;
00905 
00906     if (!X->handle) // forbid, if no widget associated
00907        return;
00908 
00909     GetRefreshSize(&width, &height);
00910 
00911     dummyEvent.type    = Expose;
00912     dummyEvent.display        = XtDisplay(X->handle);
00913     dummyEvent.send_event = True;
00914     dummyEvent.window         = XtWindow(X->handle);
00915     dummyEvent.x       = 0;
00916     dummyEvent.y       = 0;
00917     dummyEvent.width   = width;
00918     dummyEvent.height         = height;
00919     dummyEvent.count   = 0;
00920 
00921     XSendEvent(XtDisplay(X->handle), XtWindow(X->handle),
00922               False, ExposureMask, (XEvent*)&dummyEvent);
00923 }
00924 
00925 void wxWindow::ReleaseMouse(void)
00926 {
00927     if (!X->frame) // forbid, if no widget associated
00928        return;
00929 
00930     if (captured) {
00931        XtRemoveGrab(X->frame);
00932        captured = FALSE;
00933     }
00934 };
00935 
00936 void wxWindow::SetFocus(void)
00937 {
00938   wxWindow *win;
00939 
00940   if (!X->frame) // forbid, if no widget associated
00941     return;
00942 
00943   if (IsGray() || !IsShown())
00944     return;
00945 
00946   if (!WantsFocus())
00947     return;
00948 
00949   if (misc_flags & FOCUS_FLAG)
00950     /* focus is already here */
00951     return;
00952 
00953   // search for the frame of this widget
00954   win = this;
00955   for (/*wxWindow *win = this*/; win; win = win->parent) {
00956     if (wxSubType(win->__type, wxTYPE_FRAME))
00957       break;
00958   }
00959 
00960   // if found: set focus
00961   if (win)
00962     XtSetKeyboardFocus(win->X->frame, X->frame);
00963 }
00964 
00965 Bool wxWindow::Show(Bool show)
00966 {
00967     if (parent) {
00968       wxChildList *cl;
00969       cl = parent->GetChildren();
00970       cl->Show(this, show);
00971     }
00972 
00973     if (!X->handle) // forbid, if no widget associated
00974       return TRUE;
00975 
00976     if (!show)
00977       ReleaseAllFocus();
00978 
00979     /* Get rid of or restore focus traversal */
00980     if (XtIsSubclass(X->frame, xfwfCommonWidgetClass))
00981       XtVaSetValues(X->frame, XtNtraversalOn, (Boolean)show, NULL);
00982 
00983     /* Show/hide frame */
00984     if (show)
00985       XtManageChild(X->frame);
00986     else
00987       XtUnmanageChild(X->frame);
00988 
00989     SetShown(show);
00990 
00991     return TRUE;
00992 }
00993 
00994 Bool wxWindow::IsShown(void)
00995 {
00996   return !!(misc_flags & SHOWN_FLAG);
00997 }
00998 
00999 void wxWindow::SetShown(Bool shown)
01000 {
01001   if (shown)
01002     misc_flags |= SHOWN_FLAG;
01003   else
01004     misc_flags -= (misc_flags & SHOWN_FLAG);
01005 }
01006     
01007 
01008 //-----------------------------------------------------------------------------
01009 // virtual event functions, that implement the default behaviour
01010 //-----------------------------------------------------------------------------
01011 
01012 //-- DIRTY -- DIRTY -- DIRTY -- DIRTY -- DIRTY --
01013 //
01014 _XFUNCPROTOBEGIN
01015 extern EventMask _XtConvertTypeToMask(int type);   // internal Xt function
01016 extern void      _XtTranslateEvent(Widget w, XEvent *ev); // internal Xt function
01017 _XFUNCPROTOEND
01018 //
01019 // I've used the following way to intercept the incomming events:
01020 // - first Xt calls the expose method of the widget
01021 // - second it calls all event handlers installed by XtAddEventHandler
01022 // - third it evaluates the widget's translation table
01023 // --> I forbid the evaluation of the translation table and call
01024 //     _XtTranslateEvent by myself. 
01025 //
01026 //-- DIRTY -- DIRTY -- DIRTY -- DIRTY -- DIRTY --
01027 
01028 void wxWindow::OnChar(wxKeyEvent* wxevent)
01029 {
01030     GC_CAN_IGNORE XEvent onstack;
01031     XEvent *xev = (XEvent*)wxevent->eventHandle; // X event
01032     if (!xev) {
01033      xev = &onstack;
01034      xev->xkey.type = KeyPress;
01035      xev->xkey.display = wxAPP_DISPLAY;
01036      xev->xkey.window = XtWindow(X->handle);
01037      xev->xkey.root = RootWindowOfScreen(wxAPP_SCREEN);
01038      xev->xkey.subwindow = XtWindow(X->handle);
01039      xev->xkey.time = 0L;
01040      xev->xkey.send_event = 0;
01041      xev->xkey.same_screen = 0;
01042      xev->xkey.serial = 0;
01043     }
01044 
01045     // check if widget has translations and if this event is selected by the widget
01046     if (X->handle->core.tm.translations
01047        && (X->translations_eventmask & _XtConvertTypeToMask(xev->type))) {
01048       // translate wxKeyEvent to XEvent
01049       KeySym keysym;
01050       keysym = CharCodeWXToX(wxevent->keyCode);
01051       if (keysym != 0) {
01052        long kc;
01053        kc = XKeysymToKeycode(xev->xkey.display, keysym);
01054        xev->xkey.keycode = kc;
01055        xev->xkey.x    = (int)wxevent->x;
01056        xev->xkey.y    = (int)wxevent->y;
01057        xev->xkey.state &= ~(ShiftMask | ControlMask | Mod1Mask | Mod3Mask | LockMask);
01058        xev->xkey.state |= (wxevent->altDown     ? Mod3Mask    : 0) |
01059                         (wxevent->controlDown ? ControlMask : 0) |
01060                         (wxevent->metaDown    ? Mod1Mask    : 0) |
01061                         (wxevent->shiftDown   ? ShiftMask   : 0) |
01062                         (wxevent->capsDown    ? LockMask    : 0);
01063        // call Widget methods to handle this event
01064        _XtTranslateEvent(X->handle, xev);
01065       }
01066     }
01067 }
01068 
01069 void wxWindow::OnCommand(wxWindow* win, wxCommandEvent* event)
01070 {
01071     // OnCommand events are routed to the parent by default
01072     if (parent)
01073       parent->OnCommand(win, event);
01074 }
01075 
01076 void wxWindow::OnEvent(wxMouseEvent* wxevent)
01077 {
01078   EventMask  mask;
01079   XEvent    *xev = (XEvent*)wxevent->eventHandle; // X event
01080 
01081   if (!xev) return;
01082 
01083   mask = _XtConvertTypeToMask(xev->xany.type); // eventmask of event
01084 
01085   // adapt converted mask (Xt error????)
01086   if (mask & ButtonMotionMask)
01087     mask |= Button1MotionMask | Button2MotionMask | Button3MotionMask |
01088       Button4MotionMask | Button5MotionMask;
01089   // check if widget has translations and if this event is selected by the widget
01090   if (X->handle->core.tm.translations && (X->translations_eventmask & mask)) {
01091     // no translation of wxMouseEvents to XEvents as for OnChar
01092     // --- may be added on request ---
01093     // call Widget methods to handle this event
01094     _XtTranslateEvent(X->handle, xev);
01095   }
01096 }
01097 
01098 Bool wxWindow::PreOnChar(wxWindow *, wxKeyEvent *)
01099 {
01100   return FALSE;
01101 }
01102 
01103 Bool wxWindow::PreOnEvent(wxWindow *, wxMouseEvent *)
01104 {
01105   return FALSE;
01106 }
01107 
01108 Bool wxWindow::CallPreOnChar(wxWindow *win, wxKeyEvent *event)
01109 {
01110   wxWindow *p;
01111 
01112   p = win->GetParent();
01113 
01114   if (wxSubType(win->__type, wxTYPE_MENU_BAR)
01115       || wxSubType(win->__type, wxTYPE_MENU))
01116     return FALSE;
01117 
01118   if (wxSubType(win->__type, wxTYPE_FRAME)
01119       || wxSubType(win->__type, wxTYPE_DIALOG_BOX))
01120     p = NULL;
01121 
01122   return ((p && CallPreOnChar(p, event))
01123          || win->IsGray()
01124          || win->PreOnChar(this, event));
01125 }
01126 
01127 Bool wxWindow::CallPreOnEvent(wxWindow *win, wxMouseEvent *event)
01128 {
01129   wxWindow *p;
01130 
01131   p = win->GetParent();
01132 
01133   if (wxSubType(win->__type, wxTYPE_MENU_BAR)
01134       || wxSubType(win->__type, wxTYPE_MENU))
01135     return FALSE;
01136 
01137   if (wxSubType(win->__type, wxTYPE_FRAME)
01138       || wxSubType(win->__type, wxTYPE_DIALOG_BOX))
01139     p = NULL;
01140 
01141   return ((p && CallPreOnEvent(p, event)) 
01142          || win->IsGray()
01143          || win->PreOnEvent(this, event));
01144 }
01145 
01146 void wxWindow::OnPaint(void)
01147 {
01148     // This works only for subclasses of the xfwfCommonWidgetClass
01149     XfwfCallExpose(X->handle, X->expose_event, X->expose_region);
01150 }
01151 
01152 void wxWindow::OnScroll(wxScrollEvent*)
01153 {
01154 }
01155 
01156 //-----------------------------------------------------------------------------
01157 // apply event handling to a wxWindow
01158 //-----------------------------------------------------------------------------
01159 
01160 #ifdef MZ_PRECISE_GC
01161 START_XFORM_SKIP;
01162 #endif
01163 
01164 static void FreeSaferef(Widget WXUNUSED(w), wxWindow** winp,
01165                      XtPointer WXUNUSED(null))
01166 {
01167   FREE_SAFEREF((char *)winp);
01168 
01169   /* No XFORM_RESET_VAR_STACK because this one isn't xformed.  No need
01170      to xform because FREE_SAFEREF won't set the GC variable stack. */
01171 }
01172 
01173 #ifdef MZ_PRECISE_GC
01174 END_XFORM_SKIP;
01175 #endif
01176 
01177 void wxWindow::FocusChangeCallback(void*,
01178                                wxWindow **winp,
01179                                void*on)
01180 {
01181   wxWindow *win = (wxWindow *)GET_SAFEREF(winp);
01182 
01183   if (!win) {
01184 #ifdef MZ_PRECISE_GC
01185     XFORM_RESET_VAR_STACK;
01186 #endif
01187     return;
01188   }
01189 
01190   if (on) {
01191     win->misc_flags |= FOCUS_FLAG;
01192     win->OnSetFocus();
01193   } else { 
01194     win->misc_flags -= (win->misc_flags & FOCUS_FLAG);
01195     win->OnKillFocus();
01196   }
01197 
01198 #ifdef MZ_PRECISE_GC
01199   XFORM_RESET_VAR_STACK;
01200 #endif
01201 }
01202 
01203 void wxWindow::RegisterAll(Widget ww)
01204 {
01205   XtInsertEventHandler
01206     (ww,
01207      ButtonPressMask |      // for OnEvent
01208      ButtonReleaseMask |
01209      ButtonMotionMask |
01210      PointerMotionMask | PointerMotionHintMask,
01211      FALSE,
01212      (XtEventHandler)wxWindow::WindowEventHandler,
01213      (XtPointer)saferef,
01214      XtListHead);
01215   
01216   if (XtIsComposite(ww)) {
01217     Widget *w;
01218     Cardinal c, i;
01219 
01220     XtVaGetValues(ww, XtNchildren, &w, XtNnumChildren, &c, NULL);
01221     for (i = 0; i < c; i++) {
01222       RegisterAll(w[i]);
01223     }
01224   }
01225 }
01226 
01227 void wxWindow::AddEventHandlers(void)
01228 {
01229   wxWindow * win;
01230   long mask, extra_mask;
01231 
01232   if (!X->frame || !X->handle) // forbid, if no widget associated
01233     return;
01234 
01235     // event handler for frame
01236     XtInsertEventHandler(X->frame,        // handle events for frame widget
01237                       StructureNotifyMask |      // for OnSize, OnEvent
01238                       SubstructureNotifyMask,// for adding of window-eventhandler
01239                       TRUE,               // for OnClose
01240                       (XtEventHandler)wxWindow::FrameEventHandler,
01241                       (XtPointer)saferef,
01242                       XtListHead);
01243     // handle expose events (works only for subclasses of xfwfCommonWidgetClass)
01244     if (XtIsSubclass(X->handle, xfwfCommonWidgetClass)) {
01245        XtAddCallback(X->handle, XtNexposeCallback,
01246                     (XtCallbackProc)wxWindow::ExposeEventHandler,
01247                     (XtPointer)saferef);
01248        XtVaSetValues(X->handle, XtNuseExposeCallback, TRUE, NULL);
01249       XtAddCallback(X->handle, XtNfocusHiliteChange,
01250                   (XtCallbackProc)FocusChangeCallback, 
01251                   (XtPointer)saferef);
01252     }
01253     // handle scroll events (works only for scrollable widgets)
01254     if (X->scroll) {
01255       XtAddCallback(X->scroll, XtNscrollCallback,
01256                   (XtCallbackProc)wxWindow::ScrollEventHandler,
01257                   (XtPointer)saferef);
01258       if (XtIsSubclass(X->scroll, xfwfCommonWidgetClass))
01259        XtAddCallback(X->scroll, XtNfocusHiliteChange,
01260                     (XtCallbackProc)FocusChangeCallback, 
01261                     (XtPointer)saferef);
01262     }
01263 
01264     if (XtIsSubclass(X->frame, xfwfCommonWidgetClass)) {
01265       XtAddCallback(X->frame, XtNonDestroy,
01266                   (XtCallbackProc)FreeSaferef,
01267                   (XtPointer)saferef);
01268       XtAddCallback(X->frame, XtNfocusHiliteChange,
01269                   (XtCallbackProc)FocusChangeCallback, 
01270                   (XtPointer)saferef);
01271     }
01272 
01273     win = this;
01274 
01275     // for OnPaint (non-xfwfCommonWidget-subclasses)
01276     extra_mask = (XtIsSubclass(win->X->handle, xfwfCommonWidgetClass)
01277                 ? NoEventMask 
01278                 : ExposureMask);
01279 
01280     mask = XtBuildEventMask(win->X->handle);
01281     win->X->translations_eventmask = mask;
01282     XtInsertEventHandler
01283       (win->X->handle,      // handle events for client area widget
01284        KeyPressMask |       // for OnChar
01285        KeyReleaseMask |
01286        ButtonPressMask |    // for OnEvent
01287        ButtonReleaseMask |
01288        ButtonMotionMask |
01289        PointerMotionMask | PointerMotionHintMask |
01290        EnterWindowMask |
01291        LeaveWindowMask |
01292        extra_mask,
01293        FALSE,
01294        (XtEventHandler)wxWindow::WindowEventHandler,
01295        (XtPointer)saferef,
01296        XtListHead);
01297 
01298     if (__type == wxTYPE_LIST_BOX) {
01299       /* Yuck. Get Mouse-moved events in total client area of listbox */
01300       XtInsertEventHandler
01301        (XtParent(win->X->handle),
01302         ButtonPressMask |   // for OnEvent
01303         ButtonReleaseMask |
01304         ButtonMotionMask |
01305         PointerMotionMask | PointerMotionHintMask,
01306         FALSE,
01307         (XtEventHandler)wxWindow::WindowEventHandler,
01308         (XtPointer)saferef,
01309         XtListHead);
01310     }
01311 
01312     if (win->X->scroll)
01313       RegisterAll(win->X->scroll);
01314 
01315     /* Yucky hack to make PreOnChar work for messages, sliders, and gauges: */
01316     extra_mask = ((wxSubType(win->__type, wxTYPE_MESSAGE) 
01317                  || wxSubType(win->__type, wxTYPE_SLIDER) 
01318                  || wxSubType(win->__type, wxTYPE_GAUGE))
01319                 ? (KeyPressMask | KeyReleaseMask) : NoEventMask);
01320 
01321     XtInsertEventHandler
01322       (win->X->frame,       // handle events for frame widget
01323        EnterWindowMask |
01324        LeaveWindowMask |
01325        FocusChangeMask | // for OnKillFocus, OnSetFocus
01326        extra_mask,
01327        FALSE,
01328        (XtEventHandler)wxWindow::WindowEventHandler,
01329        (XtPointer)saferef,
01330        XtListHead);
01331 }
01332 
01333 void wxWindow::ExposeEventHandler(Widget     WXUNUSED(w),
01334                               wxWindow** winp,
01335                               XtPointer  p_XfwfExposeInfo)
01336 {
01337   XfwfExposeInfo *einfo;
01338   wxWindow *win = (wxWindow *)GET_SAFEREF(winp);
01339 
01340   if (!win) {
01341 #ifdef MZ_PRECISE_GC
01342     XFORM_RESET_VAR_STACK;
01343 #endif
01344     return;
01345   }
01346 
01347   einfo = (XfwfExposeInfo*)p_XfwfExposeInfo;
01348 
01349   if (win->painting_enabled) { // painting is allowed
01350     Region myregion;
01351 
01352     if (win->dc) {
01353       if (!(win->dc->ok)) { // setup drawable of dc on first expose
01354        win->dc->X->drawable = XtWindow(win->X->handle);
01355        win->dc->X->draw_window = win->dc->X->drawable;
01356        win->dc->SetBackground(win->dc->current_background_color);
01357        win->dc->Clear();
01358        win->dc->ok = TRUE;
01359       }
01360       // Set up clipping region.
01361       // Make a copy because Xt apparently has only one region that it uses
01362       myregion = XCreateRegion(); 
01363       XUnionRegion(myregion, einfo->region, myregion);
01364 
01365       win->dc->X->expose_reg = myregion;
01366       win->dc->SetCanvasClipping();
01367     } else
01368       myregion = NULL;
01369 
01370     // call refresh method
01371     win->X->expose_region = einfo->region;
01372     win->X->expose_event  = einfo->event;
01373     win->Paint();
01374 
01375     if (win->dc) {
01376       // reset clipping region
01377       win->dc->X->expose_reg = NULL;
01378       win->dc->SetCanvasClipping();
01379 
01380       XDestroyRegion(myregion);
01381     }
01382   }
01383 
01384 #ifdef MZ_PRECISE_GC
01385   XFORM_RESET_VAR_STACK;
01386 #endif
01387 }
01388 
01389 void wxWindow::FrameEventHandler(Widget w,
01390                              wxWindow **winp,
01391                              XEvent *xev,
01392                              Boolean *WXUNUSED(continue_to_dispatch_return))
01393 {
01394   wxWindow *win = (wxWindow *)GET_SAFEREF(winp);
01395   if (!win) {
01396 #ifdef MZ_PRECISE_GC
01397     XFORM_RESET_VAR_STACK;
01398 #endif
01399     return;
01400   }
01401 
01402   switch (xev->xany.type) {
01403   case ClientMessage:
01404     // only wxFrames have a WM_DELETE_WINDOW property
01405     if(!strcmp(XGetAtomName(XtDisplay(w),xev->xclient.message_type),"WM_PROTOCOLS")
01406        && !strcmp(XGetAtomName(XtDisplay(w),xev->xclient.data.l[0]),"WM_DELETE_WINDOW")){
01407       // I've reveived a WM_DELETE_WINDOW message for win
01408       wxWindow *current_modal;
01409       current_modal = wxGetModalWindow(win);
01410       if (current_modal && (current_modal != win))
01411        return;
01412        
01413       // close frame, if allowed
01414       if (win->OnClose())
01415        win->Show(FALSE);
01416     }
01417     if (wx_single_instance_tag) {
01418       if (xev->xclient.message_type == wx_single_instance_tag) {
01419        /* Accumulate msg data */
01420        long src = 0;
01421        int i;
01422        Accum_Single_Instance_Message *msg, *prev = NULL;
01423 
01424        if (!si_registered) {
01425          wxREGGLOB(si_msgs);
01426        }
01427 
01428        for (i = sizeof(Window); i--; ) {
01429          src = (src << 8) | ((int)xev->xclient.data.b[i]);
01430        }
01431 
01432        for (msg = si_msgs; msg; msg = msg->next) {
01433          if (msg->src == src)
01434            break;
01435        }
01436        if (!msg) {
01437          char *s;
01438          s = new WXGC_ATOMIC char[128];
01439          msg = new WXGC_PTRS Accum_Single_Instance_Message;
01440          msg->next = si_msgs;
01441          si_msgs = msg;
01442          msg->src = src;
01443          msg->accum = s;
01444          msg->len = 0;
01445          msg->size = 128;
01446        }
01447        
01448        {
01449          int len = sizeof(Window);
01450          while (len < 20 && xev->xclient.data.b[len]) {
01451            len++;
01452          }
01453          len -= sizeof(Window);
01454 
01455          if (len) {
01456            /* accumulate data */
01457            if (msg->size < msg->len + 1 + len) {
01458              char *naya;
01459              int new_size = msg->size * 2;
01460              naya = new WXGC_ATOMIC char[new_size];
01461              memcpy(naya, msg->accum, msg->len);
01462              msg->accum = naya;
01463              msg->size = new_size;
01464            }
01465            memcpy(msg->accum + msg->len, 
01466                  xev->xclient.data.b + sizeof(Window),
01467                  len);
01468            msg->len += len;
01469            if (len < (int)(20 - sizeof(Window)))
01470              len = 0; /* inidicate that we're done */
01471          } 
01472 
01473          if (!len) {
01474            /* done */
01475            if (prev)
01476              prev->next = msg->next;
01477            else
01478              si_msgs = msg->next;
01479            msg->accum[msg->len] = 0;
01480 
01481            parse_and_drop_runtime(msg->len, msg->accum);
01482          }
01483        }
01484       }
01485     }
01486     if (dnd_inited) {
01487       if (xev->xclient.message_type == dnd.XdndEnter) {
01488        /* Ok... */
01489       } else if (xev->xclient.message_type == dnd.XdndPosition) {
01490        wxWindow *target = NULL;
01491         
01492        /* Find immediate target window: */
01493         {
01494           Display *dpy  = XtDisplay(w);
01495           Screen  *scn  = XtScreen(w);
01496           Window  root  = RootWindowOfScreen(scn);
01497           Window  xwin  = XtWindow(w);
01498           Window  child = 0;
01499           int cx, cy;
01500          cx = XDND_POSITION_ROOT_X(xev);
01501          cy = XDND_POSITION_ROOT_Y(xev);
01502          while (1) {
01503            if (XTranslateCoordinates(dpy, root, xwin, cx, cy,
01504                                   &cx, &cy, &child)) {
01505              if (!child)
01506               break;
01507              else {
01508               root = xwin;
01509               xwin = child;
01510              }
01511            } else
01512              break;
01513          }
01514          if (xwin) {
01515            Widget cw;
01516            cw = XtWindowToWidget(dpy, xwin);
01517            if (cw) {
01518              target = win->FindChildByWidget(cw);
01519            }
01520           }
01521         }
01522 
01523        /* Does this window (if found) accept drops? Or maybe a parent? */
01524         while (target && !target->drag_accept) {
01525           if (wxSubType(target->__type, wxTYPE_FRAME)
01526              || wxSubType(target->__type, wxTYPE_DIALOG_BOX)) {
01527             target = NULL;
01528             break;
01529           } else {
01530             target = target->GetParent();
01531           }
01532         }
01533 
01534        xdnd_send_status(&dnd, XDND_ENTER_SOURCE_WIN(xev), xev->xclient.window, 
01535                          !!target,
01536                       0, 0, 0, 10, 10, dnd.XdndActionPrivate);
01537         
01538        win->dndTarget = target;
01539       } else if (xev->xclient.message_type == dnd.XdndDrop) {
01540        if (win->dndTarget) {
01541          wxWindow *target = win->dndTarget;
01542          win->dndTarget = NULL;
01543          if (!xdnd_convert_selection(&dnd, XDND_DROP_SOURCE_WIN(xev), xev->xclient.window, dnd.text_uri_list)) {
01544            long len;
01545            char *data;
01546            data = wxTheClipboard->GetClipboardData("text/uri-list", &len, XDND_DROP_TIME(xev), dnd.XdndSelection);
01547            if (data) {
01548              /* Newline-separate elements... */
01549              long offset = 0;
01550              while (offset < len) {
01551               long elem_end;
01552               for (elem_end = offset; 
01553                    (elem_end < len) && (data[elem_end] != '\r');
01554                    elem_end++) {
01555               }
01556               /* If file://... prefix (then drop it) */
01557               if ((offset + 7 <= len)
01558                   && !strncmp(data XFORM_OK_PLUS offset, "file://", 7)) {
01559                 /* Now skip the root: */
01560                 long i = offset + 7;
01561                 char *data2;
01562                 while ((i < elem_end) && (data[i] != '/')) {
01563                   i++;
01564                 }
01565                 if (i < elem_end) {
01566                   data2 = new WXGC_ATOMIC char[elem_end - i + 1];
01567                   memcpy(data2, data + i, elem_end - i);
01568                   data2[elem_end - i] = 0;
01569                   decode_percent_escapes(data2);
01570                   target->OnDropFile(data2);
01571                 }
01572               }
01573               offset = elem_end + 2; /* assume CRLF */
01574              }
01575            }
01576          }
01577        }
01578         xdnd_send_finished(&dnd, XDND_DROP_SOURCE_WIN(xev), XtWindow(w), 0);
01579       } else if (xev->xclient.message_type == dnd.XdndLeave) {
01580        win->dndTarget = NULL;
01581         xdnd_send_finished(&dnd, XDND_LEAVE_SOURCE_WIN(xev), XtWindow(w), 0);
01582       }
01583     }
01584     break;
01585   case CreateNotify:
01586     break;
01587   case ConfigureNotify:
01588     // layout window
01589     win->Layout();
01590     // notify size and position change
01591     win->OnMove(xev->xconfigure.width, xev->xconfigure.height);
01592     win->OnSize(xev->xconfigure.width, xev->xconfigure.height);
01593     break;
01594   case UnmapNotify:
01595     if (wxSubType(win->__type, wxTYPE_DIALOG_BOX)) {
01596       /* Check for a frame in the parent hierarchy: */
01597       wxWindow *p;
01598       p = win->GetParent();
01599       while (p) {
01600        if (!wxSubType(p->__type, wxTYPE_DIALOG_BOX))
01601          break;
01602        p = p->GetParent();
01603       }
01604       /* No parent? Can't iconize. */
01605       if (!p) {
01606        if (win->IsShown()) {
01607          ((wxDialogBox *)win)->Iconize(FALSE);
01608        }
01609       }
01610     }
01611     break;
01612   }
01613 
01614 #ifdef MZ_PRECISE_GC
01615   XFORM_RESET_VAR_STACK;
01616 #endif
01617 }
01618 
01619 void wxWindow::ScrollEventHandler(Widget    WXUNUSED(w),
01620                               wxWindow  **winp,
01621                               XtPointer p_XfwfScrollInfo)
01622 {
01623   XfwfScrollInfo *sinfo = (XfwfScrollInfo*)p_XfwfScrollInfo;
01624   wxScrollEvent *wxevent;
01625   int dir = 0, not_understood = 0;
01626 
01627   wxWindow *win = (wxWindow *)GET_SAFEREF(winp);
01628   if (!win) {
01629 #ifdef MZ_PRECISE_GC
01630     XFORM_RESET_VAR_STACK;
01631 #endif
01632     return;
01633   }
01634 
01635   wxevent = new wxScrollEvent();
01636   
01637   if (win->misc_flags & NO_AUTO_SCROLL_FLAG) {
01638     switch (sinfo->reason) {
01639     case XfwfSUp:    
01640       win->SetScrollPos(dir = wxVERTICAL, win->vs_pos - 1);
01641       break;
01642     case XfwfSLeft:
01643       win->SetScrollPos(dir = wxHORIZONTAL, win->hs_pos - 1);
01644       break;
01645     case XfwfSDown:
01646       win->SetScrollPos(dir = wxVERTICAL, win->vs_pos + 1);
01647       break;
01648     case XfwfSRight:
01649       win->SetScrollPos(dir = wxHORIZONTAL, win->hs_pos + 1);
01650       break;
01651     case XfwfSPageUp:
01652       win->SetScrollPos(dir = wxVERTICAL, win->vs_pos - win->vs_page);
01653       break;
01654     case XfwfSPageLeft:
01655       win->SetScrollPos(dir = wxHORIZONTAL, win->hs_pos - win->hs_page);
01656       break;
01657     case XfwfSPageDown:
01658       win->SetScrollPos(dir = wxVERTICAL, win->vs_pos + win->vs_page);
01659       break;
01660     case XfwfSPageRight:
01661       win->SetScrollPos(dir = wxHORIZONTAL, win->hs_pos + win->hs_page);
01662       break;
01663     case XfwfSTop:
01664     case XfwfSBottom:
01665       dir = wxVERTICAL;
01666       break;
01667     case XfwfSLeftSide:
01668     case XfwfSRightSide:
01669       dir = wxHORIZONTAL;
01670       break;
01671     case XfwfSDrag:
01672       { 
01673        double x, y;
01674        xws_get_scroll_pos(win->X->scroll, &x, &y);
01675        win->wxWindow::Scroll((int)(win->hs_width * x), (int)(win->vs_width * y));
01676        if (sinfo->flags & XFWF_VPOS)
01677          dir = wxVERTICAL;
01678        else
01679          dir = wxHORIZONTAL;
01680       }
01681       break;
01682     default:
01683       not_understood = 1;
01684       break;
01685     }
01686     {
01687       int pos;
01688       pos = win->GetScrollPos(dir);
01689       wxevent->pos = pos;
01690     }
01691   } else {
01692     // sinfo->gx and sinfo->gy are set by the ScrolledWindow widget
01693     XtMoveWidget(win->X->handle, sinfo->gx, sinfo->gy);
01694     win->Refresh();
01695   }
01696   
01697   if (win->misc_flags & NO_AUTO_SCROLL_FLAG) {
01698     wxevent->eventHandle = (char*)p_XfwfScrollInfo;
01699     wxevent->direction = dir;
01700     switch (sinfo->reason) {
01701     case XfwfSUp:
01702     case XfwfSLeft:  wxevent->moveType = wxEVENT_TYPE_SCROLL_LINEUP;
01703       break;
01704     case XfwfSDown:
01705     case XfwfSRight: wxevent->moveType = wxEVENT_TYPE_SCROLL_LINEDOWN;
01706       break;
01707     case XfwfSPageUp:
01708     case XfwfSPageLeft:     wxevent->moveType = wxEVENT_TYPE_SCROLL_PAGEUP;
01709       break;
01710     case XfwfSPageDown:
01711     case XfwfSPageRight:wxevent->moveType = wxEVENT_TYPE_SCROLL_PAGEDOWN;
01712       break;
01713     case XfwfSTop:
01714     case XfwfSLeftSide:     wxevent->moveType = wxEVENT_TYPE_SCROLL_TOP;
01715       break;
01716     case XfwfSBottom:
01717     case XfwfSRightSide:wxevent->moveType = wxEVENT_TYPE_SCROLL_BOTTOM;
01718       break;
01719     case XfwfSDrag:  wxevent->moveType = wxEVENT_TYPE_SCROLL_THUMBTRACK;
01720     default:
01721       break;
01722     }
01723 
01724     if (!not_understood)
01725       win->OnScroll(wxevent);
01726 
01727     wxevent->eventHandle = NULL;
01728   }
01729 
01730 #ifdef MZ_PRECISE_GC
01731   XFORM_RESET_VAR_STACK;
01732 #endif
01733 }
01734 
01735 
01736 static void AdjustMousePosition(Window xevwin, Widget handle, wxWindow *win, wxMouseEvent *wxevent)
01737 {
01738   if (xevwin != XtWindow(handle)) {
01739     Widget wgt;
01740     wgt = XtWindowToWidget(XtDisplay(handle), xevwin);
01741     if (wgt) {
01742       Position cx, cy, wx, wy;
01743       XtTranslateCoords(wgt, 0, 0, &cx, &cy);
01744       XtTranslateCoords(handle, 0, 0, &wx, &wy);
01745       wxevent->x += (cx - wx);
01746       wxevent->y += (cy - wy);
01747     }
01748   } else if (wxSubType(win->__type, wxTYPE_CANVAS)) {
01749     /* Reverse scroll effects: */
01750     int dx, dy;
01751     ((wxCanvas *)win)->ViewStart(&dx, &dy);
01752     wxevent->x -= dx;
01753     wxevent->y -= dy;
01754   }
01755 }
01756 
01757 extern Bool wxIsAlt(KeySym key_sym);
01758 
01759 /* Used for XLookupString */
01760 static XComposeStatus compose_status;
01761 #ifndef NO_XMB_LOOKUP_STRING
01762 # define XMB_KC_STATUS(status) ((status == XLookupKeySym) || (status == XLookupBoth))
01763 # define XMB_STR_STATUS(status) ((status == XLookupChars) || (status == XLookupBoth))
01764 # define XMB_STR_PREFERRED_STATUS(status, xev) ((status == XLookupChars) || ((status == XLookupBoth) && !(xev->xkey.state & ControlMask)))
01765 # define DEFAULT_XMB_STATUS XLookupKeySym
01766 # ifdef X_HAVE_UTF8_STRING
01767 #  define X___LookupString Xutf8LookupString
01768 # else
01769 #  define X___LookupString XmbLookupString
01770 # endif
01771 #else
01772 # define XMB_KC_STATUS(status) (status)
01773 # define XMB_STR_STATUS(status) 0
01774 # define XMB_STR_PREFERRED_STATUS(status, xev) 0
01775 # define DEFAULT_XMB_STATUS 1
01776 #endif
01777 
01778 static XModifierKeymap *xmodkeymap;
01779 
01780 static int extract_string_key(char *str, int slen)
01781 {
01782   if (slen > 9)
01783     slen = 9;
01784   str[slen] = 0;
01785 #ifdef X_HAVE_UTF8_STRING
01786   return wxUTF8StringToChar(str, slen);
01787 #else
01788   return wxLocaleStringToChar(str, slen);
01789 #endif
01790 }
01791 
01792 Status wxWindow::LookupKey(int unshifted, int unalted, int caps_mode,
01793                            Widget w, wxWindow *win, XEvent *xev, KeySym *_keysym, char *str, int *_len)
01794 {
01795   KeySym keysym;
01796   Status status;
01797   int len;
01798   XKeyPressedEvent evt;
01799 
01800   memcpy(&evt, &(xev->xkey), sizeof(XKeyPressedEvent));
01801 
01802   if ((evt.state & ControlMask) && !(evt.state & Mod1Mask)) {
01803     /* Control (and not AltGr) => cancel Caps Lock */
01804     evt.state -= (evt.state & LockMask);
01805   }
01806 
01807   if (unshifted) {
01808     if (evt.state & ShiftMask)
01809       evt.state -= ShiftMask;
01810     else
01811       evt.state |= ShiftMask;
01812   }
01813   if (unalted) {
01814     if (!(evt.state & Mod1Mask) == !(evt.state & ControlMask)) {
01815       if (evt.state & Mod1Mask)
01816         evt.state -= Mod1Mask;
01817       else
01818         evt.state |= Mod1Mask;
01819       if (evt.state & ControlMask)
01820         evt.state -= ControlMask;
01821       else
01822         evt.state |= ControlMask;
01823     }
01824   }
01825   if (caps_mode != 1) {
01826     if (evt.state & LockMask)
01827       evt.state -= LockMask;
01828     else if (caps_mode == 2) {
01829       evt.state |= LockMask;
01830     }
01831   }
01832     
01833 #ifndef NO_XMB_LOOKUP_STRING
01834   if (!the_im) {
01835     the_im = XOpenIM(wxAPP_DISPLAY, NULL, NULL, NULL);
01836   }
01837   if (the_im) {
01838     if (!win->X->ic) {
01839       win->X->ic = XCreateIC(the_im, 
01840                           XNInputStyle, XIMPreeditNothing | XIMStatusNothing,
01841                           NULL);
01842       win->X->us_ic = XCreateIC(the_im, 
01843                             XNInputStyle, XIMPreeditNothing | XIMStatusNothing,
01844                             NULL);
01845     }
01846   }
01847 
01848   if (win->X->ic && (xev->xany.type == KeyPress)) {
01849     XIC ic;
01850     ic = unshifted ? win->X->ic : win->X->ic;
01851     XSetICValues(ic, 
01852                XNClientWindow, XtWindow(w),
01853                XNFocusWindow,  XtWindow(w),
01854                NULL);
01855     XSetICFocus(ic);
01856 
01857     len = X___LookupString(ic, &evt, str, 10, &keysym, &status);
01858   } else
01859 #endif
01860     {
01861       (void)XLookupString(&evt, str, 10, &keysym, &compose_status);
01862       status = DEFAULT_XMB_STATUS;
01863       len = 0;
01864     }
01865 
01866   *_len = len;
01867   *_keysym = keysym;
01868   return status;
01869 }
01870 
01871 static int status_to_kc(Status status, XEvent *xev, KeySym keysym, char *str, int slen)
01872 {
01873   if (XMB_STR_PREFERRED_STATUS(status, xev))
01874     return extract_string_key(str, slen);
01875   else if (XMB_KC_STATUS(status))
01876     return CharCodeXToWX(keysym);
01877   else if (XMB_STR_STATUS(status))
01878     return extract_string_key(str, slen);
01879   else 
01880     return 0;
01881 }
01882 
01883 void wxWindow::WindowEventHandler(Widget w,
01884                               wxWindow **winp,
01885                               XEvent *xev,
01886                               Boolean *continue_to_dispatch_return)
01887 {
01888   Bool subWin;
01889   wxWindow *win = (wxWindow *)GET_SAFEREF(winp);
01890   Bool Enter=FALSE, Press=FALSE;
01891 
01892   if (!win) {
01893     *continue_to_dispatch_return = FALSE;
01894 #ifdef MZ_PRECISE_GC
01895     XFORM_RESET_VAR_STACK;
01896 #endif
01897     return;
01898   }
01899 
01900   if (XFilterEvent(xev, None)) {
01901     win->ReleaseMouse();
01902     *continue_to_dispatch_return = FALSE;
01903 #ifdef MZ_PRECISE_GC
01904     XFORM_RESET_VAR_STACK;
01905 #endif
01906     return;
01907   }
01908 
01909   subWin = (w != win->X->handle) && (w != win->X->frame);
01910 
01911     switch (xev->xany.type) {
01912     case KeyRelease:
01913         {
01914          KeySym         keysym;
01915 
01916          *continue_to_dispatch_return = FALSE;
01917          if (win->misc_flags & LAST_WAS_ALT_DOWN_FLAG) {
01918            win->misc_flags -= LAST_WAS_ALT_DOWN_FLAG;
01919 
01920            (void)XLookupString(&(xev->xkey), NULL, 0, &keysym, NULL);
01921            if (wxIsAlt(keysym)) {
01922              /* Find frame. */
01923              wxWindow *p = win;
01924              while (p) {
01925               if (wxSubType(p->__type, wxTYPE_FRAME)) {
01926                 wxMenuBar *mb;
01927                 mb = ((wxFrame *)p)->GetMenuBar();
01928                 if (mb) {
01929                   ((wxFrame *)p)->OnMenuClick();
01930                   mb->SelectAMenu();
01931                 }
01932                 break;
01933               }
01934               p = p->GetParent();
01935              }
01936            }
01937            win->current_state = xev->xkey.state;
01938            break;
01939          }
01940        }
01941     case KeyPress: 
01942       win->current_state = xev->xkey.state;
01943       { /* ^^^ fallthrough !!!! ^^^ */
01944        wxKeyEvent *wxevent;
01945        KeySym    keysym, other_keysym, alt_keysym, other_alt_keysym, caps_keysym;
01946        long       kc, other_kc, alt_kc, other_alt_kc, caps_kc;
01947        Status     status, other_status, alt_status, other_alt_status, caps_status;
01948        char       str[10], other_str[10], alt_str[10], other_alt_str[10], caps_str[10];
01949        int        slen, other_slen, alt_slen, other_alt_slen, caps_slen;
01950 
01951        wxevent = new wxKeyEvent(wxEVENT_TYPE_CHAR);
01952 
01953        status = LookupKey(0, 0, 1, w, win, xev, &keysym, str, &slen);
01954        other_status = LookupKey(1, 0, 0, w, win, xev, &other_keysym, other_str, &other_slen);
01955        alt_status = LookupKey(0, 1, 0, w, win, xev, &alt_keysym, alt_str, &alt_slen);
01956        other_alt_status = LookupKey(1, 1, 0, w, win, xev, &other_alt_keysym, other_alt_str, &other_alt_slen);
01957        caps_status = LookupKey(0, 0, 2, w, win, xev, &caps_keysym, caps_str, &caps_slen);
01958 
01959        if (xev->xany.type == KeyPress) {
01960          static int handle_alt = 0;
01961 
01962          if (!handle_alt) {
01963            if (!wxGetBoolPreference("altUpSelectsMenu", &handle_alt))
01964              handle_alt = 0;
01965            handle_alt = !handle_alt ? -1 : 1;
01966          }
01967 
01968          if (handle_alt > 0) {
01969            if (win->misc_flags & LAST_WAS_ALT_DOWN_FLAG)
01970              win->misc_flags -= LAST_WAS_ALT_DOWN_FLAG;
01971            else if (wxIsAlt(keysym) && !(xev->xkey.state & (ShiftMask | ControlMask)))
01972              win->misc_flags |= LAST_WAS_ALT_DOWN_FLAG;
01973          }
01974        }
01975 
01976         kc = status_to_kc(status, xev, keysym, str, slen);
01977         other_kc = status_to_kc(other_status, xev, other_keysym, other_str, other_slen);
01978         alt_kc = status_to_kc(alt_status, xev, alt_keysym, alt_str, alt_slen);
01979         other_alt_kc = status_to_kc(other_alt_status, xev, other_alt_keysym, other_alt_str, other_alt_slen);
01980         caps_kc = status_to_kc(caps_status, xev, caps_keysym, caps_str, caps_slen);
01981 
01982         /* Figure out key state *after* event: */
01983         {
01984           int i, j;
01985           if (!xmodkeymap)
01986             xmodkeymap = XGetModifierMapping(wxAPP_DISPLAY);
01987           for (i = 0; i < 8; i++) {
01988             for (j = 0; j < xmodkeymap->max_keypermod; j++) {
01989               if (xev->xkey.keycode == xmodkeymap->modifiermap[(i * xmodkeymap->max_keypermod) + j]) {
01990                 if (xev->xany.type == KeyPress)
01991                   win->current_state |= (1 << i);
01992                 else
01993                   win->current_state -= (1 << i);
01994               }
01995             }
01996           }
01997         }
01998 
01999        // set wxWindows event structure
02000        wxevent->eventHandle = (char*)xev;
02001        wxevent->keyCode     = (xev->xany.type == KeyPress) ? kc : WXK_RELEASE;
02002        wxevent->keyUpCode   = (xev->xany.type == KeyRelease) ? kc : WXK_PRESS;
02003        wxevent->otherKeyCode       = other_kc;
02004        wxevent->altKeyCode  = alt_kc;
02005        wxevent->otherAltKeyCode = other_alt_kc;
02006        wxevent->capsKeyCode    = caps_kc;
02007        wxevent->x           = xev->xkey.x;
02008        wxevent->y           = xev->xkey.y;
02009        wxevent->altDown     = /* xev->xkey.state & Mod3Mask */ FALSE;
02010        wxevent->controlDown = xev->xkey.state & ControlMask;
02011        wxevent->metaDown    = xev->xkey.state & Mod1Mask;
02012        wxevent->shiftDown   = xev->xkey.state & ShiftMask;
02013        wxevent->capsDown    = xev->xkey.state & LockMask;
02014        wxevent->timeStamp      = xev->xkey.time;
02015 
02016        /* Reverse scroll effects: */
02017        if (wxSubType(win->__type, wxTYPE_CANVAS)) {
02018          int dx, dy;
02019          ((wxCanvas *)win)->ViewStart(&dx, &dy);
02020          wxevent->x -= dx;
02021          wxevent->y -= dy;
02022        }
02023 
02024        *continue_to_dispatch_return = FALSE;
02025        if (!win->CallPreOnChar(win, wxevent)) {
02026          /* hack: ignore SubWin for a choice item key event: */
02027          if (subWin && (win->__type == wxTYPE_CHOICE))
02028            subWin = 0;
02029 
02030          if (subWin)
02031            *continue_to_dispatch_return = TRUE;
02032          else {
02033            /* Double-check that pre-on-char didn't disable: */
02034            if (!win->IsGray())
02035              win->OnChar(wxevent);
02036          }
02037        }
02038        wxevent->eventHandle = NULL;
02039         /* Event was handled by OnFunctionKey and/or OnChar */ }
02040        break;
02041     case ButtonPress:
02042       /* X grab doesn't work the way we'd like for panels (since they
02043         have children), unless a grab cursor is installed.
02044         Unfortunately, we also need to watch for changes to the
02045         cursor via SetCursor(). */
02046       if (win->__type == wxTYPE_PANEL) {
02047        wxWindow *p = win;
02048        while (p) {
02049          if (p->cursor)
02050            break;
02051          if (wxSubType(p->__type, wxTYPE_FRAME)
02052              || wxSubType(p->__type, wxTYPE_DIALOG_BOX))
02053            p = NULL;
02054          else
02055            p = p->GetParent();
02056        }
02057        
02058        if (p && p->cursor->Ok()) {
02059          Cursor c;
02060          c = GETCURSOR(p->cursor);
02061          XChangeActivePointerGrab(wxAPP_DISPLAY, 
02062                                (ButtonPressMask | ButtonReleaseMask
02063                                 | ButtonMotionMask | PointerMotionMask | PointerMotionHintMask
02064                                 | EnterWindowMask | LeaveWindowMask),
02065                                c, 
02066                                xev->xbutton.time);
02067          if (!grabbing_panel_regsitered) {
02068            wxREGGLOB(grabbing_panel);
02069            grabbing_panel_regsitered = 1;
02070          }
02071 
02072          grabbing_panel = win;
02073          grabbing_panel_time = xev->xbutton.time;
02074        }
02075       }
02076       Press = TRUE;
02077     case ButtonRelease:  /* ^^^^ fallthrough */
02078       win->current_state = xev->xbutton.state;
02079       if (!Press)
02080        grabbing_panel = NULL;
02081       if (win->misc_flags & LAST_WAS_ALT_DOWN_FLAG)
02082        win->misc_flags -= LAST_WAS_ALT_DOWN_FLAG;
02083       if ((xev->xbutton.button == Button4)
02084          || (xev->xbutton.button == Button5)) {
02085        /* Button4 and Button5 seem to be mapped to wheel up and down, now: */
02086        if (Press) {
02087          wxKeyEvent *wxevent;
02088 
02089          wxevent = new wxKeyEvent(wxEVENT_TYPE_CHAR);
02090 
02091          wxevent->eventHandle      = NULL;
02092          wxevent->keyCode   = ((xev->xbutton.button == Button5) 
02093                                ? WXK_WHEEL_DOWN 
02094                                : WXK_WHEEL_UP);
02095          wxevent->x         = xev->xbutton.x;
02096          wxevent->y         = xev->xbutton.y;
02097          wxevent->altDown   = FALSE;
02098          wxevent->controlDown      = xev->xbutton.state & ControlMask;
02099          wxevent->metaDown  = xev->xbutton.state & Mod1Mask;
02100          wxevent->shiftDown = xev->xbutton.state & ShiftMask;
02101          wxevent->capsDown  = xev->xbutton.state & LockMask;
02102          wxevent->timeStamp    = xev->xbutton.time;
02103 
02104          *continue_to_dispatch_return = FALSE;
02105          if (!win->CallPreOnChar(win, wxevent)) {
02106            if (subWin && (win->__type == wxTYPE_CHOICE))
02107              subWin = 0;
02108            
02109            if (subWin)
02110              *continue_to_dispatch_return = TRUE;
02111            else {
02112              /* Double-check that pre-on-char didn't disable: */
02113              if (!win->IsGray())
02114               win->OnChar(wxevent);
02115            }
02116          }      
02117        }
02118         
02119         switch (xev->xbutton.button) {
02120        case Button4: 
02121          if (Press)
02122            win->current_state |= Button4Mask;
02123          else
02124            win->current_state -= Button4Mask;
02125          break;
02126        case Button5: 
02127          if (Press)
02128            win->current_state |= Button5Mask;
02129          else
02130            win->current_state -= Button5Mask;
02131          break;
02132        }
02133       } else {
02134         wxMouseEvent *wxevent;
02135 
02136        wxevent = new wxMouseEvent;
02137        
02138        switch (xev->xbutton.button) {
02139        case Button1: 
02140          wxevent->eventType = wxEVENT_TYPE_LEFT;
02141          if (Press)
02142            win->current_state |= Button1Mask;
02143          else
02144            win->current_state -= Button1Mask;
02145          break;
02146        case Button2: 
02147          wxevent->eventType = wxEVENT_TYPE_MIDDLE; 
02148          if (Press)
02149            win->current_state |= Button2Mask;
02150          else
02151            win->current_state -= Button2Mask;
02152          break;
02153        case Button3: 
02154          wxevent->eventType = wxEVENT_TYPE_RIGHT;
02155          if (Press)
02156            win->current_state |= Button3Mask;
02157          else
02158            win->current_state -= Button3Mask;
02159          break;
02160        }
02161        if (Press) {
02162          // button is down
02163          wxevent->eventType |= wxEVENT_TYPE_DOWN;
02164          if (win->allow_dclicks) { // doubleclick handling wanted?
02165            if (xev->xbutton.button == win->X->last_clickbutton
02166               &&  (xev->xbutton.time - win->X->last_clicktime
02167                    <= (unsigned int)XtGetMultiClickTime(wxAPP_DISPLAY))) {
02168              // double click has arrived
02169              wxevent->eventType |= wxEVENT_TYPE_DOUBLE;
02170              win->X->last_clicktime = 0; 
02171            } else {
02172              // single click has arrived
02173              win->X->last_clickbutton = xev->xbutton.button;
02174              win->X->last_clicktime   = xev->xbutton.time;
02175            }
02176          }
02177        }
02178        // set wxWindows event structure
02179        wxevent->eventHandle = (char*)xev;
02180        wxevent->x           = xev->xbutton.x;
02181        wxevent->y           = xev->xbutton.y;
02182        wxevent->altDown            = /* xev->xbutton.state & Mod3Mask */ FALSE;
02183        wxevent->controlDown = xev->xbutton.state & ControlMask;
02184        wxevent->metaDown    = xev->xbutton.state & Mod1Mask;
02185        wxevent->shiftDown   = xev->xbutton.state & ShiftMask;
02186        wxevent->capsDown    = xev->xbutton.state & LockMask;
02187        wxevent->leftDown    = ((wxevent->eventType == wxEVENT_TYPE_LEFT_DOWN)
02188                                || (xev->xbutton.state & Button1Mask));
02189        wxevent->middleDown  = ((wxevent->eventType == wxEVENT_TYPE_MIDDLE_DOWN)
02190                                || (xev->xbutton.state & Button2Mask));
02191        wxevent->rightDown   = ((wxevent->eventType == wxEVENT_TYPE_RIGHT_DOWN)
02192                                || (xev->xbutton.state & Button3Mask));
02193        wxevent->timeStamp       = xev->xbutton.time;
02194 
02195        /* Adjust location of mouse-moved events when it's
02196           over sub-parts, and counter canvas scroll: */
02197        AdjustMousePosition(xev->xbutton.window, win->X->handle, win, wxevent);
02198 
02199        *continue_to_dispatch_return = FALSE;
02200        if (!win->CallPreOnEvent(win, wxevent)) {
02201          if (subWin) {
02202            *continue_to_dispatch_return = TRUE;
02203          } else {
02204            if (Press) {
02205              if (wxSubType(win->__type, wxTYPE_MENU_BAR)) {
02206               if (!((wxMenuBar *)win)->InProgress()) {
02207                 wxFrame *f;
02208                 f = (wxFrame *)(win->GetParent());
02209                 f->OnMenuClick();
02210               }
02211              } else {
02212                 if (win->WantsFocus())
02213                   win->SetFocus();
02214              }
02215            }
02216 
02217            /* It's possible that the window has become disabled... */
02218            if (!win->IsGray())
02219              win->OnEvent(wxevent);
02220          }
02221        }
02222        wxevent->eventHandle = NULL; /* MATTHEW: [5] */
02223       }
02224       break;
02225     case EnterNotify:
02226       Enter = TRUE;
02227     case LeaveNotify: /* ^^^^ fallthrough! */
02228       win->current_state = xev->xcrossing.state;
02229       if (win->misc_flags & LAST_WAS_ALT_DOWN_FLAG)
02230        win->misc_flags -= LAST_WAS_ALT_DOWN_FLAG;
02231       if (w == win->X->frame) {
02232        /* If Focus == PointerRoot, manage activation */
02233        if (xev->xcrossing.detail != NotifyInferior) {
02234          Window current;
02235          int old_revert;
02236          XGetInputFocus(XtDisplay(win->X->frame), &current, &old_revert);
02237          if (current == PointerRoot) {
02238            if (Enter)
02239              win->misc_flags |= ACTIVE_VIA_POINTER_FLAG;
02240            else
02241              win->misc_flags -= (win->misc_flags & ACTIVE_VIA_POINTER_FLAG);
02242            win->OnActivate(Enter);
02243          }
02244        }
02245       } else {
02246         wxMouseEvent *wxevent;
02247 
02248        wxevent = new wxMouseEvent(Enter 
02249                                ? wxEVENT_TYPE_ENTER_WINDOW 
02250                                : wxEVENT_TYPE_LEAVE_WINDOW);
02251 
02252        // set wxWindows event structure
02253        wxevent->eventHandle = (char*)xev;
02254        wxevent->x           = xev->xcrossing.x;
02255        wxevent->y           = xev->xcrossing.y;
02256        wxevent->altDown            = /* xev->xcrossing.state & Mod3Mask */ FALSE;
02257        wxevent->controlDown = xev->xcrossing.state & ControlMask;
02258        wxevent->metaDown    = xev->xcrossing.state & Mod1Mask;
02259        wxevent->shiftDown   = xev->xcrossing.state & ShiftMask;
02260        wxevent->capsDown    = xev->xcrossing.state & LockMask;
02261        wxevent->leftDown    = xev->xcrossing.state & Button1Mask;
02262        wxevent->middleDown  = xev->xcrossing.state & Button2Mask;
02263        wxevent->rightDown   = xev->xcrossing.state & Button3Mask;
02264        wxevent->timeStamp       = xev->xbutton.time; /* MATTHEW */
02265        *continue_to_dispatch_return = FALSE; /* Event was handled by OnEvent */ 
02266 
02267        /* Reverse scroll effects: */
02268        if (wxSubType(win->__type, wxTYPE_CANVAS)) {
02269          int dx, dy;
02270          ((wxCanvas *)win)->ViewStart(&dx, &dy);
02271          wxevent->x -= dx;
02272          wxevent->y -= dy;
02273        }
02274 
02275        if (!win->CallPreOnEvent(win, wxevent)) {
02276          if (!win->IsGray())
02277            win->OnEvent(wxevent);
02278        }
02279        wxevent->eventHandle = NULL; /* MATTHEW: [5] */
02280       }
02281       break;
02282     case MotionNotify: 
02283       {
02284        wxMouseEvent *wxevent;
02285        int skip = 0;
02286 
02287        wxevent = new wxMouseEvent(wxEVENT_TYPE_MOTION);
02288 
02289        if (xev->xmotion.is_hint == NotifyHint) {
02290          // hints need a XQueryPointer
02291          Window root, child;
02292          XQueryPointer(XtDisplay(w), XtWindow(w), &root, &child,
02293                      &(xev->xmotion.x_root), &(xev->xmotion.y_root),
02294                      &(xev->xmotion.x),      &(xev->xmotion.y),
02295                      &(xev->xmotion.state));
02296          if (xev->xmotion.state != win->current_state)
02297            skip = 1;
02298        } else
02299          win->current_state = xev->xmotion.state;
02300 
02301        if (!skip) {
02302          // set wxWindows event structure
02303          wxevent->eventHandle      = (char*)xev;
02304          wxevent->x         = xev->xmotion.x;
02305          wxevent->y         = xev->xmotion.y;
02306          wxevent->altDown          = /* xev->xmotion.state & Mod3Mask */ FALSE;
02307          wxevent->controlDown      = xev->xmotion.state & ControlMask;
02308          wxevent->metaDown  = xev->xmotion.state & Mod1Mask;
02309          wxevent->shiftDown = xev->xmotion.state & ShiftMask;
02310          wxevent->capsDown  = xev->xmotion.state & LockMask;
02311          wxevent->leftDown  = xev->xmotion.state & Button1Mask;
02312          wxevent->middleDown       = xev->xmotion.state & Button2Mask;
02313          wxevent->rightDown = xev->xmotion.state & Button3Mask;
02314          wxevent->timeStamp       = xev->xbutton.time;
02315          *continue_to_dispatch_return = FALSE; /* Event was handled by OnEvent */
02316 
02317          /* Reverse scroll effects: */
02318          AdjustMousePosition(xev->xbutton.window, win->X->handle, win, wxevent);
02319 
02320          if (!win->CallPreOnEvent(win, wxevent)) {
02321            if (subWin)
02322              *continue_to_dispatch_return = TRUE;
02323            else {
02324              if (!win->IsGray())
02325               win->OnEvent(wxevent);
02326            }
02327          }
02328          wxevent->eventHandle = NULL;
02329        }
02330       }
02331       break;
02332        /* Use focus in/out for OnActivate */
02333     case FocusIn:
02334         Enter = TRUE;
02335     case FocusOut:
02336       if (win->misc_flags & LAST_WAS_ALT_DOWN_FLAG)
02337        win->misc_flags -= LAST_WAS_ALT_DOWN_FLAG;
02338       if (xev->xfocus.detail != NotifyInferior) {
02339        Window current;
02340        if (xev->xfocus.detail == NotifyPointer) {
02341          /* NotifyPointer is meaningful if the focus is PointerRoot
02342             or we're active via the pointer */
02343          if (!Enter && (win->misc_flags & ACTIVE_VIA_POINTER_FLAG)) {
02344            current = PointerRoot;
02345          } else {
02346            int old_revert;
02347            XGetInputFocus(XtDisplay(win->X->frame), &current, &old_revert);
02348          }
02349        } else
02350          current = PointerRoot;
02351 
02352        if (current == PointerRoot) {
02353          if (xev->xfocus.detail == NotifyPointer) {
02354            if (Enter)
02355              win->misc_flags |= ACTIVE_VIA_POINTER_FLAG;
02356            else
02357              win->misc_flags -= (win->misc_flags & ACTIVE_VIA_POINTER_FLAG);
02358          }
02359          win->OnActivate(Enter);
02360        }
02361       }
02362       break;
02363     case Expose: // arrives for non-xfwfCommonWidget-subclasses only
02364        if (win->dc && win->painting_enabled) { // expose only if DC available
02365            // setup drawable of dc if dc available
02366            if (!(win->dc->ok)) { // first expose call
02367              win->dc->X->drawable = XtWindow(win->X->handle);
02368              win->dc->X->draw_window = win->dc->X->drawable;
02369              win->dc->SetBackground(win->dc->current_background_color);
02370              win->dc->Clear();
02371              win->dc->ok = TRUE;
02372            }
02373            // call refresh method
02374            win->Paint();
02375        }
02376         break;
02377     }
02378 
02379 #ifdef MZ_PRECISE_GC
02380   XFORM_RESET_VAR_STACK;
02381 #endif
02382 }
02383 
02384 Bool wxWindow::WantsFocus(void)
02385 {
02386   return TRUE;
02387 }
02388 
02389 //-----------------------------------------------------------------------------
02390 // create and destroy associated device context
02391 //-----------------------------------------------------------------------------
02392 
02393 void wxWindow::CreateDC(void)
02394 {
02395     wxWindowDC_Xinit *init;
02396 
02397     if (dc) return; // only create once!
02398 
02399     dc = DEBUG_NEW wxWindowDC;
02400     // Initialize wxWindowDC
02401     init = new wxWindowDC_Xinit;
02402     init->dpy      = wxAPP_DISPLAY; // display is global to application
02403     init->scn      = wxAPP_SCREEN;  //  screen is global to application
02404     init->owner    = this;
02405     init->drawable = XtWindow(X->handle);
02406     dc->ok = TRUE;
02407     
02408     dc->Initialize(init);
02409 
02410     dc->X->is_window = TRUE;
02411 }
02412 
02413 void wxWindow::DestroyDC(void)
02414 {
02415     if (!dc) return; // no DC to destroy
02416     // destroy device context
02417     DELETE_OBJ dc;
02418     dc = NULL;
02419 }
02420 
02421 wxWindowDC *wxWindow::GetDC(void)
02422 { 
02423   if (!dc) {
02424     if (!(style & wxNO_DC))
02425       CreateDC();
02426   }
02427   
02428   return dc; 
02429 }
02430 
02431 void wxWindow::GetTextExtent(const char *s, double *w, double *h, double *descent,
02432                           double *ext_leading, wxFont *theFont,
02433                           Bool use16bit)
02434 {
02435   if (dc) {
02436     dc->GetTextExtent(s, w, h, descent, ext_leading, theFont, use16bit);
02437     return;
02438   }
02439   
02440   if (!theFont) theFont = font;
02441   
02442   wxGetTextExtent(wxAPP_DISPLAY, 1.0, 1.0,
02443                 s, w, h, descent, ext_leading, theFont,
02444                 1, use16bit, 0, -1);
02445 }
02446 
02447 
02448 void wxWindow::ForEach(void (*foreach)(wxWindow *w, void *data), void *data)
02449 {
02450   wxChildNode *node, *next;
02451 
02452 #ifdef MZ_PRECISE_GC
02453   if (__type == wxTYPE_MENU_BAR)
02454     return;
02455 #endif
02456 
02457   for (node = children->First(); node; node = next) {
02458     wxWindow *child;
02459     next = node->Next();
02460     child = (wxWindow*)(node->Data());
02461     if (child) {
02462       child->ForEach(foreach, data);
02463     }
02464   }
02465 
02466   foreach(this, data);
02467 }
02468 
02469 long wxWindow::GetWindowHandle()
02470 {
02471   return (long)X->handle;
02472 }
02473 
02474 //-----------------------------------------------------------------------------
02475 // drag & drop
02476 //-----------------------------------------------------------------------------
02477 
02478 void wxWindow::DragAcceptFiles(Bool accept)
02479 {
02480   wxWindow *p;
02481 
02482   if (!drag_accept == !accept)
02483     return;
02484 
02485   drag_accept = accept;
02486   
02487   if (!dnd_inited) {
02488     xdnd_init(&dnd, wxAPP_DISPLAY);
02489     dnd_inited = 1;
02490   }
02491 
02492   /* Declare drag-and-drop possible at this
02493      window's top-level frame: */
02494 
02495   p = this;
02496   while (p) {
02497     if (wxSubType(p->__type, wxTYPE_FRAME)
02498        || wxSubType(p->__type, wxTYPE_DIALOG_BOX))
02499       break;
02500     p = p->GetParent();
02501   }
02502   
02503   {
02504     Atom l[2];
02505     l[0] = dnd.text_uri_list;
02506     l[1] = 0;
02507     xdnd_set_dnd_aware(&dnd, XtWindow(p->X->frame), l);
02508   }
02509 }
02510 
02511 wxWindow *wxWindow::FindChildByWidget(Widget w)
02512 {
02513   wxChildNode *node, *next;
02514   wxWindow *r;
02515 
02516   if ((w == X->frame)
02517       || (w == X->handle))
02518     return this;
02519 
02520 
02521   for (node = children->First(); node; node = next) {
02522     wxWindow *child;
02523     next = node->Next();
02524     child = (wxWindow*)(node->Data());
02525     if (child) {
02526       r = child->FindChildByWidget(w);
02527       if (r)
02528         return r;
02529     }
02530   }
02531 
02532   return NULL;
02533 }
02534 
02535 static void parse_and_drop_runtime(int len, char *s)
02536 {
02537   char **argv, *a;
02538   int cnt = 0, pos = 0;
02539   int sz;
02540 
02541   while (pos < len) {
02542     sz = 0;
02543     while ((pos < len) && (s[pos] != ':')) {
02544       sz = (sz * 10) + (s[pos] - '0');
02545       pos++;
02546     }
02547     pos++;
02548     if (sz > 0)
02549       pos += sz;
02550     cnt++;
02551   }
02552   
02553   argv = new WXGC_PTRS char*[cnt];
02554   
02555   pos = cnt = 0;
02556   while (pos < len) {
02557     sz = 0;
02558     while ((pos < len) && (s[pos] != ':')) {
02559       sz = (sz * 10) + (s[pos] - '0');
02560       pos++;
02561     }
02562     pos++;
02563 
02564     if (sz > len - pos)
02565       sz = len - pos;
02566     if (sz < 0)
02567       sz = 0;
02568     a = new WXGC_ATOMIC char[sz + 1];
02569     memcpy(a, s + pos, sz);
02570     a[sz] = 0;
02571     argv[cnt] = a;
02572     
02573     if (sz > 0)
02574       pos += sz;
02575     cnt++;
02576   }
02577   
02578   wxDrop_Runtime(argv, cnt);
02579 }
02580 
02581 static int ishexdig(char s) { 
02582   return (((s >= '0') && (s <= '9'))
02583          || ((s >= 'a') && (s <= 'f'))
02584          || ((s >= 'A') && (s <= 'F'))); 
02585 }
02586 static int hexval(char s) { 
02587   return (((s >= '0') && (s <= '9'))
02588          ? s - '0'
02589          : (((s >= 'a') && (s <= 'f'))
02590             ? s - 'a' + 10
02591             : s - 'A' + 10));
02592 }
02593 
02594 static void decode_percent_escapes(char *s)
02595 {
02596   int src = 0, dest = 0;
02597   while (s[src]) {
02598     if ((s[src] == '%')
02599        && ishexdig(s[src+1])
02600        && ishexdig(s[src+2])) {
02601       int v;
02602       v = ((hexval(s[src+1]) << 4) + hexval(s[src+2]));
02603       s[dest++] = v;
02604       src += 3;
02605     } else {
02606       s[dest++] = s[src++];
02607     }
02608   }
02609   s[dest] = 0;
02610 }