Nikolay Sivov : comctl32/monthcal: Process UpDown year control through subclass procedure.

Alexandre Julliard julliard at winehq.org
Mon Oct 12 11:19:44 CDT 2009


Module: wine
Branch: master
Commit: 2906aaf605e432bdb7d46be33727fe53a525470a
URL:    http://source.winehq.org/git/wine.git/?a=commit;h=2906aaf605e432bdb7d46be33727fe53a525470a

Author: Nikolay Sivov <bunglehead at gmail.com>
Date:   Sat Oct 10 21:04:16 2009 +0400

comctl32/monthcal: Process UpDown year control through subclass procedure.

---

 dlls/comctl32/monthcal.c       |  126 ++++++++++++++++++++++++++++-----------
 dlls/comctl32/tests/monthcal.c |   23 +++++++
 2 files changed, 113 insertions(+), 36 deletions(-)

diff --git a/dlls/comctl32/monthcal.c b/dlls/comctl32/monthcal.c
index 7697187..fc73537 100644
--- a/dlls/comctl32/monthcal.c
+++ b/dlls/comctl32/monthcal.c
@@ -128,6 +128,7 @@ typedef struct
     HWND hwndNotify;    /* Window to receive the notifications */
     HWND hWndYearEdit;  /* Window Handle of edit box to handle years */
     HWND hWndYearUpDown;/* Window Handle of updown box to handle years */
+    WNDPROC EditWndProc;  /* original Edit window procedure */
 } MONTHCAL_INFO, *LPMONTHCAL_INFO;
 
 
@@ -1355,7 +1356,7 @@ MONTHCAL_GetCurSel(const MONTHCAL_INFO *infoPtr, SYSTEMTIME *curSel)
 
 /* FIXME: if the specified date is not visible, make it visible */
 static LRESULT
-MONTHCAL_SetCurSel(MONTHCAL_INFO *infoPtr, SYSTEMTIME *curSel)
+MONTHCAL_SetCurSel(MONTHCAL_INFO *infoPtr, const SYSTEMTIME *curSel)
 {
   TRACE("%p\n", curSel);
   if(!curSel) return FALSE;
@@ -1725,6 +1726,53 @@ MONTHCAL_RButtonUp(MONTHCAL_INFO *infoPtr, LPARAM lParam)
   return 0;
 }
 
+/***
+ * DESCRIPTION:
+ * Subclassed edit control windproc function
+ *
+ * PARAMETER(S):
+ * [I] hwnd : the edit window handle
+ * [I] uMsg : the message that is to be processed
+ * [I] wParam : first message parameter
+ * [I] lParam : second message parameter
+ *
+ */
+static LRESULT CALLBACK EditWndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
+{
+    MONTHCAL_INFO *infoPtr = (MONTHCAL_INFO *)GetWindowLongPtrW(GetParent(hwnd), 0);
+
+    TRACE("(hwnd=%p, uMsg=%x, wParam=%lx, lParam=%lx)\n",
+	  hwnd, uMsg, wParam, lParam);
+
+    switch (uMsg)
+    {
+	case WM_GETDLGCODE:
+	  return DLGC_WANTARROWS | DLGC_WANTALLKEYS;
+
+	case WM_DESTROY:
+	{
+	    WNDPROC editProc = infoPtr->EditWndProc;
+	    infoPtr->EditWndProc = NULL;
+	    SetWindowLongPtrW(hwnd, GWLP_WNDPROC, (DWORD_PTR)editProc);
+	    return CallWindowProcW(editProc, hwnd, uMsg, wParam, lParam);
+	}
+
+	case WM_KILLFOCUS:
+	    break;
+
+	case WM_KEYDOWN:
+	    if ((VK_ESCAPE == (INT)wParam) || (VK_RETURN == (INT)wParam))
+		break;
+
+	default:
+	    return CallWindowProcW(infoPtr->EditWndProc, hwnd, uMsg, wParam, lParam);
+    }
+
+    SendMessageW(infoPtr->hWndYearUpDown, WM_CLOSE, 0, 0);
+    SendMessageW(hwnd, WM_CLOSE, 0, 0);
+    return 0;
+}
+
 /* creates updown control and edit box */
 static void MONTHCAL_EditYear(MONTHCAL_INFO *infoPtr)
 {
@@ -1749,6 +1797,12 @@ static void MONTHCAL_EditYear(MONTHCAL_INFO *infoPtr)
                  MAKELONG(max_allowed_date.wYear, min_allowed_date.wYear));
     SendMessageW(infoPtr->hWndYearUpDown, UDM_SETBUDDY, (WPARAM)infoPtr->hWndYearEdit, 0);
     SendMessageW(infoPtr->hWndYearUpDown, UDM_SETPOS, 0, infoPtr->curSel.wYear);
+
+    /* subclass edit box */
+    infoPtr->EditWndProc = (WNDPROC)SetWindowLongPtrW(infoPtr->hWndYearEdit,
+                                  GWLP_WNDPROC, (DWORD_PTR)EditWndProc);
+
+    SetFocus(infoPtr->hWndYearEdit);
 }
 
 static LRESULT
@@ -1757,24 +1811,12 @@ MONTHCAL_LButtonDown(MONTHCAL_INFO *infoPtr, LPARAM lParam)
   MCHITTESTINFO ht;
   DWORD hit;
 
