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

Started by
17 comments, last by szecs 14 years, 1 month ago
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);
			SCRN_HGHT = HIWORD(lParam)-MENUBAR_HEIGHT;
			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]
Advertisement
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)
Quote:Original post by szecs
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)


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.

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?
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.
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.
Quote:Original post by Pet123
hi there

1. 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 necessary

just 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.
An other question: for some reason MSDN isn't clear for me about this one:
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]
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.
Quote:Original post by szecs
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?


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.

This topic is closed to new replies.

Advertisement