1 /////////////////////////////////////////////////////////////////////////////
2 // Name: src/unix/utilsx11.cpp
3 // Purpose: Miscellaneous X11 functions (for wxCore)
4 // Author: Mattia Barbon, Vaclav Slavik, Robert Roebling
7 // Copyright: (c) wxWidgets team
8 // Licence: wxWindows licence
9 /////////////////////////////////////////////////////////////////////////////
11 #if defined(__WXX11__) || defined(__WXGTK__) || defined(__WXMOTIF__)
13 // for compilers that support precompilation, includes "wx.h".
14 #include "wx/wxprec.h"
16 #include "wx/unix/utilsx11.h"
25 #include "wx/iconbndl.h"
26 #include "wx/apptrait.h"
29 #pragma message disable nosimpint
32 #include <X11/Xatom.h>
33 #include <X11/Xutil.h>
35 #pragma message enable nosimpint
40 #ifdef GDK_WINDOWING_X11
45 // Only X11 backend is supported for wxGTK here
46 #if !defined(__WXGTK__) || defined(GDK_WINDOWING_X11)
48 // Various X11 Atoms used in this file:
49 static Atom _NET_WM_STATE
= 0;
50 static Atom _NET_WM_STATE_FULLSCREEN
= 0;
51 static Atom _NET_WM_STATE_STAYS_ON_TOP
= 0;
52 static Atom _NET_WM_WINDOW_TYPE
= 0;
53 static Atom _NET_WM_WINDOW_TYPE_NORMAL
= 0;
54 static Atom _KDE_NET_WM_WINDOW_TYPE_OVERRIDE
= 0;
55 static Atom _WIN_LAYER
= 0;
56 static Atom KWIN_RUNNING
= 0;
58 static Atom _NET_SUPPORTING_WM_CHECK
= 0;
59 static Atom _NET_SUPPORTED
= 0;
62 #define wxMAKE_ATOM(name, display) \
63 if (name == 0) name = XInternAtom((display), #name, False)
66 // X11 Window is an int type, so use the macro to suppress warnings when
68 #define WindowCast(w) (Window)(wxPtrToUInt(w))
70 // Is the window mapped?
71 static bool IsMapped(Display
*display
, Window window
)
73 XWindowAttributes attr
;
74 XGetWindowAttributes(display
, window
, &attr
);
75 return (attr
.map_state
!= IsUnmapped
);
80 // Suspends X11 errors. Used when we expect errors but they are not fatal
84 typedef int (*wxX11ErrorHandler
)(Display
*, XErrorEvent
*);
86 static int wxX11ErrorsSuspender_handler(Display
*, XErrorEvent
*) { return 0; }
89 class wxX11ErrorsSuspender
92 wxX11ErrorsSuspender(Display
*d
) : m_display(d
)
94 m_old
= XSetErrorHandler(wxX11ErrorsSuspender_handler
);
96 ~wxX11ErrorsSuspender()
99 XSetErrorHandler(m_old
);
104 wxX11ErrorHandler m_old
;
109 // ----------------------------------------------------------------------------
110 // Setting icons for window manager:
111 // ----------------------------------------------------------------------------
113 #if wxUSE_IMAGE && !wxUSE_NANOX
115 static Atom _NET_WM_ICON
= 0;
118 wxSetIconsX11(WXDisplay
* display
, WXWindow window
, const wxIconBundle
& ib
)
122 const size_t numIcons
= ib
.GetIconCount();
123 for ( size_t i
= 0; i
< numIcons
; ++i
)
125 const wxIcon icon
= ib
.GetIconByIndex(i
);
127 size
+= 2 + icon
.GetWidth() * icon
.GetHeight();
130 wxMAKE_ATOM(_NET_WM_ICON
, (Display
*)display
);
134 unsigned long* data
= new unsigned long[size
];
135 unsigned long* ptr
= data
;
137 for ( size_t i
= 0; i
< numIcons
; ++i
)
139 const wxImage image
= ib
.GetIconByIndex(i
).ConvertToImage();
140 int width
= image
.GetWidth(),
141 height
= image
.GetHeight();
142 unsigned char* imageData
= image
.GetData();
143 unsigned char* imageDataEnd
= imageData
+ ( width
* height
* 3 );
144 bool hasMask
= image
.HasMask();
145 unsigned char rMask
, gMask
, bMask
;
146 unsigned char r
, g
, b
, a
;
150 rMask
= image
.GetMaskRed();
151 gMask
= image
.GetMaskGreen();
152 bMask
= image
.GetMaskBlue();
154 else // no mask, but still init the variables to avoid warnings
164 while ( imageData
< imageDataEnd
)
169 if( hasMask
&& r
== rMask
&& g
== gMask
&& b
== bMask
)
174 *ptr
++ = ( a
<< 24 ) | ( r
<< 16 ) | ( g
<< 8 ) | b
;
180 XChangeProperty( (Display
*)display
,
185 (unsigned char*)data
, size
);
190 XDeleteProperty( (Display
*)display
,
196 #endif // wxUSE_IMAGE && !wxUSE_NANOX
198 // ----------------------------------------------------------------------------
200 // ----------------------------------------------------------------------------
202 // NB: Setting fullscreen mode under X11 is a complicated matter. There was
203 // no standard way of doing it until recently. ICCCM doesn't know the
204 // concept of fullscreen windows and the only way to make a window
205 // fullscreen is to remove decorations, resize it to cover entire screen
206 // and set WIN_LAYER_ABOVE_DOCK.
208 // This doesn't always work, though. Specifically, at least kwin from
209 // KDE 3 ignores the hint. The only way to make kwin accept our request
210 // is to emulate the way Qt does it. That is, unmap the window, set
211 // _NET_WM_WINDOW_TYPE to _KDE_NET_WM_WINDOW_TYPE_OVERRIDE (KDE extension),
212 // add _NET_WM_STATE_STAYS_ON_TOP (ditto) to _NET_WM_STATE and map
215 // Version 1.2 of Window Manager Specification (aka wm-spec aka
216 // Extended Window Manager Hints) introduced _NET_WM_STATE_FULLSCREEN
217 // window state which provides cleanest and simplest possible way of
218 // making a window fullscreen. WM-spec is a de-facto standard adopted
219 // by GNOME and KDE folks, but _NET_WM_STATE_FULLSCREEN isn't yet widely
220 // supported. As of January 2003, only GNOME 2's default WM Metacity
221 // implements, KDE will support it from version 3.2. At toolkits level,
222 // GTK+ >= 2.1.2 uses it as the only method of making windows fullscreen
223 // (that's why wxGTK will *not* switch to using gtk_window_fullscreen
224 // unless it has better compatibility with older WMs).
227 // This is what wxWidgets does in wxSetFullScreenStateX11:
228 // 1) if _NET_WM_STATE_FULLSCREEN is supported, use it
229 // 2) otherwise try WM-specific hacks (KDE, IceWM)
230 // 3) use _WIN_LAYER and hope that the WM will recognize it
231 // The code was tested with:
232 // twm, IceWM, WindowMaker, Metacity, kwin, sawfish, lesstif-mwm
235 #define WIN_LAYER_NORMAL 4
236 #define WIN_LAYER_ABOVE_DOCK 10
238 static void wxWinHintsSetLayer(Display
*display
, Window rootWnd
,
239 Window window
, int layer
)
241 wxX11ErrorsSuspender
noerrors(display
);
245 wxMAKE_ATOM( _WIN_LAYER
, display
);
247 if (IsMapped(display
, window
))
249 xev
.type
= ClientMessage
;
250 xev
.xclient
.type
= ClientMessage
;
251 xev
.xclient
.window
= window
;
252 xev
.xclient
.message_type
= _WIN_LAYER
;
253 xev
.xclient
.format
= 32;
254 xev
.xclient
.data
.l
[0] = (long)layer
;
255 xev
.xclient
.data
.l
[1] = CurrentTime
;
257 XSendEvent(display
, rootWnd
, False
,
258 SubstructureNotifyMask
, (XEvent
*) &xev
);
265 XChangeProperty(display
, window
,
266 _WIN_LAYER
, XA_CARDINAL
, 32,
267 PropModeReplace
, (unsigned char *)data
, 1);
274 static bool wxQueryWMspecSupport(Display
* WXUNUSED(display
),
275 Window
WXUNUSED(rootWnd
),
278 GdkAtom gatom
= gdk_x11_xatom_to_atom(feature
);
279 return gdk_x11_screen_supports_net_wm_hint(gdk_screen_get_default(), gatom
);
282 static bool wxQueryWMspecSupport(Display
*display
, Window rootWnd
, Atom feature
)
284 wxMAKE_ATOM(_NET_SUPPORTING_WM_CHECK
, display
);
285 wxMAKE_ATOM(_NET_SUPPORTED
, display
);
287 // FIXME: We may want to cache these checks. Note that we can't simply
288 // remember the results in global variable because the WM may go
289 // away and be replaced by another one! One possible approach
290 // would be invalidate the case every 15 seconds or so. Since this
291 // code is currently only used by wxTopLevelWindow::ShowFullScreen,
292 // it is not important that it is not optimized.
294 // If the WM supports ICCCM (i.e. the root window has
295 // _NET_SUPPORTING_WM_CHECK property that points to a WM-owned
296 // window), we could watch for DestroyNotify event on the window
297 // and invalidate our cache when the windows goes away (= WM
298 // is replaced by another one). This is what GTK+ 2 does.
299 // Let's do it only if it is needed, it requires changes to
307 unsigned long nwins
, natoms
;
309 // Is the WM ICCCM supporting?
310 XGetWindowProperty(display
, rootWnd
,
311 _NET_SUPPORTING_WM_CHECK
, 0, LONG_MAX
,
312 False
, XA_WINDOW
, &type
, &format
, &nwins
,
313 &after
, (unsigned char **)&wins
);
314 if ( type
!= XA_WINDOW
|| nwins
<= 0 || wins
[0] == None
)
318 // Query for supported features:
319 XGetWindowProperty(display
, rootWnd
,
320 _NET_SUPPORTED
, 0, LONG_MAX
,
321 False
, XA_ATOM
, &type
, &format
, &natoms
,
322 &after
, (unsigned char **)&atoms
);
323 if ( type
!= XA_ATOM
|| atoms
== NULL
)
326 // Lookup the feature we want:
327 for (unsigned i
= 0; i
< natoms
; i
++)
329 if ( atoms
[i
] == feature
)
341 #define _NET_WM_STATE_REMOVE 0
342 #define _NET_WM_STATE_ADD 1
344 static void wxWMspecSetState(Display
*display
, Window rootWnd
,
345 Window window
, int operation
, Atom state
)
347 wxMAKE_ATOM(_NET_WM_STATE
, display
);
349 if ( IsMapped(display
, window
) )
352 xev
.type
= ClientMessage
;
353 xev
.xclient
.type
= ClientMessage
;
354 xev
.xclient
.serial
= 0;
355 xev
.xclient
.send_event
= True
;
356 xev
.xclient
.display
= display
;
357 xev
.xclient
.window
= window
;
358 xev
.xclient
.message_type
= _NET_WM_STATE
;
359 xev
.xclient
.format
= 32;
360 xev
.xclient
.data
.l
[0] = operation
;
361 xev
.xclient
.data
.l
[1] = state
;
362 xev
.xclient
.data
.l
[2] = None
;
364 XSendEvent(display
, rootWnd
,
366 SubstructureRedirectMask
| SubstructureNotifyMask
,
369 // FIXME - must modify _NET_WM_STATE property list if the window
373 static void wxWMspecSetFullscreen(Display
*display
, Window rootWnd
,
374 Window window
, bool fullscreen
)
376 wxMAKE_ATOM(_NET_WM_STATE_FULLSCREEN
, display
);
377 wxWMspecSetState(display
, rootWnd
,
379 fullscreen
? _NET_WM_STATE_ADD
: _NET_WM_STATE_REMOVE
,
380 _NET_WM_STATE_FULLSCREEN
);
384 // Is the user running KDE's kwin window manager? At least kwin from KDE 3
385 // sets KWIN_RUNNING property on the root window.
386 static bool wxKwinRunning(Display
*display
, Window rootWnd
)
388 wxMAKE_ATOM(KWIN_RUNNING
, display
);
393 unsigned long nitems
, after
;
394 if (XGetWindowProperty(display
, rootWnd
,
395 KWIN_RUNNING
, 0, 1, False
, KWIN_RUNNING
,
396 &type
, &format
, &nitems
, &after
,
402 bool retval
= (type
== KWIN_RUNNING
&&
403 nitems
== 1 && data
&& ((long*)data
)[0] == 1);
408 // KDE's kwin is Qt-centric so much than no normal method of fullscreen
409 // mode will work with it. We have to carefully emulate the Qt way.
410 static void wxSetKDEFullscreen(Display
*display
, Window rootWnd
,
411 Window w
, bool fullscreen
, wxRect
*origRect
)
416 wxMAKE_ATOM(_NET_WM_WINDOW_TYPE
, display
);
417 wxMAKE_ATOM(_NET_WM_WINDOW_TYPE_NORMAL
, display
);
418 wxMAKE_ATOM(_KDE_NET_WM_WINDOW_TYPE_OVERRIDE
, display
);
419 wxMAKE_ATOM(_NET_WM_STATE_STAYS_ON_TOP
, display
);
423 data
[0] = _KDE_NET_WM_WINDOW_TYPE_OVERRIDE
;
424 data
[1] = _NET_WM_WINDOW_TYPE_NORMAL
;
429 data
[0] = _NET_WM_WINDOW_TYPE_NORMAL
;
434 // it is necessary to unmap the window, otherwise kwin will ignore us:
435 XSync(display
, False
);
437 bool wasMapped
= IsMapped(display
, w
);
440 XUnmapWindow(display
, w
);
441 XSync(display
, False
);
444 XChangeProperty(display
, w
, _NET_WM_WINDOW_TYPE
, XA_ATOM
, 32,
445 PropModeReplace
, (unsigned char *) &data
[0], lng
);
446 XSync(display
, False
);
450 XMapRaised(display
, w
);
451 XSync(display
, False
);
454 wxWMspecSetState(display
, rootWnd
, w
,
455 fullscreen
? _NET_WM_STATE_ADD
: _NET_WM_STATE_REMOVE
,
456 _NET_WM_STATE_STAYS_ON_TOP
);
457 XSync(display
, False
);
461 // NB: like many other WMs, kwin ignores the first request for a window
462 // position change after the window was mapped. This additional
463 // move+resize event will ensure that the window is restored in
464 // exactly the same position as before it was made fullscreen
465 // (because wxTopLevelWindow::ShowFullScreen will call SetSize, thus
466 // setting the position for the second time).
467 XMoveResizeWindow(display
, w
,
468 origRect
->x
, origRect
->y
,
469 origRect
->width
, origRect
->height
);
470 XSync(display
, False
);
475 wxX11FullScreenMethod
wxGetFullScreenMethodX11(WXDisplay
* display
,
478 Window root
= WindowCast(rootWindow
);
479 Display
*disp
= (Display
*)display
;
481 // if WM supports _NET_WM_STATE_FULLSCREEN from wm-spec 1.2, use it:
482 wxMAKE_ATOM(_NET_WM_STATE_FULLSCREEN
, disp
);
483 if (wxQueryWMspecSupport(disp
, root
, _NET_WM_STATE_FULLSCREEN
))
485 wxLogTrace(wxT("fullscreen"),
486 wxT("detected _NET_WM_STATE_FULLSCREEN support"));
487 return wxX11_FS_WMSPEC
;
490 // if the user is running KDE's kwin WM, use a legacy hack because
491 // kwin doesn't understand any other method:
492 if (wxKwinRunning(disp
, root
))
494 wxLogTrace(wxT("fullscreen"), wxT("detected kwin"));
498 // finally, fall back to ICCCM heuristic method:
499 wxLogTrace(wxT("fullscreen"), wxT("unknown WM, using _WIN_LAYER"));
500 return wxX11_FS_GENERIC
;
504 void wxSetFullScreenStateX11(WXDisplay
* display
, WXWindow rootWindow
,
505 WXWindow window
, bool show
,
507 wxX11FullScreenMethod method
)
509 // NB: please see the comment under "Fullscreen mode:" title above
510 // for implications of changing this code.
512 Window wnd
= WindowCast(window
);
513 Window root
= WindowCast(rootWindow
);
514 Display
*disp
= (Display
*)display
;
516 if (method
== wxX11_FS_AUTODETECT
)
517 method
= wxGetFullScreenMethodX11(display
, rootWindow
);
521 case wxX11_FS_WMSPEC
:
522 wxWMspecSetFullscreen(disp
, root
, wnd
, show
);
525 wxSetKDEFullscreen(disp
, root
, wnd
, show
, origRect
);
528 wxWinHintsSetLayer(disp
, root
, wnd
,
529 show
? WIN_LAYER_ABOVE_DOCK
: WIN_LAYER_NORMAL
);
536 // ----------------------------------------------------------------------------
537 // keycode translations
538 // ----------------------------------------------------------------------------
540 #include <X11/keysym.h>
542 // FIXME what about tables??
544 int wxCharCodeXToWX(WXKeySym keySym
)
551 id
= WXK_SHIFT
; break;
554 id
= WXK_CONTROL
; break;
559 id
= WXK_CAPITAL
; break;
561 id
= WXK_BACK
; break;
563 id
= WXK_DELETE
; break;
565 id
= WXK_CLEAR
; break;
571 id
= WXK_RETURN
; break;
573 id
= WXK_ESCAPE
; break;
576 id
= WXK_PAUSE
; break;
578 id
= WXK_NUMLOCK
; break;
580 id
= WXK_SCROLL
; break;
583 id
= WXK_HOME
; break;
587 id
= WXK_LEFT
; break;
589 id
= WXK_RIGHT
; break;
593 id
= WXK_DOWN
; break;
595 id
= WXK_PAGEDOWN
; break;
597 id
= WXK_PAGEUP
; break;
599 id
= WXK_MENU
; break;
601 id
= WXK_SELECT
; break;
603 id
= WXK_CANCEL
; break;
605 id
= WXK_PRINT
; break;
607 id
= WXK_EXECUTE
; break;
609 id
= WXK_INSERT
; break;
611 id
= WXK_HELP
; break;
614 id
= WXK_NUMPAD_MULTIPLY
; break;
616 id
= WXK_NUMPAD_ADD
; break;
618 id
= WXK_NUMPAD_SUBTRACT
; break;
620 id
= WXK_NUMPAD_DIVIDE
; break;
622 id
= WXK_NUMPAD_DECIMAL
; break;
624 id
= WXK_NUMPAD_EQUAL
; break;
626 id
= WXK_NUMPAD_SPACE
; break;
628 id
= WXK_NUMPAD_TAB
; break;
630 id
= WXK_NUMPAD_ENTER
; break;
632 id
= WXK_NUMPAD0
; break;
634 id
= WXK_NUMPAD1
; break;
636 id
= WXK_NUMPAD2
; break;
638 id
= WXK_NUMPAD3
; break;
640 id
= WXK_NUMPAD4
; break;
642 id
= WXK_NUMPAD5
; break;
644 id
= WXK_NUMPAD6
; break;
646 id
= WXK_NUMPAD7
; break;
648 id
= WXK_NUMPAD8
; break;
650 id
= WXK_NUMPAD9
; break;
652 id
= WXK_NUMPAD_INSERT
; break;
654 id
= WXK_NUMPAD_END
; break;
656 id
= WXK_NUMPAD_DOWN
; break;
657 case XK_KP_Page_Down
:
658 id
= WXK_NUMPAD_PAGEDOWN
; break;
660 id
= WXK_NUMPAD_LEFT
; break;
662 id
= WXK_NUMPAD_RIGHT
; break;
664 id
= WXK_NUMPAD_HOME
; break;
666 id
= WXK_NUMPAD_UP
; break;
668 id
= WXK_NUMPAD_PAGEUP
; break;
718 id
= (keySym
<= 255) ? (int)keySym
: -1;
724 WXKeySym
wxCharCodeWXToX(int id
)
730 case WXK_CANCEL
: keySym
= XK_Cancel
; break;
731 case WXK_BACK
: keySym
= XK_BackSpace
; break;
732 case WXK_TAB
: keySym
= XK_Tab
; break;
733 case WXK_CLEAR
: keySym
= XK_Clear
; break;
734 case WXK_RETURN
: keySym
= XK_Return
; break;
735 case WXK_SHIFT
: keySym
= XK_Shift_L
; break;
736 case WXK_CONTROL
: keySym
= XK_Control_L
; break;
737 case WXK_ALT
: keySym
= XK_Meta_L
; break;
738 case WXK_CAPITAL
: keySym
= XK_Caps_Lock
; break;
739 case WXK_MENU
: keySym
= XK_Menu
; break;
740 case WXK_PAUSE
: keySym
= XK_Pause
; break;
741 case WXK_ESCAPE
: keySym
= XK_Escape
; break;
742 case WXK_SPACE
: keySym
= ' '; break;
743 case WXK_PAGEUP
: keySym
= XK_Prior
; break;
744 case WXK_PAGEDOWN
: keySym
= XK_Next
; break;
745 case WXK_END
: keySym
= XK_End
; break;
746 case WXK_HOME
: keySym
= XK_Home
; break;
747 case WXK_LEFT
: keySym
= XK_Left
; break;
748 case WXK_UP
: keySym
= XK_Up
; break;
749 case WXK_RIGHT
: keySym
= XK_Right
; break;
750 case WXK_DOWN
: keySym
= XK_Down
; break;
751 case WXK_SELECT
: keySym
= XK_Select
; break;
752 case WXK_PRINT
: keySym
= XK_Print
; break;
753 case WXK_EXECUTE
: keySym
= XK_Execute
; break;
754 case WXK_INSERT
: keySym
= XK_Insert
; break;
755 case WXK_DELETE
: keySym
= XK_Delete
; break;
756 case WXK_HELP
: keySym
= XK_Help
; break;
757 case WXK_NUMPAD0
: keySym
= XK_KP_0
; break; case WXK_NUMPAD_INSERT
: keySym
= XK_KP_Insert
; break;
758 case WXK_NUMPAD1
: keySym
= XK_KP_1
; break; case WXK_NUMPAD_END
: keySym
= XK_KP_End
; break;
759 case WXK_NUMPAD2
: keySym
= XK_KP_2
; break; case WXK_NUMPAD_DOWN
: keySym
= XK_KP_Down
; break;
760 case WXK_NUMPAD3
: keySym
= XK_KP_3
; break; case WXK_NUMPAD_PAGEDOWN
: keySym
= XK_KP_Page_Down
; break;
761 case WXK_NUMPAD4
: keySym
= XK_KP_4
; break; case WXK_NUMPAD_LEFT
: keySym
= XK_KP_Left
; break;
762 case WXK_NUMPAD5
: keySym
= XK_KP_5
; break;
763 case WXK_NUMPAD6
: keySym
= XK_KP_6
; break; case WXK_NUMPAD_RIGHT
: keySym
= XK_KP_Right
; break;
764 case WXK_NUMPAD7
: keySym
= XK_KP_7
; break; case WXK_NUMPAD_HOME
: keySym
= XK_KP_Home
; break;
765 case WXK_NUMPAD8
: keySym
= XK_KP_8
; break; case WXK_NUMPAD_UP
: keySym
= XK_KP_Up
; break;
766 case WXK_NUMPAD9
: keySym
= XK_KP_9
; break; case WXK_NUMPAD_PAGEUP
: keySym
= XK_KP_Page_Up
; break;
767 case WXK_NUMPAD_DECIMAL
: keySym
= XK_KP_Decimal
; break; case WXK_NUMPAD_DELETE
: keySym
= XK_KP_Delete
; break;
768 case WXK_NUMPAD_MULTIPLY
: keySym
= XK_KP_Multiply
; break;
769 case WXK_NUMPAD_ADD
: keySym
= XK_KP_Add
; break;
770 case WXK_NUMPAD_SUBTRACT
: keySym
= XK_KP_Subtract
; break;
771 case WXK_NUMPAD_DIVIDE
: keySym
= XK_KP_Divide
; break;
772 case WXK_NUMPAD_ENTER
: keySym
= XK_KP_Enter
; break;
773 case WXK_NUMPAD_SEPARATOR
: keySym
= XK_KP_Separator
; break;
774 case WXK_F1
: keySym
= XK_F1
; break;
775 case WXK_F2
: keySym
= XK_F2
; break;
776 case WXK_F3
: keySym
= XK_F3
; break;
777 case WXK_F4
: keySym
= XK_F4
; break;
778 case WXK_F5
: keySym
= XK_F5
; break;
779 case WXK_F6
: keySym
= XK_F6
; break;
780 case WXK_F7
: keySym
= XK_F7
; break;
781 case WXK_F8
: keySym
= XK_F8
; break;
782 case WXK_F9
: keySym
= XK_F9
; break;
783 case WXK_F10
: keySym
= XK_F10
; break;
784 case WXK_F11
: keySym
= XK_F11
; break;
785 case WXK_F12
: keySym
= XK_F12
; break;
786 case WXK_F13
: keySym
= XK_F13
; break;
787 case WXK_F14
: keySym
= XK_F14
; break;
788 case WXK_F15
: keySym
= XK_F15
; break;
789 case WXK_F16
: keySym
= XK_F16
; break;
790 case WXK_F17
: keySym
= XK_F17
; break;
791 case WXK_F18
: keySym
= XK_F18
; break;
792 case WXK_F19
: keySym
= XK_F19
; break;
793 case WXK_F20
: keySym
= XK_F20
; break;
794 case WXK_F21
: keySym
= XK_F21
; break;
795 case WXK_F22
: keySym
= XK_F22
; break;
796 case WXK_F23
: keySym
= XK_F23
; break;
797 case WXK_F24
: keySym
= XK_F24
; break;
798 case WXK_NUMLOCK
: keySym
= XK_Num_Lock
; break;
799 case WXK_SCROLL
: keySym
= XK_Scroll_Lock
; break;
800 default: keySym
= id
<= 255 ? (KeySym
)id
: 0;
807 // ----------------------------------------------------------------------------
808 // check current state of a key
809 // ----------------------------------------------------------------------------
811 bool wxGetKeyState(wxKeyCode key
)
813 wxASSERT_MSG(key
!= WXK_LBUTTON
&& key
!= WXK_RBUTTON
&& key
!=
814 WXK_MBUTTON
, wxT("can't use wxGetKeyState() for mouse buttons"));
816 Display
*pDisplay
= (Display
*) wxGetDisplay();
818 int iKey
= wxCharCodeWXToX(key
);
820 Window wDummy1
, wDummy2
;
821 int iDummy3
, iDummy4
, iDummy5
, iDummy6
;
823 KeyCode keyCode
= XKeysymToKeycode(pDisplay
,iKey
);
824 if (keyCode
== NoSymbol
)
827 if ( IsModifierKey(iKey
) ) // If iKey is a modifier key, use a different method
829 XModifierKeymap
*map
= XGetModifierMapping(pDisplay
);
830 wxCHECK_MSG( map
, false, wxT("failed to get X11 modifiers map") );
832 for (int i
= 0; i
< 8; ++i
)
834 if ( map
->modifiermap
[map
->max_keypermod
* i
] == keyCode
)
840 XQueryPointer(pDisplay
, DefaultRootWindow(pDisplay
), &wDummy1
, &wDummy2
,
841 &iDummy3
, &iDummy4
, &iDummy5
, &iDummy6
, &iMask
);
842 XFreeModifiermap(map
);
843 return (iMask
& iKeyMask
) != 0;
846 // From the XLib manual:
847 // The XQueryKeymap() function returns a bit vector for the logical state of the keyboard,
848 // where each bit set to 1 indicates that the corresponding key is currently pressed down.
849 // The vector is represented as 32 bytes. Byte N (from 0) contains the bits for keys 8N to 8N + 7
850 // with the least-significant bit in the byte representing key 8N.
852 XQueryKeymap(pDisplay
, key_vector
);
853 return key_vector
[keyCode
>> 3] & (1 << (keyCode
& 7));
856 #endif // !defined(__WXGTK__) || defined(GDK_WINDOWING_X11)
858 // ----------------------------------------------------------------------------
859 // Launch document with default app
860 // ----------------------------------------------------------------------------
862 bool wxLaunchDefaultApplication(const wxString
& document
, int flags
)
866 // Our best best is to use xdg-open from freedesktop.org cross-desktop
867 // compatibility suite xdg-utils
868 // (see http://portland.freedesktop.org/wiki/) -- this is installed on
869 // most modern distributions and may be tweaked by them to handle
870 // distribution specifics.
871 wxString path
, xdg_open
;
872 if ( wxGetEnv("PATH", &path
) &&
873 wxFindFileInPath(&xdg_open
, path
, "xdg-open") )
875 if ( wxExecute(xdg_open
+ " " + document
) )
882 // ----------------------------------------------------------------------------
883 // Launch default browser
884 // ----------------------------------------------------------------------------
886 bool wxDoLaunchDefaultBrowser(const wxString
& url
, int flags
)
890 // Our best best is to use xdg-open from freedesktop.org cross-desktop
891 // compatibility suite xdg-utils
892 // (see http://portland.freedesktop.org/wiki/) -- this is installed on
893 // most modern distributions and may be tweaked by them to handle
894 // distribution specifics. Only if that fails, try to find the right
895 // browser ourselves.
896 wxString path
, xdg_open
;
897 if ( wxGetEnv("PATH", &path
) &&
898 wxFindFileInPath(&xdg_open
, path
, "xdg-open") )
900 if ( wxExecute(xdg_open
+ " " + url
) )
904 wxString desktop
= wxTheApp
->GetTraits()->GetDesktopEnvironment();
906 // GNOME and KDE desktops have some applications which should be always installed
907 // together with their main parts, which give us the
908 if (desktop
== wxT("GNOME"))
910 wxArrayString errors
;
911 wxArrayString output
;
913 // gconf will tell us the path of the application to use as browser
914 long res
= wxExecute( wxT("gconftool-2 --get /desktop/gnome/applications/browser/exec"),
915 output
, errors
, wxEXEC_NODISABLE
);
916 if (res
>= 0 && errors
.GetCount() == 0)
918 wxString cmd
= output
[0];
919 cmd
<< wxT(' ') << url
;
924 else if (desktop
== wxT("KDE"))
926 // kfmclient directly opens the given URL
927 if (wxExecute(wxT("kfmclient openURL ") + url
))
934 #endif // __WXX11__ || __WXGTK__ || __WXMOTIF__