1 ///////////////////////////////////////////////////////////////////////////// 
   2 // Name:        src/unix/utilsx11.cpp 
   3 // Purpose:     Miscellaneous X11 functions 
   4 // Author:      Mattia Barbon, Vaclav Slavik, Robert Roebling 
   8 // Copyright:   (c) wxWidgets team 
   9 // Licence:     wxWindows licence 
  10 ///////////////////////////////////////////////////////////////////////////// 
  12 #if defined(__WXX11__) || defined(__WXGTK__) || defined(__WXMOTIF__) 
  14 // for compilers that support precompilation, includes "wx.h". 
  15 #include "wx/wxprec.h" 
  17 #include "wx/unix/utilsx11.h" 
  26 #include "wx/iconbndl.h" 
  29 #pragma message disable nosimpint 
  32 #include <X11/Xatom.h> 
  33 #include <X11/Xutil.h> 
  35 #pragma message enable nosimpint 
  43 // Various X11 Atoms used in this file: 
  44 static Atom _NET_WM_STATE 
= 0; 
  45 static Atom _NET_WM_STATE_FULLSCREEN 
= 0; 
  46 static Atom _NET_WM_STATE_STAYS_ON_TOP 
= 0; 
  47 static Atom _NET_WM_WINDOW_TYPE 
= 0; 
  48 static Atom _NET_WM_WINDOW_TYPE_NORMAL 
= 0; 
  49 static Atom _KDE_NET_WM_WINDOW_TYPE_OVERRIDE 
= 0; 
  50 static Atom _WIN_LAYER 
= 0; 
  51 static Atom KWIN_RUNNING 
= 0; 
  53 static Atom _NET_SUPPORTING_WM_CHECK 
= 0; 
  54 static Atom _NET_SUPPORTED 
