[BUG_FIXED] (Author: jgr [SF user name: joerngr]) Fix dragging undocked window performance issue while using Vista Aero UI style.
git-svn-id: svn://svn.tuxfamily.org/svnroot/notepadplus/repository/trunk@658 f5eea248-9336-0410-98b8-ebc06183d4e3
This commit is contained in:
parent
3fa8a89e76
commit
2c05fa7f37
|
@ -14,6 +14,10 @@
|
||||||
//You should have received a copy of the GNU General Public License
|
//You should have received a copy of the GNU General Public License
|
||||||
//along with this program; if not, write to the Free Software
|
//along with this program; if not, write to the Free Software
|
||||||
//Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
//Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||||
|
//
|
||||||
|
// Changed something around drawRectangle() (for details see there) to enhance
|
||||||
|
// speed and consistency of the drag-rectangle - August 2010, Joern Gruel (jg)
|
||||||
|
|
||||||
|
|
||||||
#include "precompiledHeaders.h"
|
#include "precompiledHeaders.h"
|
||||||
#include "Gripper.h"
|
#include "Gripper.h"
|
||||||
|
@ -77,7 +81,6 @@ Gripper::Gripper()
|
||||||
_hInst = NULL;
|
_hInst = NULL;
|
||||||
_hParent = NULL;
|
_hParent = NULL;
|
||||||
_hSelf = NULL;
|
_hSelf = NULL;
|
||||||
|
|
||||||
_pDockMgr = NULL;
|
_pDockMgr = NULL;
|
||||||
_pCont = NULL;
|
_pCont = NULL;
|
||||||
|
|
||||||
|
@ -97,7 +100,7 @@ Gripper::Gripper()
|
||||||
_hbm = NULL;
|
_hbm = NULL;
|
||||||
_hbrush = NULL;
|
_hbrush = NULL;
|
||||||
|
|
||||||
|
memset(&_rcPrev, 0, sizeof(RECT));
|
||||||
memset(&_rcItem, 0, sizeof(RECT));
|
memset(&_rcItem, 0, sizeof(RECT));
|
||||||
memset(&_tcItem, 0, sizeof(TCITEM));
|
memset(&_tcItem, 0, sizeof(TCITEM));
|
||||||
memset(&_dockData, 0, sizeof(tDockMgr));
|
memset(&_dockData, 0, sizeof(tDockMgr));
|
||||||
|
@ -211,7 +214,7 @@ LRESULT Gripper::runProc(UINT message, WPARAM wParam, LPARAM lParam)
|
||||||
getMousePoints(&pt, &ptBuf);
|
getMousePoints(&pt, &ptBuf);
|
||||||
|
|
||||||
/* erase last drawn rectangle */
|
/* erase last drawn rectangle */
|
||||||
drawRectangle(ptBuf);
|
drawRectangle(NULL);
|
||||||
|
|
||||||
/* end hooking */
|
/* end hooking */
|
||||||
::UnhookWindowsHookEx(hookMouse);
|
::UnhookWindowsHookEx(hookMouse);
|
||||||
|
@ -298,18 +301,13 @@ void Gripper::onMove()
|
||||||
::GetCursorPos(&pt);
|
::GetCursorPos(&pt);
|
||||||
getMousePoints(&pt, &ptBuf);
|
getMousePoints(&pt, &ptBuf);
|
||||||
|
|
||||||
/* On first time: Do not erase previous rect, because it dosn't exist */
|
|
||||||
if (_bPtOldValid == TRUE)
|
|
||||||
drawRectangle(ptBuf);
|
|
||||||
|
|
||||||
/* tab reordering only when tab was selected */
|
/* tab reordering only when tab was selected */
|
||||||
if (_startMovingFromTab == TRUE)
|
if (_startMovingFromTab == TRUE)
|
||||||
{
|
{
|
||||||
doTabReordering(pt);
|
doTabReordering(pt);
|
||||||
}
|
}
|
||||||
|
|
||||||
drawRectangle(pt);
|
drawRectangle(&pt);
|
||||||
_bPtOldValid = TRUE;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -324,14 +322,14 @@ void Gripper::onButtonUp()
|
||||||
::GetCursorPos(&pt);
|
::GetCursorPos(&pt);
|
||||||
getMousePoints(&pt, &ptBuf);
|
getMousePoints(&pt, &ptBuf);
|
||||||
|
|
||||||
/* do nothing, when old point is not valid */
|
// do nothing, when old point is not valid
|
||||||
if (_bPtOldValid == FALSE)
|
if (_bPtOldValid == FALSE)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
/* erase last drawn rectangle */
|
// erase last drawn rectangle
|
||||||
drawRectangle(ptBuf);
|
drawRectangle(NULL);
|
||||||
|
|
||||||
/* look if current position is within dockable area */
|
// look if current position is within dockable area
|
||||||
DockingCont* pDockCont = contHitTest(pt);
|
DockingCont* pDockCont = contHitTest(pt);
|
||||||
|
|
||||||
if (pDockCont == NULL)
|
if (pDockCont == NULL)
|
||||||
|
@ -523,14 +521,53 @@ void Gripper::doTabReordering(POINT pt)
|
||||||
::UpdateWindow(_hParent);
|
::UpdateWindow(_hParent);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Changed behaviour (jg): Now this function handles erasing of drag-rectangles and drawing of
|
||||||
void Gripper::drawRectangle(POINT pt)
|
// new ones within one drawing step to the desktop. This is against flickering, but also it is
|
||||||
|
// necessary for the Vista Aero style - because in this case the control is given so much to
|
||||||
|
// the graphics driver, that accesses (especially read accesses) to the desktop window become
|
||||||
|
// too expensive to access it more than absolutely necessary. Besides, usage of the function
|
||||||
|
// ::LockWindowUpdate() was added, because with often redrawn windows in the background we had
|
||||||
|
// inconsistencies while erasing our drag-rectangle (because it could already have been erased
|
||||||
|
// on some places).
|
||||||
|
//
|
||||||
|
// Parameter pPt==NULL says that only erasing is wanted and the drag-rectangle is no more needed,
|
||||||
|
// thatswhy this also leads to a call of ::LockWindowUpdate(NULL) to enable drawing by others again.
|
||||||
|
// The previously drawn rectangle is memoried within _rectPrev (and _bPtOldValid says if it already
|
||||||
|
// is valid - did not change this members name because didn't want change too much at once).
|
||||||
|
//
|
||||||
|
// I was too lazy to always draw four rectangles for the four edges of the drag-rectangle - it seems
|
||||||
|
// that drawing an outer rectangle first and then erasing the inner stuff by drawing a second,
|
||||||
|
// smaller rectangle inside seems to be not slower - wich comes not unawaited, because it is mostly
|
||||||
|
// hardware-driven and each single draw has its own fixed costs.
|
||||||
|
//
|
||||||
|
// For further solutions I think we should leave this classic way of dragging and better use
|
||||||
|
// alpha-blending and always move the whole content of the toolbars - so we could leave the
|
||||||
|
// ::LockWindowUpdate() behind us.
|
||||||
|
//
|
||||||
|
// Besides, while debugging into the dragging process please let the ::LockWindowUpdate() out,
|
||||||
|
// by #undef the USE_LOCKWINDOWUPDATE in gripper.h, because it works for your debugging window
|
||||||
|
// as well, of course. Or just try by this #define what difference it makes.
|
||||||
|
//
|
||||||
|
void Gripper::drawRectangle(const POINT* pPt)
|
||||||
{
|
{
|
||||||
HANDLE hbrushOrig = NULL;
|
HBRUSH hbrushOrig= NULL;
|
||||||
|
HBITMAP hbmOrig = NULL;
|
||||||
RECT rc = {0};
|
RECT rc = {0};
|
||||||
|
RECT rcNew = {0};
|
||||||
|
RECT rcOld = _rcPrev;
|
||||||
|
|
||||||
|
// Get a screen device context with backstage redrawing disabled - to have a consistently
|
||||||
|
// and stable drawn rectangle while floating - keep in mind, that we must ensure, that
|
||||||
|
// finally ::LockWindowUpdate(NULL) will be called, to enable drawing for others again.
|
||||||
if (!_hdc)
|
if (!_hdc)
|
||||||
_hdc = ::GetDC(NULL);
|
{
|
||||||
|
HWND hWnd= ::GetDesktopWindow();
|
||||||
|
#if defined (USE_LOCKWINDOWUPDATE)
|
||||||
|
_hdc= ::GetDCEx(hWnd, NULL, ::LockWindowUpdate(hWnd) ? DCX_WINDOW|DCX_CACHE|DCX_LOCKWINDOWUPDATE : DCX_WINDOW|DCX_CACHE);
|
||||||
|
#else
|
||||||
|
_hdc= ::GetDCEx(hWnd, NULL, DCX_WINDOW|DCX_CACHE);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
// Create a brush with the appropriate bitmap pattern to draw our drag rectangle
|
// Create a brush with the appropriate bitmap pattern to draw our drag rectangle
|
||||||
if (!_hbm)
|
if (!_hbm)
|
||||||
|
@ -538,25 +575,90 @@ void Gripper::drawRectangle(POINT pt)
|
||||||
if (!_hbrush)
|
if (!_hbrush)
|
||||||
_hbrush = ::CreatePatternBrush(_hbm);
|
_hbrush = ::CreatePatternBrush(_hbm);
|
||||||
|
|
||||||
|
if (pPt != NULL)
|
||||||
|
{
|
||||||
// Determine whether to draw a solid drag rectangle or checkered
|
// Determine whether to draw a solid drag rectangle or checkered
|
||||||
getMovingRect(pt, &rc);
|
// ???(jg) solid or checked ??? - must have been an old comment, I didn't
|
||||||
|
// find here this difference, but at least it's a question of drag-rects size
|
||||||
|
//
|
||||||
|
getMovingRect(*pPt, &rcNew);
|
||||||
|
_rcPrev= rcNew; // save the new drawn rcNew
|
||||||
|
|
||||||
::SetBrushOrgEx(_hdc, rc.left, rc.top, 0);
|
// note that from here for handling purposes the right and bottom values of the rects
|
||||||
hbrushOrig = ::SelectObject(_hdc, _hbrush);
|
// contain width and height - its handsome, but i find it dangerous, but didn't want to
|
||||||
|
// change that already this time.
|
||||||
|
|
||||||
// line: left
|
if (_bPtOldValid)
|
||||||
::PatBlt(_hdc, rc.left, rc.top, 3, rc.bottom - 3, PATINVERT);
|
{
|
||||||
// line: top
|
// okay, there already a drag-rect has been drawn - and its position
|
||||||
::PatBlt(_hdc, rc.left + 3, rc.top, rc.right - 3, 3, PATINVERT);
|
// had been saved within the rectangle _rectPrev, wich already had been
|
||||||
// line: right
|
// copied into rcOld in the beginning, and a new drag position
|
||||||
::PatBlt(_hdc, rc.left + rc.right - 3, rc.top + 3, 3, rc.bottom - 3, PATINVERT);
|
// is available, too.
|
||||||
// line: bottom
|
// If now rcOld and rcNew are the same, just stop further handling to not
|
||||||
::PatBlt(_hdc, rc.left, rc.top + rc.bottom - 3, rc.right - 3, 3, PATINVERT);
|
// draw the same drag-rectangle twice (this really happens, it should be
|
||||||
|
// better avoided anywhere earlier)
|
||||||
|
//
|
||||||
|
if (rcOld.left==rcNew.left && rcOld.right==rcNew.right && rcOld.top== rcNew.top && rcOld.bottom==rcNew.bottom)
|
||||||
|
return;
|
||||||
|
|
||||||
// destroy resources
|
rc.left = min(rcOld.left, rcNew.left);
|
||||||
::SelectObject(_hdc, hbrushOrig);
|
rc.top = min(rcOld.top, rcNew.top);
|
||||||
|
rc.right = max(rcOld.left + rcOld.right, rcNew.left + rcNew.right);
|
||||||
|
rc.bottom = max(rcOld.top + rcOld.bottom, rcNew.top + rcNew.bottom);
|
||||||
|
rc.right -= rc.left;
|
||||||
|
rc.bottom-= rc.top;
|
||||||
|
}
|
||||||
|
else rc= rcNew; // only new rect will be drawn
|
||||||
|
}
|
||||||
|
else rc= rcOld; // only old rect will be drawn - to erase it
|
||||||
|
|
||||||
|
// now rc contains the rectangle wich encloses all needed, new and/or previous rectangle
|
||||||
|
// because in the following we drive within a memory device context wich is limited to rc,
|
||||||
|
// we have to localize rcNew and rcOld within rc...
|
||||||
|
//
|
||||||
|
rcOld.left= rcOld.left - rc.left;
|
||||||
|
rcOld.top = rcOld.top - rc.top;
|
||||||
|
rcNew.left= rcNew.left - rc.left;
|
||||||
|
rcNew.top = rcNew.top - rc.top;
|
||||||
|
|
||||||
|
HDC hdcMem= ::CreateCompatibleDC(_hdc);
|
||||||
|
HBITMAP hBm= ::CreateCompatibleBitmap(_hdc, rc.right, rc.bottom);
|
||||||
|
hbrushOrig= (HBRUSH)::SelectObject(hdcMem, hBm);
|
||||||
|
|
||||||
|
::SetBrushOrgEx(hdcMem, rc.left%8, rc.top%8, 0);
|
||||||
|
hbmOrig= (HBITMAP)::SelectObject(hdcMem, _hbrush);
|
||||||
|
|
||||||
|
::BitBlt(hdcMem, 0, 0, rc.right, rc.bottom, _hdc, rc.left, rc.top, SRCCOPY);
|
||||||
|
if (_bPtOldValid)
|
||||||
|
{ // erase the old drag-rectangle
|
||||||
|
::PatBlt(hdcMem, rcOld.left , rcOld.top , rcOld.right , rcOld.bottom , PATINVERT);
|
||||||
|
::PatBlt(hdcMem, rcOld.left+3, rcOld.top+3, rcOld.right-6, rcOld.bottom-6, PATINVERT);
|
||||||
|
}
|
||||||
|
if (pPt != NULL)
|
||||||
|
{ // draw the new drag-rectangle
|
||||||
|
::PatBlt(hdcMem, rcNew.left , rcNew.top , rcNew.right , rcNew.bottom , PATINVERT);
|
||||||
|
::PatBlt(hdcMem, rcNew.left+3, rcNew.top+3, rcNew.right-6, rcNew.bottom-6, PATINVERT);
|
||||||
|
}
|
||||||
|
::BitBlt(_hdc, rc.left, rc.top, rc.right, rc.bottom, hdcMem, 0, 0, SRCCOPY);
|
||||||
|
|
||||||
|
SelectObject(hdcMem, hbrushOrig);
|
||||||
|
SelectObject(hdcMem, hbmOrig);
|
||||||
|
DeleteObject(hBm);
|
||||||
|
DeleteDC(hdcMem);
|
||||||
|
|
||||||
|
if (pPt == NULL)
|
||||||
|
{
|
||||||
|
#if defined(USE_LOCKWINDOWUPDATE)
|
||||||
|
::LockWindowUpdate(NULL);
|
||||||
|
#endif
|
||||||
|
_bPtOldValid= FALSE;
|
||||||
|
if (_hdc)
|
||||||
|
{
|
||||||
|
::ReleaseDC(0, _hdc);
|
||||||
|
_hdc= NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else _bPtOldValid= TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -29,6 +29,10 @@
|
||||||
class DockingCont;
|
class DockingCont;
|
||||||
class DockingManager;
|
class DockingManager;
|
||||||
|
|
||||||
|
// For the following #define see the comments at drawRectangle() definition. (jg)
|
||||||
|
#define USE_LOCKWINDOWUPDATE
|
||||||
|
//#undef USE_LOCKWINDOWUPDATE
|
||||||
|
|
||||||
|
|
||||||
// Used by getRectAndStyle() to draw the drag rectangle
|
// Used by getRectAndStyle() to draw the drag rectangle
|
||||||
static const WORD DotPattern[] =
|
static const WORD DotPattern[] =
|
||||||
|
@ -54,6 +58,11 @@ public:
|
||||||
|
|
||||||
~Gripper() {
|
~Gripper() {
|
||||||
if (_hdc) {
|
if (_hdc) {
|
||||||
|
// usually this should already have been done by a call to drawRectangle(),
|
||||||
|
// here just for cases where usual handling was interrupted (jg)
|
||||||
|
#ifdef USE_LOCKWINDOWUPDATE
|
||||||
|
::LockWindowUpdate(NULL);
|
||||||
|
#endif
|
||||||
::ReleaseDC(0, _hdc);
|
::ReleaseDC(0, _hdc);
|
||||||
}
|
}
|
||||||
if (_hbm) {
|
if (_hbm) {
|
||||||
|
@ -75,7 +84,7 @@ protected :
|
||||||
void onButtonUp();
|
void onButtonUp();
|
||||||
|
|
||||||
void doTabReordering(POINT pt);
|
void doTabReordering(POINT pt);
|
||||||
void drawRectangle(POINT pt);
|
void drawRectangle(const POINT* pPt);
|
||||||
void getMousePoints(POINT* pt, POINT* ptPrev);
|
void getMousePoints(POINT* pt, POINT* ptPrev);
|
||||||
void getMovingRect(POINT pt, RECT *rc);
|
void getMovingRect(POINT pt, RECT *rc);
|
||||||
DockingCont * contHitTest(POINT pt);
|
DockingCont * contHitTest(POINT pt);
|
||||||
|
@ -120,6 +129,9 @@ private:
|
||||||
POINT _ptOld;
|
POINT _ptOld;
|
||||||
BOOL _bPtOldValid;
|
BOOL _bPtOldValid;
|
||||||
|
|
||||||
|
// remember last drawn rectangle (jg)
|
||||||
|
RECT _rcPrev;
|
||||||
|
|
||||||
// for sorting tabs
|
// for sorting tabs
|
||||||
HWND _hTab;
|
HWND _hTab;
|
||||||
HWND _hTabSource;
|
HWND _hTabSource;
|
||||||
|
|
Loading…
Reference in New Issue