[prev in list] [next in list] [prev in thread] [next in thread]
List: kde-usability
Subject: Re: RFC: Restricting mouse in popup menus
From: Lubos Lunak <l.lunak () suse ! cz>
Date: 2005-05-18 14:52:20
Message-ID: 200505181652.21090.l.lunak () suse ! cz
[Download RAW message or body]
On Tuesday 17 of May 2005 21:59, Diego Moya (a.k.a. TuringTest) wrote:
> On 17/05/05, Lubos Lunak <l.lunak@suse.cz> wrote:
> > 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.
>
> I would allow it but only as long as the mouse button is pressed, thus
> turning it into a quasimode.
> ( http://www.answers.com/main/ntquery?s=quasimode ).
Hmm, the definition means nothing to me other than being a definition.
As for keeping the mouse pressed, the intention is to make navigation in the
menus easier. I don't think having to keep a mouse button pressed helps that,
rather the other way around.
>
> > 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 ;).
>
> The reason it feels odd is because it breaks one of the main
> established dogmas of GUIs, that of the mouse always moving freely no
> matter the state of the system. A really big consistency break. Not
> good.
I didn't know there was such a dogma. Actually the reason why it felt odd for
me was that the computer was moving the mouse instead of me (which I'm sure
is also described among some dogmas as a no-no).
>
> In general, restricting the movement of the mouse to a section of the
> screen is a bad idea, because it forbids the user to change her mind
> an beginning a different task. In particular, it would make impossible
> to cancel the menu without making a selection.
That's why there's the area at the top where clicking cancels the menu.
> Changing the cursor image or hiding it while the quasimode is active
> would solve this problem by clearly changing the perception of the
> user on what's happening.
Sounds like a very good idea ... *checking* ... hmm, now there's one more
#define NO_CURSOR. Either there's no cursor at all, so there's no longer
"restricted" mouse movement, but perhaps it's too strange to have no cursor
at all, or there's a different arrow shape.
Are the attached patches better?
--
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/
["qapplication_x11.cpp.patch" (text/x-diff)]
--- qapplication_x11.cpp.sav 2005-04-11 13:09:46.000000000 +0200
+++ qapplication_x11.cpp 2005-05-18 16:16:34.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"
@@ -3847,8 +3848,50 @@ bool qt_try_modal( QWidget *widget, XEve
QWidget *widget The popup widget to be removed
*****************************************************************************/
+#define CHANGE_ACCEL
+#define NO_CURSOR
+//#define RESET_MOUSE_POS
+#if defined(NO_CURSOR) && !defined(RESET_MOUSE_POS)
+#define RESET_MOUSE_POS
+#endif
+#include <X11/cursorfont.h>
+
+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++;
@@ -3859,22 +3902,44 @@ 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)) ) {
+#ifndef NO_CURSOR
+ static Cursor cur = XCreateFontCursor( popup->x11Display(), XC_arrow );
+#endif
r = XGrabPointer( popup->x11Display(), popup->winId(), TRUE,
(uint)(ButtonPressMask | ButtonReleaseMask |
ButtonMotionMask | EnterWindowMask |
LeaveWindowMask | PointerMotionMask),
GrabModeSync, GrabModeAsync,
- None, None, CurrentTime );
+#ifdef NO_CURSOR
+ popupRegionWindow, blankCursor.handle(), CurrentTime );
+#else
+ popupRegionWindow, cur, CurrentTime );
+#endif
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 );
}
@@ -3902,6 +3967,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) ) )
@@ -3913,6 +3981,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 ) {
@@ -3935,21 +4006,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 );
+ }
}
}
["qpopupmenu.cpp.patch" (text/x-diff)]
--- qpopupmenu.cpp.sav 2005-03-30 17:50:32.000000000 +0200
+++ qpopupmenu.cpp 2005-05-17 14:37:31.000000000 +0200
@@ -854,6 +854,7 @@ bool QPopupMenu::tryMenuBar( QMouseEvent
*/
bool QPopupMenu::tryMouseEvent( QPopupMenu *p, QMouseEvent * e)
{
+ return false;
if ( p == this )
return FALSE;
QPoint pos = mapFromGlobal( e->globalPos() );
@@ -1602,7 +1603,7 @@ void QPopupMenu::mousePressEvent( QMouse
int item = itemAtPos( e->pos() );
if ( item == -1 ) {
if ( !rect().contains(e->pos()) && !tryMenuBar(e) ) {
- byeMenuBar();
+ hide();
}
return;
}
@@ -1637,6 +1638,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
@@ -1652,10 +1656,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() ) {
@@ -1761,14 +1771,14 @@ 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
d->hasmouse = 1;
- 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 );
@@ -1787,14 +1797,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();
_______________________________________________
kde-usability mailing list
kde-usability@kde.org
https://mail.kde.org/mailman/listinfo/kde-usability
[prev in list] [next in list] [prev in thread] [next in thread]
Configure |
About |
News |
Add a list |
Sponsored by KoreLogic