Fixes for mousePosition().

Since Qt propagates mouse events up the widget hierarchy, it's better
to filter out Qt events rather than X events for the decoration.

svn path=/trunk/kdebase/kwin/; revision=252346
icc-effect-5.14.5
Luboš Luňák 2003-09-19 11:11:07 +00:00
parent 5f4b9de17c
commit 9fac9d2a43
11 changed files with 152 additions and 117 deletions

View File

@ -263,6 +263,7 @@ void Client::updateDecoration( bool check_workspace_pos, bool force )
decoration = workspace()->createDecoration( bridge );
// TODO check decoration's minimum size?
decoration->init();
decoration->widget()->installEventFilter( this );
XReparentWindow( qt_xdisplay(), decoration->widget()->winId(), frameId(), 0, 0 );
decoration->widget()->lower();
decoration->borders( border_left, border_right, border_top, border_bottom );

View File

@ -78,7 +78,7 @@ class Client : public QObject, public KDecorationDefines
QSize clientSize() const;
void windowEvent( XEvent* e );
bool decorationEvent( XEvent* e );
virtual bool eventFilter( QObject* o, QEvent* e );
bool manage( Window w, bool isMapped );
@ -287,13 +287,12 @@ class Client : public QObject, public KDecorationDefines
void configureRequestEvent( XConfigureRequestEvent* e );
void propertyNotifyEvent( XPropertyEvent* e );
void clientMessageEvent( XClientMessageEvent* e );
bool buttonPressEvent( XButtonEvent* e );
bool buttonReleaseEvent( XButtonEvent* e );
bool motionNotifyEvent( XMotionEvent* e );
bool buttonPressEvent( Window w, int button, int state, int x, int y, int x_root, int y_root );
bool buttonReleaseEvent( Window w, int button, int state, int x, int y, int x_root, int y_root );
bool motionNotifyEvent( Window w, int state, int x, int y, int x_root, int y_root );
void enterNotifyEvent( XCrossingEvent* e );
void leaveNotifyEvent( XCrossingEvent* e );
void visibilityNotifyEvent( XVisibilityEvent* e );
void convertCrossingToMotionEvent( XCrossingEvent* e );
void focusInEvent( XFocusInEvent* e );
void focusOutEvent( XFocusOutEvent* e );
@ -781,7 +780,6 @@ kdbgstream& operator<<( kdbgstream& stream, const Client* );
KWIN_COMPARE_PREDICATE( WindowMatchPredicate, Window, cl->window() == value );
KWIN_COMPARE_PREDICATE( FrameIdMatchPredicate, Window, cl->frameId() == value );
KWIN_COMPARE_PREDICATE( WrapperIdMatchPredicate, Window, cl->wrapperId() == value );
KWIN_COMPARE_PREDICATE( DecorationIdMatchPredicate, Window, cl->decorationId() == value );
} // namespace

View File

@ -36,3 +36,4 @@ porting:
- windowWrapperShowEvent() is gone
- animateIconifyOrDeiconify() -> animateMinimize() - just drop it if it's empty
- pay special attention to SLOT() names and cases where you need to use 'widget()' instead of 'this'
- buttons should use setCursor() if they don't want cursor set by mousePosition()

View File

