--Boundary-00=_jbeiC22CmUVDToM Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: 7bit Content-Disposition: inline Hello, I'd like to get some feedback on the attached Qt patches :). The idea is based on a feature from the window manager called WindowLab (ggl:windowlab). In short, when a popup menu is open, the mouse movement is restricted only to the area of the popup - this allows navigating in the menus only using vertical movement and clicking. In not so short: When a popup is opened, the mouse area is restricted to its geometry plus 2 pixels above. The mouse pointer is initially positioned in that area above the popup, and clicking there closes it. Submenus don't open automatically, they always have to be clicked. The patch also significantly increases the mouse acceleration threshold, so that the mouse is less sensitive in the popup. This should have some advantages: - The already mentioned vertical-only movement. Since the mouse is restricted to the popup geometry, you cannot move it out by going far to the left or right. Opening a submenu restricts the y-position to the submenu's geometry, closing the submenu moves it back. It's not possible to accidentally open another submenu while trying to move the mouse to the right to a submenu. - Since the starting position is always at the topleft corner above the popup, one cannot accidentally click the bottommost Quit/Close/Whatever entry as sometimes happens with popups opened close to the bottom screen edge. This also means the navigation in the popup is always the same. The main disadvantage that I've found out so far is that it feels a bit odd, at least for the first five minutes, but since it seems to fit well together with the standalone menubar feature, which is also KDE-only, I guess this should not be a big problem ;). There are two #define's in the code that select whether to change the mouse acceleration threshold (CHANGE_ACCEL) and whether to restore the mouse position after closing a popup (RESET_MOUSE_POS). I'm not sure if they're better turned on or off. If people like this, I intend to clean up the patches and make it an optional KDE feature. -- Lubos Lunak KDE developer --------------------------------------------------------------------- SuSE CR, s.r.o. e-mail: l.lunak@suse.cz , l.lunak@kde.org Drahobejlova 27 tel: +420 2 9654 2373 190 00 Praha 9 fax: +420 2 9654 2374 Czech Republic http://www.suse.cz/ --Boundary-00=_jbeiC22CmUVDToM Content-Type: text/x-diff; charset="utf-8"; name="qapplication_x11.cpp.patch" Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename="qapplication_x11.cpp.patch" --- qapplication_x11.cpp.sav 2005-05-05 13:45:18.000000000 +0200 +++ qapplication_x11.cpp 2005-05-17 13:30:25.000000000 +0200 @@ -87,6 +87,7 @@ #include "qsettings.h" #include "qstylefactory.h" #include "qfileinfo.h" +#include "qpopupmenu.h" // Input method stuff - UNFINISHED #include "qinputcontext_p.h" @@ -3846,8 +3847,45 @@ bool qt_try_modal( QWidget *widget, XEve QWidget *widget The popup widget to be removed *****************************************************************************/ +#define RESET_MOUSE_POS +#define CHANGE_ACCEL + +static Window popupRegionWindow = None; +static QValueList< QPoint >* popupPointerPositions; +static void popupApplyRegion( QWidget* popup, bool set ) +{ + QRect r( 0, 0, XDisplayWidth( popup->x11Display(), popup->x11Screen()), + XDisplayHeight( popup->x11Display(), popup->x11Screen())); + QPopupMenu* p = qt_cast< QPopupMenu* >( popup ); + if( p ) { + r = p->contentsRect(); + r.moveBy( p->x(), p->y()); + r.addCoords( 0, -2, 0, 0 ); + if( set ) { + if( !popupPointerPositions ) { + popupPointerPositions = new QValueList< QPoint >; + Q_CHECK_PTR( popupPointerPositions ); + } + popupPointerPositions->append( QCursor::pos()); + } + } + XMoveResizeWindow( popup->x11Display(), popupRegionWindow, + r.x(), r.y(), r.width(), r.height()); + if( p ) { + if( set ) { + XWarpPointer( popup->x11Display(), None, popupRegionWindow, 0, 0, 0, 0, 0, 0 ); + } else { + QPoint p = popupPointerPositions->back(); + popupPointerPositions->pop_back(); +#ifdef RESET_MOUSE_POS + QCursor::setPos( p ); +#endif + } + } +} static int openPopupCount = 0; +static int accelthresh; void QApplication::openPopup( QWidget *popup ) { openPopupCount++; @@ -3858,6 +3896,15 @@ void QApplication::openPopup( QWidget *p popupWidgets->append( popup ); // add to end of list if ( popupWidgets->count() == 1 && !qt_nograb() ){ // grab mouse/keyboard + XSetWindowAttributes attrs; + attrs.override_redirect = True; + popupRegionWindow = XCreateWindow( popup->x11Display(), + RootWindow( popup->x11Display(), popup->x11Screen()), + 0, 0, 1, 1, 0, 0, + InputOnly, CopyFromParent, CWOverrideRedirect, &attrs ); + popupApplyRegion( popup, true ); + XLowerWindow( popup->x11Display(), popupRegionWindow ); + XMapWindow( popup->x11Display(), popupRegionWindow ); int r = XGrabKeyboard( popup->x11Display(), popup->winId(), FALSE, GrabModeSync, GrabModeAsync, CurrentTime ); if ( (popupGrabOk = (r == GrabSuccess)) ) { @@ -3866,14 +3913,20 @@ void QApplication::openPopup( QWidget *p ButtonMotionMask | EnterWindowMask | LeaveWindowMask | PointerMotionMask), GrabModeSync, GrabModeAsync, - None, None, CurrentTime ); + popupRegionWindow, None, CurrentTime ); if ( (popupGrabOk = (r == GrabSuccess)) ) XAllowEvents( popup->x11Display(), SyncPointer, CurrentTime ); else XUngrabKeyboard( popup->x11Display(), CurrentTime ); - } +#ifdef CHANGE_ACCEL + int dummy; + XGetPointerControl( popup->x11Display(), &dummy, &dummy, &accelthresh ); + XChangePointerControl( popup->x11Display(), False, True, 1, 1, 200 ); +#endif + } } else if ( popupGrabOk ) { + popupApplyRegion( popup, true ); XAllowEvents( popup->x11Display(), SyncPointer, CurrentTime ); } @@ -3901,6 +3954,9 @@ void QApplication::closePopup( QWidget * popupCloseDownMode = TRUE; // control mouse events delete popupWidgets; popupWidgets = 0; +#ifdef CHANGE_ACCEL + XChangePointerControl( popup->x11Display(), False, True, 1, 1, accelthresh ); +#endif if ( !qt_nograb() && popupGrabOk ) { // grabbing not disabled if ( mouseButtonState != 0 || popup->geometry(). contains(QPoint(mouseGlobalXPos, mouseGlobalYPos) ) ) @@ -3912,6 +3968,9 @@ void QApplication::closePopup( QWidget * XAllowEvents( popup->x11Display(), ReplayPointer,CurrentTime ); } XUngrabPointer( popup->x11Display(), CurrentTime ); + popupApplyRegion( popup, false ); + XDestroyWindow( popup->x11Display(), popupRegionWindow ); + popupRegionWindow = None; XFlush( popup->x11Display() ); } if ( active_window ) { @@ -3934,21 +3993,9 @@ void QApplication::closePopup( QWidget * else aw->setFocus(); QFocusEvent::resetReason(); - if ( popupWidgets->count() == 1 && !qt_nograb() ){ // grab mouse/keyboard - int r = XGrabKeyboard( aw->x11Display(), aw->winId(), FALSE, - GrabModeSync, GrabModeAsync, CurrentTime ); - if ( (popupGrabOk = (r == GrabSuccess)) ) { - r = XGrabPointer( aw->x11Display(), aw->winId(), TRUE, - (uint)(ButtonPressMask | ButtonReleaseMask | - ButtonMotionMask | EnterWindowMask | - LeaveWindowMask | PointerMotionMask), - GrabModeSync, GrabModeAsync, - None, None, CurrentTime ); - - if ( (popupGrabOk = (r == GrabSuccess)) ) - XAllowEvents( aw->x11Display(), SyncPointer, CurrentTime ); - } - } + if ( popupGrabOk ) { + popupApplyRegion( aw, false ); + } } } --Boundary-00=_jbeiC22CmUVDToM Content-Type: text/x-diff; charset="utf-8"; name="qpopupmenu.cpp.patch" Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename="qpopupmenu.cpp.patch" --- qpopupmenu.cpp.sav 2005-05-05 13:46:05.000000000 +0200 +++ qpopupmenu.cpp 2005-05-17 13:30:43.000000000 +0200 @@ -851,6 +851,7 @@ bool QPopupMenu::tryMenuBar( QMouseEvent */ bool QPopupMenu::tryMouseEvent( QPopupMenu *p, QMouseEvent * e) { + return false; if ( p == this ) return FALSE; QPoint pos = mapFromGlobal( e->globalPos() ); @@ -1598,7 +1599,7 @@ void QPopupMenu::mousePressEvent( QMouse int item = itemAtPos( e->pos() ); if ( item == -1 ) { if ( !rect().contains(e->pos()) && !tryMenuBar(e) ) { - byeMenuBar(); + hide(); } return; } @@ -1633,6 +1634,9 @@ void QPopupMenu::mouseReleaseEvent( QMou if ( !parentMenu && !mouseBtDn && actItem < 0 && motion < 6 ) return; + if( !mouseBtDn ) + return; + mouseBtDn = FALSE; // if the user released the mouse outside the menu, pass control @@ -1648,10 +1652,16 @@ void QPopupMenu::mouseReleaseEvent( QMou if ( actItem < 0 ) { // we do not have an active item // if the release is inside without motion (happens with // oversized popup menus on small screens), ignore it - if ( rect().contains( e->pos() ) && motion < 6 ) - return; - else - byeMenuBar(); +// if ( rect().contains( e->pos() ) && motion < 6 ) +// return; +// else +// hide(); + QMenuData* p = parentMenu; + hide(); +#ifndef QT_NO_MENUBAR + if ( p && p->isMenuBar ) + ((QMenuBar*) p)->goodbye( TRUE ); +#endif } else { // selected menu item! register QMenuItem *mi = mitems->at(actItem); if ( mi ->widget() ) { @@ -1747,13 +1757,13 @@ void QPopupMenu::mouseMoveEvent( QMouseE updateRow( lastActItem ); if ( lastActItem > 0 || ( !rect().contains( e->pos() ) && !tryMenuBar( e ) ) ) { - popupSubMenuLater(style().styleHint(QStyle::SH_PopupMenu_SubMenuPopupDelay, - this), this); +// popupSubMenuLater(style().styleHint(QStyle::SH_PopupMenu_SubMenuPopupDelay, +// this), this); } } else { // mouse on valid item // but did not register mouse press - if ( (e->state() & Qt::MouseButtonMask) && !mouseBtDn ) - mouseBtDn = TRUE; // so mouseReleaseEvent will pop down +// if ( (e->state() & Qt::MouseButtonMask) && !mouseBtDn ) +// mouseBtDn = TRUE; // so mouseReleaseEvent will pop down register QMenuItem *mi = mitems->at( item ); @@ -1772,14 +1782,14 @@ void QPopupMenu::mouseMoveEvent( QMouseE if ( style().styleHint(QStyle::SH_PopupMenu_SloppySubMenus, this) && d->mouseMoveBuffer.contains( e->pos() ) ) { actItem = item; - popupSubMenuLater( style().styleHint(QStyle::SH_PopupMenu_SubMenuPopupDelay, this) * 6, - this ); +// popupSubMenuLater( style().styleHint(QStyle::SH_PopupMenu_SubMenuPopupDelay, this) * 6, +// this ); return; } if ( mi->popup() || ( popupActive >= 0 && popupActive != item )) - popupSubMenuLater( style().styleHint(QStyle::SH_PopupMenu_SubMenuPopupDelay, this), - this ); +;// popupSubMenuLater( style().styleHint(QStyle::SH_PopupMenu_SubMenuPopupDelay, this), +// this ); else if ( singleSingleShot ) singleSingleShot->stop(); --Boundary-00=_jbeiC22CmUVDToM Content-Type: text/plain; charset="us-ascii" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit Content-Disposition: inline _______________________________________________ kde-usability mailing list kde-usability@kde.org https://mail.kde.org/mailman/listinfo/kde-usability --Boundary-00=_jbeiC22CmUVDToM--