From kde-optimize Tue Feb 04 12:08:00 2003 From: Lubos Lunak Date: Tue, 04 Feb 2003 12:08:00 +0000 To: kde-optimize Subject: Re: Drag and drop optimization X-MARC-Message: https://marc.info/?l=kde-optimize&m=104436060424892 MIME-Version: 1 Content-Type: multipart/mixed; boundary="--Boundary-00=_g06P+JEqeULzfj8" --Boundary-00=_g06P+JEqeULzfj8 Content-Type: text/plain; charset="iso-8859-1" Content-Transfer-Encoding: 7bit Content-Disposition: inline On Thursday 30 of January 2003 02:04, Wilco Greven wrote: > Hello, > > The accompanying patch speeds up the part of Qt's dnd code which looks up > the window under the cursor (*). The critical part of this code is the > function findClientWindow. One call takes about 100 ms. Most of this time > of this is spend in XGetWindowAttributes. > > The replacement avoids uses the NETWM client list stacking looks at the > windows starting from the top of the client stack. Here are some > testresults comparing the two methods: > > KCounterProf:findRealWindow took approx 117.79 ms > findRealWindow was called 584 times > Window returned: 22001b3 > KCounterProf:findRealWindowNETWM took approx 3.32 ms > Window returned: 22001b3 > > KCounterProf:findRealWindow took approx 113.16 ms > findRealWindow was called 582 times > Window returned: 1a00002 > KCounterProf:findRealWindowNETWM took approx 2.17 ms > Window returned: 1a00002 > > KCounterProf:findRealWindow took approx 114.25 ms > findRealWindow was called 583 times > Window returned: 2c02673 > KCounterProf:findRealWindowNETWM took approx 2.70 ms > Window returned: 2c02673 Strange, I get quite different numbers. It's 850MHz CPU, so it's notably faster, but also the improvements differ. When checking the whole QDragManager::move() method, findRealWindow() takes about 66% of the whole method. Your optimized version takes it down to 33%, thus saving half of the time. Perhaps you have many more windows open than I did, or maybe your testcase is wrong (at least, you shouldn't use random input, as that gives unreproducable results). Does your patch make a difference also in reality, e.g. when dragging in Konqy? > > So far the biggest problem I can see is that the code relies on a NETWM > compliant window manager. For the rest it's hard to say because I don't > know X11 that well. In order to make your code really work, you'd have to go back to XGetWindowAttributes and additionally check the map_state in the struct to be IsMapped. To check if the window manager supports the stacking property, you can use qt_net_supports(). However, perhaps I have something better. Please try the attached patch. It should do two things: First, it makes a "hole" in the dragged pixmap, so XTranslateCoordinates() always finds the window under it, thus making findRealWindow() unnecessary. Second, if the app cannot catch up with the XServer sending the mouse move events, it tries to discard multiple move events. The second change doesn't actually help on my computer, because I have to try really hard to get CPU usage up to 100%, but on slower computers it should help (the CPU usage will be 100% too, but it won't demand more). In general, I don't think there can be done much more. This is a tough problem, actually. One more thing to do could be to have larger 'sameanswer' area (see the XDND spec), but I'm afraid that wouldn't be that trivial in Qt. I tried also some other things, like updating the icon position only every X ms, but that didn't look nice. And, actually, if the discarding of superfluous move events will help to make it visually acceptable without the icon lagging behind the cursor, I think there no need for further optimizations. -- 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/ --Boundary-00=_g06P+JEqeULzfj8 Content-Type: text/x-diff; charset="iso-8859-1"; name="qdnd_x11.cpp.patch" Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename="qdnd_x11.cpp.patch" --- qdnd_x11.cpp.sav 2003-01-02 12:22:59.000000000 +0100 +++ qdnd_x11.cpp 2003-02-04 13:01:13.000000000 +0100 @@ -54,8 +54,8 @@ // 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 @@ -245,23 +245,40 @@ static const char* const default_pm[] = "X X X X X X X" }; +#include +#include + class QShapedPixmapWidget : public QWidget { QPixmap pixmap; public: QShapedPixmapWidget(int screen = -1) : QWidget(QApplication::desktop()->screen( screen ), - 0, WStyle_Customize | WStyle_Tool | WStyle_NoBorder | WX11BypassWM ) + 0, WStyle_Customize | WStyle_Tool | WStyle_NoBorder | WX11BypassWM ), oldpmser( 0 ), oldbmser( 0 ) { } - void setPixmap(QPixmap pm) + void setPixmap(QPixmap pm, QPoint hot) { - pixmap = pm; - if ( pixmap.mask() ) { - setMask( *pixmap.mask() ); - } else { - clearMask(); + int bmser = pm.mask() ? pm.mask()->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()); + QBitmap mask = pixmap.mask() ? *pixmap.mask() : QBitmap( pm.width(), pm.height()); + if( hotspot_in ) { + if( !pixmap.mask()) + mask.fill( Qt::color1 ); + QPainter p( &mask ); + p.setPen( Qt::color0 ); + p.drawPoint( hot.x(), hot.y()); + p.end(); + pm.setMask( mask ); } + setMask( mask ); + pixmap = pm; resize(pm.width(),pm.height()); } @@ -269,6 +286,9 @@ public: { bitBlt(this,0,0,&pixmap); } + int oldpmser; + int oldbmser; + QPoint oldhot; }; QShapedPixmapWidget * qt_xdnd_deco = 0; @@ -865,6 +885,38 @@ void QDragManager::timerEvent( QTimerEve move( QCursor::pos() ); } +static bool was_move = false; +static bool found = false; +static +Bool predicate( Display*, XEvent* ev, XPointer ) +{ + if( found ) + return False; + if( ev->type == MotionNotify ) + { + was_move = true; + found = true; + } + if( ev->type == ButtonPress || ev->type == ButtonRelease + || ev->type == XKeyPress || ev->type == XKeyRelease + || ev->type == ClientMessage ) + { + was_move = false; + found = true; + } + return False; +} + +static +bool another_movement() +{ + was_move = false; + found = false; + XEvent dummy; + XCheckIfEvent( qt_xdisplay(), &dummy, predicate, NULL ); + return was_move; +} + bool QDragManager::eventFilter( QObject * o, QEvent * e) { if ( beingCancelled ) { @@ -887,8 +939,14 @@ bool QDragManager::eventFilter( QObject if ( e->type() == QEvent::MouseMove ) { QMouseEvent* me = (QMouseEvent *)e; - updateMode(me->stateAfter()); - move( me->globalPos() ); + if( !another_movement()) { + updateMode(me->stateAfter()); + move( me->globalPos() ); + } + else { + static int i = 0; + qDebug( "AVOIDING %d", ++i ); + } return TRUE; } else if ( e->type() == QEvent::MouseButtonRelease ) { qApp->removeEventFilter( this ); @@ -1136,6 +1194,7 @@ void QDragManager::move( const QPoint & Window targetW = qt_x11_findClientWindow( target, qt_wm_state, TRUE ); if (targetW) target = targetW; + qDebug( "TAR: 0x%lx 0x%lx 0x%lx", target, targetW, qt_xdnd_deco->winId()); if ( qt_xdnd_deco && (!target || target == qt_xdnd_deco->winId()) ) { target = findRealWindow(globalPos,rootwin,6); } @@ -1700,7 +1759,7 @@ void QDragManager::updatePixmap() defaultPm = new QPixmap(default_pm); pm = *defaultPm; } - qt_xdnd_deco->setPixmap(pm); + qt_xdnd_deco->setPixmap(pm, pm_hot); qt_xdnd_deco->move(QCursor::pos()-pm_hot); qt_xdnd_deco->repaint(FALSE); //if ( willDrop ) { --Boundary-00=_g06P+JEqeULzfj8-- _______________________________________________ Kde-optimize mailing list Kde-optimize@mail.kde.org http://mail.kde.org/mailman/listinfo/kde-optimize