https://git.reactos.org/?p=reactos.git;a=commitdiff;h=7e396787ed00a3939031447725f79697a41878e1

commit 7e396787ed00a3939031447725f79697a41878e1
Author:     Denis Malikov <[email protected]>
AuthorDate: Tue Jan 15 20:36:41 2019 +0700
Commit:     Hermès BÉLUSCA - MAÏTO <[email protected]>
CommitDate: Tue Jan 15 14:36:41 2019 +0100

    [WIN32SS:NTUSER] Implement "Window Snap" feature (#1226)
    
    Implemented the following actions: stick the window on the left/right or 
maximize it,
    with the following shortcuts:
     - Win key + Arrows;
     - drag to left/right screen border;
     - double-click on top/bottom.
    
    CORE-12845
---
 win32ss/user/ntuser/defwnd.c    | 86 +++++++++++++++++++++++++++++++++++++++++
 win32ss/user/ntuser/hotkey.c    | 13 +++++++
 win32ss/user/ntuser/hotkey.h    |  6 +++
 win32ss/user/ntuser/input.c     |  5 +++
 win32ss/user/ntuser/nonclient.c | 72 ++++++++++++++++++++++++++++++++--
 5 files changed, 178 insertions(+), 4 deletions(-)

diff --git a/win32ss/user/ntuser/defwnd.c b/win32ss/user/ntuser/defwnd.c
index eb7284150c..d00d9aa853 100644
--- a/win32ss/user/ntuser/defwnd.c
+++ b/win32ss/user/ntuser/defwnd.c
@@ -781,6 +781,92 @@ IntDefWindowProc(
                co_IntSendMessage(UserHMGetHandle(Wnd), WM_CONTEXTMENU, 
(WPARAM)UserHMGetHandle(Wnd), MAKELPARAM(-1, -1));
             }
          }
+         if (IS_KEY_DOWN(gafAsyncKeyState, VK_LWIN) || 
IS_KEY_DOWN(gafAsyncKeyState, VK_RWIN))
+         {
+            PWND topWnd = UserGetWindowObject(UserGetForegroundWindow());
+            
+            if (topWnd)
+            {
+               if (wParam == VK_DOWN)
+               {
+                  co_IntSendMessage(UserHMGetHandle(topWnd), WM_SYSCOMMAND, 
(topWnd->style & WS_MAXIMIZE) ? SC_RESTORE : SC_MINIMIZE, lParam);
+               }    
+               else
+               if (wParam == VK_UP)
+               {
+                  RECT currentRect = (topWnd->InternalPos.NormalRect.right == 
topWnd->InternalPos.NormalRect.left) || 
+                                     (topWnd->InternalPos.NormalRect.top == 
topWnd->InternalPos.NormalRect.bottom)
+                                       ? topWnd->rcWindow 
+                                       : topWnd->InternalPos.NormalRect;
+                  co_IntSendMessage(UserHMGetHandle(topWnd), WM_SYSCOMMAND, 
SC_MAXIMIZE, 0);
+                  
+                  // save normal rect if maximazing snapped window
+                  topWnd->InternalPos.NormalRect = currentRect;
+               }
+               else
+               if (wParam == VK_LEFT || wParam == VK_RIGHT)
+               {
+                  RECT snapRect;
+                  RECT normalRect;
+                  RECT windowRect;
+                  BOOL snapped = FALSE;
+                  normalRect = topWnd->InternalPos.NormalRect;
+                  snapped = (normalRect.left != 0 
+                          && normalRect.right != 0
+                          && normalRect.top != 0
+                          && normalRect.bottom != 0);
+
+                  if (topWnd->style & WS_MAXIMIZE)
+                  {
+                     co_IntSendMessage(UserHMGetHandle(topWnd), WM_SYSCOMMAND, 
SC_RESTORE, lParam);
+                     snapped = FALSE;
+                  }
+                  
+                  windowRect = topWnd->rcWindow;
+
+                  UserSystemParametersInfo(SPI_GETWORKAREA, 0, &snapRect, 0);
+                  if (wParam == VK_LEFT)
+                  {
+                     snapRect.right = (snapRect.right - snapRect.left) / 2 + 
snapRect.left;
+                  }
+                  else // VK_RIGHT
+                  {
+                     snapRect.left = (snapRect.right - snapRect.left) / 2 + 
snapRect.left;
+                  }
+
+                  if (snapped)
+                  {
+                     // if window was snapped but moved to other location - 
restore normal size
+                     if (snapRect.left != windowRect.left ||
+                         snapRect.right != windowRect.right ||
+                         snapRect.top != windowRect.top ||
+                         snapRect.bottom != windowRect.bottom)
+                     {
+                        RECT empty = {0, 0, 0, 0};
+                        co_WinPosSetWindowPos(topWnd,
+                                        0,
+                                        normalRect.left,
+                                        normalRect.top,
+                                        normalRect.right - normalRect.left,
+                                        normalRect.bottom - normalRect.top,
+                                        0);
+                        topWnd->InternalPos.NormalRect = empty;
+                     }
+                  }
+                  else
+                  {
+                     co_WinPosSetWindowPos(topWnd,
+                                        0,
+                                        snapRect.left,
+                                        snapRect.top,
+                                        snapRect.right - snapRect.left,
+                                        snapRect.bottom - snapRect.top,
+                                        0);
+                     topWnd->InternalPos.NormalRect = windowRect;
+                  }
+               }
+            }
+         }
          break;
 
       case WM_SYSKEYDOWN:
