# win32 not to redraw while resize (openGL)+custom window skin+others

## Recommended Posts

Hi all! The question is the opposite as usual: why is the window redrawing constantly when resized/moved? I know this is the behavior most of us want, but I don't (for performance reasons). And a related question: I'm not sure that my redrawing (WM_PAINT) stuff is good at all. The program should redraw, only if I want it to. (So no constant updates) The old version worked as expected: it didn't redraw, while the left button were pressed during resize/move. The updates woks as expected otherwise. Old message loop:
while( !EscapeGame )
{
if( PeekMessage(&msg,NULL,0,0,PM_REMOVE) )
{

if( msg.message==WM_QUIT )
EscapeGame = true;

else
{	TranslateMessage(&msg);
DispatchMessage(&msg);
}
continue;
}

Display();//if I comment this out, and use WM_PAINT/UpdateWindow in windProc, the problem is the same
WaitMessage();
}


New message loop:
while( GetMessage( &msg, NULL, 0, 0 ) )
{
if (msg.message==WM_QUIT)
{
break;
}
else
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}


WindProc:
LRESULT CALLBACK WndProc(HWND hWnd,UINT uMsg,WPARAM wParam,LPARAM lParam)
{
switch(uMsg)
{
case WM_ACTIVATE:
if( !GameOver && GameStarted )
{	int minimized = HIWORD(wParam);

if ( minimized && win_state.Active )
{
PauseTimeStart = timeGetTime();
win_state.Active = false;
}
else if( !minimized && !win_state.Active )
{
TimeStart += (timeGetTime() - PauseTimeStart);
TimerFunc();

win_state.Active = true;
}
}

InvalidateRect(win_state.hWnd, NULL, FALSE);
UpdateWindow(win_state.hWnd);

return 0;

case WM_CLOSE:

...

InvalidateRect(win_state.hWnd, NULL, FALSE);
UpdateWindow(win_state.hWnd);

return 0;

case WM_GETMINMAXINFO:
{
PMINMAXINFO minmax;

minmax = (PMINMAXINFO)lParam;

minmax->ptMinTrackSize.x = 400;
minmax->ptMinTrackSize.y = 300;

}
//InvalidateRect(win_state.hWnd, NULL, FALSE);
//UpdateWindow(win_state.hWnd);
return 0;

case WM_TIMER:

//the old version didn't redraw, even when the timer expired
// timer values are about 0.5 seconds (quite slow)

...

InvalidateRect(win_state.hWnd, NULL, FALSE);
UpdateWindow(win_state.hWnd);

return 0;

case WM_SIZE:
if( wParam != SIZE_MINIMIZED )
{
SCRN_WDTH = LOWORD(lParam);
ResizeWindow(SCRN_WDTH, SCRN_HGHT);

//InvalidateRect(win_state.hWnd, NULL, FALSE);
//UpdateWindow(win_state.hWnd);//redraws, even when commented
}
return 0;

case WM_LBUTTONDOWN:
Lft_Btn = true;
SetCapture(win_state.hWnd);

if( Rgt_Btn )
Lft_Rgt_Dwn = true;

...

InvalidateRect(win_state.hWnd, NULL, FALSE);
UpdateWindow(win_state.hWnd);
return 0;

case WM_MBUTTONDOWN:
Mdl_Btn = true;
SetCapture(win_state.hWnd);

InvalidateRect(win_state.hWnd, NULL, FALSE);
UpdateWindow(win_state.hWnd);
return 0;

case WM_RBUTTONDOWN:
Rgt_Btn = true;
if( Lft_Btn )
Lft_Rgt_Dwn = true;
...

InvalidateRect(win_state.hWnd, NULL, FALSE);
UpdateWindow(win_state.hWnd);

return 0;

case WM_LBUTTONUP:
Lft_Btn = false;
if( !Mdl_Btn )
ReleaseCapture();
...

InvalidateRect(win_state.hWnd, NULL, FALSE);
UpdateWindow(win_state.hWnd);

return 0;

case WM_MBUTTONUP:
Mdl_Btn = false;
if( !Lft_Btn )
ReleaseCapture();

InvalidateRect(win_state.hWnd, NULL, FALSE);
UpdateWindow(win_state.hWnd);

return 0;

case WM_RBUTTONUP:
Rgt_Btn = false;
...

InvalidateRect(win_state.hWnd, NULL, FALSE);
UpdateWindow(win_state.hWnd);

return 0;

case WM_MOUSEMOVE:
MouseX = (int)(short)LOWORD(lParam);
MouseY = (int)(short)HIWORD(lParam);

MouseDX = MouseX - MousePrevX;
MouseDY = MouseY - MousePrevY;

MousePrevX = MouseX;
MousePrevY = MouseY;

...

InvalidateRect(win_state.hWnd, NULL, FALSE);
UpdateWindow(win_state.hWnd);

return 0;

case WM_MOUSE_ROLL:
CurrentChar = wParam;

...

InvalidateRect(win_state.hWnd, NULL, FALSE);
UpdateWindow(win_state.hWnd);

return 0;

case WM_CHAR:
CurrentChar = wParam;
...

InvalidateRect(win_state.hWnd, NULL, FALSE);
UpdateWindow(win_state.hWnd);

return 0;

case WM_KEYDOWN:
CurrentChar = wParam;
...

InvalidateRect(win_state.hWnd, NULL, FALSE);
UpdateWindow(win_state.hWnd);

return 0;

case WM_PAINT: // WM_PAINT, and UpdateWindow is only used with the new version of the message loop

Display();
ValidateRect(win_state.hWnd, NULL);

return 0;
}

return DefWindowProc(hWnd,uMsg,wParam,lParam);
}


