From 10097b5e146b33310917a99a8e8c3dcee46d4f4a Mon Sep 17 00:00:00 2001 From: Martin Smith Date: Sat, 4 Jan 2020 11:25:44 +0000 Subject: [PATCH 1/5] Rename IOUtils and fix FileExists edge case --- Lib/IOUtils.ahk | 51 +++++++++++++++++++++++++++++++++++++++++ Lib/PathUtils.ahk | 30 ------------------------ Lib/UserDataUtils.ahk | 4 ++-- Lib/WindowPositions.ahk | 43 ++++++++++++++++++++++++++-------- 4 files changed, 86 insertions(+), 42 deletions(-) create mode 100644 Lib/IOUtils.ahk delete mode 100644 Lib/PathUtils.ahk diff --git a/Lib/IOUtils.ahk b/Lib/IOUtils.ahk new file mode 100644 index 0000000..8e4d16c --- /dev/null +++ b/Lib/IOUtils.ahk @@ -0,0 +1,51 @@ +#include Lib\StringUtils.ahk + +;-------------------------------------------------------------------------------- +; CombinePaths - Append path2 to path1, ensuring the correct delimiters are in place +CombinePaths(path1, path2) +{ + return EnsureEndsWith(path1, "\") . path2 +} + +;-------------------------------------------------------------------------------- +; CombinePaths - Append multiple paths together, ensuring the correct delimiters are in place +CombinePathA(paths*) +{ + newPath := + + Loop, %path% + { + if (newPath = "") + { + newPath := path + } + else + { + newPath := EnsureEndsWith(newPath, "\") . path + } + } + + return newPath +} + +;-------------------------------------------------------------------------------- +; FileExists - Determines if a file exists +FileExists(fileName) +{ + fileAttribute := FileExist(fileName) + + exists := (fileAttribute && fileAttribute != "X") + + return exists +} + +;-------------------------------------------------------------------------------- +; FolderExists - Determines if a folder exists +FolderExists(folderName) +{ + folderAttribute := FileExist(folderName) + + exists := (folderAttribute && InStr(folderAttribute, "D")) + + return exists +} diff --git a/Lib/PathUtils.ahk b/Lib/PathUtils.ahk deleted file mode 100644 index b6440a1..0000000 --- a/Lib/PathUtils.ahk +++ /dev/null @@ -1,30 +0,0 @@ -#include Lib\StringUtils.ahk - -CombinePaths(path1, path2) -{ - return EnsureEndsWith(path1, "\") . path2 -} - -CombinePathA(paths*) -{ - newPath := - - Loop, %path% - { - if (newPath = "") - { - newPath := path - } - else - { - newPath := EnsureEndsWith(newPath, "\") . path - } - } - - return newPath -} - -DirectoryExists(path) -{ - return Instr(FileExist(path), "D") -} diff --git a/Lib/UserDataUtils.ahk b/Lib/UserDataUtils.ahk index 47f51f1..85d30f1 100644 --- a/Lib/UserDataUtils.ahk +++ b/Lib/UserDataUtils.ahk @@ -1,6 +1,6 @@ #Include Lib\Logging.ahk #Include Lib\StringUtils.ahk -#Include Lib\PathUtils.ahk +#Include Lib\IOUtils.ahk ;-------------------------------------------------------------------------------- ; Globals @@ -17,7 +17,7 @@ UserDataUtils_OnInit() UserDataPath := CombinePaths(A_AppData, AppName) - If (!DirectoryExists(UserDataPath)) + If (!FolderExists(UserDataPath)) { LogText("Creating UserDataPath: " . UserDataPath) FileCreateDir, %UserDataPath% diff --git a/Lib/WindowPositions.ahk b/Lib/WindowPositions.ahk index 9e53c6c..77cff70 100644 --- a/Lib/WindowPositions.ahk +++ b/Lib/WindowPositions.ahk @@ -1,9 +1,10 @@ #Include Lib\Logging.ahk #Include Lib\StringUtils.ahk -#Include Lib\PathUtils.ahk +#Include Lib\IOUtils.ahk #Include Lib\WindowObjects.ahk #Include Lib\WindowFunctions.ahk #Include Lib\MathUtils.ahk +#Include Lib\IOUtils.ahk #Include Lib\UserDataUtils.ahk #Include Lib\PleasantNotify.ahk @@ -21,16 +22,16 @@ WindowPositions_OnInit() } ;-------------------------------------------------------------------------------- +; HasSavedWindowPositionFile - Is there a file of saved Window Positions HasSavedWindowPositionFile(desktopSize) { fileName := GetWindowPositionsDataFileName(desktopSize) - exists := FileExist(fileName) - - return (exists && exists != "X") + return FileExists(fileName) } ;-------------------------------------------------------------------------------- +; GetWindowPositionsDataFileName - Get the appropriate saved Window Positions filename GetWindowPositionsDataFileName(desktopSize) { global WindowPositionsBaseFileName @@ -51,6 +52,7 @@ GetWindowPositionsDataFileName(desktopSize) } ;-------------------------------------------------------------------------------- +; BuildWindowFromDefinition - Build a Window Definition from a text string BuildWindowFromDefinition(text, separator = "|") { parts := StrSplit(text, separator) @@ -69,6 +71,7 @@ BuildWindowFromDefinition(text, separator = "|") } ;-------------------------------------------------------------------------------- +; GetWindowDefinition - Create a text representation of a Window Definition GetWindowDefinition(window, separator = "|") { parts := [] @@ -88,6 +91,7 @@ GetWindowDefinition(window, separator = "|") } ;-------------------------------------------------------------------------------- +; HasWindowMoved - Check two window positions are equivalent HasWindowMoved(window1, window2) { if (window1.Left <> window2.Left) @@ -105,13 +109,14 @@ HasWindowMoved(window1, window2) } ;-------------------------------------------------------------------------------- -SaveWindowPositions() +; SaveWindowPositions - Save all the current window positions to a file +SaveWindowPositions(includeOffScreenWindows) { desktopSize := GetDesktopSize() fileName := GetWindowPositionsDataFileName(desktopSize) - If FileExist(fileName) + If (FileExists(fileName)) { LogText("Removing old Data File: " . fileName) FileDelete , %fileName% @@ -128,6 +133,17 @@ SaveWindowPositions() LogText(A_Index . ": " . window.Description) isVisible := IsWindowVisible(windowHandle) + if (!isVisible) + { + LogText("Ignoring InVisible: " . window.Description) + continue + } + isOnScreen := IsWindowOnScreen(windowHandle) + if (!isOnScreen && !includeOffScreenWindows) + { + LogText("Ignoring Off-Screen: " . window.Description) + continue + } restored := GetWindowNormalPosition(windowHandle) if (!restored.IsValid) @@ -168,13 +184,14 @@ SaveWindowPositions() } ;-------------------------------------------------------------------------------- -RestoreWindowPositions() +; RestoreWindowPositions - Restores window positions from a file +RestoreWindowPositions(includeOffScreenWindows) { desktopSize := GetDesktopSize() fileName := GetWindowPositionsDataFileName(desktopSize) - If !FileExist(fileName) + If (!FileExists(fileName)) { MsgBox , 48, Restore Window Positions, Unable to locate file %fileName% return @@ -188,10 +205,16 @@ RestoreWindowPositions() break savedWindow := BuildWindowFromDefinition(A_LoopReadLine) - if savedWindow + if (!savedWindow) + continue + + if (!IsRectOnScreen(savedWindow) && !includeOffScreenWindows) { - savedWindows.Push(savedWindow) + LogText("Ignoring Off-Screen: " . savedWindow.Description) + continue } + + savedWindows.Push(savedWindow) } restoreCount := 0 From 69540c41e4d1b5e275ef0ee05a7a62d1070d091b Mon Sep 17 00:00:00 2001 From: Martin Smith Date: Sat, 4 Jan 2020 11:26:16 +0000 Subject: [PATCH 2/5] Comments and a version bump --- Lib/DesktopIcons.ahk | 10 ++++------ Lib/MathUtils.ahk | 7 ++++++- Setup/WindowMenu_Setup.iss | 4 ++-- WindowExtensions.ahk | 7 ++----- 4 files changed, 14 insertions(+), 14 deletions(-) diff --git a/Lib/DesktopIcons.ahk b/Lib/DesktopIcons.ahk index 05bddfb..3a523b3 100644 --- a/Lib/DesktopIcons.ahk +++ b/Lib/DesktopIcons.ahk @@ -1,6 +1,6 @@ #Include Lib\Logging.ahk #Include Lib\StringUtils.ahk -#Include Lib\PathUtils.ahk +#Include Lib\IOUtils.ahk #Include Lib\WindowObjects.ahk #Include Lib\MathUtils.ahk #Include Lib\UserDataUtils.ahk @@ -39,9 +39,7 @@ HasSavedDesktopIconsFile(desktopSize) { fileName := GetDesktopIconsDataFileName(desktopSize) - exists := FileExist(fileName) - - return (exists && exists != "X") + return FileExists(fileName) } ;-------------------------------------------------------------------------------- @@ -167,7 +165,7 @@ SaveDesktopIcons() fileName := GetDesktopIconsDataFileName(desktopSize) - If FileExist(fileName) + If (FileExists(fileName)) { LogText("Removing old Data File: " . fileName) FileDelete , %fileName% @@ -208,7 +206,7 @@ RestoreDesktopIcons() fileName := GetDesktopIconsDataFileName(desktopSize) - If !FileExist(fileName) + If (!FileExists(fileName)) { MsgBox , 48, Restore Desktop Icons, Unable to locate file %fileName% return diff --git a/Lib/MathUtils.ahk b/Lib/MathUtils.ahk index 1c46bc1..1763658 100644 --- a/Lib/MathUtils.ahk +++ b/Lib/MathUtils.ahk @@ -1,4 +1,5 @@ - +;-------------------------------------------------------------------------------- +; MinOf - Find the lower of 2 numbers MinOf(a, b) { if (a < b) @@ -11,6 +12,8 @@ MinOf(a, b) } } +;-------------------------------------------------------------------------------- +; MaxOf - Find the higher of 2 numbers MaxOf(a, b) { if (a > b) @@ -23,6 +26,8 @@ MaxOf(a, b) } } +;-------------------------------------------------------------------------------- +; ContainsFlag - Does a value contain a bitwise value ContainsFlag(value, bitwiseFlag) { return (bitwiseFlag > 0) && (value & bitwiseFlag) > 0 diff --git a/Setup/WindowMenu_Setup.iss b/Setup/WindowMenu_Setup.iss index 869fa67..7055823 100644 --- a/Setup/WindowMenu_Setup.iss +++ b/Setup/WindowMenu_Setup.iss @@ -1,11 +1,11 @@ #define AppName "WindowExtensions" #define AppTitle "Window Extensions" -#define AppVersion "1.6.0" +#define AppVersion "1.6.1" [Setup] AppName={#AppName} AppVersion={#AppVersion} -AppCopyright=Copyright © 2019 DNX Solutions Ltd +AppCopyright=Copyright © 2020 Martin Smith DefaultDirName={commonpf}\DNXSolutions\{#AppName} OutputDir=. OutputBaseFilename={#AppName}_Install_v{#AppVersion} diff --git a/WindowExtensions.ahk b/WindowExtensions.ahk index 40bc9df..48e2222 100644 --- a/WindowExtensions.ahk +++ b/WindowExtensions.ahk @@ -12,9 +12,10 @@ SetTitleMatchMode, 2 AppName := "WindowExtensions" AppTitle := "Window Extensions" AppDescription := "Window Extensions Menu and HotKeys" +AppCopyright := "Copyright © 2020 Martin Smith" AppNotes := "Concise and consistent control over Window Positions. Right-click right half of Window Caption bar to invoke, or hit WinKey-W" AppURL := "https://github.com/martinsmith1968/WindowExtensions" -AppVersion := "1.6.0.0" +AppVersion := "1.6.1.0" ;-------------------------------------------------------------------------------- ; Includes @@ -48,10 +49,6 @@ G_UserConfig := G_ActiveWindow := G_CurrentMouse := G_MenuTitle := AppTitle -G_SaveWindowPositionsMenuTitle := "" -G_RestoreWindowPositionsMenuTitle := "" -G_SaveDesktopIconsMenuTitle := "" -G_RestoreDesktopIconsMenuTitle := "" OnExit, ExitHandler From 87f0b25986193f10ca812514f956bbf1e879ec50 Mon Sep 17 00:00:00 2001 From: Martin Smith Date: Sat, 4 Jan 2020 11:26:46 +0000 Subject: [PATCH 3/5] Support new properties and allow Config Sections --- Lib/UserConfig.ahk | 22 +++++++++++++ WindowExtensionsUserConfig.ahk | 52 ++++++++++++++++++++----------- WindowExtensionsUserConfigGui.ahk | 15 ++++++--- 3 files changed, 66 insertions(+), 23 deletions(-) diff --git a/Lib/UserConfig.ahk b/Lib/UserConfig.ahk index 9e221f1..6bc0074 100644 --- a/Lib/UserConfig.ahk +++ b/Lib/UserConfig.ahk @@ -58,6 +58,24 @@ class UserConfig IniWrite, %value%, %dataFileName%, %section%, %key% } + GetSectionNameFromFunc(func, defaultName := "General") + { + bits := StrSplit(func, ".") + + sectionName := bits[2] + + if (sectionName =) + sectionName := func + + nameParts := StrSplit(sectionName, "_") + if (nameParts.length() > 1) + sectionName := nameParts[1] + else + sectionName := defaultName + + return sectionName + } + GetPropertyNameFromFunc(func) { bits := StrSplit(func, ".") @@ -67,6 +85,10 @@ class UserConfig if (propertyName =) propertyName := func + nameParts := StrSplit(propertyName, "_") + if (nameParts.length() > 1) + propertyName := nameParts[2] + return propertyName } diff --git a/WindowExtensionsUserConfig.ahk b/WindowExtensionsUserConfig.ahk index 4861b43..2b52073 100644 --- a/WindowExtensionsUserConfig.ahk +++ b/WindowExtensionsUserConfig.ahk @@ -53,7 +53,7 @@ WindowExtensionsUserConfig_OnStartup() } if (G_UserConfig.RestoreWindowPositionsOnStartup) { - RestoreWindowPositions() + RestoreWindowPositions(G_UserConfig.WindowPositions_IncludeOffScreenWindows) } } @@ -65,8 +65,9 @@ DefaultGridGutterSize := 5 DefaultSpanMonitorGutterSize := 5 DefaultRestoreDesktopIconsOnStartup := false DefaultRestoreWindowPositionsOnStartup := false -DefaultWindowPositionsMenuLocation := 0 -DefaultDesktopIconsMenuLocation := 0 +DefaultWindowPositionsMenuLocation := 2 +DefaultDesktopIconsMenuLocation := 2 +DefaultWindowPositions_IncludeOffScreenWindows := false InitDefaults() { @@ -94,17 +95,18 @@ DefaultDesktopIconsMenuLocation := 0 this.Properties.push("RestoreWindowPositionsOnStartup") this.Properties.push("WindowPositionsMenuLocation") this.Properties.push("DesktopIconsMenuLocation") + this.Properties.push("WindowPositions_IncludeOffScreenWindows") } CascadeGutterSize { get { - return base.GetValue("General", base.GetPropertyNameFromFunc(A_ThisFunc), this.DefaultCascadeGutterSize, "integer") + return base.GetValue(base.GetSectionNameFromFunc(A_ThisFunc), base.GetPropertyNameFromFunc(A_ThisFunc), this.DefaultCascadeGutterSize, "integer") } set { - base.SetValue("General", base.GetPropertyNameFromFunc(A_ThisFunc), value) + base.SetValue(base.GetSectionNameFromFunc(A_ThisFunc), base.GetPropertyNameFromFunc(A_ThisFunc), value) } } @@ -112,11 +114,11 @@ DefaultDesktopIconsMenuLocation := 0 { get { - return base.GetValue("General", base.GetPropertyNameFromFunc(A_ThisFunc), this.DefaultColumnGutterSize, "integer") + return base.GetValue(base.GetSectionNameFromFunc(A_ThisFunc), base.GetPropertyNameFromFunc(A_ThisFunc), this.DefaultColumnGutterSize, "integer") } set { - base.SetValue("General", base.GetPropertyNameFromFunc(A_ThisFunc), value) + base.SetValue(base.GetSectionNameFromFunc(A_ThisFunc), base.GetPropertyNameFromFunc(A_ThisFunc), value) } } @@ -124,11 +126,11 @@ DefaultDesktopIconsMenuLocation := 0 { get { - return base.GetValue("General", base.GetPropertyNameFromFunc(A_ThisFunc), this.DefaultGridGutterSize, "integer") + return base.GetValue(base.GetSectionNameFromFunc(A_ThisFunc), base.GetPropertyNameFromFunc(A_ThisFunc), this.DefaultGridGutterSize, "integer") } set { - base.SetValue("General", base.GetPropertyNameFromFunc(A_ThisFunc), value) + base.SetValue(base.GetSectionNameFromFunc(A_ThisFunc), base.GetPropertyNameFromFunc(A_ThisFunc), value) } } @@ -136,11 +138,11 @@ DefaultDesktopIconsMenuLocation := 0 { get { - return base.GetValue("General", base.GetPropertyNameFromFunc(A_ThisFunc), this.DefaultSpanMonitorGutterSize, "integer") + return base.GetValue(base.GetSectionNameFromFunc(A_ThisFunc), base.GetPropertyNameFromFunc(A_ThisFunc), this.DefaultSpanMonitorGutterSize, "integer") } set { - base.SetValue("General", base.GetPropertyNameFromFunc(A_ThisFunc), value) + base.SetValue(base.GetSectionNameFromFunc(A_ThisFunc), base.GetPropertyNameFromFunc(A_ThisFunc), value) } } @@ -148,11 +150,11 @@ DefaultDesktopIconsMenuLocation := 0 { get { - return base.GetValue("General", base.GetPropertyNameFromFunc(A_ThisFunc), this.DefaultRestoreDesktopIconsOnStartup, "boolean") + return base.GetValue(base.GetSectionNameFromFunc(A_ThisFunc), base.GetPropertyNameFromFunc(A_ThisFunc), this.DefaultRestoreDesktopIconsOnStartup, "boolean") } set { - base.SetValue("General", base.GetPropertyNameFromFunc(A_ThisFunc), value) + base.SetValue(base.GetSectionNameFromFunc(A_ThisFunc), base.GetPropertyNameFromFunc(A_ThisFunc), value) } } @@ -160,11 +162,11 @@ DefaultDesktopIconsMenuLocation := 0 { get { - return base.GetValue("General", base.GetPropertyNameFromFunc(A_ThisFunc), this.DefaultRestoreWindowPositionsOnStartup, "boolean") + return base.GetValue(base.GetSectionNameFromFunc(A_ThisFunc), base.GetPropertyNameFromFunc(A_ThisFunc), this.DefaultRestoreWindowPositionsOnStartup, "boolean") } set { - base.SetValue("General", base.GetPropertyNameFromFunc(A_ThisFunc), value) + base.SetValue(base.GetSectionNameFromFunc(A_ThisFunc), base.GetPropertyNameFromFunc(A_ThisFunc), value) } } @@ -172,11 +174,11 @@ DefaultDesktopIconsMenuLocation := 0 { get { - return base.GetValue("General", base.GetPropertyNameFromFunc(A_ThisFunc), this.DefaultWindowPositionsMenuLocation, "integer") + return base.GetValue(base.GetSectionNameFromFunc(A_ThisFunc), base.GetPropertyNameFromFunc(A_ThisFunc), this.DefaultWindowPositionsMenuLocation, "integer") } set { - base.SetValue("General", base.GetPropertyNameFromFunc(A_ThisFunc), value) + base.SetValue(base.GetSectionNameFromFunc(A_ThisFunc), base.GetPropertyNameFromFunc(A_ThisFunc), value) } } @@ -184,11 +186,23 @@ DefaultDesktopIconsMenuLocation := 0 { get { - return base.GetValue("General", base.GetPropertyNameFromFunc(A_ThisFunc), this.DefaultDesktopIconsMenuLocation, "integer") + return base.GetValue(base.GetSectionNameFromFunc(A_ThisFunc), base.GetPropertyNameFromFunc(A_ThisFunc), this.DefaultDesktopIconsMenuLocation, "integer") } set { - base.SetValue("General", base.GetPropertyNameFromFunc(A_ThisFunc), value) + base.SetValue(base.GetSectionNameFromFunc(A_ThisFunc), base.GetPropertyNameFromFunc(A_ThisFunc), value) + } + } + + WindowPositions_IncludeOffScreenWindows + { + get + { + return base.GetValue(base.GetSectionNameFromFunc(A_ThisFunc), base.GetPropertyNameFromFunc(A_ThisFunc), this.DefaultWindowPositions_IncludeOffScreenWindows, "boolean") + } + set + { + base.SetValue(base.GetSectionNameFromFunc(A_ThisFunc), base.GetPropertyNameFromFunc(A_ThisFunc), value) } } } diff --git a/WindowExtensionsUserConfigGui.ahk b/WindowExtensionsUserConfigGui.ahk index b12211e..24e2c3f 100644 --- a/WindowExtensionsUserConfigGui.ahk +++ b/WindowExtensionsUserConfigGui.ahk @@ -17,6 +17,7 @@ BuildUserConfigGui(windowExtensionsUserConfig) global restoreWindowPositionsOnStartup global desktopIconsMenuLocation global windowPositionsMenuLocation + global windowPositionsIncludeOffScreenWindows global MenuLocationValues global MenuLocationItems @@ -29,6 +30,7 @@ BuildUserConfigGui(windowExtensionsUserConfig) restoreWindowPositionsOnStartup := windowExtensionsUserConfig.RestoreWindowPositionsOnStartup ? 1 : 0 desktopIconsMenuLocation := windowExtensionsUserConfig.DesktopIconsMenuLocation windowPositionsMenuLocation := windowExtensionsUserConfig.WindowPositionsMenuLocation + windowPositionsIncludeOffScreenWindows := windowExtensionsUserConfig.WindowPositions_IncludeOffScreenWindows ? 1 : 0 desktopIconsMenuLocationChoice := IndexOf(MenuLocationValues, desktopIconsMenuLocation) windowPositionsMenuLocationChoice := IndexOf(MenuLocationValues, windowPositionsMenuLocation) @@ -44,6 +46,7 @@ BuildUserConfigGui(windowExtensionsUserConfig) Gui, Config:Add, Text,, Restore Window Positions on Startup: Gui, Config:Add, Text,, Save / Restore Window Positions Menu Location: Gui, Config:Add, Text,, Save / Restore Desktop Icons Menu Location: + Gui, Config:Add, Text,, Include Off-Screen Windows on Save / Restore: Gui, Config:Add, Edit, ym w80 Gui, Config:Add, UpDown, vcascadeGutterSize Range0-100, %cascadeGutterSize% Gui, Config:Add, Edit, w80 @@ -52,12 +55,13 @@ BuildUserConfigGui(windowExtensionsUserConfig) Gui, Config:Add, UpDown, vgridGutterSize Range0-100, %gridGutterSize% Gui, Config:Add, Edit, w80 Gui, Config:Add, UpDown, vspanMonitorGutterSize Range0-100, %spanMonitorGutterSize% - Gui, Config:Add, Checkbox, vrestoreDesktopIconsOnStartup Checked%restoreDesktopIconsOnStartup%, + Gui, Config:Add, Checkbox, vrestoreDesktopIconsOnStartup Checked%restoreDesktopIconsOnStartup% Gui, Config:Add, Checkbox, vrestoreWindowPositionsOnStartup Checked%restoreWindowPositionsOnStartup%, `n Gui, Config:Add, DropDownList, vwindowPositionsMenuLocation AltSubmit Choose%windowPositionsMenuLocationChoice%, %menuLocationItemsText% Gui, Config:Add, DropDownList, vdesktopIconsMenuLocation AltSubmit Choose%desktopIconsMenuLocationChoice%, %menuLocationItemsText% - Gui, Config:Add, Button, default x240 y230 w80, OK ; The label ButtonOK (if it exists) will be run when the button is pressed. - Gui, Config:Add, Button, x330 y230 w80, Cancel ; The label ButtonCancel (if it exists) will be run when the button is pressed. + Gui, Config:Add, Checkbox, vwindowPositionsIncludeOffScreenWindows x257 y223 Checked%windowPositionsIncludeOffScreenWindows% + Gui, Config:Add, Button, default x245 y245 w80, OK ; The label ButtonOK (if it exists) will be run when the button is pressed. + Gui, Config:Add, Button, x330 y245 w80, Cancel ; The label ButtonCancel (if it exists) will be run when the button is pressed. } DestroyUserConfigGui() @@ -98,8 +102,10 @@ ConfigButtonOK: global columnGutterSize global gridGutterSize global spanMonitorGutterSize - + global restoreDesktopIconsOnStartup + global restoreWindowPositionsOnStartup global MenuLocationValues + global windowPositionsIncludeOffScreenWindows Gui, Config:Submit @@ -111,6 +117,7 @@ ConfigButtonOK: G_UserConfig.RestoreWindowPositionsOnStartup := restoreWindowPositionsOnStartup G_UserConfig.DesktopIconsMenuLocation := MenuLocationValues[desktopIconsMenuLocation] G_UserConfig.WindowPositionsMenuLocation := MenuLocationValues[windowPositionsMenuLocation] + G_UserConfig.WindowPositions_IncludeOffScreenWindows := windowPositionsIncludeOffScreenWindows G_UserConfig.Save() OnUserConfigUpdated() From 6809974170f5c091ea3df8bef1abf662a0f2c89a Mon Sep 17 00:00:00 2001 From: Martin Smith Date: Sat, 4 Jan 2020 11:27:21 +0000 Subject: [PATCH 4/5] Support detecting if a window is one screen and implement user config setting --- Lib/WindowFunctions.ahk | 34 ++++++++++++++++++++++++++++++++++ Lib/WindowObjects.ahk | 8 ++++++++ WindowMenu.ahk | 4 ++-- 3 files changed, 44 insertions(+), 2 deletions(-) diff --git a/Lib/WindowFunctions.ahk b/Lib/WindowFunctions.ahk index 1c0fbd3..c393266 100644 --- a/Lib/WindowFunctions.ahk +++ b/Lib/WindowFunctions.ahk @@ -211,6 +211,40 @@ IsWindowVisible(windowHandle) return result <> 0 } +;-------------------------------------------------------------------------------- +; IsWindowOnScreen - Detect if a window handle is showing on any monitor +IsWindowOnScreen(windowHandle) +{ + WinGetPos, left, top, width, height, ahk_id %windowHandle% + + rect := new Rectangle(left, top, width, height) + + return IsRectOnScreen(rect) +} + +;-------------------------------------------------------------------------------- +; IsRectOnScreen - Detect if a rectangle is within any monitor +IsRectOnScreen(rect) +{ + monitorIndex := GetMonitorIndexAt(rect.Left, rect.Top) + if (monitorIndex >= 0) + return true + + monitorIndex := GetMonitorIndexAt(rect.Left, rect.Bottom) + if (monitorIndex >= 0) + return true + + monitorIndex := GetMonitorIndexAt(rect.Right, rect.Top) + if (monitorIndex >= 0) + return true + + monitorIndex := GetMonitorIndexAt(rect.Right, rect.Bottom) + if (monitorIndex >= 0) + return true + + return false +} + ;-------------------------------------------------------------------------------- ; GetWindowNormalPosition - Get the restored position of a window GetWindowNormalPosition(windowHandle) diff --git a/Lib/WindowObjects.ahk b/Lib/WindowObjects.ahk index 4c2a061..365f7da 100644 --- a/Lib/WindowObjects.ahk +++ b/Lib/WindowObjects.ahk @@ -250,6 +250,14 @@ Class Window extends Rectangle } } + IsOnScreen + { + get + { + return IsWindowOnScreen(this.WindowHandle) + } + } + MonitorIndex { get diff --git a/WindowMenu.ahk b/WindowMenu.ahk index 3fd065a..0f04824 100644 --- a/WindowMenu.ahk +++ b/WindowMenu.ahk @@ -258,11 +258,11 @@ return ;-------------------------------------------------------------------------------- SaveWindowPositionsHandler: -SaveWindowPositions() +SaveWindowPositions(G_UserConfig.WindowPositions_IncludeOffScreenWindows) return RestoreWindowPositionsHandler: -RestoreWindowPositions() +RestoreWindowPositions(G_UserConfig.WindowPositions_IncludeOffScreenWindows) return ;-------------------------------------------------------------------------------- From c8c826614cfe47aab671fc409e8dd97bc57edb18 Mon Sep 17 00:00:00 2001 From: Martin Smith Date: Sat, 4 Jan 2020 11:27:30 +0000 Subject: [PATCH 5/5] Doc updates --- Docs/ConfigurationDialog.png | Bin 10461 -> 6132 bytes Docs/releasenotes.md | 7 ++++++- Docs/todo.md | 7 +++++++ 3 files changed, 13 insertions(+), 1 deletion(-) diff --git a/Docs/ConfigurationDialog.png b/Docs/ConfigurationDialog.png index aed6fbbdce31357474cb4205bcf0ca7d9a57f40b..be67c7fdee04a6513c66965bf83f78df885415d0 100644 GIT binary patch literal 6132 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 literal 10461 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 Zw>8Ms%CmAA`H{p2Z=@BaN`Xcn{sRY9Hwpj% diff --git a/Docs/releasenotes.md b/Docs/releasenotes.md index 3f1b797..14c40ed 100644 --- a/Docs/releasenotes.md +++ b/Docs/releasenotes.md @@ -1,6 +1,11 @@ # Release Notes -## v1.6.0 - 2020-01-04 +## v1.6.1 - 2020-01-04 + +- Fixed issue with Restore Window Positions which would position Windows Settings screen when it wasn't visible before +- Minor documentation updates for new Config settings + +## v1.6.0 - 2020-01-03 - Restructured code radically to better organise modules and avoid multi module hell of inline startup code - Implemented options to control which menus the Save / Restore Window Positions and Desktop Icons appear in diff --git a/Docs/todo.md b/Docs/todo.md index 3518a21..f7b6ba2 100644 --- a/Docs/todo.md +++ b/Docs/todo.md @@ -3,3 +3,10 @@ - History list of Saved Window Positions - History list of Saved Desktop Icon Positions - Add icons to other context menu items +- Convert Configuration dialog to use Tabbed controls +- Auto-Save Window Positions on a schedule +- Auto-Save Desktop Icons on a schedule + +## Bugs + +- If Desktop has 2 icons with the same name (1 user, 1 public), it doesn't always move the icon