private void StepTimer_Tick(object sender, EventArgs e) { // winHandles.Clear(); // winHandles.Add( Win32.FindWindow("Notepad", "todo.txt - Notepad")); MoveWindows.Clear(); Win32.RECT rect = new Win32.RECT(); // first pass select what windows we should maniplate foreach (IntPtr handle in WinHandles) { if(!Win32.GetWindowRect(handle, ref rect)) continue; // if off screen or minimized if (rect.Top == -32000 || (rect.Left == 0 && rect.Top == TaskbarTop)) continue; // if the height is bigger the the vertical space, dont move if (rect.Height > Desktop.Height - Abd.rc.Height || rect.Width > Desktop.Width) continue; if (!WindowPos.ContainsKey(handle)) WindowPos[handle] = new WinInfo(); WinInfo info = WindowPos[handle]; info.Rect = rect; info.Handle = handle; MoveWindows.Add(info); } // of those windows what are the shelves, windows other windows can rest on Shelves.Clear(); foreach (WinInfo info in MoveWindows) { // shelf may need to be broken into multiple pieces depending on whats covering it Recurse = 0; TestShelf(info.Handle, info.Rect); } IntPtr activeWindow = Win32.GetForegroundWindow(); // move the windows according to gravity and the shelf space foreach (WinInfo info in MoveWindows) { IntPtr handle = info.Handle; rect = info.Rect; double dT = (double)(DateTime.Now.Ticks - info.LastRun.Ticks) / (double)TimeSpan.TicksPerSecond; // prevent window from dropping while user is holding it short keyState = Win32.GetKeyState(Win32.VirtualKeyStates.VK_LBUTTON); bool mouseDown = (keyState & Win32.KEY_PRESSED) > 0; Win32.POINT cursorPos; Win32.GetCursorPos(out cursorPos); // used also at end of func // only give window momentum if dragging the header if (mouseDown && activeWindow == handle && rect.Left < cursorPos.X && cursorPos.X < rect.Right && rect.Top < cursorPos.Y && cursorPos.Y < rect.Top + 26) { info.Vx = (double)(cursorPos.X - info.LastX) / dT; info.Vy = (double)(cursorPos.Y - info.LastY) / dT; /*smush - cant resize window while dragging for some reason // if drag started off screen ignore smush if (rect.Right > Abd.rc.Width) { int width = Abd.rc.Width - rect.Left; uint windowStyles = (uint)Win32.GetWindowLongPtr(handle, (int)Win32.GStyles.GWL_STYLE); Win32.SetWindowPos(handle, IntPtr.Zero, rect.Left, rect.Top, width, rect.Height, 0); //Win32.MoveWindow(handle, rect.Left, rect.Top, width, rect.Height, false); } else if (rect.Left < 0) { }*/ } int moveX = 0; int moveY = 0; // move window in x direction if (!mouseDown) { double Ax = 0; if (info.Vx > 0) // moving left, slow down right Ax = -12000; else if (info.Vx < 0) // moving left, slow down right Ax = 12000; // if past right side , bounce back if (rect.Right + moveX > Abd.rc.Width) Ax = -12000; else if (rect.Left + moveX < 0) Ax = 12000; // calc the amount of next move given current velocity and acceleration during time change moveX = (int)(info.Vx * dT + Ax * Math.Pow(dT, 2)); // x = vt + at^2 // if passing right side if (rect.Right < Abd.rc.Width && rect.Right + moveX > Abd.rc.Width) { moveX = Bounce(dT, Abd.rc.Width - rect.Right, ref info.Vx, Ax); // if still past bounds after second bounce, move into place if (rect.Right + moveX > Abd.rc.Width) { info.Vx = 0; moveX = Abd.rc.Width - rect.Right; } } // if passing left side else if (rect.Left > 0 && rect.Left + moveX < 0) { moveX = Bounce(dT, -rect.Left, ref info.Vx, Ax); // if still past bounds after second bounce, move into place if (rect.Left + moveX < 0) { info.Vx = 0; moveX = 0 - rect.Left; } } // if window coast in x in one direction and starts going in other, then stop it double newVx = info.Vx + Ax * dT; if (info.Vx > 0 && newVx < 0) // moving left info.Vx = 0; else if (info.Vx < 0 && newVx > 0) // moving right info.Vx = 0; else info.Vx = newVx; } // not on taskbar and mouse not down, drop it or pop it if (!(mouseDown && activeWindow == handle) && !OnShelf(info)) { double Ay = 0; // if the top is above the taskbar move down if (rect.Bottom < TaskbarTop) Ay = DownAcceleration; // else the bottom is below the taskbar, move up else Ay = UpAcceleration; moveY = (int)(info.Vy * dT + Ay * Math.Pow(dT, 2)); // x = vt + at^2 // if moving down, set target shelf if (Ay > 0) info.TargetShelf = GetTargetShelf(info); // bounce - if accelerating down, and moving through bottom if (Ay > 0 && rect.Bottom + moveY > info.TargetShelf) { moveY = Bounce(dT, info.TargetShelf - rect.Bottom, ref info.Vy, Ay); // if still below taskbar, thats two bounces below, end it here if (rect.Bottom + moveY > info.TargetShelf) { info.Vy = 0; moveY = info.TargetShelf - rect.Bottom; } } // not hitting anything, move normally else { // v = a * t info.Vy = info.Vy + Ay * dT; } //System.Diagnostics.Debug.WriteLine(DateTime.Now.Millisecond.ToString() + " - h:" + handle.ToString() + " x:" + (rect.Top + moveY).ToString() + " dx:" + moveY.ToString() + " v:" + info.Vy.ToString()); } if (moveY != 0 || moveX != 0) Win32.MoveWindow(handle, rect.Left + moveX, rect.Top + moveY, rect.Width, rect.Height, false); // always set this if either run move or not info.LastRun = DateTime.Now; info.LastX = cursorPos.X; info.LastY = cursorPos.Y; } }
private void TestShelf(IntPtr handle, Win32.RECT shelf) { if (shelf.Width == 0) return; // test top 3 points on window Win32.POINT testPoint = new Win32.POINT(); Recurse++; if (Recurse > 5) { int i = 0; i++; return; } for (int i = 0; i < ShelfTest; i++) { testPoint.X = shelf.Left + (shelf.Width-1) * i / (ShelfTest-1); // 0/4, 5 points, is 4 widths testPoint.Y = shelf.Top; IntPtr maybeChild = Win32.WindowFromPoint(testPoint); IntPtr winAtPoint = Win32.GetParent(maybeChild); if (winAtPoint == IntPtr.Zero) winAtPoint = maybeChild; // if we're on top, continue if (winAtPoint == handle) continue; Win32.RECT rect = new Win32.RECT(); if (!Win32.GetWindowRect(winAtPoint, ref rect)) continue; // left side point if(i == 0) { // test if shelf completely covered, return if so if (rect.Left <= shelf.Left && shelf.Right <= rect.Right) return; // left side of shelf is covered, mod it to covering window shelf.Left = rect.Right; } // interior point else if(i < ShelfTest - 1) { // check if right side covered if (rect.Right > shelf.Right) { shelf.Right = rect.Left; break; } // shelf is split into two, recurse right side Win32.RECT rightShelf = shelf; rightShelf.Left = rect.Right + 1 ; TestShelf(handle, rightShelf); // add left side shelf.Right = rect.Left; break; } // right point else { // set right of shelf to covering windows extent shelf.Right = rect.Left; } } Shelves.Add(shelf); }
private void RefreshTimer_Tick(object sender, EventArgs e) { if (onoff) { freshWindows = new List<IntPtr>(); Win32.EnumWindows(EnumWindow, IntPtr.Zero); Abd = new Win32.APPBARDATA(); Win32.SHAppBarMessage(Win32.ABM_GETTASKBARPOS, ref Abd); TaskbarTop = Abd.rc.Top; Desktop = new Win32.RECT(); Win32.GetWindowRect(Win32.GetDesktopWindow(), ref Desktop); onoff = false; } else { WinHandles = freshWindows; onoff = true; } }