News:

Masm32 SDK description, downloads and other helpful links
Message to All Guests
NB: Posting URL's See here: Posted URL Change

Main Menu

Other top windows flicker: how to prevent WM_PAINT broadcast?

Started by jj2007, January 10, 2016, 09:18:56 PM

Previous topic - Next topic

jj2007

I have a stupid little app (exe attached, source is a bit too complex) that shows a clock using inter alia CreateEllipticRgn and SetWindowRgn.

After reading several times the excellent Flicker-free Drawing tutorial, I am still stuck (and no, CS_VREDRAW and CS_HREDRAW styles are not set). Same applies to possible causes explained here, like LockWindowUpdate or WM_SETTINGCHANGE.

The problem is that when I repaint the time$ 12:34:56 once a second, other underlying top level windows repaint. Which probably means that somehow they get a WM_PAINT message via some broadcast mechanism. Since there is nothing to repaint, actually, i'd like to stop this broadcasting. Any ideas?

P.S.: When launching Notepad.exe, its menus flicker even if the entire Notepad window is far a way from the clock. So it is really a kind of system-wide repaint issue. Btw Firefox does NOT flicker.

P.P.S.: It turns out (with Spy++) that other windows get a WM_SYNCPAINT message. That can be suppressed by using the SWP_DEFERERASE flag in SetWindowPos. Problem is I am nowhere using SetWindowPos, so that cannot be the cause ::)

P.P.P.S.: Using GetDC instead of BeginPaint to paint the time "solves" the problem. So apparently BeginPaint/EndPaint are somehow involved in generating the WM_SYNCPAINT message.

Grincheux

It is 13:21:29 since five minutes!

Have you thought to WM_ERASEBCKGRND

Grincheux

I don't agree, if you tell MoveWindow that it must not send a WM_PAINT it does not send it.
Idem for SystemParametersInfo, and it depends which function is called. GET or SET and within the set function it is not obliged to send  a broadcast message.

Grincheux

http://f0dder.reteam.org/wm_timer.htm

If the problem was from WM_TIMER?
Try to catch the timer after GetMessage and never pass it to dispatch message

jj2007

Philippe,
Thanks but this is about WM_SYNCPAINT being sent to other top-level windows.


jj2007

Quote from: TWell on January 10, 2016, 11:43:56 PM
Like this here

Raymond writes: "When a window has been hidden, shown, moved or sized, the system may determine that it needs to send a WM_SYNC­PAINT message to the windows of other threads."

Point is, my windows gets an internal painting onto its own client area due to a SetTimer(). It doesn't get hidden, shown, moved or sized, so why the hell does the stupid OS instruct other windows to redraw?

I found a really clumsy workaround:

Case WM_TIMER
invoke GetDC, hWnd
push eax
push hWnd
push PtDC
mov PtDC, eax
GuiSetFill 4
GuiText 34.5, 70.0, Time$, bcol 0, fcol RgbCol(0, 0, 255)
pop PtDC
call ReleaseDC


Works like a charm, see attached exe, but this is really a hack, not a solution :(


qWord

Quote from: jj2007 on January 11, 2016, 01:54:08 AMso why the hell does the stupid OS instruct other windows to redraw?
Because you decided to use error-prone "optimizations" in API code.
MREAL macros - when you need floating point arithmetic while assembling!

jj2007

Quote from: qWord on January 11, 2016, 03:12:48 AM
Quote from: jj2007 on January 11, 2016, 01:54:08 AMso why the hell does the stupid OS instruct other windows to redraw?
Because you decided to use error-prone "optimizations" in API code.

Hmmm... that looks promising: Can you explain which "optimisation" triggers the sync message?

qWord

MREAL macros - when you need floating point arithmetic while assembling!

jj2007

Quote from: qWord on January 11, 2016, 03:34:37 AM
InvalidateRect@TimeProc -> hWnd

:t

My fault :redface: I think I started that cbTimer as a frameless proc and changed my mind later. So with uses esi edi ebx the stack[3*4] arg was no longer hwnd but rather a zero...

Just for curiosity: How did you find it so quickly? You hooked InvalidateRect?

qWord

Quote from: jj2007 on January 11, 2016, 04:05:46 AM
Just for curiosity: How did you find it so quickly? You hooked InvalidateRect?
yes, I set a breakpoint an CALL in TimeProc. (after recognizing that you still handle message wrong...)
MREAL macros - when you need floating point arithmetic while assembling!

jj2007

OK. To sum it up:

If you use InvalidateRect, hWnd, 0, 0 then make sure hWnd is really your window's handle. If you pass a zero instead, the OS sends a WM_SYNC­PAINT message to all top-level windows, and you'll get a lot of flicker all over the place.

qWord

There is no reason to know WM_SYNCPAINT, because it is a system internal message.
msdn actual explain it very well:
Quote from: msdn: InvalidateRect, hWndA handle to the window whose update region has changed. If this parameter is NULL, the system invalidates and redraws all windows, not just the windows for this application, and sends the WM_ERASEBKGND and WM_NCPAINT messages before the function returns. Setting this parameter to NULL is not recommended.

MREAL macros - when you need floating point arithmetic while assembling!