{"id":8863,"date":"2011-12-19T07:00:00","date_gmt":"2011-12-19T07:00:00","guid":{"rendered":"https:\/\/blogs.msdn.microsoft.com\/oldnewthing\/2011\/12\/19\/paint-messages-will-come-in-as-fast-as-you-let-them\/"},"modified":"2011-12-19T07:00:00","modified_gmt":"2011-12-19T07:00:00","slug":"paint-messages-will-come-in-as-fast-as-you-let-them","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/oldnewthing\/20111219-00\/?p=8863","title":{"rendered":"Paint messages will come in as fast as you let them"},"content":{"rendered":"<p>There is a class of messages which are generated on demand rather than explicitly posted into a message queue. If you call <code>Get&shy;Message<\/code> or <code>Peek&shy;Message<\/code> and the queue is empty, then the window manager will look to see if one of these generated-on-demand messages is due, messages like <code>WM_TIMER<\/code>, <code>WM_MOUSE&shy;MOVE<\/code>, and <code>WM_PAINT<\/code>.\n Neil wonders, &#8220;<a href=\"http:\/\/blogs.msdn.com\/b\/oldnewthing\/archive\/2006\/02\/20\/535440.aspx#541386\">In that program that called <code>Invalidate&shy;Rect<\/code> 100,000 times, how many paint messages were generated<\/a>?&#8221;\n The Zen answer to this question is &#8220;Yes.&#8221;\n A more practical answer is &#8220;As many as you can get.&#8221;\n When somebody calls <code>Invalidate&shy;Rect<\/code>, the window manager adds the specified rectangle to the window&#8217;s invalid region (or invalidates the entire client area if no rectangle is provided) and sets a flag that says &#8220;Yo, there&#8217;s painting to be done!&#8221; (It&#8217;s not actually a flag, but you can think of it that way.)\n When a message retrieval function finds that there are no incoming sent messages to be dispatched nor any applicable messages in the queue to be retrieved, it looks at these extra flags to see if it should generate a message on the fly. If the &#8220;Yo, there&#8217;s painting to be done!&#8221; flag is set on a window that the thread is responsible for, a <code>WM_PAINT<\/code> message is generated for that window. (Similarly, a <code>WM_TIMER<\/code> is generated if a timer has elapsed, and a <code>WM_MOUSE&shy;MOVE<\/code> is generated if the mouse has moved since the last time this thread retrieved a mouse message.)\n Therefore, the number of <code>WM_PAINT<\/code> messages by 100,000 invalidations is not deterministic, but it&#8217;ll be at least one and may be as high as 100,000. It&#8217;s basically just a race between the invalidation thread and the paint thread.<\/p>\n<table>\n<tr>\n<td><code>Invalidate&shy;Rect<\/code><\/td>\n<\/tr>\n<tr>\n<td><code>Invalidate&shy;Rect<\/code><\/td>\n<\/tr>\n<tr>\n<td><\/td>\n<td><code>Get&shy;Message<\/code> (retrieves <code>WM_PAINT<\/code>)<\/td>\n<\/tr>\n<tr>\n<td><\/td>\n<td><code>WM_PAINT<\/code> dispatched<\/td>\n<\/tr>\n<tr>\n<td><\/td>\n<td><code>Get&shy;Message<\/code> (waits for a message)<\/td>\n<\/tr>\n<tr>\n<td><code>Invalidate&shy;Rect<\/code><\/td>\n<\/tr>\n<tr>\n<td><\/td>\n<td><code>Get&shy;Message<\/code> (returns with <code>WM_PAINT<\/code>)<\/td>\n<\/tr>\n<tr>\n<td><code>Invalidate&shy;Rect<\/code><\/td>\n<\/tr>\n<tr>\n<td><\/td>\n<td><code>WM_PAINT<\/code> dispatched<\/td>\n<\/tr>\n<tr>\n<td><code>Invalidate&shy;Rect<\/code><\/td>\n<\/tr>\n<tr>\n<td><\/td>\n<td><code>Get&shy;Message<\/code> (retrieves <code>WM_PAINT<\/code>)<\/td>\n<\/tr>\n<tr>\n<td><code>Invalidate&shy;Rect<\/code><\/td>\n<\/tr>\n<tr>\n<td><code>Invalidate&shy;Rect<\/code><\/td>\n<\/tr>\n<tr>\n<td><\/td>\n<td><code>WM_PAINT<\/code> dispatched<\/td>\n<\/tr>\n<tr>\n<td><\/td>\n<td><code>Get&shy;Message<\/code> (retrieves <code>WM_PAINT<\/code>)<\/td>\n<\/tr>\n<tr>\n<td><code>Invalidate&shy;Rect<\/code><\/td>\n<\/tr>\n<tr>\n<td><\/td>\n<td><code>WM_PAINT<\/code> dispatched<\/td>\n<\/tr>\n<tr>\n<td><\/td>\n<td><code>Get&shy;Message<\/code> (retrieves <code>WM_PAINT<\/code>)<\/td>\n<\/tr>\n<tr>\n<td><\/td>\n<td><code>WM_PAINT<\/code> dispatched<\/td>\n<\/tr>\n<tr>\n<td><\/td>\n<td><code>Get&shy;Message<\/code> (waits for a message)<\/td>\n<\/tr>\n<\/table>\n<p> If the thread doing the painting manages to call <code>Get&shy;Message<\/code> between each call to <code>Invalidate&shy;Rect<\/code>, then it will see every invalidation. On the other hand (which is more likely), it only manages to call <code>Get&shy;Message<\/code> after a few invalidations have taken place, it will see the accumulated invalidation in a single <code>WM_PAINT<\/code> message.<\/p>\n<p> Now that you understand how generated messages work, you can answer this question which sometimes comes in: <\/p>\n<blockquote class=\"q\"><p> If the user is continuously moving the mouse, how many <code>WM_MOUSE&shy;MOVE<\/code> messages will I get? <\/p><\/blockquote>\n","protected":false},"excerpt":{"rendered":"<p>There is a class of messages which are generated on demand rather than explicitly posted into a message queue. If you call Get&shy;Message or Peek&shy;Message and the queue is empty, then the window manager will look to see if one of these generated-on-demand messages is due, messages like WM_TIMER, WM_MOUSE&shy;MOVE, and WM_PAINT. Neil wonders, &#8220;In [&hellip;]<\/p>\n","protected":false},"author":1069,"featured_media":111744,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[1],"tags":[25],"class_list":["post-8863","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-oldnewthing","tag-code"],"acf":[],"blog_post_summary":"<p>There is a class of messages which are generated on demand rather than explicitly posted into a message queue. If you call Get&shy;Message or Peek&shy;Message and the queue is empty, then the window manager will look to see if one of these generated-on-demand messages is due, messages like WM_TIMER, WM_MOUSE&shy;MOVE, and WM_PAINT. Neil wonders, &#8220;In [&hellip;]<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/8863","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/users\/1069"}],"replies":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/comments?post=8863"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/8863\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/media\/111744"}],"wp:attachment":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/media?parent=8863"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/categories?post=8863"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/tags?post=8863"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}