VirtualBox

儲存庫 vbox 的更動 63553


忽略:
時間撮記:
2016-8-16 下午01:05:32 (8 年 以前)
作者:
vboxsync
訊息:

bugref:8151: FE/Qt: improve X11 keyboard capturing: revert r110029 for now.

檔案:
修改 1 筆資料

圖例:

未更動
新增
刪除
  • trunk/src/VBox/Frontends/VirtualBox/src/runtime/UIKeyboardHandler.cpp

    r63492 r63553  
    1414 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
    1515 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
    16  */
    17 
    18 /*
    19  * Things worth testing when changing this code:
    20  *  * That automatic keyboard capture works.
    21  *  * That the keyboard is captured when the mouse is.
    22  *  * That the host key releases the keyboard when the keyboard is captured
    23  *    but the mouse not, and both when both are.
    24  *  * That the keyboard is captured when the mouse capture notification is
    25  *    displayed.
    26  *  * That keyboard capture works on X11 hosts when windows are dragged with
    27  *    various window managers.
    28  *  * That multiple machine windows do not fight for the focus on X11 hosts
    29  *    (noticeable through strange modifier key and capitals behaviour).
    3016 */
    3117
     
    283269        return;
    284270
    285     /* On X11 we do not grab the keyboard as soon as it is captured, but delay it until the
    286      * first keypress after the capture.  We do this for several reasons.  First, when several
    287      * windows are created they all try to capture the keyboard when they get the focus.  Due to
    288      * the asynchronous nature of X11 the first window may only gets notified after the last is
    289      * created, and there is a dance if they respond to the notifications by grabbing the keyboard
    290      * and trigger new focus changes in the process.  Second, it is sometimes inconvenient to
    291      * grab the keyboard immediately on focus change: some window managers set the focus then
    292      * try to grab the keyboard themselves, and sulk if they fail by refusing to e.g. drag a
    293      * window using its title bar.  This code uses a hack by taking (ulong)~0 as a parameter to
    294      * finalise the capture. */
     271#if defined(VBOX_WS_X11) && QT_VERSION >= 0x050000
     272    /* Due to X11 async nature we may have lost the focus already by the time we get the focus
     273     * notification, so we do a sanity check that we still have it. If we don't have the focus
     274     * and grab the keyboard now that will cause focus change which we want to avoid. This change
     275     * potentially leads to a loop where two windows are continually responding to outdated focus events. */
     276    const xcb_get_input_focus_cookie_t xcbFocusCookie = xcb_get_input_focus(QX11Info::connection());
     277    xcb_get_input_focus_reply_t *pFocusReply = xcb_get_input_focus_reply(QX11Info::connection(), xcbFocusCookie, NULL);
     278    WId actualWinId = 0;
     279    if (pFocusReply)
     280    {
     281        actualWinId = pFocusReply->focus;
     282        free(pFocusReply);
     283    }
     284    else
     285        LogRel(("GUI: UIKeyboardHandler::captureKeyboard: XCB error on acquiring focus information detected!\n"));
     286    if (m_windows.value(uScreenId)->winId() != actualWinId)
     287        return;
     288
     289    /* Delay capturing the keyboard if the mouse button is held down and the mouse is not
     290     * captured to work around window managers which transfer the focus when the user
     291     * clicks in the title bar and then try to grab the keyboard and sulk if they fail.
     292     * If the click is inside of our views we will do the capture when it is released. */
     293    const xcb_query_pointer_cookie_t xcbPointerCookie = xcb_query_pointer(QX11Info::connection(), QX11Info::appRootWindow());
     294    xcb_query_pointer_reply_t *pPointerReply = xcb_query_pointer_reply(QX11Info::connection(), xcbPointerCookie, NULL);
     295    if (!uisession()->isMouseCaptured() && pPointerReply && (pPointerReply->mask & XCB_KEY_BUT_MASK_BUTTON_1))
     296    {
     297        free(pPointerReply);
     298        return;
     299    }
     300    free(pPointerReply);
     301#endif /* VBOX_WS_X11 && QT_VERSION >= 0x050000 */
    295302
    296303    /* If such view exists: */
    297     if (m_views.contains(uScreenId)
    298 #if defined(VBOX_WS_X11) && QT_VERSION >= 0x050000
    299         || ((uScreenId == (ulong)~0) && m_views.contains(m_idxDelayedKeyboardCaptureView))
    300 #endif
    301         )
     304    if (m_views.contains(uScreenId))
    302305    {
    303306#if defined(VBOX_WS_MAC)
     
    368371# else /* QT_VERSION >= 0x050000 */
    369372
    370         if (uScreenId != (ulong)~0)
    371         {
    372             m_idxDelayedKeyboardCaptureView = uScreenId;
    373             return;
    374         }
    375         uScreenId = m_idxDelayedKeyboardCaptureView;
    376373        /* On X11, we are using XCB stuff to grab the keyboard.
    377374         * This stuff is a part of the active keyboard grabbing functionality.
    378          * Active keyboard grabbing causes a problems on many window managers - a window cannot
     375         * Active keyboard grabbing causes a problems on certain old window managers - a window cannot
    379376         * be moved using the mouse. So we additionally grabbing the mouse as well to detect that user
    380377         * is trying to click outside of internal window geometry. */
    381378
    382         /* Grab the mouse button.  We do not check for failure as we do not currently implement a
    383          * back-up plan. */
    384         xcb_grab_button_checked(QX11Info::connection(), 0, QX11Info::appRootWindow(),
    385                                 XCB_EVENT_MASK_BUTTON_PRESS, XCB_GRAB_MODE_SYNC, XCB_GRAB_MODE_ASYNC,
    386                                 XCB_NONE, XCB_NONE, XCB_BUTTON_INDEX_1, XCB_MOD_MASK_ANY);
     379        /* Grab the mouse button (if mouse is not captured),
     380         * We do not check for failure as we do not currently implement a back-up plan. */
     381        if (!uisession()->isMouseCaptured())
     382            xcb_grab_button_checked(QX11Info::connection(), 0, QX11Info::appRootWindow(),
     383                                    XCB_EVENT_MASK_BUTTON_PRESS, XCB_GRAB_MODE_SYNC, XCB_GRAB_MODE_ASYNC,
     384                                    XCB_NONE, XCB_NONE, XCB_BUTTON_INDEX_1, XCB_MOD_MASK_ANY);
    387385        /* And grab the keyboard, using XCB directly, as Qt does not report failure. */
    388386        xcb_grab_keyboard_cookie_t xcbGrabCookie = xcb_grab_keyboard(QX11Info::connection(), false, m_views[uScreenId]->winId(),
     
    392390        {
    393391            /* Try again later: */
     392            m_idxDelayedKeyboardCaptureView = uScreenId;
    394393            free(pGrabReply);
    395394            return;
     
    13801379            /* If we were asked to grab the keyboard previously but had to delay it
    13811380             * then try again on every key press and release event until we manage: */
    1382             captureKeyboard((ulong)~0);
     1381            if (m_idxDelayedKeyboardCaptureView != -1)
     1382                captureKeyboard(m_idxDelayedKeyboardCaptureView);
    13831383
    13841384            /* Cast to XCB key-event: */
     
    14841484            }
    14851485            /* Else if the event happened outside of our view areas then release the keyboard,
    1486              * but capture it again (delayed) immediately.  If the event causes us to loose the
    1487              * focus then the delayed capture will not happen: */
     1486             * but set the delayed capture index so that it will be captured again if we still
     1487             * have the focus after the event is handled: */
    14881488            releaseKeyboard();
    1489             captureKeyboard(uScreenId);
     1489            m_idxDelayedKeyboardCaptureView = uScreenId;
    14901490            /* And re-send the event so that the window which it was meant for actually gets it: */
    14911491            xcb_allow_events_checked(QX11Info::connection(), XCB_ALLOW_REPLAY_POINTER, pButtonEvent->time);
     
    17991799                    if (!isAutoCaptureDisabled() && autoCaptureSetGlobally())
    18001800#endif /* !VBOX_WS_WIN */
     1801#if defined(VBOX_WS_X11) && QT_VERSION >= 0x050000
     1802                        m_idxDelayedKeyboardCaptureView = uScreenId;
     1803#else /* !VBOX_WS_X11 || QT_VERSION < 0x050000 */
    18011804                        captureKeyboard(uScreenId);
     1805#endif /* !VBOX_WS_X11 || QT_VERSION < 0x050000 */
    18021806                    /* Reset the single-time disable capture flag: */
    18031807                    if (isAutoCaptureDisabled())
注意: 瀏覽 TracChangeset 來幫助您使用更動檢視器

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette