3 author: Lubos Lunak <l.lunak@kde.org>
7 for example: Open Konqueror window, showing some files. Start dragging one
8 desktop icon. If you press/release Ctrl, there'll be a '+' attached to the
9 icon, showing the DND operation. Now, while still doing DND, make the
10 Konqueror window active (Alt+Tab with KDE-3.1.2+, hover over its taskbar
11 entry, Ctrl+Fn to switch to a different virtual desktop, etc.). As soon as
12 the app performing DND is not the active application, and the mouse is not
13 moving, pressing/releasing Ctrl doesn't do anything, the state only updates
14 when the mouse is moved.
16 This is caused by the fact that Qt has only pointer grab when doing DND, but
17 doesn't have keyboard grab. I actually consider this a good thing, because
18 the only keys important for DND are modifiers, and they come together with
19 pointer events, and not having keyboard grab allows using keyboard shortcuts
20 like Alt+Tab while DND. However, when the mouse is not moved, and only a
21 modifier key is pressed/released, the app won't get any mouse event, and
22 won't also get the keyboard event.
24 The attached patch changes Qt to explicitly check the modifiers state using
25 XQueryPointer() if there's wasn't recently any mouse/keyboard event, which
26 ensures the state is updated even in the situation described above.
28 --- src/kernel/qapplication_x11.cpp.sav 2003-06-21 12:31:35.000000000 +0200
29 +++ src/kernel/qapplication_x11.cpp 2003-06-21 12:35:44.000000000 +0200
30 @@ -4053,7 +4053,7 @@ void QApplication::closePopup( QWidget *
31 // Keyboard event translation
34 -static int translateButtonState( int s )
35 +int qt_x11_translateButtonState( int s )
38 if ( s & Button1Mask )
39 @@ -4119,7 +4119,7 @@ bool QETWidget::translateMouseEvent( con
40 pos.ry() = lastMotion.y;
41 globalPos.rx() = lastMotion.x_root;
42 globalPos.ry() = lastMotion.y_root;
43 - state = translateButtonState( lastMotion.state );
44 + state = qt_x11_translateButtonState( lastMotion.state );
45 if ( qt_button_down && (state & (LeftButton |
47 RightButton ) ) == 0 )
48 @@ -4143,7 +4143,7 @@ bool QETWidget::translateMouseEvent( con
49 pos.ry() = xevent->xcrossing.y;
50 globalPos.rx() = xevent->xcrossing.x_root;
51 globalPos.ry() = xevent->xcrossing.y_root;
52 - state = translateButtonState( xevent->xcrossing.state );
53 + state = qt_x11_translateButtonState( xevent->xcrossing.state );
54 if ( qt_button_down && (state & (LeftButton |
56 RightButton ) ) == 0 )
57 @@ -4155,7 +4155,7 @@ bool QETWidget::translateMouseEvent( con
58 pos.ry() = event->xbutton.y;
59 globalPos.rx() = event->xbutton.x_root;
60 globalPos.ry() = event->xbutton.y_root;
61 - state = translateButtonState( event->xbutton.state );
62 + state = qt_x11_translateButtonState( event->xbutton.state );
63 switch ( event->xbutton.button ) {
64 case Button1: button = LeftButton; break;
65 case Button2: button = MidButton; break;
66 @@ -4950,7 +4950,7 @@ bool QETWidget::translateKeyEventInterna
67 XKeyEvent xkeyevent = event->xkey;
69 // save the modifier state, we will use the keystate uint later by passing
70 - // it to translateButtonState
71 + // it to qt_x11_translateButtonState
72 uint keystate = event->xkey.state;
73 // remove the modifiers where mode_switch exists... HPUX machines seem
74 // to have alt *AND* mode_switch both in Mod1Mask, which causes
75 @@ -5064,7 +5064,7 @@ bool QETWidget::translateKeyEventInterna
79 - state = translateButtonState( keystate );
80 + state = qt_x11_translateButtonState( keystate );
82 static int directionKeyEvent = 0;
83 if ( qt_use_rtl_extensions && type == QEvent::KeyRelease ) {
84 --- src/kernel/qdnd_x11.cpp.sav 2003-06-30 15:26:42.000000000 +0200
85 +++ src/kernel/qdnd_x11.cpp 2003-06-30 15:32:23.000000000 +0200
86 @@ -114,6 +114,8 @@ Atom qt_xdnd_finished;
87 Atom qt_xdnd_type_list;
88 const int qt_xdnd_version = 4;
90 +extern int qt_x11_translateButtonState( int s );
94 // The Xdnd spec allows for user-defined actions. This could be implemented
95 @@ -198,6 +200,8 @@ static Atom qt_xdnd_source_current_time;
96 static int qt_xdnd_current_screen = -1;
97 // state of dragging... true if dragging, false if not
98 bool qt_xdnd_dragging = FALSE;
99 +// need to check state of keyboard modifiers
100 +static bool need_modifiers_check = FALSE;
102 // dict of payload data, sorted by type atom
103 static QIntDict<QByteArray> * qt_xdnd_target_data = 0;
104 @@ -879,8 +883,20 @@ void qt_handle_xdnd_finished( QWidget *,
106 void QDragManager::timerEvent( QTimerEvent* e )
108 - if ( e->timerId() == heartbeat && qt_xdnd_source_sameanswer.isNull() )
109 - move( QCursor::pos() );
110 + if ( e->timerId() == heartbeat ) {
111 + if( need_modifiers_check ) {
112 + Window root, child;
113 + int root_x, root_y, win_x, win_y;
115 + XQueryPointer( qt_xdisplay(), qt_xrootwin( qt_xdnd_current_screen ),
116 + &root, &child, &root_x, &root_y, &win_x, &win_y, &mask );
117 + if( updateMode( (ButtonState)qt_x11_translateButtonState( mask )))
118 + qt_xdnd_source_sameanswer = QRect(); // force move
120 + need_modifiers_check = TRUE;
121 + if( qt_xdnd_source_sameanswer.isNull() )
122 + move( QCursor::pos() );
126 static bool qt_xdnd_was_move = false;
127 @@ -948,6 +964,7 @@ bool QDragManager::eventFilter( QObject
128 updateMode(me->stateAfter());
129 move( me->globalPos() );
131 + need_modifiers_check = FALSE;
133 } else if ( e->type() == QEvent::MouseButtonRelease ) {
134 qApp->removeEventFilter( this );
135 @@ -986,9 +1003,11 @@ bool QDragManager::eventFilter( QObject
136 beingCancelled = FALSE;
139 - updateMode(ke->stateAfter());
140 - qt_xdnd_source_sameanswer = QRect(); // force move
141 - move( QCursor::pos() );
142 + if( updateMode(ke->stateAfter())) {
143 + qt_xdnd_source_sameanswer = QRect(); // force move
144 + move( QCursor::pos() );
146 + need_modifiers_check = FALSE;
148 return TRUE; // Eat all key events
150 @@ -1014,10 +1033,10 @@ bool QDragManager::eventFilter( QObject
153 static Qt::ButtonState oldstate;
154 -void QDragManager::updateMode( ButtonState newstate )
155 +bool QDragManager::updateMode( ButtonState newstate )
157 if ( newstate == oldstate )
160 const int both = ShiftButton|ControlButton;
161 if ( (newstate & both) == both ) {
162 global_requested_action = QDropEvent::Link;
163 @@ -1041,6 +1060,7 @@ void QDragManager::updateMode( ButtonSta
171 @@ -1707,6 +1727,7 @@ bool QDragManager::drag( QDragObject * o
172 qt_xdnd_source_sameanswer = QRect();
173 move(QCursor::pos());
174 heartbeat = startTimer(200);
175 + need_modifiers_check = FALSE;
178 qApp->setOverrideCursor( arrowCursor );
179 --- src/kernel/qdragobject.h.sav 2003-05-19 22:34:43.000000000 +0200
180 +++ src/kernel/qdragobject.h 2001-01-01 01:01:00.000000000 +0100
181 @@ -248,7 +248,7 @@ private:
184 QDragObject * object;
185 - void updateMode( ButtonState newstate );
186 + bool updateMode( ButtonState newstate );
189 QWidget * dragSource;