diff options
author | Jon TURNEY <jon.turney@dronecode.org.uk> | 2013-06-27 23:56:23 +0100 |
---|---|---|
committer | Jon TURNEY <jon.turney@dronecode.org.uk> | 2014-03-03 14:33:09 +0000 |
commit | b634e909895f6001e7d9543e1350b20c82c8c01c (patch) | |
tree | 8643d6369d572b1ab111eacc0a7341ae0916aea2 /hw | |
parent | 0fc84a2bb6970f6b05a19cd8b32a7f3f7fd148b3 (diff) |
hw/xwin: More closely follow ICCCM for setting input focus
In multiwindow mode, more closely follow ICCCM section 4.1.7 when setting X
input focus to a window when the native Windows window acquires input focus:
- If InputHint is FALSE, don't use XSetInputFocus()
- If the window supports the WM_TAKE_FOCUS protocol, send a WM_TAKE_FOCUS message
This helps JDK 1.7 clients acquire the focus correctly.
Also, factor out checking client support for a given WM_PROTOCOLS protocol as a
separate function.
Signed-off-by: Jon TURNEY <jon.turney@dronecode.org.uk>
Reviewed-by: Colin Harrison <colin.harrison@virgin.net>
Diffstat (limited to 'hw')
-rw-r--r-- | hw/xwin/winmultiwindowwm.c | 77 |
1 files changed, 59 insertions, 18 deletions
diff --git a/hw/xwin/winmultiwindowwm.c b/hw/xwin/winmultiwindowwm.c index c6da7772c..9f12521bc 100644 --- a/hw/xwin/winmultiwindowwm.c +++ b/hw/xwin/winmultiwindowwm.c @@ -111,6 +111,7 @@ typedef struct _WMInfo { WMMsgQueueRec wmMsgQueue; Atom atmWmProtos; Atom atmWmDelete; + Atom atmWmTakeFocus; Atom atmPrivMap; Bool fAllowOtherWM; } WMInfoRec, *WMInfoPtr; @@ -453,6 +454,27 @@ GetWindowName(Display * pDisplay, Window iWin, char **ppWindowName) } /* + * Does the client support the specified WM_PROTOCOLS protocol? + */ + +static Bool +IsWmProtocolAvailable(Display * pDisplay, Window iWindow, Atom atmProtocol) +{ + int i, n, found = 0; + Atom *protocols; + + if (XGetWMProtocols(pDisplay, iWindow, &protocols, &n)) { + for (i = 0; i < n; ++i) + if (protocols[i] == atmProtocol) + ++found; + + XFree(protocols); + } + + return found > 0; +} + +/* * Send a message to the X server from the WM thread */ @@ -805,21 +827,10 @@ winMultiWindowWMProc(void *pArg) ErrorF("\tWM_WM_KILL\n"); #endif { - int i, n, found = 0; - Atom *protocols; - - /* --- */ - if (XGetWMProtocols(pWMInfo->pDisplay, - pNode->msg.iWindow, &protocols, &n)) { - for (i = 0; i < n; ++i) - if (protocols[i] == pWMInfo->atmWmDelete) - ++found; - - XFree(protocols); - } - /* --- */ - if (found) + if (IsWmProtocolAvailable(pWMInfo->pDisplay, + pNode->msg.iWindow, + pWMInfo->atmWmDelete)) SendXMessage(pWMInfo->pDisplay, pNode->msg.iWindow, pWMInfo->atmWmProtos, pWMInfo->atmWmDelete); @@ -832,11 +843,39 @@ winMultiWindowWMProc(void *pArg) #if CYGMULTIWINDOW_DEBUG ErrorF("\tWM_WM_ACTIVATE\n"); #endif - /* Set the input focus */ - XSetInputFocus(pWMInfo->pDisplay, - pNode->msg.iWindow, - RevertToPointerRoot, CurrentTime); + + /* + ICCCM 4.1.7 is pretty opaque, but it appears that the rules are + actually quite simple: + -- the WM_HINTS input field determines whether the WM should call + XSetInputFocus() + -- independently, the WM_TAKE_FOCUS protocol determines whether + the WM should send a WM_TAKE_FOCUS ClientMessage. + */ + { + Bool neverFocus = FALSE; + XWMHints *hints = XGetWMHints(pWMInfo->pDisplay, pNode->msg.iWindow); + + if (hints) { + if (hints->flags & InputHint) + neverFocus = !hints->input; + XFree(hints); + } + + if (!neverFocus) + XSetInputFocus(pWMInfo->pDisplay, + pNode->msg.iWindow, + RevertToPointerRoot, CurrentTime); + + if (IsWmProtocolAvailable(pWMInfo->pDisplay, + pNode->msg.iWindow, + pWMInfo->atmWmTakeFocus)) + SendXMessage(pWMInfo->pDisplay, + pNode->msg.iWindow, + pWMInfo->atmWmProtos, pWMInfo->atmWmTakeFocus); + + } break; case WM_WM_NAME_EVENT: @@ -1404,6 +1443,8 @@ winInitMultiWindowWM(WMInfoPtr pWMInfo, WMProcArgPtr pProcArg) "WM_PROTOCOLS", False); pWMInfo->atmWmDelete = XInternAtom(pWMInfo->pDisplay, "WM_DELETE_WINDOW", False); + pWMInfo->atmWmTakeFocus = XInternAtom(pWMInfo->pDisplay, + "WM_TAKE_FOCUS", False); pWMInfo->atmPrivMap = XInternAtom(pWMInfo->pDisplay, WINDOWSWM_NATIVE_HWND, False); |