diff --git a/win32ss/user/ntuser/hotkey.c b/win32ss/user/ntuser/hotkey.c
index f393906b20..02b504fe66 100644
--- a/win32ss/user/ntuser/hotkey.c
+++ b/win32ss/user/ntuser/hotkey.c
@@ -250,6 +250,19 @@ co_UserProcessHotKeys(WORD wVk, BOOL bIsDown)
                return FALSE;
             }
         }
+        
+        if (pHotKey->id == IDHK_SNAP_LEFT ||
+            pHotKey->id == IDHK_SNAP_RIGHT ||
+            pHotKey->id == IDHK_SNAP_UP ||
+            pHotKey->id == IDHK_SNAP_DOWN)
+        {
+            HWND topWnd = UserGetForegroundWindow();
+            if (topWnd)
+            {
+                UserPostMessage(topWnd, WM_KEYDOWN, wVk, 0);
+            }
+            return TRUE;
+        }
 
         if (!pHotKey->pWnd)
         {
diff --git a/win32ss/user/ntuser/hotkey.h b/win32ss/user/ntuser/hotkey.h
index b965677417..e86452204c 100644
--- a/win32ss/user/ntuser/hotkey.h
+++ b/win32ss/user/ntuser/hotkey.h
@@ -16,6 +16,12 @@ typedef struct _HOT_KEY
 #define IDHK_WINKEY    -7
 #define IDHK_REACTOS   -8
 
+/* Window Snap Hot Keys */
+#define IDHK_SNAP_LEFT   -10
+#define IDHK_SNAP_RIGHT  -11
+#define IDHK_SNAP_UP     -12
+#define IDHK_SNAP_DOWN   -13
+
 VOID FASTCALL UnregisterWindowHotKeys(PWND Window);
 VOID FASTCALL UnregisterThreadHotKeys(PTHREADINFO pti);
 BOOL NTAPI co_UserProcessHotKeys(WORD wVk, BOOL bIsDown);
diff --git a/win32ss/user/ntuser/input.c b/win32ss/user/ntuser/input.c
index e4dbbabba0..520ccca9eb 100644
--- a/win32ss/user/ntuser/input.c
+++ b/win32ss/user/ntuser/input.c
@@ -202,6 +202,11 @@ RawInputThreadMain(VOID)
                 UserEnterExclusive();
                 // Register the Window hotkey.
                 UserRegisterHotKey(PWND_BOTTOM, IDHK_WINKEY, MOD_WIN, 0);
+                // Register the Window Snap hotkey.
+                UserRegisterHotKey(PWND_BOTTOM, IDHK_SNAP_LEFT, MOD_WIN, 
VK_LEFT);
+                UserRegisterHotKey(PWND_BOTTOM, IDHK_SNAP_RIGHT, MOD_WIN, 
VK_RIGHT);
+                UserRegisterHotKey(PWND_BOTTOM, IDHK_SNAP_UP, MOD_WIN, VK_UP);
+                UserRegisterHotKey(PWND_BOTTOM, IDHK_SNAP_DOWN, MOD_WIN, 
VK_DOWN);
                 // Register the debug hotkeys.
                 StartDebugHotKeys();
                 UserLeave();
diff --git a/win32ss/user/ntuser/nonclient.c b/win32ss/user/ntuser/nonclient.c
index 8f45582142..7a5fcc445e 100644
--- a/win32ss/user/ntuser/nonclient.c
+++ b/win32ss/user/ntuser/nonclient.c
@@ -391,10 +391,59 @@ DefWndDoSizeMove(PWND pwnd, WORD wParam)
       if (!co_IntGetPeekMessage(&msg, 0, 0, 0, PM_REMOVE, TRUE)) break;
       if (IntCallMsgFilter( &msg, MSGF_SIZE )) continue;
 
-      /* Exit on button-up, Return, or Esc */
-      if ((msg.message == WM_LBUTTONUP) ||
-         ((msg.message == WM_KEYDOWN) &&
-          ((msg.wParam == VK_RETURN) || (msg.wParam == VK_ESCAPE)))) break;
+      /* Exit on button-up */
+      if (msg.message == WM_LBUTTONUP)
+      {
+         // check for snapping if was moved by caption
+         if (hittest == HTCAPTION)
+         {
+            RECT snapRect;
+            BOOL doSideSnap = FALSE;
+            UserSystemParametersInfo(SPI_GETWORKAREA, 0, &snapRect, 0);
+
+            // snap to left
+            if (pt.x <= snapRect.left)
+            {
+               snapRect.right = (snapRect.right - snapRect.left) / 2 + 
snapRect.left;
+               doSideSnap = TRUE;
+            }
+            // snap to right
+            if (pt.x >= snapRect.right-1)
+            {
+               snapRect.left = (snapRect.right - snapRect.left) / 2 + 
snapRect.left;
+               doSideSnap = TRUE;
+            }
+            
+            if (doSideSnap)
+            {
+               co_WinPosSetWindowPos(pwnd,
+                                     0,
+                                     snapRect.left,
+                                     snapRect.top,
+                                     snapRect.right - snapRect.left,
+                                     snapRect.bottom - snapRect.top,
+                                     0);
+               pwnd->InternalPos.NormalRect = origRect;
+            }
+            else
+            {
+               // maximize if on dragged to top
+               if (pt.y <= snapRect.top)
+               {
+                  co_IntSendMessage(UserHMGetHandle(pwnd), WM_SYSCOMMAND, 
SC_MAXIMIZE, 0);
+                  pwnd->InternalPos.NormalRect = origRect;
+               }
+            }
+         }
+         break;
+      }
+      
+      /* Exit on Return or Esc */
+      if (msg.message == WM_KEYDOWN &&
+          (msg.wParam == VK_RETURN || msg.wParam == VK_ESCAPE))
+      {
+         break;
+      }
 
       if ((msg.message != WM_KEYDOWN) && (msg.message != WM_MOUSEMOVE))
       {
@@ -1565,6 +1614,21 @@ NC_HandleNCLButtonDblClk(PWND pWnd, WPARAM wParam, 
LPARAM lParam)
       co_IntSendMessage(UserHMGetHandle(pWnd), WM_SYSCOMMAND, SC_CLOSE, 
lParam);
       break;
     }
+    case HTTOP:
+    case HTBOTTOM:
+    {
+      RECT sizingRect = pWnd->rcWindow, mouseRect;
+      UserSystemParametersInfo(SPI_GETWORKAREA, 0, &mouseRect, 0);
+        
+      co_WinPosSetWindowPos(pWnd,
+                            0,
+                            sizingRect.left,
+                            mouseRect.top,
+                            sizingRect.right - sizingRect.left,
+                            mouseRect.bottom - mouseRect.top,
+                            0);
+      break;
+    }
     default:
       return NC_HandleNCLButtonDown(pWnd, wParam, lParam);
   }

Reply via email to