title: WM_PAINT: Manage hovering on an item of a tab control
body: <p>So I'm overriding the WM_PAINT message of a tab control to add a close button, and to make a consistent look with the other controls of my application, I need to highlight the currently hovered item. The problem is the repainting does not work as expected, and I don't know how to manage the hovering state. The hovered item doesn't know when the mouse cursor has left it.</p>
  <p>Here is a piece of code:</p>
  <pre class="lang-cpp prettyprint-override"><code>    switch (msg) {
      case WM_PAINT:
      {
          auto style = GetWindowLongPtr(m_self, GWL_STYLE);
          // Let the system process the WM_PAINT message if the Owner Draw Fixed style is set.
          if (style &amp; TCS_OWNERDRAWFIXED) {
              break;
          }
          PAINTSTRUCT ps{};
          HDC hdc = BeginPaint(m_self, &amp;ps);
          RECT rc{};
          GetClientRect(m_self, &amp;rc);
  
          // Paint the background
          HBRUSH bkgnd_brush = GetSysColorBrush(COLOR_BTNFACE);
          FillRect(hdc, &amp;rc, bkgnd_brush);
          DeleteObject(bkgnd_brush);
  
          // Get infos about the control
          int tabsCount = TabCtrl_GetItemCount(m_self);
          int tabsSelect = TabCtrl_GetCurSel(m_self);
          int ctl_identifier = GetDlgCtrlID(m_self);
  
          // Draw each items
          for (int i = 0; i &lt; tabsCount; ++i) {
              DRAWITEMSTRUCT dis{ ODT_TAB, ctl_identifier, static_cast&lt;UINT&gt;(i), 
              ODA_DRAWENTIRE, 0, m_self, hdc, RECT{}, 0 };
              TabCtrl_GetItemRect(m_self, i, &amp;dis.rcItem);
              const UINT buffSize = 128;
              wchar_t buff[buffSize];
              TCITEM ti{};
              ti.mask = TCIF_TEXT;
              ti.pszText = buff;
              ti.cchTextMax = buffSize;
              this-&gt;Notify&lt;int, LPTCITEM&gt;(TCM_GETITEM, i, &amp;ti); // Template class == SendMessageW
  
              // Get item state
              bool isHover = false;
              HBRUSH hBrush = NULL;
              POINT pt{};
              GetCursorPos(&amp;pt);
              ScreenToClient(m_self, &amp;pt);
              // Item's bounds
              if ((pt.x &gt;= dis.rcItem.left &amp;&amp; pt.x &lt;= dis.rcItem.right) &amp;&amp; (pt.y &gt;= dis.rcItem.top &amp;&amp; pt.y &lt;= dis.rcItem.bottom)) {
                  m_hoveredTab = dis.rcItem;
                  isHover = true;
              }
  
              // Paint item according to its current state
              hBrush = CreateSolidBrush(
              (i == tabsSelect) ? 
              RGB(255, 131, 10) : isHover ? 
              RGB(255, 10, 73) : RGB(102, 10, 255));
              
              FillRect(hdc, &amp;dis.rcItem, hBrush);
              DeleteObject(hBrush);
              
              // Draw Text
              SetBkMode(hdc, TRANSPARENT);
              SetTextColor(hdc, RGB(0, 0, 0));
              DrawTextW(hdc, buff, lstrlen(buff), &amp;dis.rcItem, DT_SINGLELINE | DT_LEFT | DT_VCENTER);
          }
          EndPaint(m_self, &amp;ps);
          return 0;
      }
  
      // MOUSE EVENTS
      case WM_MOUSEMOVE:
      {
          if (m_mouseTracking == FALSE) {
              TRACKMOUSEEVENT trackMouseStruct{};
              trackMouseStruct.cbSize = sizeof(trackMouseStruct);
              trackMouseStruct.dwFlags = TME_HOVER | TME_LEAVE;
              trackMouseStruct.hwndTrack = m_self;
              trackMouseStruct.dwHoverTime = 1; // Shorter hover time to instantly hover a tab item
              m_mouseTracking = TrackMouseEvent(&amp;trackMouseStruct);
          }
          break;
      }
  
      case WM_MOUSEHOVER:
      {
          m_lostFocus = false;
          break;
      }
  
      case WM_MOUSELEAVE:
      {
          m_mouseTracking = FALSE;
          m_lostFocus = true;
          break;
      }
  
    . . .
  </code></pre>