diff options
Diffstat (limited to 'tqtinterface/qt4/src/kernel/tqdnd_x11.cpp')
-rw-r--r-- | tqtinterface/qt4/src/kernel/tqdnd_x11.cpp | 138 |
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 |