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_ICON 
= 0; 
  45 static Atom _NET_WM_STATE 
= 0; 
  46 static Atom _NET_WM_STATE_FULLSCREEN 
= 0; 
  47 static Atom _NET_WM_STATE_STAYS_ON_TOP 
= 0; 
  48 static Atom _NET_WM_WINDOW_TYPE 
= 0; 
  49 static Atom _NET_WM_WINDOW_TYPE_NORMAL 
= 0; 
  50 static Atom _KDE_NET_WM_WINDOW_TYPE_OVERRIDE 
= 0; 
  51 static Atom _WIN_LAYER 
= 0; 
  52 static Atom KWIN_RUNNING 
= 0; 
  54 static Atom _NET_SUPPORTING_WM_CHECK 
= 0; 
  55 static Atom _NET_SUPPORTED 
= 0; 
  58 #define wxMAKE_ATOM(name, display) \ 
  59     if (name == 0) name = XInternAtom((display), #name, False) 
  62 // X11 Window is an int type, so use the macro to suppress warnings when 
  64 #define WindowCast(w) (Window)(wxPtrToUInt(w)) 
  66 // Is the window mapped? 
  67 static bool IsMapped(Display 
*display
, Window window
) 
  69     XWindowAttributes attr
; 
  70     XGetWindowAttributes(display
, window
, &attr
); 
  71     return (attr
.map_state 
!= IsUnmapped
); 
  76 // Suspends X11 errors. Used when we expect errors but they are not fatal 
  80     typedef int (*wxX11ErrorHandler
)(Display 
*, XErrorEvent 
*); 
  82     static int wxX11ErrorsSuspender_handler(Display
*, XErrorEvent
*) { return 0; } 
  85 class wxX11ErrorsSuspender
 
  88     wxX11ErrorsSuspender(Display 
*d
) : m_display(d
) 
  90         m_old 
= XSetErrorHandler(wxX11ErrorsSuspender_handler
); 
  92     ~wxX11ErrorsSuspender() 
  95         XSetErrorHandler(m_old
); 
 100     wxX11ErrorHandler m_old
; 
 105 // ---------------------------------------------------------------------------- 
 106 // Setting icons for window manager: 
 107 // ---------------------------------------------------------------------------- 
 109 void wxSetIconsX11( WXDisplay
* display
, WXWindow window
, 
 110                     const wxIconBundle
& ib 
) 
 114     size_t i
, max 
= ib
.m_icons
.GetCount(); 
 116     for( i 
= 0; i 
< max
; ++i 
) 
 117         if( ib
.m_icons
[i
].Ok() ) 
 118             size 
+= 2 + ib
.m_icons
[i
].GetWidth() * ib
.m_icons
[i
].GetHeight(); 
 120     wxMAKE_ATOM(_NET_WM_ICON
, (Display
*)display
); 
 124 //       The code below is correct for 64-bit machines also. 
 125 //       wxUint32* data = new wxUint32[size]; 
 126 //       wxUint32* ptr = data; 
 127         unsigned long* data 
= new unsigned long[size
]; 
 128         unsigned long* ptr 
= data
; 
 130         for( i 
= 0; i 
< max
; ++i 
) 
 132             const wxImage image 
= ib
.m_icons
[i
].ConvertToImage(); 
 133             int width 
= image
.GetWidth(), height 
= image
.GetHeight(); 
 134             unsigned char* imageData 
= image
.GetData(); 
 135             unsigned char* imageDataEnd 
= imageData 
+ ( width 
* height 
* 3 ); 
 136             bool hasMask 
= image
.HasMask(); 
 137             unsigned char rMask
, gMask
, bMask
; 
 138             unsigned char r
, g
, b
, a
; 
 142                 rMask 
= image
.GetMaskRed(); 
 143                 gMask 
= image
.GetMaskGreen(); 
 144                 bMask 
= image
.GetMaskBlue(); 
 146             else // no mask, but still init the variables to avoid warnings 
 156             while( imageData 
< imageDataEnd 
) { 
 160                 if( hasMask 
&& r 
== rMask 
&& g 
== gMask 
&& b 
== bMask 
) 
 165                 *ptr
++ = ( a 
<< 24 ) | ( r 
<< 16 ) | ( g 
<< 8 ) | b
; 
 171         XChangeProperty( (Display
*)display
, 
 176                          (unsigned char*)data
, size 
); 
 181         XDeleteProperty( (Display
*)display
, 
 185 #endif // !wxUSE_NANOX 
 189 // ---------------------------------------------------------------------------- 
 191 // ---------------------------------------------------------------------------- 
 193 // NB: Setting fullscreen mode under X11 is a complicated matter. There was 
 194 //     no standard way of doing it until recently. ICCCM doesn't know the 
 195 //     concept of fullscreen windows and the only way to make a window 
 196 //     fullscreen is to remove decorations, resize it to cover entire screen 
 197 //     and set WIN_LAYER_ABOVE_DOCK. 
 199 //     This doesn't always work, though. Specifically, at least kwin from 
 200 //     KDE 3 ignores the hint. The only way to make kwin accept our request 
 201 //     is to emulate the way Qt does it. That is, unmap the window, set 
 202 //     _NET_WM_WINDOW_TYPE to _KDE_NET_WM_WINDOW_TYPE_OVERRIDE (KDE extension), 
 203 //     add _NET_WM_STATE_STAYS_ON_TOP (ditto) to _NET_WM_STATE and map 
 206 //     Version 1.2 of Window Manager Specification (aka wm-spec aka 
 207 //     Extended Window Manager Hints) introduced _NET_WM_STATE_FULLSCREEN 
 208 //     window state which provides cleanest and simplest possible way of 
 209 //     making a window fullscreen. WM-spec is a de-facto standard adopted 
 210 //     by GNOME and KDE folks, but _NET_WM_STATE_FULLSCREEN isn't yet widely 
 211 //     supported. As of January 2003, only GNOME 2's default WM Metacity 
 212 //     implements, KDE will support it from version 3.2. At toolkits level, 
 213 //     GTK+ >= 2.1.2 uses it as the only method of making windows fullscreen 
 214 //     (that's why wxGTK will *not* switch to using gtk_window_fullscreen 
 215 //     unless it has better compatibility with older WMs). 
 218 //     This is what wxWidgets does in wxSetFullScreenStateX11: 
 219 //       1) if _NET_WM_STATE_FULLSCREEN is supported, use it 
 220 //       2) otherwise try WM-specific hacks (KDE, IceWM) 
 221 //       3) use _WIN_LAYER and hope that the WM will recognize it 
 222 //     The code was tested with: 
 223 //     twm, IceWM, WindowMaker, Metacity, kwin, sawfish, lesstif-mwm 
 226 #define  WIN_LAYER_NORMAL       4 
 227 #define  WIN_LAYER_ABOVE_DOCK  10 
 229 static void wxWinHintsSetLayer(Display 
*display
, Window rootWnd
, 
 230                                Window window
, int layer
) 
 232     wxX11ErrorsSuspender 
noerrors(display
); 
 236     wxMAKE_ATOM( _WIN_LAYER
, display 
); 
 238     if (IsMapped(display
, window
)) 
 240         xev
.type 
= ClientMessage
; 
 241         xev
.xclient
.type 
= ClientMessage
; 
 242         xev
.xclient
.window 
= window
; 
 243         xev
.xclient
.message_type 
= _WIN_LAYER
; 
 244         xev
.xclient
.format 
= 32; 
 245         xev
.xclient
.data
.l
[0] = (long)layer
; 
 246         xev
.xclient
.data
.l
[1] = CurrentTime
; 
 248         XSendEvent(display
, rootWnd
, False
, 
 249                    SubstructureNotifyMask
, (XEvent
*) &xev
); 
 256         XChangeProperty(display
, window
, 
 257                         _WIN_LAYER
, XA_CARDINAL
, 32, 
 258                         PropModeReplace
, (unsigned char *)data
, 1); 
 265 static bool wxQueryWMspecSupport(Display
* WXUNUSED(display
), 
 266                                  Window 
WXUNUSED(rootWnd
), 
 269     GdkAtom gatom 
= gdk_x11_xatom_to_atom(feature
); 
 270     return gdk_net_wm_supports(gatom
); 
 273 static bool wxQueryWMspecSupport(Display 
*display
, Window rootWnd
, Atom feature
) 
 275     wxMAKE_ATOM(_NET_SUPPORTING_WM_CHECK
, display
); 
 276     wxMAKE_ATOM(_NET_SUPPORTED
, display
); 
 278     // FIXME: We may want to cache these checks. Note that we can't simply 
 279     //        remember the results in global variable because the WM may go 
 280     //        away and be replaced by another one! One possible approach 
 281     //        would be invalidate the case every 15 seconds or so. Since this 
 282     //        code is currently only used by wxTopLevelWindow::ShowFullScreen, 
 283     //        it is not important that it is not optimized. 
 285     //        If the WM supports ICCCM (i.e. the root window has 
 286     //        _NET_SUPPORTING_WM_CHECK property that points to a WM-owned 
 287     //        window), we could watch for DestroyNotify event on the window 
 288     //        and invalidate our cache when the windows goes away (= WM 
 289     //        is replaced by another one). This is what GTK+ 2 does. 
 290     //        Let's do it only if it is needed, it requires changes to 
 298     unsigned long nwins
, natoms
; 
 300     // Is the WM ICCCM supporting? 
 301     XGetWindowProperty(display
, rootWnd
, 
 302                        _NET_SUPPORTING_WM_CHECK
, 0, LONG_MAX
, 
 303                        False
, XA_WINDOW
, &type
, &format
, &nwins
, 
 304                        &after
, (unsigned char **)&wins
); 
 305     if ( type 
!= XA_WINDOW 
|| nwins 
<= 0 || wins
[0] == None 
) 
 309     // Query for supported features: 
 310     XGetWindowProperty(display
, rootWnd
, 
 311                        _NET_SUPPORTED
, 0, LONG_MAX
, 
 312                        False
, XA_ATOM
, &type
, &format
, &natoms
, 
 313                        &after
, (unsigned char **)&atoms
); 
 314     if ( type 
!= XA_ATOM 
|| atoms 
== NULL 
) 
 317     // Lookup the feature we want: 
 318     for (unsigned i 
= 0; i 
< natoms
; i
++) 
 320         if ( atoms
[i
] == feature 
) 
 332 #define _NET_WM_STATE_REMOVE        0 
 333 #define _NET_WM_STATE_ADD           1 
 335 static void wxWMspecSetState(Display 
*display
, Window rootWnd
, 
 336                              Window window
, int operation
, Atom state
) 
 338     wxMAKE_ATOM(_NET_WM_STATE
, display
); 
 340     if ( IsMapped(display
, window
) ) 
 343         xev
.type 
= ClientMessage
; 
 344         xev
.xclient
.type 
= ClientMessage
; 
 345         xev
.xclient
.serial 
= 0; 
 346         xev
.xclient
.send_event 
= True
; 
 347         xev
.xclient
.display 
= display
; 
 348         xev
.xclient
.window 
= window
; 
 349         xev
.xclient
.message_type 
= _NET_WM_STATE
; 
 350         xev
.xclient
.format 
= 32; 
 351         xev
.xclient
.data
.l
[0] = operation
; 
 352         xev
.xclient
.data
.l
[1] = state
; 
 353         xev
.xclient
.data
.l
[2] = None
; 
 355         XSendEvent(display
, rootWnd
, 
 357                    SubstructureRedirectMask 
| SubstructureNotifyMask
, 
 360     // FIXME - must modify _NET_WM_STATE property list if the window 
 364 static void wxWMspecSetFullscreen(Display 
*display
, Window rootWnd
, 
 365                                   Window window
, bool fullscreen
) 
 367     wxMAKE_ATOM(_NET_WM_STATE_FULLSCREEN
, display
); 
 368     wxWMspecSetState(display
, rootWnd
, 
 370                      fullscreen 
? _NET_WM_STATE_ADD 
: _NET_WM_STATE_REMOVE
, 
 371                       _NET_WM_STATE_FULLSCREEN
); 
 375 // Is the user running KDE's kwin window manager? At least kwin from KDE 3 
 376 // sets KWIN_RUNNING property on the root window. 
 377 static bool wxKwinRunning(Display 
*display
, Window rootWnd
) 
 379     wxMAKE_ATOM(KWIN_RUNNING
, display
); 
 384     unsigned long nitems
, after
; 
 385     if (XGetWindowProperty(display
, rootWnd
, 
 386                            KWIN_RUNNING
, 0, 1, False
, KWIN_RUNNING
, 
 387                            &type
, &format
, &nitems
, &after
, 
 388                            (unsigned char**)&data
) != Success
) 
 393     bool retval 
= (type 
== KWIN_RUNNING 
&& 
 394                    nitems 
== 1 && data 
&& data
[0] == 1); 
 399 // KDE's kwin is Qt-centric so much than no normal method of fullscreen 
 400 // mode will work with it. We have to carefully emulate the Qt way. 
 401 static void wxSetKDEFullscreen(Display 
*display
, Window rootWnd
, 
 402                                Window w
, bool fullscreen
, wxRect 
*origRect
) 
 407     wxMAKE_ATOM(_NET_WM_WINDOW_TYPE
, display
); 
 408     wxMAKE_ATOM(_NET_WM_WINDOW_TYPE_NORMAL
, display
); 
 409     wxMAKE_ATOM(_KDE_NET_WM_WINDOW_TYPE_OVERRIDE
, display
); 
 410     wxMAKE_ATOM(_NET_WM_STATE_STAYS_ON_TOP
, display
); 
 414         data
[0] = _KDE_NET_WM_WINDOW_TYPE_OVERRIDE
; 
 415         data
[1] = _NET_WM_WINDOW_TYPE_NORMAL
; 
 420         data
[0] = _NET_WM_WINDOW_TYPE_NORMAL
; 
 425     // it is necessary to unmap the window, otherwise kwin will ignore us: 
 426     XSync(display
, False
); 
 428     bool wasMapped 
= IsMapped(display
, w
); 
 431         XUnmapWindow(display
, w
); 
 432         XSync(display
, False
); 
 435     XChangeProperty(display
, w
, _NET_WM_WINDOW_TYPE
, XA_ATOM
, 32, 
 436                     PropModeReplace
, (unsigned char *) &data
[0], lng
); 
 437     XSync(display
, False
); 
 441         XMapRaised(display
, w
); 
 442         XSync(display
, False
); 
 445     wxWMspecSetState(display
, rootWnd
, w
, 
 446                      fullscreen 
? _NET_WM_STATE_ADD 
: _NET_WM_STATE_REMOVE
, 
 447                      _NET_WM_STATE_STAYS_ON_TOP
); 
 448     XSync(display
, False
); 
 452         // NB: like many other WMs, kwin ignores the first request for a window 
 453         //     position change after the window was mapped. This additional 
 454         //     move+resize event will ensure that the window is restored in 
 455         //     exactly the same position as before it was made fullscreen 
 456         //     (because wxTopLevelWindow::ShowFullScreen will call SetSize, thus 
 457         //     setting the position for the second time). 
 458         XMoveResizeWindow(display
, w
, 
 459                           origRect
->x
, origRect
->y
, 
 460                           origRect
->width
, origRect
->height
); 
 461         XSync(display
, False
); 
 466 wxX11FullScreenMethod 
wxGetFullScreenMethodX11(WXDisplay
* display
, 
 469     Window root 
= WindowCast(rootWindow
); 
 470     Display 
*disp 
= (Display
*)display
; 
 472     // if WM supports _NET_WM_STATE_FULLSCREEN from wm-spec 1.2, use it: 
 473     wxMAKE_ATOM(_NET_WM_STATE_FULLSCREEN
, disp
); 
 474     if (wxQueryWMspecSupport(disp
, root
, _NET_WM_STATE_FULLSCREEN
)) 
 476         wxLogTrace(_T("fullscreen"), 
 477                    _T("detected _NET_WM_STATE_FULLSCREEN support")); 
 478         return wxX11_FS_WMSPEC
; 
 481     // if the user is running KDE's kwin WM, use a legacy hack because 
 482     // kwin doesn't understand any other method: 
 483     if (wxKwinRunning(disp
, root
)) 
 485         wxLogTrace(_T("fullscreen"), _T("detected kwin")); 
 489     // finally, fall back to ICCCM heuristic method: 
 490     wxLogTrace(_T("fullscreen"), _T("unknown WM, using _WIN_LAYER")); 
 491     return wxX11_FS_GENERIC
; 
 495 void wxSetFullScreenStateX11(WXDisplay
* display
, WXWindow rootWindow
, 
 496                              WXWindow window
, bool show
, 
 498                              wxX11FullScreenMethod method
) 
 500     // NB: please see the comment under "Fullscreen mode:" title above 
 501     //     for implications of changing this code. 
 503     Window wnd 
= WindowCast(window
); 
 504     Window root 
= WindowCast(rootWindow
); 
 505     Display 
*disp 
= (Display
*)display
; 
 507     if (method 
== wxX11_FS_AUTODETECT
) 
 508         method 
= wxGetFullScreenMethodX11(display
, rootWindow
); 
 512         case wxX11_FS_WMSPEC
: 
 513             wxWMspecSetFullscreen(disp
, root
, wnd
, show
); 
 516             wxSetKDEFullscreen(disp
, root
, wnd
, show
, origRect
); 
 519             wxWinHintsSetLayer(disp
, root
, wnd
, 
 520                                show 
? WIN_LAYER_ABOVE_DOCK 
: WIN_LAYER_NORMAL
); 
 527 // ---------------------------------------------------------------------------- 
 528 // keycode translations 
 529 // ---------------------------------------------------------------------------- 
 531 #include <X11/keysym.h> 
 533 // FIXME what about tables?? 
 535 int wxCharCodeXToWX(KeySym keySym
) 
 542             id 
= WXK_SHIFT
; break; 
 545             id 
= WXK_CONTROL
; break; 
 550             id 
= WXK_CAPITAL
; break; 
 552             id 
= WXK_BACK
; break; 
 554             id 
= WXK_DELETE
; break; 
 556             id 
= WXK_CLEAR
; break; 
 562             id 
= WXK_RETURN
; break; 
 564             id 
= WXK_ESCAPE
; break; 
 567             id 
= WXK_PAUSE
; break; 
 569             id 
= WXK_NUMLOCK
; break; 
 571             id 
= WXK_SCROLL
; break; 
 574             id 
= WXK_HOME
; break; 
 578             id 
= WXK_LEFT
; break; 
 580             id 
= WXK_RIGHT
; break; 
 584             id 
= WXK_DOWN
; break; 
 586             id 
= WXK_PAGEDOWN
; break; 
 588             id 
= WXK_PAGEUP
; break; 
 590             id 
= WXK_MENU
; break; 
 592             id 
= WXK_SELECT
; break; 
 594             id 
= WXK_CANCEL
; break; 
 596             id 
= WXK_PRINT
; break; 
 598             id 
= WXK_EXECUTE
; break; 
 600             id 
= WXK_INSERT
; break; 
 602             id 
= WXK_HELP
; break; 
 605             id 
= WXK_NUMPAD_MULTIPLY
; break; 
 607             id 
= WXK_NUMPAD_ADD
; break; 
 609             id 
= WXK_NUMPAD_SUBTRACT
; break; 
 611             id 
= WXK_NUMPAD_DIVIDE
; break; 
 613             id 
= WXK_NUMPAD_DECIMAL
; break; 
 615             id 
= WXK_NUMPAD_EQUAL
; break; 
 617             id 
= WXK_NUMPAD_SPACE
; break; 
 619             id 
= WXK_NUMPAD_TAB
; break; 
 621             id 
= WXK_NUMPAD_ENTER
; break; 
 623             id 
= WXK_NUMPAD0
; break; 
 625             id 
= WXK_NUMPAD1
; break; 
 627             id 
= WXK_NUMPAD2
; break; 
 629             id 
= WXK_NUMPAD3
; break; 
 631             id 
= WXK_NUMPAD4
; break; 
 633             id 
= WXK_NUMPAD5
; break; 
 635             id 
= WXK_NUMPAD6
; break; 
 637             id 
= WXK_NUMPAD7
; break; 
 639             id 
= WXK_NUMPAD8
; break; 
 641             id 
= WXK_NUMPAD9
; break; 
 643             id 
= WXK_NUMPAD_INSERT
; break; 
 645             id 
= WXK_NUMPAD_END
; break; 
 647             id 
= WXK_NUMPAD_DOWN
; break; 
 648         case XK_KP_Page_Down
: 
 649             id 
= WXK_NUMPAD_PAGEDOWN
; break; 
 651             id 
= WXK_NUMPAD_LEFT
; break; 
 653             id 
= WXK_NUMPAD_RIGHT
; break; 
 655             id 
= WXK_NUMPAD_HOME
; break; 
 657             id 
= WXK_NUMPAD_UP
; break; 
 659             id 
= WXK_NUMPAD_PAGEUP
; break; 
 709             id 
= (keySym 
<= 255) ? (int)keySym 
: -1; 
 715 KeySym 
wxCharCodeWXToX(int id
) 
 721         case WXK_CANCEL
:        keySym 
= XK_Cancel
; break; 
 722         case WXK_BACK
:          keySym 
= XK_BackSpace
; break; 
 723         case WXK_TAB
:           keySym 
= XK_Tab
; break; 
 724         case WXK_CLEAR
:         keySym 
= XK_Clear
; break; 
 725         case WXK_RETURN
:        keySym 
= XK_Return
; break; 
 726         case WXK_SHIFT
:         keySym 
= XK_Shift_L
; break; 
 727         case WXK_CONTROL
:       keySym 
= XK_Control_L
; break; 
 728         case WXK_ALT
:           keySym 
= XK_Meta_L
; break; 
 729         case WXK_CAPITAL
:       keySym 
= XK_Caps_Lock
; break; 
 730         case WXK_MENU 
:         keySym 
= XK_Menu
; break; 
 731         case WXK_PAUSE
:         keySym 
= XK_Pause
; break; 
 732         case WXK_ESCAPE
:        keySym 
= XK_Escape
; break; 
 733         case WXK_SPACE
:         keySym 
= ' '; break; 
 734         case WXK_PAGEUP
:        keySym 
= XK_Prior
; break; 
 735         case WXK_PAGEDOWN
:      keySym 
= XK_Next
; break; 
 736         case WXK_END
:           keySym 
= XK_End
; break; 
 737         case WXK_HOME 
:         keySym 
= XK_Home
; break; 
 738         case WXK_LEFT 
:         keySym 
= XK_Left
; break; 
 739         case WXK_UP
:            keySym 
= XK_Up
; break; 
 740         case WXK_RIGHT
:         keySym 
= XK_Right
; break; 
 741         case WXK_DOWN 
:         keySym 
= XK_Down
; break; 
 742         case WXK_SELECT
:        keySym 
= XK_Select
; break; 
 743         case WXK_PRINT
:         keySym 
= XK_Print
; break; 
 744         case WXK_EXECUTE
:       keySym 
= XK_Execute
; break; 
 745         case WXK_INSERT
:        keySym 
= XK_Insert
; break; 
 746         case WXK_DELETE
:        keySym 
= XK_Delete
; break; 
 747         case WXK_HELP 
:         keySym 
= XK_Help
; break; 
 748         case WXK_NUMPAD0
:       keySym 
= XK_KP_0
; break; case WXK_NUMPAD_INSERT
:     keySym 
= XK_KP_Insert
; break; 
 749         case WXK_NUMPAD1
:       keySym 
= XK_KP_1
; break; case WXK_NUMPAD_END
:           keySym 
= XK_KP_End
; break; 
 750         case WXK_NUMPAD2
:       keySym 
= XK_KP_2
; break; case WXK_NUMPAD_DOWN
:      keySym 
= XK_KP_Down
; break; 
 751         case WXK_NUMPAD3
:       keySym 
= XK_KP_3
; break; case WXK_NUMPAD_PAGEDOWN
:  keySym 
= XK_KP_Page_Down
; break; 
 752         case WXK_NUMPAD4
:       keySym 
= XK_KP_4
; break; case WXK_NUMPAD_LEFT
:         keySym 
= XK_KP_Left
; break; 
 753         case WXK_NUMPAD5
:       keySym 
= XK_KP_5
; break; 
 754         case WXK_NUMPAD6
:       keySym 
= XK_KP_6
; break; case WXK_NUMPAD_RIGHT
:       keySym 
= XK_KP_Right
; break; 
 755         case WXK_NUMPAD7
:       keySym 
= XK_KP_7
; break; case WXK_NUMPAD_HOME
:       keySym 
= XK_KP_Home
; break; 
 756         case WXK_NUMPAD8
:       keySym 
= XK_KP_8
; break; case WXK_NUMPAD_UP
:             keySym 
= XK_KP_Up
; break; 
 757         case WXK_NUMPAD9
:       keySym 
= XK_KP_9
; break; case WXK_NUMPAD_PAGEUP
:   keySym 
= XK_KP_Page_Up
; break; 
 758         case WXK_NUMPAD_DECIMAL
:    keySym 
= XK_KP_Decimal
; break; case WXK_NUMPAD_DELETE
:   keySym 
= XK_KP_Delete
; break; 
 759         case WXK_NUMPAD_MULTIPLY
:   keySym 
= XK_KP_Multiply
; break; 
 760         case WXK_NUMPAD_ADD
:             keySym 
= XK_KP_Add
; break; 
 761         case WXK_NUMPAD_SUBTRACT
: keySym 
= XK_KP_Subtract
; break; 
 762         case WXK_NUMPAD_DIVIDE
:        keySym 
= XK_KP_Divide
; break; 
 763         case WXK_NUMPAD_ENTER
:        keySym 
= XK_KP_Enter
; break; 
 764         case WXK_NUMPAD_SEPARATOR
:  keySym 
= XK_KP_Separator
; break; 
 765         case WXK_F1
:            keySym 
= XK_F1
; break; 
 766         case WXK_F2
:            keySym 
= XK_F2
; break; 
 767         case WXK_F3
:            keySym 
= XK_F3
; break; 
 768         case WXK_F4
:            keySym 
= XK_F4
; break; 
 769         case WXK_F5
:            keySym 
= XK_F5
; break; 
 770         case WXK_F6
:            keySym 
= XK_F6
; break; 
 771         case WXK_F7
:            keySym 
= XK_F7
; break; 
 772         case WXK_F8
:            keySym 
= XK_F8
; break; 
 773         case WXK_F9
:            keySym 
= XK_F9
; break; 
 774         case WXK_F10
:           keySym 
= XK_F10
; break; 
 775         case WXK_F11
:           keySym 
= XK_F11
; break; 
 776         case WXK_F12
:           keySym 
= XK_F12
; break; 
 777         case WXK_F13
:           keySym 
= XK_F13
; break; 
 778         case WXK_F14
:           keySym 
= XK_F14
; break; 
 779         case WXK_F15
:           keySym 
= XK_F15
; break; 
 780         case WXK_F16
:           keySym 
= XK_F16
; break; 
 781         case WXK_F17
:           keySym 
= XK_F17
; break; 
 782         case WXK_F18
:           keySym 
= XK_F18
; break; 
 783         case WXK_F19
:           keySym 
= XK_F19
; break; 
 784         case WXK_F20
:           keySym 
= XK_F20
; break; 
 785         case WXK_F21
:           keySym 
= XK_F21
; break; 
 786         case WXK_F22
:           keySym 
= XK_F22
; break; 
 787         case WXK_F23
:           keySym 
= XK_F23
; break; 
 788         case WXK_F24
:           keySym 
= XK_F24
; break; 
 789         case WXK_NUMLOCK
:       keySym 
= XK_Num_Lock
; break; 
 790         case WXK_SCROLL
:        keySym 
= XK_Scroll_Lock
; break; 
 791         default:                keySym 
= id 
<= 255 ? (KeySym
)id 
: 0; 
 798 // ---------------------------------------------------------------------------- 
 799 // check current state of a key 
 800 // ---------------------------------------------------------------------------- 
 802 bool wxGetKeyState(wxKeyCode key
) 
 804     wxASSERT_MSG(key 
!= WXK_LBUTTON 
&& key 
!= WXK_RBUTTON 
&& key 
!= 
 805         WXK_MBUTTON
, wxT("can't use wxGetKeyState() for mouse buttons")); 
 807     Display 
*pDisplay 
= (Display
*) wxGetDisplay(); 
 809     int iKey 
= wxCharCodeWXToX(key
); 
 811     Window       wDummy1
, wDummy2
; 
 812     int          iDummy3
, iDummy4
, iDummy5
, iDummy6
; 
 814     XModifierKeymap
* map 
= XGetModifierMapping(pDisplay
); 
 815     KeyCode keyCode 
= XKeysymToKeycode(pDisplay
,iKey
); 
 816     if (keyCode 
== NoSymbol
) 
 819     if ( IsModifierKey(iKey
) )  // If iKey is a modifier key, use a different method 
 821         for (int i 
= 0; i 
< 8; ++i
) 
 823             if ( map
->modifiermap
[map
->max_keypermod 
* i
] == keyCode
) 
 829         XQueryPointer(pDisplay
, DefaultRootWindow(pDisplay
), &wDummy1
, &wDummy2
, 
 830                         &iDummy3
, &iDummy4
, &iDummy5
, &iDummy6
, &iMask 
); 
 831         XFreeModifiermap(map
); 
 832         return (iMask 
& iKeyMask
) != 0; 
 835     // From the XLib manual: 
 836     // The XQueryKeymap() function returns a bit vector for the logical state of the keyboard,  
 837     // where each bit set to 1 indicates that the corresponding key is currently pressed down.  
 838     // The vector is represented as 32 bytes. Byte N (from 0) contains the bits for keys 8N to 8N + 7  
 839     // with the least-significant bit in the byte representing key 8N. 
 841     XQueryKeymap(pDisplay
, key_vector
); 
 842     return key_vector
[keyCode 
>> 3] & (1 << (keyCode 
& 7));  
 845 #endif // __WXX11__ || __WXGTK__ || __WXMOTIF__