= 0; 
  57 #define wxMAKE_ATOM(name, display) \ 
  58     if (name == 0) name = XInternAtom((display), #name, False) 
  61 // X11 Window is an int type, so use the macro to suppress warnings when 
  63 #define WindowCast(w) (Window)(wxPtrToUInt(w)) 
  65 // Is the window mapped? 
  66 static bool IsMapped(Display 
*display
, Window window
) 
  68     XWindowAttributes attr
; 
  69     XGetWindowAttributes(display
, window
, &attr
); 
  70     return (attr
.map_state 
!= IsUnmapped
); 
  75 // Suspends X11 errors. Used when we expect errors but they are not fatal 
  79     typedef int (*wxX11ErrorHandler
)(Display 
*, XErrorEvent 
*); 
  81     static int wxX11ErrorsSuspender_handler(Display
*, XErrorEvent
*) { return 0; } 
  84 class wxX11ErrorsSuspender
 
  87     wxX11ErrorsSuspender(Display 
*d
) : m_display(d
) 
  89         m_old 
= XSetErrorHandler(wxX11ErrorsSuspender_handler
); 
  91     ~wxX11ErrorsSuspender() 
  94         XSetErrorHandler(m_old
); 
  99     wxX11ErrorHandler m_old
; 
 104 // ---------------------------------------------------------------------------- 
 105 // Setting icons for window manager: 
 106 // ---------------------------------------------------------------------------- 
 108 #if wxUSE_IMAGE && !wxUSE_NANOX 
 110 static Atom _NET_WM_ICON 
= 0; 
 113 wxSetIconsX11(WXDisplay
* display
, WXWindow window
, const wxIconBundle
& ib
) 
 117     const size_t numIcons 
= ib
.GetIconCount(); 
 118     for ( size_t i 
= 0; i 
< numIcons
; ++i 
) 
 120         const wxIcon icon 
= ib
.GetIconByIndex(i
); 
 122         size 
+= 2 + icon
.GetWidth() * icon
.GetHeight(); 
 125     wxMAKE_ATOM(_NET_WM_ICON
, (Display
*)display
); 
 129         unsigned long* data 
= new unsigned long[size
]; 
 130         unsigned long* ptr 
= data
; 
 132         for ( size_t i 
= 0; i 
< numIcons
; ++i 
) 
 134             const wxImage image 
= ib
.GetIconByIndex(i
).ConvertToImage(); 
 135             int width 
= image
.GetWidth(), 
 136                 height 
= image
.GetHeight(); 
 137             unsigned char* imageData 
= image
.GetData(); 
 138             unsigned char* imageDataEnd 
= imageData 
+ ( width 
* height 
* 3 ); 
 139             bool hasMask 
= image
.HasMask(); 
 140             unsigned char rMask
, gMask
, bMask
; 
 141             unsigned char r
, g
, b
, a
; 
 145                 rMask 
= image
.GetMaskRed(); 
 146                 gMask 
= image
.GetMaskGreen(); 
 147                 bMask 
= image
.GetMaskBlue(); 
 149             else // no mask, but still init the variables to avoid warnings 
 159             while ( imageData 
< imageDataEnd 
) 
 164                 if( hasMask 
&& r 
== rMask 
&& g 
== gMask 
&& b 
== bMask 
) 
 169                 *ptr
++ = ( a 
<< 24 ) | ( r 
<< 16 ) | ( g 
<< 8 ) | b
; 
 175         XChangeProperty( (Display
*)display
, 
 180                          (unsigned char*)data
, size 
); 
 185         XDeleteProperty( (Display
*)display
, 
 191 #endif // wxUSE_IMAGE && !wxUSE_NANOX 
 193 // ---------------------------------------------------------------------------- 
 195 // ---------------------------------------------------------------------------- 
 197 // NB: Setting fullscreen mode under X11 is a complicated matter. There was 
 198 //     no standard way of doing it until recently. ICCCM doesn't know the 
 199 //     concept of fullscreen windows and the only way to make a window 
 200 //     fullscreen is to remove decorations, resize it to cover entire screen 
 201 //     and set WIN_LAYER_ABOVE_DOCK. 
 203 //     This doesn't always work, though. Specifically, at least kwin from 
 204 //     KDE 3 ignores the hint. The only way to make kwin accept our request 
 205 //     is to emulate the way Qt does it. That is, unmap the window, set 
 206 //     _NET_WM_WINDOW_TYPE to _KDE_NET_WM_WINDOW_TYPE_OVERRIDE (KDE extension), 
 207 //     add _NET_WM_STATE_STAYS_ON_TOP (ditto) to _NET_WM_STATE and map 
 210 //     Version 1.2 of Window Manager Specification (aka wm-spec aka 
 211 //     Extended Window Manager Hints) introduced _NET_WM_STATE_FULLSCREEN 
 212 //     window state which provides cleanest and simplest possible way of 
 213 //     making a window fullscreen. WM-spec is a de-facto standard adopted 
 214 //     by GNOME and KDE folks, but _NET_WM_STATE_FULLSCREEN isn't yet widely 
 215 //     supported. As of January 2003, only GNOME 2's default WM Metacity 
 216 //     implements, KDE will support it from version 3.2. At toolkits level, 
 217 //     GTK+ >= 2.1.2 uses it as the only method of making windows fullscreen 
 218 //     (that's why wxGTK will *not* switch to using gtk_window_fullscreen 
 219 //     unless it has better compatibility with older WMs). 
 222 //     This is what wxWidgets does in wxSetFullScreenStateX11: 
 223 //       1) if _NET_WM_STATE_FULLSCREEN is supported, use it 
 224 //       2) otherwise try WM-specific hacks (KDE, IceWM) 
 225 //       3) use _WIN_LAYER and hope that the WM will recognize it 
 226 //     The code was tested with: 
 227 //     twm, IceWM, WindowMaker, Metacity, kwin, sawfish, lesstif-mwm 
 230 #define  WIN_LAYER_NORMAL       4 
 231 #define  WIN_LAYER_ABOVE_DOCK  10 
 233 static void wxWinHintsSetLayer(Display 
*display
, Window rootWnd
, 
 234                                Window window
, int layer
) 
 236     wxX11ErrorsSuspender 
noerrors(display
); 
 240     wxMAKE_ATOM( _WIN_LAYER
, display 
); 
 242     if (IsMapped(display
, window
)) 
 244         xev
.type 
= ClientMessage
; 
 245         xev
.xclient
.type 
= ClientMessage
; 
 246         xev
.xclient
.window 
= window
; 
 247         xev
.xclient
.message_type 
= _WIN_LAYER
; 
 248         xev
.xclient
.format 
= 32; 
 249         xev
.xclient
.data
.l
[0] = (long)layer
; 
 250         xev
.xclient
.data
.l
[1] = CurrentTime
; 
 252         XSendEvent(display
, rootWnd
, False
, 
 253                    SubstructureNotifyMask
, (XEvent
*) &xev
); 
 260         XChangeProperty(display
, window
, 
 261                         _WIN_LAYER
, XA_CARDINAL
, 32, 
 262                         PropModeReplace
, (unsigned char *)data
, 1); 
 269 static bool wxQueryWMspecSupport(Display
* WXUNUSED(display
), 
 270                                  Window 
WXUNUSED(rootWnd
), 
 273     GdkAtom gatom 
= gdk_x11_xatom_to_atom(feature
); 
 274     return gdk_net_wm_supports(gatom
); 
 277 static bool wxQueryWMspecSupport(Display 
*display
, Window rootWnd
, Atom feature
) 
 279     wxMAKE_ATOM(_NET_SUPPORTING_WM_CHECK
, display
); 
 280     wxMAKE_ATOM(_NET_SUPPORTED
, display
); 
 282     // FIXME: We may want to cache these checks. Note that we can't simply 
 283     //        remember the results in global variable because the WM may go 
 284     //        away and be replaced by another one! One possible approach 
 285     //        would be invalidate the case every 15 seconds or so. Since this 
 286     //        code is currently only used by wxTopLevelWindow::ShowFullScreen, 
 287     //        it is not important that it is not optimized. 
 289     //        If the WM supports ICCCM (i.e. the root window has 
 290     //        _NET_SUPPORTING_WM_CHECK property that points to a WM-owned 
 291     //        window), we could watch for DestroyNotify event on the window 
 292     //        and invalidate our cache when the windows goes away (= WM 
 293     //        is replaced by another one). This is what GTK+ 2 does. 
 294     //        Let's do it only if it is needed, it requires changes to 
 302     unsigned long nwins
, natoms
; 
 304     // Is the WM ICCCM supporting? 
 305     XGetWindowProperty(display
, rootWnd
, 
 306                        _NET_SUPPORTING_WM_CHECK
, 0, LONG_MAX
, 
 307                        False
, XA_WINDOW
, &type
, &format
, &nwins
, 
 308                        &after
, (unsigned char **)&wins
); 
 309     if ( type 
!= XA_WINDOW 
|| nwins 
<= 0 || wins
[0] == None 
) 
 313     // Query for supported features: 
 314     XGetWindowProperty(display
, rootWnd
, 
 315                        _NET_SUPPORTED
, 0, LONG_MAX
, 
 316                        False
, XA_ATOM
, &type
, &format
, &natoms
, 
 317                        &after
, (unsigned char **)&atoms
); 
 318     if ( type 
!= XA_ATOM 
|| atoms 
== NULL 
) 
 321     // Lookup the feature we want: 
 322     for (unsigned i 
= 0; i 
< natoms
; i
++) 
 324         if ( atoms
[i
] == feature 
) 
 336 #define _NET_WM_STATE_REMOVE        0 
 337 #define _NET_WM_STATE_ADD           1 
 339 static void wxWMspecSetState(Display 
*display
, Window rootWnd
, 
 340                              Window window
, int operation
, Atom state
) 
 342     wxMAKE_ATOM(_NET_WM_STATE
, display
); 
 344     if ( IsMapped(display
, window
) ) 
 347         xev
.type 
= ClientMessage
; 
 348         xev
.xclient
.type 
= ClientMessage
; 
 349         xev
.xclient
.serial 
= 0; 
 350         xev
.xclient
.send_event 
= True
; 
 351         xev
.xclient
.display 
= display
; 
 352         xev
.xclient
.window 
= window
; 
 353         xev
.xclient
.message_type 
= _NET_WM_STATE
; 
 354         xev
.xclient
.format 
= 32; 
 355         xev
.xclient
.data
.l
[0] = operation
; 
 356         xev
.xclient
.data
.l
[1] = state
; 
 357         xev
.xclient
.data
.l
[2] = None
; 
 359         XSendEvent(display
, rootWnd
, 
 361                    SubstructureRedirectMask 
| SubstructureNotifyMask
, 
 364     // FIXME - must modify _NET_WM_STATE property list if the window 
 368 static void wxWMspecSetFullscreen(Display 
*display
, Window rootWnd
, 
 369                                   Window window
, bool fullscreen
) 
 371     wxMAKE_ATOM(_NET_WM_STATE_FULLSCREEN
, display
); 
 372     wxWMspecSetState(display
, rootWnd
, 
 374                      fullscreen 
? _NET_WM_STATE_ADD 
: _NET_WM_STATE_REMOVE
, 
 375                       _NET_WM_STATE_FULLSCREEN
); 
 379 // Is the user running KDE's kwin window manager? At least kwin from KDE 3 
 380 // sets KWIN_RUNNING property on the root window. 
 381 static bool wxKwinRunning(Display 
*display
, Window rootWnd
) 
 383     wxMAKE_ATOM(KWIN_RUNNING
, display
); 
 388     unsigned long nitems
, after
; 
 389     if (XGetWindowProperty(display
, rootWnd
, 
 390                            KWIN_RUNNING
, 0, 1, False
, KWIN_RUNNING
, 
 391                            &type
, &format
, &nitems
, &after
, 
 392                            (unsigned char**)&data
) != Success
) 
 397     bool retval 
= (type 
== KWIN_RUNNING 
&& 
 398                    nitems 
== 1 && data 
&& data
[0] == 1); 
 403 // KDE's kwin is Qt-centric so much than no normal method of fullscreen 
 404 // mode will work with it. We have to carefully emulate the Qt way. 
 405 static void wxSetKDEFullscreen(Display 
*display
, Window rootWnd
, 
 406                                Window w
, bool fullscreen
, wxRect 
*origRect
) 
 411     wxMAKE_ATOM(_NET_WM_WINDOW_TYPE
, display
); 
 412     wxMAKE_ATOM(_NET_WM_WINDOW_TYPE_NORMAL
, display
); 
 413     wxMAKE_ATOM(_KDE_NET_WM_WINDOW_TYPE_OVERRIDE
, display
); 
 414     wxMAKE_ATOM(_NET_WM_STATE_STAYS_ON_TOP
, display
); 
 418         data
[0] = _KDE_NET_WM_WINDOW_TYPE_OVERRIDE
; 
 419         data
[1] = _NET_WM_WINDOW_TYPE_NORMAL
; 
 424         data
[0] = _NET_WM_WINDOW_TYPE_NORMAL
; 
 429     // it is necessary to unmap the window, otherwise kwin will ignore us: 
 430     XSync(display
, False
); 
 432     bool wasMapped 
= IsMapped(display
, w
); 
 435         XUnmapWindow(display
, w
); 
 436         XSync(display
, False
); 
 439     XChangeProperty(display
, w
, _NET_WM_WINDOW_TYPE
, XA_ATOM
, 32, 
 440                     PropModeReplace
, (unsigned char *) &data
[0], lng
); 
 441     XSync(display
, False
); 
 445         XMapRaised(display
, w
); 
 446         XSync(display
, False
); 
 449     wxWMspecSetState(display
, rootWnd
, w
, 
 450                      fullscreen 
? _NET_WM_STATE_ADD 
: _NET_WM_STATE_REMOVE
, 
 451                      _NET_WM_STATE_STAYS_ON_TOP
); 
 452     XSync(display
, False
); 
 456         // NB: like many other WMs, kwin ignores the first request for a window 
 457         //     position change after the window was mapped. This additional 
 458         //     move+resize event will ensure that the window is restored in 
 459         //     exactly the same position as before it was made fullscreen 
 460         //     (because wxTopLevelWindow::ShowFullScreen will call SetSize, thus 
 461         //     setting the position for the second time). 
 462         XMoveResizeWindow(display
, w
, 
 463                           origRect
->x
, origRect
->y
, 
 464                           origRect
->width
, origRect
->height
); 
 465         XSync(display
, False
); 
 470 wxX11FullScreenMethod 
wxGetFullScreenMethodX11(WXDisplay
* display
, 
 473     Window root 
= WindowCast(rootWindow
); 
 474     Display 
*disp 
= (Display
*)display
; 
 476     // if WM supports _NET_WM_STATE_FULLSCREEN from wm-spec 1.2, use it: 
 477     wxMAKE_ATOM(_NET_WM_STATE_FULLSCREEN
, disp
); 
 478     if (wxQueryWMspecSupport(disp
, root
, _NET_WM_STATE_FULLSCREEN
)) 
 480         wxLogTrace(_T("fullscreen"), 
 481                    _T("detected _NET_WM_STATE_FULLSCREEN support")); 
 482         return wxX11_FS_WMSPEC
; 
 485     // if the user is running KDE's kwin WM, use a legacy hack because 
 486     // kwin doesn't understand any other method: 
 487     if (wxKwinRunning(disp
, root
)) 
 489         wxLogTrace(_T("fullscreen"), _T("detected kwin")); 
 493     // finally, fall back to ICCCM heuristic method: 
 494     wxLogTrace(_T("fullscreen"), _T("unknown WM, using _WIN_LAYER")); 
 495     return wxX11_FS_GENERIC
; 
 499 void wxSetFullScreenStateX11(WXDisplay
* display
, WXWindow rootWindow
, 
 500                              WXWindow window
, bool show
, 
 502                              wxX11FullScreenMethod method
) 
 504     // NB: please see the comment under "Fullscreen mode:" title above 
 505     //     for implications of changing this code. 
 507     Window wnd 
= WindowCast(window
); 
 508     Window root 
= WindowCast(rootWindow
); 
 509     Display 
*disp 
= (Display
*)display
; 
 511     if (method 
== wxX11_FS_AUTODETECT
) 
 512         method 
= wxGetFullScreenMethodX11(display
, rootWindow
); 
 516         case wxX11_FS_WMSPEC
: 
 517             wxWMspecSetFullscreen(disp
, root
, wnd
, show
); 
 520             wxSetKDEFullscreen(disp
, root
, wnd
, show
, origRect
); 
 523             wxWinHintsSetLayer(disp
, root
, wnd
, 
 524                                show 
? WIN_LAYER_ABOVE_DOCK 
: WIN_LAYER_NORMAL
); 
 531 // ---------------------------------------------------------------------------- 
 532 // keycode translations 
 533 // ---------------------------------------------------------------------------- 
 535 #include <X11/keysym.h> 
 537 // FIXME what about tables?? 
 539 int wxCharCodeXToWX(KeySym keySym
) 
 546             id 
= WXK_SHIFT
; break; 
 549             id 
= WXK_CONTROL
; break; 
 554             id 
= WXK_CAPITAL
; break; 
 556             id 
= WXK_BACK
; break; 
 558             id 
= WXK_DELETE
; break; 
 560             id 
= WXK_CLEAR
; break; 
 566             id 
= WXK_RETURN
; break; 
 568             id 
= WXK_ESCAPE
; break; 
 571             id 
= WXK_PAUSE
; break; 
 573             id 
= WXK_NUMLOCK
; break; 
 575             id 
= WXK_SCROLL
; break; 
 578             id 
= WXK_HOME
; break; 
 582             id 
= WXK_LEFT
; break; 
 584             id 
= WXK_RIGHT
; break; 
 588             id 
= WXK_DOWN
; break; 
 590             id 
= WXK_PAGEDOWN
; break; 
 592             id 
= WXK_PAGEUP
; break; 
 594             id 
= WXK_MENU
; break; 
 596             id 
= WXK_SELECT
; break; 
 598             id 
= WXK_CANCEL
; break; 
 600             id 
= WXK_PRINT
; break; 
 602             id 
= WXK_EXECUTE
; break; 
 604             id 
= WXK_INSERT
; break; 
 606             id 
= WXK_HELP
; break; 
 609             id 
= WXK_NUMPAD_MULTIPLY
; break; 
 611             id 
= WXK_NUMPAD_ADD
; break; 
 613             id 
= WXK_NUMPAD_SUBTRACT
; break; 
 615             id 
= WXK_NUMPAD_DIVIDE
; break; 
 617             id 
= WXK_NUMPAD_DECIMAL
; break; 
 619             id 
= WXK_NUMPAD_EQUAL
; break; 
 621             id 
= WXK_NUMPAD_SPACE
; break; 
 623             id 
= WXK_NUMPAD_TAB
; break; 
 625             id 
= WXK_NUMPAD_ENTER
; break; 
 627             id 
= WXK_NUMPAD0
; break; 
 629             id 
= WXK_NUMPAD1
; break; 
 631             id 
= WXK_NUMPAD2
; break; 
 633             id 
= WXK_NUMPAD3
; break; 
 635             id 
= WXK_NUMPAD4
; break; 
 637             id 
= WXK_NUMPAD5
; break; 
 639             id 
= WXK_NUMPAD6
; break; 
 641             id 
= WXK_NUMPAD7
; break; 
 643             id 
= WXK_NUMPAD8
; break; 
 645             id 
= WXK_NUMPAD9
; break; 
 647             id 
= WXK_NUMPAD_INSERT
; break; 
 649             id 
= WXK_NUMPAD_END
; break; 
 651             id 
= WXK_NUMPAD_DOWN
; break; 
 652         case XK_KP_Page_Down
: 
 653             id 
= WXK_NUMPAD_PAGEDOWN
; break; 
 655             id 
= WXK_NUMPAD_LEFT
; break; 
 657             id 
= WXK_NUMPAD_RIGHT
; break; 
 659             id 
= WXK_NUMPAD_HOME
; break; 
 661             id 
= WXK_NUMPAD_UP
; break; 
 663             id 
= WXK_NUMPAD_PAGEUP
; break; 
 713             id 
= (keySym 
<= 255) ? (int)keySym 
: -1; 
 719 KeySym 
wxCharCodeWXToX(int id
) 
 725         case WXK_CANCEL
:        keySym 
= XK_Cancel
; break; 
 726         case WXK_BACK
:          keySym 
= XK_BackSpace
; break; 
 727         case WXK_TAB
:           keySym 
= XK_Tab
; break; 
 728         case WXK_CLEAR
:         keySym 
= XK_Clear
; break; 
 729         case WXK_RETURN
:        keySym 
= XK_Return
; break; 
 730         case WXK_SHIFT
:         keySym 
= XK_Shift_L
; break; 
 731         case WXK_CONTROL
:       keySym 
= XK_Control_L
; break; 
 732         case WXK_ALT
:           keySym 
= XK_Meta_L
; break; 
 733         case WXK_CAPITAL
:       keySym 
= XK_Caps_Lock
; break; 
 734         case WXK_MENU 
:         keySym 
= XK_Menu
; break; 
 735         case WXK_PAUSE
:         keySym 
= XK_Pause
; break; 
 736         case WXK_ESCAPE
:        keySym 
= XK_Escape
; break; 
 737         case WXK_SPACE
:         keySym 
= ' '; break; 
 738         case WXK_PAGEUP
:        keySym 
= XK_Prior
; break; 
 739         case WXK_PAGEDOWN
:      keySym 
= XK_Next
; break; 
 740         case WXK_END
:           keySym 
= XK_End
; break; 
 741         case WXK_HOME 
:         keySym 
= XK_Home
; break; 
 742         case WXK_LEFT 
:         keySym 
= XK_Left
; break; 
 743         case WXK_UP
:            keySym 
= XK_Up
; break; 
 744         case WXK_RIGHT
:         keySym 
= XK_Right
; break; 
 745         case WXK_DOWN 
:         keySym 
= XK_Down
; break; 
 746         case WXK_SELECT
:        keySym 
= XK_Select
; break; 
 747         case WXK_PRINT
:         keySym 
= XK_Print
; break; 
 748         case WXK_EXECUTE
:       keySym 
= XK_Execute
; break; 
 749         case WXK_INSERT
:        keySym 
= XK_Insert
; break; 
 750         case WXK_DELETE
:        keySym 
= XK_Delete
; break; 
 751         case WXK_HELP 
:         keySym 
= XK_Help
; break; 
 752         case WXK_NUMPAD0
:       keySym 
= XK_KP_0
; break; case WXK_NUMPAD_INSERT
:     keySym 
= XK_KP_Insert
; break; 
 753         case WXK_NUMPAD1
:       keySym 
= XK_KP_1
; break; case WXK_NUMPAD_END
:           keySym 
= XK_KP_End
; break; 
 754         case WXK_NUMPAD2
:       keySym 
= XK_KP_2
; break; case WXK_NUMPAD_DOWN
:      keySym 
= XK_KP_Down
; break; 
 755         case WXK_NUMPAD3
:       keySym 
= XK_KP_3
; break; case WXK_NUMPAD_PAGEDOWN
:  keySym 
= XK_KP_Page_Down
; break; 
 756         case WXK_NUMPAD4
:       keySym 
= XK_KP_4
; break; case WXK_NUMPAD_LEFT
:         keySym 
= XK_KP_Left
; break; 
 757         case WXK_NUMPAD5
:       keySym 
= XK_KP_5
; break; 
 758         case WXK_NUMPAD6
:       keySym 
= XK_KP_6
; break; case WXK_NUMPAD_RIGHT
:       keySym 
= XK_KP_Right
; break; 
 759         case WXK_NUMPAD7
:       keySym 
= XK_KP_7
; break; case WXK_NUMPAD_HOME
:       keySym 
= XK_KP_Home
; break; 
 760         case WXK_NUMPAD8
:       keySym 
= XK_KP_8
; break; case WXK_NUMPAD_UP
:             keySym 
= XK_KP_Up
; break; 
 761         case WXK_NUMPAD9
:       keySym 
= XK_KP_9
; break; case WXK_NUMPAD_PAGEUP
:   keySym 
= XK_KP_Page_Up
; break; 
 762         case WXK_NUMPAD_DECIMAL
:    keySym 
= XK_KP_Decimal
; break; case WXK_NUMPAD_DELETE
:   keySym 
= XK_KP_Delete
; break; 
 763         case WXK_NUMPAD_MULTIPLY
:   keySym 
= XK_KP_Multiply
; break; 
 764         case WXK_NUMPAD_ADD
:             keySym 
= XK_KP_Add
; break; 
 765         case WXK_NUMPAD_SUBTRACT
: keySym 
= XK_KP_Subtract
; break; 
 766         case WXK_NUMPAD_DIVIDE
:        keySym 
= XK_KP_Divide
; break; 
 767         case WXK_NUMPAD_ENTER
:        keySym 
= XK_KP_Enter
; break; 
 768         case WXK_NUMPAD_SEPARATOR
:  keySym 
= XK_KP_Separator
; break; 
 769         case WXK_F1
:            keySym 
= XK_F1
; break; 
 770         case WXK_F2
:            keySym 
= XK_F2
; break; 
 771         case WXK_F3
:            keySym 
= XK_F3
; break; 
 772         case WXK_F4
:            keySym 
= XK_F4
; break; 
 773         case WXK_F5
:            keySym 
= XK_F5
; break; 
 774         case WXK_F6
:            keySym 
= XK_F6
; break; 
 775         case WXK_F7
:            keySym 
= XK_F7
; break; 
 776         case WXK_F8
:            keySym 
= XK_F8
; break; 
 777         case WXK_F9
:            keySym 
= XK_F9
; break; 
 778         case WXK_F10
:           keySym 
= XK_F10
; break; 
 779         case WXK_F11
:           keySym 
= XK_F11
; break; 
 780         case WXK_F12
:           keySym 
= XK_F12
; break; 
 781         case WXK_F13
:           keySym 
= XK_F13
; break; 
 782         case WXK_F14
:           keySym 
= XK_F14
; break; 
 783         case WXK_F15
:           keySym 
= XK_F15
; break; 
 784         case WXK_F16
:           keySym 
= XK_F16
; break; 
 785         case WXK_F17
:           keySym 
= XK_F17
; break; 
 786         case WXK_F18
:           keySym 
= XK_F18
; break; 
 787         case WXK_F19
:           keySym 
= XK_F19
; break; 
 788         case WXK_F20
:           keySym 
= XK_F20
; break; 
 789         case WXK_F21
:           keySym 
= XK_F21
; break; 
 790         case WXK_F22
:           keySym 
= XK_F22
; break; 
 791         case WXK_F23
:           keySym 
= XK_F23
; break; 
 792         case WXK_F24
:           keySym 
= XK_F24
; break; 
 793         case WXK_NUMLOCK
:       keySym 
= XK_Num_Lock
; break; 
 794         case WXK_SCROLL
:        keySym 
= XK_Scroll_Lock
; break; 
 795         default:                keySym 
= id 
<= 255 ? (KeySym
)id 
: 0; 
 802 // ---------------------------------------------------------------------------- 
 803 // check current state of a key 
 804 // ---------------------------------------------------------------------------- 
 806 bool wxGetKeyState(wxKeyCode key
) 
 808     wxASSERT_MSG(key 
!= WXK_LBUTTON 
&& key 
!= WXK_RBUTTON 
&& key 
!= 
 809         WXK_MBUTTON
, wxT("can't use wxGetKeyState() for mouse buttons")); 
 811     Display 
*pDisplay 
= (Display
*) wxGetDisplay(); 
 813     int iKey 
= wxCharCodeWXToX(key
); 
 815     Window       wDummy1
, wDummy2
; 
 816     int          iDummy3
, iDummy4
, iDummy5
, iDummy6
; 
 818     KeyCode keyCode 
= XKeysymToKeycode(pDisplay
,iKey
); 
 819     if (keyCode 
== NoSymbol
) 
 822     if ( IsModifierKey(iKey
) )  // If iKey is a modifier key, use a different method 
 824         XModifierKeymap 
*map 
= XGetModifierMapping(pDisplay
); 
 825         wxCHECK_MSG( map
, false, _T("failed to get X11 modifiers map") ); 
 827         for (int i 
= 0; i 
< 8; ++i
) 
 829             if ( map
->modifiermap
[map
->max_keypermod 
* i
] == keyCode
) 
 835         XQueryPointer(pDisplay
, DefaultRootWindow(pDisplay
), &wDummy1
, &wDummy2
, 
 836                         &iDummy3
, &iDummy4
, &iDummy5
, &iDummy6
, &iMask 
); 
 837         XFreeModifiermap(map
); 
 838         return (iMask 
& iKeyMask
) != 0; 
 841     // From the XLib manual: 
 842     // The XQueryKeymap() function returns a bit vector for the logical state of the keyboard, 
 843     // where each bit set to 1 indicates that the corresponding key is currently pressed down. 
 844     // The vector is represented as 32 bytes. Byte N (from 0) contains the bits for keys 8N to 8N + 7 
 845     // with the least-significant bit in the byte representing key 8N. 
 847     XQueryKeymap(pDisplay
, key_vector
); 
 848     return key_vector
[keyCode 
>> 3] & (1 << (keyCode 
& 7)); 
 851 #endif // __WXX11__ || __WXGTK__ || __WXMOTIF__