summaryrefslogtreecommitdiffstats
path: root/tqtinterface/qt4/src/kernel/tqdnd_x11.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'tqtinterface/qt4/src/kernel/tqdnd_x11.cpp')
-rw-r--r--tqtinterface/qt4/src/kernel/tqdnd_x11.cpp138
1 files changed, 118 insertions, 20 deletions
diff --git a/tqtinterface/qt4/src/kernel/tqdnd_x11.cpp b/tqtinterface/qt4/src/kernel/tqdnd_x11.cpp
index 7882349..3ba66b9 100644
--- a/tqtinterface/qt4/src/kernel/tqdnd_x11.cpp
+++ b/tqtinterface/qt4/src/kernel/tqdnd_x11.cpp
@@ -52,13 +52,15 @@
#include "tqdragobject.h"
#include "tqobjectlist.h"
#include "tqcursor.h"
+#include "tqbitmap.h"
+#include "tqpainter.h"
#include "tqt_x11_p.h"
// conflict resolution
-// unused, may be used again later: const int XKeyPress = KeyPress;
-// unused, may be used again later: const int XKeyRelease = KeyRelease;
+const int XKeyPress = KeyPress;
+const int XKeyRelease = KeyRelease;
#undef KeyPress
#undef KeyRelease
@@ -114,6 +116,8 @@ Atom qt_xdnd_finished;
Atom qt_xdnd_type_list;
const int qt_xdnd_version = 4;
+extern int qt_x11_translateButtonState( int s );
+
// Actions
//
// The Xdnd spec allows for user-defined actions. This could be implemented
@@ -199,6 +203,8 @@ static Time qt_xdnd_target_current_time;
static int qt_xdnd_current_screen = -1;
// state of dragging... true if dragging, false if not
bool qt_xdnd_dragging = FALSE;
+// need to check state of keyboard modifiers
+static bool need_modifiers_check = FALSE;
// dict of payload data, sorted by type atom
static TQIntDict<TQByteArray> * qt_xdnd_target_data = 0;
@@ -257,21 +263,49 @@ class TQShapedPixmapWidget : public TQWidget {
public:
TQShapedPixmapWidget(int screen = -1) :
TQWidget(TQApplication::desktop()->screen( screen ),
- 0, (Qt::WindowType)(WStyle_Customize | WStyle_Tool | WStyle_NoBorder | WX11BypassWM) )
+ 0, (Qt::WindowType)(WStyle_Customize | WStyle_Tool | WStyle_NoBorder | WX11BypassWM) ), oldpmser( 0 ), oldbmser( 0 )
{
+ x11SetWindowType( X11WindowTypeDND );
}
- void setPixmap(TQPixmap pm)
+ void setPixmap(TQPixmap pm, TQPoint hot)
{
- const TQBitmap* mask = pm.tqmask();
- if ( mask ) {
+ int bmser = pm.tqmask() ? pm.tqmask()->serialNumber() : 0;
+ if( oldpmser == pm.serialNumber() && oldbmser == bmser
+ && oldhot == hot )
+ return;
+ oldpmser = pm.serialNumber();
+ oldbmser = bmser;
+ oldhot = hot;
+ bool hotspot_in = !(hot.x() < 0 || hot.y() < 0 || hot.x() >= pm.width() || hot.y() >= pm.height());
+// if the pixmap has hotspot in its area, make a "hole" in it at that position
+// this will allow XTranslateCoordinates() to find directly the window below the cursor instead
+// of finding this pixmap, and therefore there won't be needed any (slow) search for the window
+// using findRealWindow()
+ if( hotspot_in ) {
+ TQBitmap tqmask = pm.tqmask() ? *pm.tqmask() : TQBitmap( pm.width(), pm.height());
+ if( !pm.tqmask())
+ tqmask.fill( TQt::color1 );
+ TQPainter p( &tqmask );
+ p.setPen( TQt::color0 );
+ p.drawPoint( hot.x(), hot.y());
+ p.end();
+ pm.setMask( tqmask );
+ setMask( tqmask );
+ } else if ( pm.tqmask() ) {
setMask( *mask );
} else {
clearMask();
}
resize(pm.width(),pm.height());
setErasePixmap(pm);
+ erase();
}
+
+private:
+ int oldpmser;
+ int oldbmser;
+ TQPoint oldhot;
};
static TQShapedPixmapWidget * qt_xdnd_deco = 0;
@@ -875,8 +909,59 @@ void qt_handle_xdnd_finished( TQWidget *, const XEvent * xe, bool passive )
void TQDragManager::timerEvent( TQTimerEvent* e )
{
- if ( e->timerId() == heartbeat && qt_xdnd_source_sameanswer.isNull() )
- move( TQCursor::pos() );
+ if ( e->timerId() == heartbeat ) {
+ if( need_modifiers_check ) {
+ Window root, child;
+ int root_x, root_y, win_x, win_y;
+ unsigned int tqmask;
+ XQueryPointer( qt_xdisplay(), qt_xrootwin( qt_xdnd_current_screen ),
+ &root, &child, &root_x, &root_y, &win_x, &win_y, &tqmask );
+ if( updateMode( (ButtonState)qt_x11_translateButtonState( tqmask )))
+ qt_xdnd_source_sameanswer = TQRect(); // force move
+ }
+ need_modifiers_check = TRUE;
+ if( qt_xdnd_source_sameanswer.isNull() )
+ move( TQCursor::pos() );
+ }
+}
+
+static bool qt_xdnd_was_move = false;
+static bool qt_xdnd_found = false;
+// check whole incoming X queue for move events
+// checking whole queue is done by always returning False in the predicate
+// if there's another move event in the queue, and there's not a mouse button
+// or keyboard or ClientMessage event before it, the current move event
+// may be safely discarded
+// this helps avoiding being overloaded by being flooded from many events
+// from the XServer
+static
+Bool qt_xdnd_predicate( Display*, XEvent* ev, XPointer )
+{
+ if( qt_xdnd_found )
+ return False;
+ if( ev->type == MotionNotify )
+ {
+ qt_xdnd_was_move = true;
+ qt_xdnd_found = true;
+ }
+ if( ev->type == ButtonPress || ev->type == ButtonRelease
+ || ev->type == XKeyPress || ev->type == XKeyRelease
+ || ev->type == ClientMessage )
+ {
+ qt_xdnd_was_move = false;
+ qt_xdnd_found = true;
+ }
+ return False;
+}
+
+static
+bool qt_xdnd_another_movement()
+{
+ qt_xdnd_was_move = false;
+ qt_xdnd_found = false;
+ XEvent dummy;
+ XCheckIfEvent( qt_xdisplay(), &dummy, qt_xdnd_predicate, NULL );
+ return qt_xdnd_was_move;
}
bool TQDragManager::eventFilter( TQObject * o, TQEvent * e)
@@ -901,8 +986,11 @@ bool TQDragManager::eventFilter( TQObject * o, TQEvent * e)
if ( e->type() == TQEvent::MouseMove ) {
TQMouseEvent* me = (TQMouseEvent *)e;
- updateMode(me->stateAfter());
- move( me->globalPos() );
+ if( !qt_xdnd_another_movement()) {
+ updateMode(me->stateAfter());
+ move( me->globalPos() );
+ }
+ need_modifiers_check = FALSE;
return TRUE;
} else if ( e->type() == TQEvent::MouseButtonRelease ) {
tqApp->removeEventFilter( this );
@@ -941,9 +1029,11 @@ bool TQDragManager::eventFilter( TQObject * o, TQEvent * e)
beingCancelled = FALSE;
tqApp->exit_loop();
} else {
- updateMode(ke->stateAfter());
- qt_xdnd_source_sameanswer = TQRect(); // force move
- move( TQCursor::pos() );
+ if( updateMode(ke->stateAfter())) {
+ qt_xdnd_source_sameanswer = TQRect(); // force move
+ move( TQCursor::pos() );
+ }
+ need_modifiers_check = FALSE;
}
return TRUE; // Eat all key events
}
@@ -970,10 +1060,10 @@ bool TQDragManager::eventFilter( TQObject * o, TQEvent * e)
static TQt::ButtonState oldstate;
-void TQDragManager::updateMode( TQt::ButtonState newstate )
+bool TQDragManager::updateMode( TQt::ButtonState newstate )
{
if ( newstate == oldstate )
- return;
+ return false;
const int both = ShiftButton|ControlButton;
if ( (newstate & both) == both ) {
global_requested_action = TQDropEvent::Link;
@@ -997,6 +1087,7 @@ void TQDragManager::updateMode( TQt::ButtonState newstate )
}
}
oldstate = newstate;
+ return true;
}
@@ -1138,12 +1229,13 @@ void TQDragManager::move( const TQPoint & globalPos )
// recreate the pixmap on the new screen...
delete qt_xdnd_deco;
qt_xdnd_deco = new TQShapedPixmapWidget( screen );
+ qt_xdnd_deco->x11SetWindowTransient( dragSource->tqtopLevelWidget());
if (!TQWidget::mouseGrabber()) {
updatePixmap();
qt_xdnd_deco->grabMouse();
}
}
- updatePixmap();
+ updatePixmap( globalPos );
if ( qt_xdnd_source_sameanswer.contains( globalPos ) &&
qt_xdnd_source_sameanswer.isValid() ) {
@@ -1691,6 +1783,7 @@ bool TQDragManager::drag( TQDragObject * o, TQDragObject::DragMode mode )
dragSource = (TQWidget *)(object->tqparent());
+ qt_xdnd_deco->x11SetWindowTransient( dragSource->tqtopLevelWidget());
tqApp->installEventFilter( this );
qt_xdnd_source_current_time = GET_QT_X_TIME();
XSetSelectionOwner( TQPaintDevice::x11AppDisplay(), qt_xdnd_selection,
@@ -1703,6 +1796,7 @@ bool TQDragManager::drag( TQDragObject * o, TQDragObject::DragMode mode )
qt_xdnd_source_sameanswer = TQRect();
move(TQCursor::pos());
heartbeat = startTimer(200);
+ need_modifiers_check = FALSE;
#ifndef TQT_NO_CURSOR
tqApp->setOverrideCursor( Qt::ArrowCursor );
@@ -1736,7 +1830,7 @@ bool TQDragManager::drag( TQDragObject * o, TQDragObject::DragMode mode )
// qt_xdnd_source_object persists until we get an xdnd_finish message
}
-void TQDragManager::updatePixmap()
+void TQDragManager::updatePixmap( const TQPoint& cursorPos )
{
if ( qt_xdnd_deco ) {
TQPixmap pm;
@@ -1751,9 +1845,8 @@ void TQDragManager::updatePixmap()
defaultPm = new TQPixmap(default_pm);
pm = *defaultPm;
}
- qt_xdnd_deco->setPixmap(pm);
- qt_xdnd_deco->move(TQCursor::pos()-pm_hot);
- qt_xdnd_deco->tqrepaint(FALSE);
+ qt_xdnd_deco->setPixmap(pm, pm_hot);
+ qt_xdnd_deco->move(cursorPos-pm_hot);
//if ( willDrop ) {
qt_xdnd_deco->show();
//} else {
@@ -1762,4 +1855,9 @@ void TQDragManager::updatePixmap()
}
}
+void TQDragManager::updatePixmap()
+{
+ updatePixmap( TQCursor::pos());
+}
+
#endif // TQT_NO_DRAGANDDROP