Note, that this means the window is updated on almost every events, but I will make it to redraw only when I want it to. Or is it something with the validate/invalidate pairs? How can I get back to the "default" redraw behavior? Thanks for answers in advance! [Edited by - szecs on March 16, 2010 5:15:25 AM]

##### Share on other sites
An other question:
Is there a way to define custom skin for a window (titlebar +borders +minimize/close buttons)?

Or I have to make a window with no title bar, and draw the stuff myself + reimplement all the functions? (that's okay, but I don't want to jump into it, if there's a much simpler solution)

##### Share on other sites
Quote:
 Original post by szecsIs there a way to define custom skin for a window (titlebar +borders +minimize/close buttons)?Or I have to make a window with no title bar, and draw the stuff myself + reimplement all the functions? (that's okay, but I don't want to jump into it, if there's a much simpler solution)

The only way I know to do it is to do it all yourself. Create your window barebones with the WS_POPUP style, paint the whole thing, even the stuff that constitutes the "non-client area", in WM_PAINT, and handle WM_NCHITTEST appropriately. WM_NCHITTEST is what tells Windows that the user is, for example, dragging the title bar; it's the key to whole thing.

##### Share on other sites
Quote:
 And a related question: I'm not sure that my redrawing (WM_PAINT) stuff is good at all.

I'd need to see what the Display() function in your WM_PAINT handler is doing. I'm not following the code: don't understand how Display() is not getting the window's HWND, because aren't you going to have to call BeginPaint() with a window handle?

##### Share on other sites
hi there

1. Why don't you just leave windows OnPint() empty since you are using a timer?
like this :
LRESULT OnPaint(UINT, WPARAM, LPARAM, BOOL &){    CPaintDC dc();    return 0;}

2. When you resize to shrink a WIN32 window, the system very likely wont issue a WM_PAINT message, since your DC is larger than current window size, so no re-paint is needed (the larger part will be clipped anyway)

3. Same as above, when you MOVE a window you should not received WM_PAINT either, since the window DC size is not changed. (Drag while showing content?)

4. InvalidateRect() is just enough and i dont think update window is necessary

5. custom window skin : google 'Layered Window' may help

just my two cents anyway.

##### Share on other sites
Oh, sorry, completely forgot to mention: I use openGL for drawing. So it has its device context set up at initialization.

Thanks for your tip about WM_NCHITTEST, it seems a bit hard (MSDN doesn't explain the use of it in detail), but I have a GUI anyway, so I can implement the stuff there. It's just i don't want to update the window when WM_SIZE, because the rendering is quite slow. It's okay in the program, but can be annoying, when even moving/resizing the window is choppy.

##### Share on other sites
Quote:
 Original post by Pet123hi there1. Why don't you just leave windows OnPint() empty since you are using a timer?like this :*** Source Snippet Removed ***2. When you resize to shrink a WIN32 window, the system very likely wont issue a WM_PAINT message, since your DC is larger than current window size, so no re-paint is needed (the larger part will be clipped anyway)3. Same as above, when you MOVE a window you should not received WM_PAINT either, since the window DC size is not changed. (Drag while showing content?)4. InvalidateRect() is just enough and i dont think update window is necessaryjust my two cents anyway.
That's the problem, I don't want to update the window when moving/resizing (I don't call update in WM_SIZE), but it updates regardless of it.
Yes, InvalidateRect is enough, but the problem is the same.

##### Share on other sites
Does SetTimer issue WM_TIMER messages repeatedly, or just issues one message?
My guess is that it issues messages repeatedly, but I'm not sure, maybe there's a bug somewhere in my code.

Sorry, I don't want separate threads for these small questions.

EDIT: yup, repeatedly. I should have tried before asking...

[Edited by - szecs on March 16, 2010 5:18:51 AM]

##### Share on other sites
The original question is still a mystery for me. I mean how can the window be updated, when I don't call update/invalidaterect in the WM_SIZE handler?

The Layered Window stuff will be needed, so thanks for that.

##### Share on other sites
Quote:
 Original post by szecsThe original question is still a mystery for me. I mean how can the window be updated, when I don't call update/invalidaterect in the WM_SIZE handler?

Off the top of my head, I don't know. Are you concerned about the time that the redraws take or is is that they are creating a flicker? Because if it's a flicker you want to get rid of, you could double-buffer in your WM_PAINT.

##### Share on other sites
Quote:
Original post by jwezorek
Quote:
 Original post by szecsThe original question is still a mystery for me. I mean how can the window be updated, when I don't call update/invalidaterect in the WM_SIZE handler?

Off the top of my head, I don't know. Are you concerned about the time that the redraws take or is is that they are creating a flicker? Because if it's a flicker you want to get rid of, you could double-buffer in your WM_PAINT.
After all, it's not a big issue.
Sometimes in takes about 100 ms to render the scene, and this produces a bit choppy feel, which is okay in the application (mostly things are redrawn on events), but a bit annoying with resizing/moving the window.
And I want to understand why causes this behavior, because I want to as much control of the redrawing as possible.
I use double buffering BTW.

##### Share on other sites
Other question:
I want to maximize the window, but it will cover the taskbar, and I don't want that.
This is related to the window type: I have borderless/titlebar-less window:
CreateWindowEx(WS_EX_APPWINDOW|WS_EX_WINDOWEDGE,		WIND_CLASS_NAME,		WIND_CLASS_NAME,		WS_POPUP | WS_CLIPCHILDREN | WS_CLIPSIBLINGS,		...

I tried the followings:
if( maximize ){		SetWindowLong(	win_state.hWnd,GWL_STYLE,							WS_POPUP|WS_CLIPCHILDREN|WS_CLIPSIBLINGS|WS_THICKFRAME);	ShowWindow(win_state.hWnd,SW_MAXIMIZE);	SetWindowPos(win_state.hWnd,HWND_TOP,0,0,0,0,						SWP_NOMOVE|SWP_NOSIZE|SWP_NOZORDER|SWP_FRAMECHANGED);			}else{	SetWindowLong(	win_state.hWnd,GWL_STYLE,							WS_POPUP|WS_CLIPCHILDREN|WS_CLIPSIBLINGS);	ShowWindow(win_state.hWnd,SW_RESTORE);	SetWindowPos(win_state.hWnd,HWND_TOP,0,0,0,0,						SWP_NOMOVE|SWP_NOSIZE|SWP_NOZORDER|SWP_FRAMECHANGED);}

if( maximize ){		SetWindowLong(	win_state.hWnd,GWL_STYLE,							WS_POPUP|WS_CLIPCHILDREN|WS_CLIPSIBLINGS|WS_THICKFRAME);	SetWindowPos(win_state.hWnd,HWND_TOP,0,0,0,0,						SWP_NOMOVE|SWP_NOSIZE|SWP_NOZORDER|SWP_FRAMECHANGED);	ShowWindow(win_state.hWnd,SW_MAXIMIZE);			}else{	SetWindowLong(	win_state.hWnd,GWL_STYLE,							WS_POPUP|WS_CLIPCHILDREN|WS_CLIPSIBLINGS);	SetWindowPos(win_state.hWnd,HWND_TOP,0,0,0,0,						SWP_NOMOVE|SWP_NOSIZE|SWP_NOZORDER|SWP_FRAMECHANGED);	ShowWindow(win_state.hWnd,SW_RESTORE);}
Neither did the trick, plus the window can't be restored to its original size (without SetWindowLong/SetWindowPos the restoration is fine)

Is there a way around this, or I have to set (and keep track of) the window coordinates myself? And calculate the width of the taskbar somehow?

##### Share on other sites
You can prevent WM_PAINT from triggering if you call ValidateRect after you resize the window or do anything which would otherwise result in a WM_PAINT message being sent.

You can find out the size of various (non window) elements on the screen by using GetSystemMetrics. Also SystemParametersInfo.

##### Share on other sites
Quote:
 Original post by szecsThe question is the opposite as usual: why is the window redrawing constantly when resized/moved?I know this is the behavior most of us want, but I don't (for performance reasons).

To override full window drag (or size) you should detect the WM_ENTERSIZEMOVE / WM_EXITSIZEMOVE messages and set a flag that tells your WM_PAINT handler whether it should draw or not.

##### Share on other sites
Thanks, I'll look into it (since I use my own rezizing function (with MoveWindow) it will be tricky).
But I realized, that it's not a big issue after all. It's a game, so the user won't want to drag it or resize it too often, if so, the choppiness is acceptable.
And I tried resizing Visual Studio, well it's choppy as hell.

##### Share on other sites
The maximize/minimize thing is still not solved.
I can use systemmetrics to maximize myself, but this way the small "transition animation" would be missed (when the titlebar transitions smoothly (interestingly, I have that titlebar in the "animation", even the window doesn't have one)).
And for some reason, SM_CYFULLSCREEN returns wrong value (smaller, than the possible y resolution).
It would be the best to get the ShowWindow(win_state.hWnd,SW_MAXIMIZE/SW_RESTORE) thing working.

Thanks.

##### Share on other sites
Quote:
 And for some reason, SM_CYFULLSCREEN returns wrong value (smaller, than the possible y resolution).

It returns the height of the client area of a fullscreen window. Which the the screen resolution minus the taskbar size minus the window title bar and borders, etc.
Sometimes you need to take into account the menu bar size too

##### Share on other sites
Someone solved this problem on another message board:

You call ShowWindow with the SW_SHOWMAXIMIZED flag, which causes the popup window to take up the entire screen. Then you catch the following message and adjust the size of the parameters:

case WM_GETMINMAXINFO:  	 	      {  	 	         RECT WorkArea; SystemParametersInfo( SPI_GETWORKAREA, 0, &WorkArea, 0 );  	 	         ( ( MINMAXINFO * )lParam )->ptMaxSize.x = ( WorkArea.right - WorkArea.left );  	         ( ( MINMAXINFO * )lParam )->ptMaxSize.y = ( WorkArea.bottom - WorkArea.top );  	         ( ( MINMAXINFO * )lParam )->ptMaxPosition.x = WorkArea.left;  	         ( ( MINMAXINFO * )lParam )->ptMaxPosition.y = WorkArea.top;  	 	         return 0;  	 	      }

This code just prevents the task bar from being hidden, but Windows will treat the maximized size as whatever size you specify.

##### Share on other sites
Thank you very much man!

I tried to catch WM_GETMINMAXINFO before, but with

minmax->ptMaxTrackSize.x = width;
minmax->ptMaxTrackSize.y = height;

which did nothing. So many parameters in so many combinations

Thanks again!

Only one thing left: layered window, I hope it can be used with openGL context.

## Create an account

Register a new account

• ### Forum Statistics

• Total Topics
628360
• Total Posts
2982262

• 10
• 9
• 13
• 24
• 11