VirtualBox

Changeset 64831 in vbox


Ignore:
Timestamp:
Dec 12, 2016 11:14:22 AM (8 years ago)
Author:
vboxsync
Message:

bugref:8151: FE/Qt: improve X11 keyboard capturing: simplify passing through of mouse clicks when the keyboard is captured. Instead of trying to inject them into the Qt event handlers if they are for us, just let X11 re-send them and do not intercept them the second time. This works better with the different ways Qt plug-ins might and do handle X11 input and also makes mouse drags (implicit button grabs) work which start inside our window and continue outside it. This notably makes dragging guest windows in seamless mode work again.

Location:
trunk/src/VBox/Frontends/VirtualBox/src/runtime
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/Frontends/VirtualBox/src/runtime/UIKeyboardHandler.cpp

    r64181 r64831  
    366366         * This stuff is a part of the active keyboard grabbing functionality.
    367367         * Active keyboard grabbing causes a problems on many window managers - a window cannot
    368          * be moved using the mouse. So we additionally grabbing the mouse as well to detect that
    369          * user is trying to click outside of internal window geometry. */
    370 
    371          /* Grab the mouse button if the cursor is outside of our views.
     368         * be moved using the mouse. So we additionally grab the mouse buttons as well to detect
     369         * that the user is trying to click outside of the internal window geometry and release
     370         * the keyboard before the target window sees the click. (GNOME Shell's hot corner has
     371         * the same problem. At present we just let that problem be.) */
     372
     373         /* Grab the mouse button.
    372374          * We do not check for failure as we do not currently implement a back-up plan. */
    373          if (!isItListenedView(QApplication::widgetAt(QCursor::pos())))
    374              xcb_grab_button_checked(QX11Info::connection(), 0, QX11Info::appRootWindow(),
    375                                      XCB_EVENT_MASK_BUTTON_PRESS, XCB_GRAB_MODE_SYNC, XCB_GRAB_MODE_ASYNC,
    376                                      XCB_NONE, XCB_NONE, XCB_BUTTON_INDEX_ANY, XCB_MOD_MASK_ANY);
     375         xcb_grab_button_checked(QX11Info::connection(), 0, QX11Info::appRootWindow(),
     376                                 XCB_EVENT_MASK_BUTTON_PRESS, XCB_GRAB_MODE_SYNC, XCB_GRAB_MODE_ASYNC,
     377                                 XCB_NONE, XCB_NONE, XCB_BUTTON_INDEX_ANY, XCB_MOD_MASK_ANY);
    377378        /* And grab the keyboard, using XCB directly, as Qt does not report failure. */
    378379        xcb_grab_keyboard_cookie_t xcbGrabCookie = xcb_grab_keyboard(QX11Info::connection(), false, m_views[m_iKeyboardCaptureViewIndex]->winId(),
     
    17741775                break;
    17751776            }
    1776 #if defined(VBOX_WS_X11) && QT_VERSION >= 0x050000
    1777             case QEvent::Enter:
    1778             {
    1779                 /* Release the mouse button grab.
    1780                  * We do not check for failure as we do not currently implement a back-up plan. */
    1781                 xcb_ungrab_button_checked(QX11Info::connection(), XCB_BUTTON_INDEX_ANY,
    1782                                           QX11Info::appRootWindow(), XCB_MOD_MASK_ANY);
    1783 
    1784                 break;
    1785             }
    1786             case QEvent::Leave:
    1787             {
    1788                 /* Grab the mouse button if the keyboard is captured.
    1789                  * We do not check for failure as we do not currently implement a back-up plan. */
    1790                 if (m_fIsKeyboardCaptured)
    1791                     xcb_grab_button_checked(QX11Info::connection(), 0, QX11Info::appRootWindow(),
    1792                                             XCB_EVENT_MASK_BUTTON_PRESS, XCB_GRAB_MODE_SYNC, XCB_GRAB_MODE_ASYNC,
    1793                                             XCB_NONE, XCB_NONE, XCB_BUTTON_INDEX_ANY, XCB_MOD_MASK_ANY);
    1794 
    1795                 break;
    1796             }
    1797 #endif /* VBOX_WS_X11 && QT_VERSION >= 0x050000 */
    17981777            case QEvent::KeyPress:
    17991778            case QEvent::KeyRelease:
  • trunk/src/VBox/Frontends/VirtualBox/src/runtime/UIMouseHandler.cpp

    r63601 r64831  
    375375                break;
    376376
    377             /* If we see a mouse press outside of our views while the mouse is not
    378              * captured, release the keyboard before letting the event owner see it.
    379              * This is because some owners cannot deal with failures to grab the
    380              * keyboard themselves (e.g. window managers dragging windows).
    381              * Only works if we have passively grabbed the mouse button. */
     377            /* If we see a mouse press from a grab while the mouse is not captured,
     378             * release the keyboard before letting the event owner see it. This is
     379             * because some owners cannot deal with failures to grab the keyboard
     380             * themselves (e.g. window managers dragging windows). */
    382381
    383382            /* Cast to XCB button-event: */
    384383            xcb_button_press_event_t *pButtonEvent = static_cast<xcb_button_press_event_t*>(pMessage);
    385384
    386             /* Detect the widget which should receive the event actually: */
    387             const QWidget *pWidget = qApp->widgetAt(pButtonEvent->root_x, pButtonEvent->root_y);
    388             if (pWidget)
     385            /* If this event is from our button grab then it will be reported relative to the root
     386             * window and not to ours. In that case release the keyboard capture, re-capture it
     387             * delayed, which will fail if we have lost the input focus in the mean-time, replay
     388             * the button event for normal delivery (possibly straight back to us, but not relative
     389             * to root this time) and tell Qt not to further process this event: */
     390            if (pButtonEvent->event == pButtonEvent->root)
    389391            {
    390                 /* Redirect the event to corresponding widget: */
    391                 const QPoint pos = pWidget->mapFromGlobal(QPoint(pButtonEvent->root_x, pButtonEvent->root_y));
    392                 pButtonEvent->event = pWidget->effectiveWinId();
    393                 pButtonEvent->event_x = pos.x();
    394                 pButtonEvent->event_y = pos.y();
    395                 xcb_ungrab_pointer_checked(QX11Info::connection(), pButtonEvent->time);
    396                 break;
     392                machineLogic()->keyboardHandler()->releaseKeyboard();
     393                /** @todo It would be nicer to do this in the normal Qt button event
     394                  *       handler to avoid avoidable races if the event was not for us. */
     395                machineLogic()->keyboardHandler()->captureKeyboard(uScreenId);
     396                /* Re-send the event so that the window which it was meant for gets it: */
     397                xcb_allow_events_checked(QX11Info::connection(), XCB_ALLOW_REPLAY_POINTER, pButtonEvent->time);
     398                /* Do not let Qt see the event: */
     399                return true;
    397400            }
    398             /* Else if the event happened outside of our view areas then release the keyboard,
    399              * but capture it again (delayed) immediately. If the event causes us to loose the
    400              * focus then the delayed capture will not happen: */
    401             machineLogic()->keyboardHandler()->releaseKeyboard();
    402             machineLogic()->keyboardHandler()->captureKeyboard(uScreenId);
    403             /* And re-send the event so that the window which it was meant for actually gets it: */
    404             xcb_allow_events_checked(QX11Info::connection(), XCB_ALLOW_REPLAY_POINTER, pButtonEvent->time);
    405             break;
    406401        }
    407402        default:
     
    761756                {
    762757                    QMouseEvent *pMouseEvent = static_cast<QMouseEvent*>(pEvent);
     758#if defined(VBOX_WS_X11) && QT_VERSION >= 0x050000
     759                    /* When the keyboard is captured, we also capture mouse button
     760                     * events, and release the keyboard and re-capture it delayed
     761                     * on every mouse click. When the click is inside our window
     762                     * area though the delay is not needed or wanted. Calling
     763                     * finaliseCaptureKeyboard() skips the delay if a delayed
     764                     * capture is in progress and has no effect if not: */
     765                    if (pEvent->type() == QEvent::MouseButtonPress)
     766                        machineLogic()->keyboardHandler()->finaliseCaptureKeyboard();
     767#endif /* VBOX_WS_X11 && QT_VERSION >= 0x050000 */
    763768                    m_iLastMouseWheelDelta = 0;
    764769                    if (mouseEvent(pMouseEvent->type(), uScreenId,
Note: See TracChangeset for help on using the changeset viewer.

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