Работа с окнами как в Windows 7: обновление
- modified:
- reading: 4 minutes
Программа для работы с окнами в Windows, идеи и удобства были позаимствованы из Windows 7. Программа позволяет при помощи горячих клавиш передвигать окно по экрану, размещать его в стадиях максимизации, обычного окна, а так же самое основное - размещать окна максимизированные на половину экрана. Работает с Vista и WinXP (как x86, так и x64).
В новой версии программы исправлены некоторые ошибки:
а) Не минимизировались диалоговые окна (те, которые не могут менять размер).
б) Программа не работала с окном Google Chrome (об этом подробнее немного ниже).
А так же основное добавлены возможности перемещения окна между экранами.
Скачать новую версию можно отсюда.
Сначала пару слов о проблеме с Chrome. Я ее не обнаружил. Версия хрома у меня 2.0.160.0, пробовал в Vista. Но все же я сделал отдельную сборку, в которой в методе проверке окна на IsResizableWindow добавил такую проверку
StringBuilder sb = new StringBuilder(100);
if (WAWindows.GetClassName(window, sb, sb.Capacity) != IntPtr.Zero
&& sb.ToString().StartsWith("Chrome_"))
return true;
Вроде должно работать.
Теперь о перемещении окна между экранами. Задача оказалась не такой уж сложной. Первое что нужно сделать, это определить на какой монитор все таки пользователь желает переместить окно, тут мне пришлось сделать в лоб, пробежаться по всем экранам, и те которые соприкасаются (сторона соприкосновения зависит от нажатой клавиши) туда и отслылать, вот код нахождения экрана:
private static Screen GetScreenToMove(Screen screen, Keys keys)
{
foreach (Screen scr in Screen.AllScreens)
{
if (!scr.Equals(screen))
{
switch (keys)
{
case Keys.Left:
if (scr.WorkingArea.Right == screen.WorkingArea.Left
&& scr.WorkingArea.Top == scr.WorkingArea.Top)
return scr;
break;
case Keys.Right:
if (scr.WorkingArea.Left == screen.WorkingArea.Right
&& scr.WorkingArea.Top == scr.WorkingArea.Top)
return scr;
break;
case Keys.Down:
if (scr.WorkingArea.Top == screen.WorkingArea.Bottom
&& scr.WorkingArea.Left == scr.WorkingArea.Left)
return scr;
break;
case Keys.Up:
if (scr.WorkingArea.Bottom == screen.WorkingArea.Top
&& scr.WorkingArea.Left == scr.WorkingArea.Left)
return scr;
break;
}
}
}
return null;
}
Дальше же нужно просто отправить окно в выбранный экран, отправляю я окно с учетом пропорций, то есть: если окно занимало 50% от экрана, оно и на новом экране будет столько же занимать.
Но возникла проблема с FullScreen приложениями, а именно, если, к примеру, фильм развернуть на весь экран и попытаться перебросить это окно на другой экран - ничего не происходило, оказалось данное окно не определяется как имеющее WsSizeBox, потому пришлось их распозновать следующим способом (тут может кто то подскажет что то более граммотное):
private static bool IsFullScreenWindow(WAWindows.Rect rect, Screen scr)
{
return rect.Left == scr.Bounds.Left && rect.Top == scr.Bounds.Top
&& rect.Width == scr.Bounds.Width && rect.Height == scr.Bounds.Height;
}
Еще один интересный факт, что когда я перемещал FullScreen окна по экранам, то в какой то момент они просто теряются, я понял, что окно остается на старом экране, а размеры и позиция я задаю ему нового экрана. Решение: при установлении размеров мне приходится сначала установить размеры на пару пикселей в ширину и в высоту меньше экрана (чтобы окно разполагалось точно только на этом экране), а потом восстанавливать до FullScreen размеров, выглядит это, примерно, так
// Fix for full screen windows
if (isFullScreenWindow)
WAWindows.SetWindowPos(window, WAWindows.HwndTop, x + 1, y + 1, cx - 2, cy - 2, WAWindows.SwpShowWindow);
WAWindows.SetWindowPos(window, WAWindows.HwndTop, x, y, cx, cy, WAWindows.SwpShowWindow);
Еще один неприятный момент был, что когда окно на одном экране максимизированное, его перемещаем на другой экран, а потом восстанавливаем в Normal, то оно летит на предыдущий экран, потому как там его и максимизировали и окно запомнило тот размер и расположение, потому пришлось для таких случаев написать такой FIX:
// Fixed problem with restore on other screen
Screen newScreen = Screen.FromHandle(window);
if (!newScreen.Equals(screen))
{
if (WAWindows.GetWindowRect(window, out rect))
MoveToNewScreen(window, newScreen, screen, rect, isResizableWindow, false);
}
Это вроде все неприятные моменты с которыми я столкнулся. Если есть предложения или замечания, то с удовольствием их выслушаю.
P.S. Мне еще приходило письмо с предложением и патчем от Andir R со следующими словами:
Добавил в неё возможность двойной максимизации. Суть следующая:
1) При первоначальной максимизации (с помощью хоткея), окно не максимизируется, а изменяется до заданных размеров,
2) Вторичная максимизация уже вызывает настоящую максимизацию. В обратном порядке действует аналогично. Зачем это нужно: На широких мониторах с большим разрешением полная максимизация окна, зачастую, не нужна совсем, но увеличивать окно до определённых размеров всё равно приходится.
Мне показалась данная функциональность не настолько уж и необходимой, по крайней мере я ей пользоваться точно не буду, если нужна будет большинству народа, то включу ее как нибудь в свой проект.