-  if (infoPtr->hWndYearUpDown)
+  /* Actually we don't need input focus for calendar, this is used to kill
+     year updown and its buddy edit box */
+  if (IsWindow(infoPtr->hWndYearUpDown))
   {
-      infoPtr->curSel.wYear = SendMessageW(infoPtr->hWndYearUpDown, UDM_SETPOS, 0, 0);
-      if(!DestroyWindow(infoPtr->hWndYearUpDown))
-      {
-          FIXME("Can't destroy Updown Control\n");
-      }
-      else
-	  infoPtr->hWndYearUpDown = 0;
-
-      if(!DestroyWindow(infoPtr->hWndYearEdit))
-      {
-          FIXME("Can't destroy Updown Control\n");
-      }
-      else
-          infoPtr->hWndYearEdit = 0;
-
-      InvalidateRect(infoPtr->hwndSelf, NULL, FALSE);
+      SetFocus(infoPtr->hwndSelf);
+      return 0;
   }
 
   SetCapture(infoPtr->hwndSelf);
@@ -1899,6 +1941,8 @@ MONTHCAL_LButtonUp(MONTHCAL_INFO *infoPtr, LPARAM lParam)
 
   SendMessageW(infoPtr->hwndNotify, WM_NOTIFY, nmhdr.idFrom, (LPARAM)&nmhdr);
 
+  if(!(infoPtr->status & MC_SEL_LBUTDOWN)) return 0;
+
   ht.cbSize = sizeof(MCHITTESTINFO);
   ht.pt.x = (short)LOWORD(lParam);
   ht.pt.y = (short)HIWORD(lParam);
@@ -2049,21 +2093,6 @@ MONTHCAL_Paint(MONTHCAL_INFO *infoPtr, HDC hdc_paint)
   return 0;
 }
 
-
-static LRESULT
-MONTHCAL_KillFocus(const MONTHCAL_INFO *infoPtr, HWND hFocusWnd)
-{
-  TRACE("\n");
-
-  if (infoPtr->hwndNotify != hFocusWnd)
-    ShowWindow(infoPtr->hwndSelf, SW_HIDE);
-  else
-    InvalidateRect(infoPtr->hwndSelf, NULL, TRUE);
-
-  return 0;
-}
-
-
 static LRESULT
 MONTHCAL_SetFocus(const MONTHCAL_INFO *infoPtr)
 {
@@ -2360,6 +2389,31 @@ MONTHCAL_Destroy(MONTHCAL_INFO *infoPtr)
   return 0;
 }
 
+/*
+ * Handler for WM_NOTIFY messages
+ */
+static LRESULT
+MONTHCAL_Notify(MONTHCAL_INFO *infoPtr, NMHDR *hdr)
+{
+  /* notification from year edit updown */
+  if (hdr->code == UDN_DELTAPOS)
+  {
+    NMUPDOWN *nmud = (NMUPDOWN*)hdr;
+
+    if (hdr->hwndFrom == infoPtr->hWndYearUpDown)
+    {
+      /* year value limits are set up explicitly after updown creation */
+      if ((nmud->iDelta + nmud->iPos) != infoPtr->curSel.wYear)
+      {
+        SYSTEMTIME new_date = infoPtr->curSel;
+
+        new_date.wYear = nmud->iDelta + nmud->iPos;
+        MONTHCAL_SetCurSel(infoPtr, &new_date);
+      }
+    }
+  }
+  return 0;
+}
 
 static LRESULT WINAPI
 MONTHCAL_WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
@@ -2439,9 +2493,6 @@ MONTHCAL_WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
   case WM_GETDLGCODE:
     return DLGC_WANTARROWS | DLGC_WANTCHARS;
 
-  case WM_KILLFOCUS:
-    return MONTHCAL_KillFocus(infoPtr, (HWND)wParam);
-
   case WM_RBUTTONUP:
     return MONTHCAL_RButtonUp(infoPtr, lParam);
 
@@ -2464,6 +2515,9 @@ MONTHCAL_WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
   case WM_SIZE:
     return MONTHCAL_Size(infoPtr, (SHORT)LOWORD(lParam), (SHORT)HIWORD(lParam));
 
+  case WM_NOTIFY:
+    return MONTHCAL_Notify(infoPtr, (NMHDR*)lParam);
+
   case WM_CREATE:
     return MONTHCAL_Create(hwnd, (LPCREATESTRUCTW)lParam);
 
diff --git a/dlls/comctl32/tests/monthcal.c b/dlls/comctl32/tests/monthcal.c
index 21c171e..d767066 100644
--- a/dlls/comctl32/tests/monthcal.c
+++ b/dlls/comctl32/tests/monthcal.c
@@ -1647,6 +1647,28 @@ static void test_monthcal_selrange(void)
     DestroyWindow(hwnd);
 }
 
+static void test_killfocus(void)
+{
+    HWND hwnd;
+    DWORD style;
+
+    hwnd = create_monthcal_control(0);
+
+    /* make parent invisible */
+    style = GetWindowLong(parent_wnd, GWL_STYLE);
+    SetWindowLong(parent_wnd, GWL_STYLE, style &~ WS_VISIBLE);
+
+    SendMessage(hwnd, WM_KILLFOCUS, (WPARAM)GetDesktopWindow(), 0);
+
+    style = GetWindowLong(hwnd, GWL_STYLE);
+    ok(style & WS_VISIBLE, "Expected WS_VISIBLE to be set\n");
+
+    style = GetWindowLong(parent_wnd, GWL_STYLE);
+    SetWindowLong(parent_wnd, GWL_STYLE, style | WS_VISIBLE);
+
+    DestroyWindow(hwnd);
+}
+
 START_TEST(monthcal)
 {
     HMODULE hComctl32;
@@ -1684,6 +1706,7 @@ START_TEST(monthcal)
     test_monthcal_size();
     test_monthcal_maxselday();
     test_monthcal_selrange();
+    test_killfocus();
 
     flush_sequences(sequences, NUM_MSG_SEQUENCES);
     DestroyWindow(parent_wnd);




More information about the wine-cvs mailing list