@ -439,6 +439,7 @@ KDEDefaultButton::KDEDefaultButton(KDEDefaultClient *parent, const char *name,
: QButton(parent->widget(), name)
{
QToolTip::add( this, tip );
setCursor( arrowCursor );
setBackgroundMode( QWidget::NoBackground );
setToggleButton( isStickyButton );

View File

@ -548,6 +548,7 @@ KeramikButton::KeramikButton( KeramikClient* c, const char *name, Button btn, co
{
QToolTip::add( this, tip ); // FRAME
setBackgroundMode( NoBackground );
setCursor( arrowCursor );
setFixedSize( 17, 17 );
setToggleButton( (button == OnAllDesktopsButton) );

View File

@ -232,6 +232,7 @@ LaptopClientButton::LaptopClientButton(int w, int h, LaptopClient *parent,
const QString& tip)
: QButton(parent->widget(), name), client(parent)
{
setCursor( arrowCursor );
defaultSize = QSize(w, h);
setFixedHeight(h);
resize(defaultSize);

View File

@ -228,6 +228,7 @@ ModernButton::ModernButton(ModernSys *parent, const char *name,
: QButton(parent->widget(), name)
{
setBackgroundMode( NoBackground );
setCursor( arrowCursor );
QBitmap mask(14, 15, QPixmap::defaultDepth() > 8 ?
btnhighcolor_mask_bits : lowcolor_mask_bits, true);
resize(14, 15);

View File

@ -237,6 +237,7 @@ RedmondButton::RedmondButton(RedmondDeco *parent, const char *name,
{
// Eliminate background flicker
setBackgroundMode( NoBackground );
setCursor( arrowCursor );
menuBtn = menuButton;
miniBtn = isMini;

View File

@ -21,6 +21,7 @@ void Decoration::init()
{
button = new QPushButton( widget());
button->show();
button->setCursor( arrowCursor );
button->move( 0, 0 );
connect( button, SIGNAL( clicked()), SLOT( closeWindow()));
QToolTip::add( button, "Zelva Mana" );

View File

@ -222,11 +222,6 @@ bool Workspace::workspaceEvent( XEvent * e )
c->windowEvent( e );
return true;
}
if( Client* c = findClient( DecorationIdMatchPredicate( e->xany.window )))
{
if( c->decorationEvent( e ))
return true;
}
switch (e->type)
{
@ -487,7 +482,8 @@ void Client::windowEvent( XEvent* e )
case ButtonPress:
updateUserTime();
workspace()->setWasUserInteraction();
buttonPressEvent( &e->xbutton );
buttonPressEvent( e->xbutton.window, e->xbutton.button, e->xbutton.state,
e->xbutton.x, e->xbutton.y, e->xbutton.x_root, e->xbutton.y_root );
return;
case KeyRelease:
// don't update user time on releases
@ -498,17 +494,26 @@ void Client::windowEvent( XEvent* e )
// don't update user time on releases
// e.g. if the user presses Alt+F2, the Alt release
// would appear as user input to the currently active window
buttonReleaseEvent( &e->xbutton );
buttonReleaseEvent( e->xbutton.window, e->xbutton.button, e->xbutton.state,
e->xbutton.x, e->xbutton.y, e->xbutton.x_root, e->xbutton.y_root );
return;
case MotionNotify:
motionNotifyEvent( &e->xmotion );
motionNotifyEvent( e->xbutton.window, e->xbutton.state,
e->xbutton.x, e->xbutton.y, e->xbutton.x_root, e->xbutton.y_root );
return;
case EnterNotify:
enterNotifyEvent( &e->xcrossing );
convertCrossingToMotionEvent( &e->xcrossing );
// MotionNotify is guaranteed to be generated only if the mouse
// move start and ends in the window; for cases when it only
// starts or only ends there, Enter/LeaveNotify are generated.
// Fake a MotionEvent in such cases to make handle of mouse
// events simpler (Qt does that too).
motionNotifyEvent( e->xcrossing.window, e->xcrossing.state,
e->xcrossing.x, e->xcrossing.y, e->xcrossing.x_root, e->xcrossing.y_root );
return;
case LeaveNotify:
convertCrossingToMotionEvent( &e->xcrossing );
motionNotifyEvent( e->xcrossing.window, e->xcrossing.state,
e->xcrossing.x, e->xcrossing.y, e->xcrossing.x_root, e->xcrossing.y_root );
return leaveNotifyEvent( &e->xcrossing );
case FocusIn:
return focusInEvent( &e->xfocus );
@ -541,35 +546,6 @@ void Client::windowEvent( XEvent* e )
}
}
// MotionNotify is guaranteed to be generated only if the mouse
// move start and ends in the window; for cases when it only
// starts or only ends there, Enter/LeaveNotify are generated.
// Fake a MotionEvent in such cases to make handle of mouse
// events simpler (Qt does that too).
void Client::convertCrossingToMotionEvent( XCrossingEvent* e )
{
if( e->mode == NotifyNormal )
{
XMotionEvent ev2;
ev2.type = MotionNotify;
ev2.serial = e->serial;
ev2.send_event = e->send_event;
ev2.display = e->display;
ev2.window = e->window;
ev2.root = e->root;
ev2.subwindow = e->subwindow;
ev2.time = e->time;
ev2.x = e->x;
ev2.y = e->y;
ev2.x_root = e->x_root;
ev2.y_root = e->y_root;
ev2.state = e->state;
ev2.is_hint = False;
ev2.same_screen = e->same_screen;
motionNotifyEvent( &ev2 );
}
}
/*!
Handles map requests of the client window
*/
@ -1032,39 +1008,99 @@ void Client::updateMouseGrab()
None, None );
}
bool Client::buttonPressEvent( XButtonEvent* e )
int qtToX11Button( Qt::ButtonState button )
{
if( button == Qt::LeftButton )
return Button1;
else if( button == Qt::MidButton )
return Button2;
else if( button == Qt::RightButton )
return Button3;
return AnyButton;
}
int qtToX11State( Qt::ButtonState state )
{
int ret = 0;
if( state & Qt::LeftButton )
ret |= Button1Mask;
if( state & Qt::MidButton )
ret |= Button2Mask;
if( state & Qt::RightButton )
ret |= Button3Mask;
if( state & Qt::ShiftButton )
ret |= ShiftMask;
if( state & Qt::ControlButton )
ret |= ControlMask;
if( state & Qt::AltButton )
ret |= KKeyNative::modX(KKey::ALT);
if( state & Qt::MetaButton )
ret |= KKeyNative::modX(KKey::WIN);
return ret;
}
// Qt propagates mouse events up the widget hierachy, which means events
// for the decoration window cannot be (easily) intercepted as X11 events
bool Client::eventFilter( QObject* o, QEvent* e )
{
if( decoration == NULL
|| o != decoration->widget())
return false;
if( e->type() == QEvent::MouseButtonPress )
{
QMouseEvent* ev = static_cast< QMouseEvent* >( e );
return buttonPressEvent( decorationId(), qtToX11Button( ev->button()), qtToX11State( ev->state()),
ev->x(), ev->y(), ev->globalX(), ev->globalY() );
}
if( e->type() == QEvent::MouseButtonRelease )
{
QMouseEvent* ev = static_cast< QMouseEvent* >( e );
return buttonReleaseEvent( decorationId(), qtToX11Button( ev->button()), qtToX11State( ev->state()),
ev->x(), ev->y(), ev->globalX(), ev->globalY() );
}
if( e->type() == QEvent::MouseMove ) // FRAME i fake z enter/leave?
{
QMouseEvent* ev = static_cast< QMouseEvent* >( e );
return motionNotifyEvent( decorationId(), qtToX11State( ev->state()),
ev->x(), ev->y(), ev->globalX(), ev->globalY() );
}
return false;
}
// return value matters only when filtering events before decoration gets them
bool Client::buttonPressEvent( Window w, int button, int state, int x, int y, int x_root, int y_root )
{
if (buttonDown)
{
kdDebug( 1212 ) << "Double button press:" << ( e->window == decorationId())
<< ":" << ( e->window == frameId()) << ":" << ( e->window == wrapperId()) << endl;
if( e->window == wrapperId())
kdDebug( 1212 ) << "Double button press:" << ( w == decorationId())
<< ":" << ( w == frameId()) << ":" << ( w == wrapperId()) << endl;
if( w == wrapperId())
XAllowEvents(qt_xdisplay(), SyncPointer, CurrentTime ); //qt_x_time);
return true;
}
if( e->window == wrapperId() || e->window == frameId() || e->window == decorationId())
if( w == wrapperId() || w == frameId() || w == decorationId())
{ // FRAME neco s tohohle by se melo zpracovat, nez to dostane dekorace
updateUserTime();
workspace()->setWasUserInteraction();
uint keyModX = (options->keyCmdAllModKey() == Qt::Key_Meta) ?
KKeyNative::modX(KKey::WIN) :
KKeyNative::modX(KKey::ALT);
bool bModKeyHeld = ( e->state & KKeyNative::accelModMaskX()) == keyModX;
bool bModKeyHeld = ( state & KKeyNative::accelModMaskX()) == keyModX;
if( isSplash()
&& e->button == Button1 && !bModKeyHeld )
&& button == Button1 && !bModKeyHeld )
{ // hide splashwindow if the user clicks on it
hideClient( true );
if( e->window == wrapperId())
if( w == wrapperId())
XAllowEvents(qt_xdisplay(), SyncPointer, CurrentTime ); //qt_x_time);
return true;
}
if ( isActive() && e->window == wrapperId()
if ( isActive() && w == wrapperId()
&& ( options->clickRaise && !bModKeyHeld ) )
{
if ( e->button < 4 ) // exclude wheel
if ( button < 4 ) // exclude wheel
autoRaise();
}
@ -1073,7 +1109,7 @@ bool Client::buttonPressEvent( XButtonEvent* e )
if ( bModKeyHeld )
{
was_action = true;
switch (e->button)
switch (button)
{
case Button1:
com = options->commandAll1();
@ -1088,10 +1124,10 @@ bool Client::buttonPressEvent( XButtonEvent* e )
}
else
{ // inactive inner window
if( !isActive() && e->window == wrapperId())
if( !isActive() && w == wrapperId())
{
was_action = true;
switch (e->button)
switch (button)
{
case Button1:
com = options->commandWindow1();
@ -1109,30 +1145,32 @@ bool Client::buttonPressEvent( XButtonEvent* e )
}
if( was_action )
{
bool replay = performMouseCommand( com, QPoint( e->x_root, e->y_root) );
bool replay = performMouseCommand( com, QPoint( x_root, y_root) );
if ( isSpecialWindow() && !isOverride())
replay = TRUE;
if( e->window == wrapperId()) // these can come only from a grab
if( w == wrapperId()) // these can come only from a grab
XAllowEvents(qt_xdisplay(), replay? ReplayPointer : SyncPointer, CurrentTime ); //qt_x_time);
return true;
}
}
if( e->window == wrapperId()) // these can come only from a grab
if( w == wrapperId()) // these can come only from a grab
{
XAllowEvents(qt_xdisplay(), ReplayPointer, CurrentTime ); //qt_x_time);
return true;
}
if( e->window == decorationId())
if( w == decorationId())
return false; // don't eat decoration events
if( e->window == frameId())
processDecorationButtonPress( e->button, e->state, e->x, e->y, e->x_root, e->y_root );
if( w == frameId())
processDecorationButtonPress( button, state, x, y, x_root, y_root );
return true;
}
// this function processes button press events only after decoration decides not to handle them,
// unlike buttonPressEvent(), which (when the window is decoration) filters events before decoration gets them
void Client::processDecorationButtonPress( int button, int /*state*/, int x, int y, int x_root, int y_root )
{
Options::MouseCommand com = Options::MouseNothing;
@ -1146,9 +1184,10 @@ void Client::processDecorationButtonPress( int button, int /*state*/, int x, int
com = active ? options->commandActiveTitlebar2() : options->commandInactiveTitlebar2();
else if ( button == Button3 )
com = active ? options->commandActiveTitlebar3() : options->commandInactiveTitlebar3();
if( com != Options::MouseOperationsMenu )
if( com != Options::MouseOperationsMenu // actions where it's not possible to get the matching
&& com != Options::MouseMinimize ) // mouse release event
{
// FRAME mouseMoveEvent( e );
// FRAME mouseMoveEvent( e ); shouldn't be necessary
buttonDown = TRUE;
moveOffset = QPoint( x, y );
invertedMoveOffset = rect().bottomRight() - moveOffset;
@ -1157,26 +1196,53 @@ void Client::processDecorationButtonPress( int button, int /*state*/, int x, int
performMouseCommand( com, QPoint( x_root, y_root ));
}
bool Client::buttonReleaseEvent( XButtonEvent* e )
// called from decoration
void Client::processMousePressEvent( QMouseEvent* e )
{
if( e->window == decorationId() && !buttonDown)
if( e->type() != QEvent::MouseButtonPress )
{
kdWarning() << "processMousePressEvent()" << endl;
return;
}
int button;
switch( e->button())
{
case LeftButton:
button = Button1;
break;
case MidButton:
button = Button2;
break;
case RightButton:
button = Button3;
break;
default:
return;
}
processDecorationButtonPress( button, e->state(), e->x(), e->y(), e->globalX(), e->globalY());
}
// return value matters only when filtering events before decoration gets them
bool Client::buttonReleaseEvent( Window w, int /*button*/, int state, int x, int y, int x_root, int y_root )
{
if( w == decorationId() && !buttonDown)
return false;
if( e->window == wrapperId())
if( w == wrapperId())
{
XAllowEvents(qt_xdisplay(), SyncPointer, CurrentTime ); //qt_x_time);
return true;
}
if( e->window != frameId() && e->window != decorationId())
if( w != frameId() && w != decorationId())
return true;
if ( (e->state & ( Button1Mask & Button2Mask & Button3Mask )) == 0 )
if ( (state & ( Button1Mask & Button2Mask & Button3Mask )) == 0 )
{
buttonDown = FALSE;
if ( moveResizeMode )
{
finishMoveResize( false );
// mouse position is still relative to old Client position, adjust it
QPoint mousepos( e->x_root - x(), e->y_root - y());
QPoint mousepos( x_root - x, y_root - y );
mode = mousePosition( mousepos );
setCursor( mode );
}
@ -1184,20 +1250,19 @@ bool Client::buttonReleaseEvent( XButtonEvent* e )
return true;
}
bool Client::motionNotifyEvent( XMotionEvent* e )
// return value matters only when filtering events before decoration gets them
bool Client::motionNotifyEvent( Window w, int /*state*/, int x, int y, int x_root, int y_root )
{
if( e->window != frameId() && e->window != decorationId())
if( w != frameId() && w != decorationId())
return true; // care only about the whole frame
if ( !buttonDown )
{
MousePosition newmode = mousePosition( QPoint( e->x, e->y ));
MousePosition newmode = mousePosition( QPoint( x, y ));
if( newmode != mode )
setCursor( newmode );
mode = newmode;
return true;
}
if( e->window == decorationId() && !buttonDown)
return false;
}
if(( mode == Center && !isMovable())
|| ( mode != Center && ( isShade() || !isResizable())))
@ -1205,7 +1270,7 @@ bool Client::motionNotifyEvent( XMotionEvent* e )
if ( !moveResizeMode )
{
QPoint p( QPoint( e->x, e->y ) - moveOffset );
QPoint p( QPoint( x, y ) - moveOffset );
if (p.manhattanLength() >= 6)
startMoveResize();
else
@ -1216,7 +1281,7 @@ bool Client::motionNotifyEvent( XMotionEvent* e )
if ( mode != Center && shade_mode != ShadeNone )
setShade( ShadeNone );
QPoint globalPos( e->x_root, e->y_root );
QPoint globalPos( x_root, y_root );
QRect desktopArea = workspace()->clientArea( globalPos );
QPoint p = globalPos + invertedMoveOffset;
@ -1417,43 +1482,6 @@ void Client::focusOutEvent( XFocusOutEvent* e )
setActive( FALSE );
}
bool Client::decorationEvent( XEvent* e )
{
if( e->type == ButtonPress )
return buttonPressEvent( &e->xbutton );
if( e->type == ButtonRelease )
return buttonReleaseEvent( &e->xbutton );
if( e->type == MotionNotify )
return motionNotifyEvent( &e->xmotion ); // FRAME i fake z enter/leave?
return false;
}
// called from decoration
void Client::processMousePressEvent( QMouseEvent* e )
{
if( e->type() != QEvent::MouseButtonPress )
{
kdWarning() << "processMousePressEvent()" << endl;
return;
}
int button;
switch( e->button())
{
case LeftButton:
button = Button1;
break;
case MidButton:
button = Button2;
break;
case RightButton:
button = Button3;
break;
default:
return;
}
processDecorationButtonPress( button, e->state(), e->x(), e->y(), e->globalX(), e->globalY());
}
void Client::visibilityNotifyEvent( XVisibilityEvent * e)
{
if( e->window != frameId())

View File

@ -64,6 +64,7 @@ void KDecoration::setMainWidget( QWidget* w )
{
assert( w_ == NULL );
w_ = w;
w->setMouseTracking( true );
widget()->resize( geometry().size());
}