From 5f666b20d14c4fe1264ad863747e4f19db631283 Mon Sep 17 00:00:00 2001 From: Kang Yu Date: Mon, 28 Apr 2025 16:36:47 -0700 Subject: [PATCH 01/22] avoid wrong matching --- .../Common/PersistentWindowProcessor.cs | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/Ninjacrab.PersistentWindows.Solution/Common/PersistentWindowProcessor.cs b/Ninjacrab.PersistentWindows.Solution/Common/PersistentWindowProcessor.cs index 20b9297..3634e4f 100644 --- a/Ninjacrab.PersistentWindows.Solution/Common/PersistentWindowProcessor.cs +++ b/Ninjacrab.PersistentWindows.Solution/Common/PersistentWindowProcessor.cs @@ -1568,10 +1568,16 @@ namespace PersistentWindows.Common { foreach (var dm in monitorApplications[curDisplayKey][h]) { + if (IsMinimized(h) != dm.IsMinimized) + continue; + if (User32.IsWindowVisible(h) == dm.IsInvisible) + continue; if (dm.ProcessName == procName) + { proc_name_match_cnt++; - if (dm.ClassName == className) - class_name_match_cnt++; + if (dm.ClassName == className) + class_name_match_cnt++; + } break; } } From f66dc3afd8f1a2c024e58ed7620d56dc87be970c Mon Sep 17 00:00:00 2001 From: Kang Yu Date: Wed, 30 Apr 2025 19:47:32 -0700 Subject: [PATCH 02/22] match new window with killed one in LIFO style --- .../Common/PersistentWindowProcessor.cs | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/Ninjacrab.PersistentWindows.Solution/Common/PersistentWindowProcessor.cs b/Ninjacrab.PersistentWindows.Solution/Common/PersistentWindowProcessor.cs index 3634e4f..1eb5531 100644 --- a/Ninjacrab.PersistentWindows.Solution/Common/PersistentWindowProcessor.cs +++ b/Ninjacrab.PersistentWindows.Solution/Common/PersistentWindowProcessor.cs @@ -1493,6 +1493,8 @@ namespace PersistentWindows.Common int similar_pos_cnt = 0; int diff_size = int.MaxValue; IntPtr similar_pos_hid = IntPtr.Zero; + DateTime last_killed_time = new DateTime(0); + IntPtr last_killed_hid = IntPtr.Zero; var deadAppPos = deadApps[curDisplayKey]; lock(captureLock) @@ -1541,6 +1543,12 @@ namespace PersistentWindows.Common similar_pos_cnt++; similar_pos_hid = kid; } + + if (appPos.CaptureTime > last_killed_time) + { + last_killed_time = appPos.CaptureTime; + last_killed_hid = kid; + } } if (pos_match_cnt == 1) @@ -1564,6 +1572,7 @@ namespace PersistentWindows.Common int proc_name_match_cnt = 0; int class_name_match_cnt = 0; + int class_name_mismatch_cnt = 0; foreach(var h in monitorApplications[curDisplayKey].Keys) { foreach (var dm in monitorApplications[curDisplayKey][h]) @@ -1577,21 +1586,27 @@ namespace PersistentWindows.Common proc_name_match_cnt++; if (dm.ClassName == className) class_name_match_cnt++; + else + class_name_mismatch_cnt++; } break; } } - //force match if hwnd is the first live window of the app + //force match last killed pos if hwnd is the first live window of the app if (proc_name_match_cnt == 0) - return similar_pos_hid; + return last_killed_hid; + //force match most closest pos if hwnd is the first sub window of the app if (proc_name_match_cnt == 1 && class_name_match_cnt == 0) return similar_pos_hid; //force match if hwnd-like window has multiple instantiations but has only one top-level matching candidate if (similar_pos_cnt == 1 && class_name_match_cnt > 0) return similar_pos_hid; + + if (class_name_match_cnt > 0 && class_name_mismatch_cnt == 0) + return last_killed_hid; } return IntPtr.Zero; From f05d569387b0366b8e3a8649a8c4c099e54cfa32 Mon Sep 17 00:00:00 2001 From: Kang Yu Date: Thu, 1 May 2025 09:57:36 -0700 Subject: [PATCH 03/22] #400, fix wrong mismatch of dialog of different style --- .../Common/Models/ApplicationDisplayMetrics.cs | 2 ++ .../Common/PersistentWindowProcessor.cs | 12 ++++++++++++ 2 files changed, 14 insertions(+) diff --git a/Ninjacrab.PersistentWindows.Solution/Common/Models/ApplicationDisplayMetrics.cs b/Ninjacrab.PersistentWindows.Solution/Common/Models/ApplicationDisplayMetrics.cs index a18acd2..1c4acc4 100644 --- a/Ninjacrab.PersistentWindows.Solution/Common/Models/ApplicationDisplayMetrics.cs +++ b/Ninjacrab.PersistentWindows.Solution/Common/Models/ApplicationDisplayMetrics.cs @@ -26,6 +26,8 @@ namespace PersistentWindows.Common.Models public bool IsFullScreen { get; set; } public bool IsMinimized { get; set; } public bool IsInvisible { get; set; } + public long Style { get; set; } + public long ExtStyle { get; set; } // for restore window position to display session end time public DateTime CaptureTime { get; set; } diff --git a/Ninjacrab.PersistentWindows.Solution/Common/PersistentWindowProcessor.cs b/Ninjacrab.PersistentWindows.Solution/Common/PersistentWindowProcessor.cs index 1eb5531..afaa950 100644 --- a/Ninjacrab.PersistentWindows.Solution/Common/PersistentWindowProcessor.cs +++ b/Ninjacrab.PersistentWindows.Solution/Common/PersistentWindowProcessor.cs @@ -1496,6 +1496,9 @@ namespace PersistentWindows.Common DateTime last_killed_time = new DateTime(0); IntPtr last_killed_hid = IntPtr.Zero; + long style = User32.GetWindowLong(hwnd, User32.GWL_STYLE); + long ext_style = User32.GetWindowLong(hwnd, User32.GWL_EXSTYLE); + var deadAppPos = deadApps[curDisplayKey]; lock(captureLock) foreach (var kid in deadAppPos.Keys) @@ -1505,6 +1508,11 @@ namespace PersistentWindows.Common if (!procName.Equals(appPos.ProcessName)) continue; + if (appPos.Style != 0 && style != appPos.Style) + continue; + if (appPos.ExtStyle != 0 && ext_style != appPos.ExtStyle) + continue; + if (!className.Equals(appPos.ClassName)) { if (className.Length != appPos.ClassName.Length) @@ -1513,6 +1521,7 @@ namespace PersistentWindows.Common continue; } + if (IsMinimized(hwnd) != appPos.IsMinimized) continue; if (User32.IsWindowVisible(hwnd) == appPos.IsInvisible) @@ -3319,6 +3328,9 @@ namespace PersistentWindows.Common NeedUpdateWindowPlacement = false, ScreenPosition = screenPosition, + Style = User32.GetWindowLong(hwnd, User32.GWL_STYLE), + ExtStyle = User32.GetWindowLong(hwnd, User32.GWL_EXSTYLE), + IsTopMost = IsWindowTopMost(hwnd), NeedClearTopMost = false, From 5d26d86e2831b18d72531e0c05f8bfe02836eccb Mon Sep 17 00:00:00 2001 From: Kang Yu Date: Thu, 1 May 2025 11:16:42 -0700 Subject: [PATCH 04/22] speedup auto-restore-new-window, reduce killed window entry by wild matching non-resizable window which will not be restored --- .../Common/PersistentWindowProcessor.cs | 37 ++++--------------- 1 file changed, 8 insertions(+), 29 deletions(-) diff --git a/Ninjacrab.PersistentWindows.Solution/Common/PersistentWindowProcessor.cs b/Ninjacrab.PersistentWindows.Solution/Common/PersistentWindowProcessor.cs index afaa950..4c79016 100644 --- a/Ninjacrab.PersistentWindows.Solution/Common/PersistentWindowProcessor.cs +++ b/Ninjacrab.PersistentWindows.Solution/Common/PersistentWindowProcessor.cs @@ -1486,8 +1486,6 @@ namespace PersistentWindows.Common if (!string.IsNullOrEmpty(className)) { - int title_match_cnt = 0; - IntPtr title_match_hid = IntPtr.Zero; int pos_match_cnt = 0; IntPtr pos_match_hid = IntPtr.Zero; int similar_pos_cnt = 0; @@ -1521,7 +1519,6 @@ namespace PersistentWindows.Common continue; } - if (IsMinimized(hwnd) != appPos.IsMinimized) continue; if (User32.IsWindowVisible(hwnd) == appPos.IsInvisible) @@ -1534,12 +1531,6 @@ namespace PersistentWindows.Common if (rect.Equals(r) && title.Equals(appPos.Title)) return kid; - if (title.Equals(appPos.Title)) - { - title_match_hid = kid; - ++title_match_cnt; - } - if (rect.Equals(r)) { pos_match_cnt++; @@ -1569,13 +1560,9 @@ namespace PersistentWindows.Common return similar_pos_hid; } - /* - if (title_match_cnt == 1) - { - Log.Event($"matching window with same title"); - return title_match_hid; - } - */ + if (!IsResizableWindow(hwnd)) + return similar_pos_hid; + if (!monitorApplications.ContainsKey(curDisplayKey)) return IntPtr.Zero; @@ -1586,9 +1573,9 @@ namespace PersistentWindows.Common { foreach (var dm in monitorApplications[curDisplayKey][h]) { - if (IsMinimized(h) != dm.IsMinimized) + if (style != dm.Style && dm.Style != 0) continue; - if (User32.IsWindowVisible(h) == dm.IsInvisible) + if (ext_style != dm.ExtStyle && dm.ExtStyle != 0) continue; if (dm.ProcessName == procName) { @@ -2141,24 +2128,14 @@ namespace PersistentWindows.Common { case User32Events.EVENT_OBJECT_CREATE: { - if (idObject != 0) - // ignore non-window object (caret etc) - return; - if (restoringFromDB) return; if (freezeCapture || !monitorApplications.ContainsKey(curDisplayKey)) return; - /* - //try to inherit from killed window database - if (FindMatchingKilledWindow(hwnd) != IntPtr.Zero) - { - } - */ userMove = true; - StartCaptureTimer(UserMoveLatency * 4); + StartCaptureTimer(UserMoveLatency / 2); } break; @@ -3241,6 +3218,8 @@ namespace PersistentWindows.Common restoringFromMem = true; RestoreApplicationsOnCurrentDisplays(curDisplayKey, hwnd, prevDisplayMetrics.CaptureTime); restoringFromMem = false; + userMove = true; + StartCaptureTimer(UserMoveLatency / 2); } } return true; From 9661f8bd798495c23611043ee1193a1c7b3ea103 Mon Sep 17 00:00:00 2001 From: Kang Yu Date: Thu, 1 May 2025 11:30:27 -0700 Subject: [PATCH 05/22] undo wild match for non-resizable window --- .../Common/PersistentWindowProcessor.cs | 3 --- 1 file changed, 3 deletions(-) diff --git a/Ninjacrab.PersistentWindows.Solution/Common/PersistentWindowProcessor.cs b/Ninjacrab.PersistentWindows.Solution/Common/PersistentWindowProcessor.cs index 4c79016..2f15a7b 100644 --- a/Ninjacrab.PersistentWindows.Solution/Common/PersistentWindowProcessor.cs +++ b/Ninjacrab.PersistentWindows.Solution/Common/PersistentWindowProcessor.cs @@ -1560,9 +1560,6 @@ namespace PersistentWindows.Common return similar_pos_hid; } - if (!IsResizableWindow(hwnd)) - return similar_pos_hid; - if (!monitorApplications.ContainsKey(curDisplayKey)) return IntPtr.Zero; From 304c654e80efa2eb35a6b17c35b43b10a86a8017 Mon Sep 17 00:00:00 2001 From: Kang Yu Date: Thu, 1 May 2025 14:55:44 -0700 Subject: [PATCH 06/22] inherit window in stack order (last kill, first inherit) --- .../Common/PersistentWindowProcessor.cs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Ninjacrab.PersistentWindows.Solution/Common/PersistentWindowProcessor.cs b/Ninjacrab.PersistentWindows.Solution/Common/PersistentWindowProcessor.cs index 2f15a7b..ccf7e96 100644 --- a/Ninjacrab.PersistentWindows.Solution/Common/PersistentWindowProcessor.cs +++ b/Ninjacrab.PersistentWindows.Solution/Common/PersistentWindowProcessor.cs @@ -1984,7 +1984,9 @@ namespace PersistentWindows.Common } // for matching new window with killed one - monitorApplications[display_config][hwnd].Last().ProcessName = windowProcessName[hwnd]; + var dm = monitorApplications[display_config][hwnd].Last(); + if (dm.SnapShotFlags == 0) + dm.CaptureTime = DateTime.Now; //for inheritence in LIFO stile deadApps[display_config][hwnd] = monitorApplications[display_config][hwnd]; From e7b141e095ee4e2f7cd39130701055a3f73f4c4a Mon Sep 17 00:00:00 2001 From: Kang Yu Date: Thu, 1 May 2025 15:01:17 -0700 Subject: [PATCH 07/22] further speedup auto-restore-new-window --- .../Common/PersistentWindowProcessor.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Ninjacrab.PersistentWindows.Solution/Common/PersistentWindowProcessor.cs b/Ninjacrab.PersistentWindows.Solution/Common/PersistentWindowProcessor.cs index ccf7e96..196105f 100644 --- a/Ninjacrab.PersistentWindows.Solution/Common/PersistentWindowProcessor.cs +++ b/Ninjacrab.PersistentWindows.Solution/Common/PersistentWindowProcessor.cs @@ -2134,7 +2134,7 @@ namespace PersistentWindows.Common return; userMove = true; - StartCaptureTimer(UserMoveLatency / 2); + StartCaptureTimer(UserMoveLatency / 4); } break; From 1fd82f35c8abd3f624d468bda7dcaee97a7999a5 Mon Sep 17 00:00:00 2001 From: Kang Yu Date: Thu, 1 May 2025 15:42:07 -0700 Subject: [PATCH 08/22] avoid trigger batch restore in restore single window mode --- .../Common/PersistentWindowProcessor.cs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/Ninjacrab.PersistentWindows.Solution/Common/PersistentWindowProcessor.cs b/Ninjacrab.PersistentWindows.Solution/Common/PersistentWindowProcessor.cs index 196105f..baf2f32 100644 --- a/Ninjacrab.PersistentWindows.Solution/Common/PersistentWindowProcessor.cs +++ b/Ninjacrab.PersistentWindows.Solution/Common/PersistentWindowProcessor.cs @@ -106,6 +106,7 @@ namespace PersistentWindows.Common private Timer restoreTimer; private Timer restoreFinishedTimer; public bool restoringFromMem = false; // automatic restore from memory or snapshot + private bool restoreSingleWindow = false; public bool restoringFromDB = false; // manual restore from DB public bool autoInitialRestoreFromDB = false; public bool restoringSnapshot = false; // implies restoringFromMem @@ -2113,7 +2114,7 @@ namespace PersistentWindows.Common if (eventType == User32Events.EVENT_OBJECT_LOCATIONCHANGE) { - if ((remoteSession || restoreTimes >= MinRestoreTimes) && !restoringSnapshot) + if (((remoteSession && !restoreSingleWindow) || restoreTimes >= MinRestoreTimes) && !restoringSnapshot) { // restore is not finished as long as window location keeps changing CancelRestoreFinishedTimer(); @@ -3214,8 +3215,10 @@ namespace PersistentWindows.Common if (!restoringFromDB && IsResizableWindow(hwnd)) { Log.Trace($"restore {windowTitle[hwnd]} to last captured position"); + restoreSingleWindow = true; restoringFromMem = true; RestoreApplicationsOnCurrentDisplays(curDisplayKey, hwnd, prevDisplayMetrics.CaptureTime); + restoreSingleWindow = false; restoringFromMem = false; userMove = true; StartCaptureTimer(UserMoveLatency / 2); From 4998a104ea1e37b2aec448b54237afbaf8aded5e Mon Sep 17 00:00:00 2001 From: Kang Yu Date: Thu, 1 May 2025 15:46:41 -0700 Subject: [PATCH 09/22] tag 5.64 --- .../SystrayShell/Properties/AssemblyInfo.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Ninjacrab.PersistentWindows.Solution/SystrayShell/Properties/AssemblyInfo.cs b/Ninjacrab.PersistentWindows.Solution/SystrayShell/Properties/AssemblyInfo.cs index a465d6e..7b0bef2 100644 --- a/Ninjacrab.PersistentWindows.Solution/SystrayShell/Properties/AssemblyInfo.cs +++ b/Ninjacrab.PersistentWindows.Solution/SystrayShell/Properties/AssemblyInfo.cs @@ -31,5 +31,5 @@ using System.Runtime.InteropServices; // You can specify all the values or you can default the Build and Revision Numbers // by using the '*' as shown below: // [assembly: AssemblyVersion("1.0.*")] -[assembly: AssemblyVersion("5.63.*")] +[assembly: AssemblyVersion("5.64.*")] From 9e85ee58109e1d0320a86883a85cc70b324bf9c4 Mon Sep 17 00:00:00 2001 From: Kang Yu Date: Thu, 1 May 2025 17:10:45 -0700 Subject: [PATCH 10/22] #369, fix crash on windows 11 when launching webpage --- .../SystrayShell/SystrayForm.cs | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/Ninjacrab.PersistentWindows.Solution/SystrayShell/SystrayForm.cs b/Ninjacrab.PersistentWindows.Solution/SystrayShell/SystrayForm.cs index e7bd829..28c2a48 100644 --- a/Ninjacrab.PersistentWindows.Solution/SystrayShell/SystrayForm.cs +++ b/Ninjacrab.PersistentWindows.Solution/SystrayShell/SystrayForm.cs @@ -252,7 +252,16 @@ namespace PersistentWindows.SystrayShell if (!upgradeDownloaded.ContainsKey(latestVersion)) { - Process.Start(Program.ProjectUrl + "/releases"); + string url = Program.ProjectUrl + "/releases"; + var os_version = Environment.OSVersion; + if (os_version.Version.Major < 10) + Process.Start(url); + else if (os_version.Version.Build < 22000) + Process.Start(url); + /* windows 11 + else + Process.Start(new ProcessStartInfo(url)); + */ var src_file = $"{Program.ProjectUrl}/releases/download/{latestVersion}/{System.Windows.Forms.Application.ProductName}{latestVersion}.zip"; var dst_file = $"{Program.AppdataFolder}/upgrade.zip"; From 2c06fe1684950d30a3ca3a6bbe4d9a82dc311f84 Mon Sep 17 00:00:00 2001 From: Kang Yu Date: Thu, 1 May 2025 23:43:38 -0700 Subject: [PATCH 11/22] =?UTF-8?q?#388=EF=BC=8C=20fix=20mismatch=20killed?= =?UTF-8?q?=20window=20for=20jEdit?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Common/PersistentWindowProcessor.cs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/Ninjacrab.PersistentWindows.Solution/Common/PersistentWindowProcessor.cs b/Ninjacrab.PersistentWindows.Solution/Common/PersistentWindowProcessor.cs index baf2f32..08a63b5 100644 --- a/Ninjacrab.PersistentWindows.Solution/Common/PersistentWindowProcessor.cs +++ b/Ninjacrab.PersistentWindows.Solution/Common/PersistentWindowProcessor.cs @@ -1571,10 +1571,11 @@ namespace PersistentWindows.Common { foreach (var dm in monitorApplications[curDisplayKey][h]) { - if (style != dm.Style && dm.Style != 0) + if (IsMinimized(hwnd) != dm.IsMinimized) continue; - if (ext_style != dm.ExtStyle && dm.ExtStyle != 0) + if (User32.IsWindowVisible(hwnd) == dm.IsInvisible) continue; + if (dm.ProcessName == procName) { proc_name_match_cnt++; From e8f06c1368519e328952866daa0c485918566a11 Mon Sep 17 00:00:00 2001 From: Kang Yu Date: Sat, 3 May 2025 16:15:24 -0700 Subject: [PATCH 12/22] no need to write xml when restore finished, as it is done in session end --- .../Common/PersistentWindowProcessor.cs | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/Ninjacrab.PersistentWindows.Solution/Common/PersistentWindowProcessor.cs b/Ninjacrab.PersistentWindows.Solution/Common/PersistentWindowProcessor.cs index 08a63b5..805b477 100644 --- a/Ninjacrab.PersistentWindows.Solution/Common/PersistentWindowProcessor.cs +++ b/Ninjacrab.PersistentWindows.Solution/Common/PersistentWindowProcessor.cs @@ -769,8 +769,6 @@ namespace PersistentWindows.Common Log.Event("Restore finished in pass {0} with {1} windows recovered for display setting {2}", restorePass, numWindowRestored, curDisplayKey); sessionActive = true; - WriteDataDump(); - if (!wasRestoringSnapshot && !wasRestoringFromDB) { if (!snapshotTakenTime.ContainsKey(curDisplayKey)) @@ -865,6 +863,7 @@ namespace PersistentWindows.Common (s, e) => { process.PriorityClass = ProcessPriorityClass.High; + EndDisplaySession(); WriteDataDump(); Log.Event("Session ending"); }; @@ -873,6 +872,9 @@ namespace PersistentWindows.Common this.displaySettingsChangingHandler = (s, e) => { + if (fastRestore) + process.PriorityClass = ProcessPriorityClass.High; + if (!freezeCapture) { lastDisplayChangeTime = DateTime.Now; @@ -895,9 +897,6 @@ namespace PersistentWindows.Common this.displaySettingsChangedHandler = (s, e) => { - if (fastRestore) - process.PriorityClass = ProcessPriorityClass.High; - string displayKey = GetDisplayKey(); Log.Event("Display settings changed {0}", displayKey); From 4df563f1bb45ae3418862e8a365865fdd8bd090c Mon Sep 17 00:00:00 2001 From: Kang Yu Date: Sat, 3 May 2025 16:33:47 -0700 Subject: [PATCH 13/22] speedup PW startup restore by setting set process priority to high during the first 10 seconds of PW starting --- .../SystrayShell/Program.cs | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/Ninjacrab.PersistentWindows.Solution/SystrayShell/Program.cs b/Ninjacrab.PersistentWindows.Solution/SystrayShell/Program.cs index 37705b2..909c6d8 100644 --- a/Ninjacrab.PersistentWindows.Solution/SystrayShell/Program.cs +++ b/Ninjacrab.PersistentWindows.Solution/SystrayShell/Program.cs @@ -48,6 +48,15 @@ if not errorlevel 1 goto wait_to_finish"; [STAThread] static void Main(string[] args) { + var process = Process.GetCurrentProcess(); + var process_priority = process.PriorityClass; + process.PriorityClass = ProcessPriorityClass.High; + var timer = new System.Threading.Timer(state => + { + process.PriorityClass = process_priority; + }); + timer.Change(10000, System.Threading.Timeout.Infinite); + Application.EnableVisualStyles(); Application.SetCompatibleTextRenderingDefault(false); From cad1ec393fe5475d3d4f8c02a1e409cbf3ec7d95 Mon Sep 17 00:00:00 2001 From: Kang Yu Date: Sat, 3 May 2025 17:24:44 -0700 Subject: [PATCH 14/22] restore process priority 10 seconds after startup --- .../Common/PersistentWindowProcessor.cs | 4 +--- .../SystrayShell/Program.cs | 18 +++++++++--------- 2 files changed, 10 insertions(+), 12 deletions(-) diff --git a/Ninjacrab.PersistentWindows.Solution/Common/PersistentWindowProcessor.cs b/Ninjacrab.PersistentWindows.Solution/Common/PersistentWindowProcessor.cs index 805b477..8760539 100644 --- a/Ninjacrab.PersistentWindows.Solution/Common/PersistentWindowProcessor.cs +++ b/Ninjacrab.PersistentWindows.Solution/Common/PersistentWindowProcessor.cs @@ -161,7 +161,7 @@ namespace PersistentWindows.Common private static Dictionary windowProcessName = new Dictionary(); private Process process; - private ProcessPriorityClass processPriority; + public ProcessPriorityClass processPriority; private string appDataFolder; public bool redirectAppDataFolder = false; @@ -594,8 +594,6 @@ namespace PersistentWindows.Common public bool Start(bool auto_restore_from_db, bool auto_restore_last_capture_at_startup) { process = Process.GetCurrentProcess(); - processPriority = process.PriorityClass; - string productName = System.Windows.Forms.Application.ProductName; appDataFolder = redirectAppDataFolder ? "." : Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), productName); diff --git a/Ninjacrab.PersistentWindows.Solution/SystrayShell/Program.cs b/Ninjacrab.PersistentWindows.Solution/SystrayShell/Program.cs index 909c6d8..73168a9 100644 --- a/Ninjacrab.PersistentWindows.Solution/SystrayShell/Program.cs +++ b/Ninjacrab.PersistentWindows.Solution/SystrayShell/Program.cs @@ -48,15 +48,6 @@ if not errorlevel 1 goto wait_to_finish"; [STAThread] static void Main(string[] args) { - var process = Process.GetCurrentProcess(); - var process_priority = process.PriorityClass; - process.PriorityClass = ProcessPriorityClass.High; - var timer = new System.Threading.Timer(state => - { - process.PriorityClass = process_priority; - }); - timer.Change(10000, System.Threading.Timeout.Infinite); - Application.EnableVisualStyles(); Application.SetCompatibleTextRenderingDefault(false); @@ -65,6 +56,15 @@ if not errorlevel 1 goto wait_to_finish"; pwp = new PersistentWindowProcessor(); + var process = Process.GetCurrentProcess(); + pwp.processPriority = process.PriorityClass; + process.PriorityClass = ProcessPriorityClass.High; + var timer = new System.Threading.Timer(state => + { + process.PriorityClass = pwp.processPriority; + }); + timer.Change(10000, System.Threading.Timeout.Infinite); + bool splash = true; int delay_restart = 0; int relaunch_delay = 0; From f7eb0abe432a744bb83bd269b6f9110a393feb5b Mon Sep 17 00:00:00 2001 From: Kang Yu Date: Sat, 3 May 2025 22:24:20 -0700 Subject: [PATCH 15/22] speedup inheritance in case window create event is delayed --- .../Common/PersistentWindowProcessor.cs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/Ninjacrab.PersistentWindows.Solution/Common/PersistentWindowProcessor.cs b/Ninjacrab.PersistentWindows.Solution/Common/PersistentWindowProcessor.cs index 8760539..c53cb6b 100644 --- a/Ninjacrab.PersistentWindows.Solution/Common/PersistentWindowProcessor.cs +++ b/Ninjacrab.PersistentWindows.Solution/Common/PersistentWindowProcessor.cs @@ -34,7 +34,7 @@ namespace PersistentWindows.Common public int UserForcedRestoreLatency = 0; private const int CaptureLatency = 3000; // delay in milliseconds from window OS move to capture private const int UserMoveLatency = 1000; // delay in milliseconds from user move/minimize/unminimize/maximize to capture, must < CaptureLatency - private const int ForegroundTimerLatency = UserMoveLatency / 5; + private const int ForegroundTimerLatency = UserMoveLatency / 4; private const int MaxUserMoves = 4; // max user window moves per capture cycle private const int MinWindowOsMoveEvents = 12; // threshold of window move events initiated by OS per capture cycle private const int MaxSnapshots = 38; // 0-9, a-z, ` (for redo last auto restore) and final one for undo last snapshot restore @@ -483,6 +483,10 @@ namespace PersistentWindows.Common } else if (fullScreenGamingWindow == IntPtr.Zero) { + //create window event may be delayed + if (hwnd != IntPtr.Zero) + CaptureWindow(hwnd, 0, DateTime.Now, curDisplayKey); + StartCaptureTimer(); //speed up initial capture From 11d0c30ddbb6b0d1b2e7008b723a71e2d93208bb Mon Sep 17 00:00:00 2001 From: Kang Yu Date: Sat, 3 May 2025 23:12:28 -0700 Subject: [PATCH 16/22] disable double restore full screen window due to invisible window issue --- .../Common/PersistentWindowProcessor.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Ninjacrab.PersistentWindows.Solution/Common/PersistentWindowProcessor.cs b/Ninjacrab.PersistentWindows.Solution/Common/PersistentWindowProcessor.cs index c53cb6b..216855a 100644 --- a/Ninjacrab.PersistentWindows.Solution/Common/PersistentWindowProcessor.cs +++ b/Ninjacrab.PersistentWindows.Solution/Common/PersistentWindowProcessor.cs @@ -3698,6 +3698,7 @@ namespace PersistentWindows.Common 0, 0, 0, UIntPtr.Zero); Log.Error("restore full screen window {0}", GetWindowTitle(hwnd)); + /* Thread.Sleep(3 * double_clck_interval); style = User32.GetWindowLong(hwnd, User32.GWL_STYLE); @@ -3722,6 +3723,7 @@ namespace PersistentWindows.Common } Log.Error("fail to restore full screen window {0}", GetWindowTitle(hwnd)); + */ } private void RestoreSnapWindow(IntPtr hwnd, RECT target_pos) From 3884c4446fd5d330369262e5fef9347375df3012 Mon Sep 17 00:00:00 2001 From: Kang Yu Date: Sat, 3 May 2025 23:23:51 -0700 Subject: [PATCH 17/22] no fast capture if window is marked no restore --- .../Common/PersistentWindowProcessor.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Ninjacrab.PersistentWindows.Solution/Common/PersistentWindowProcessor.cs b/Ninjacrab.PersistentWindows.Solution/Common/PersistentWindowProcessor.cs index 216855a..cfed54d 100644 --- a/Ninjacrab.PersistentWindows.Solution/Common/PersistentWindowProcessor.cs +++ b/Ninjacrab.PersistentWindows.Solution/Common/PersistentWindowProcessor.cs @@ -484,7 +484,7 @@ namespace PersistentWindows.Common else if (fullScreenGamingWindow == IntPtr.Zero) { //create window event may be delayed - if (hwnd != IntPtr.Zero) + if (hwnd != IntPtr.Zero && !noRestoreWindows.Contains(hwnd)) CaptureWindow(hwnd, 0, DateTime.Now, curDisplayKey); StartCaptureTimer(); From 3d2ed7395c47cf367b0aa37aaa0b8c25a87f649e Mon Sep 17 00:00:00 2001 From: Kang Yu Date: Sat, 3 May 2025 23:26:00 -0700 Subject: [PATCH 18/22] tag 5.65 --- .../SystrayShell/Properties/AssemblyInfo.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Ninjacrab.PersistentWindows.Solution/SystrayShell/Properties/AssemblyInfo.cs b/Ninjacrab.PersistentWindows.Solution/SystrayShell/Properties/AssemblyInfo.cs index 7b0bef2..03b8722 100644 --- a/Ninjacrab.PersistentWindows.Solution/SystrayShell/Properties/AssemblyInfo.cs +++ b/Ninjacrab.PersistentWindows.Solution/SystrayShell/Properties/AssemblyInfo.cs @@ -31,5 +31,5 @@ using System.Runtime.InteropServices; // You can specify all the values or you can default the Build and Revision Numbers // by using the '*' as shown below: // [assembly: AssemblyVersion("1.0.*")] -[assembly: AssemblyVersion("5.64.*")] +[assembly: AssemblyVersion("5.65.*")] From 3a473bdc109e0d1f1acfbf8a3ed63bc70e896b25 Mon Sep 17 00:00:00 2001 From: Kang Yu Date: Mon, 5 May 2025 17:49:23 -0700 Subject: [PATCH 19/22] [dual pos switch] use first diff pos as background match --- .../Common/PersistentWindowProcessor.cs | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/Ninjacrab.PersistentWindows.Solution/Common/PersistentWindowProcessor.cs b/Ninjacrab.PersistentWindows.Solution/Common/PersistentWindowProcessor.cs index cfed54d..7ea75c3 100644 --- a/Ninjacrab.PersistentWindows.Solution/Common/PersistentWindowProcessor.cs +++ b/Ninjacrab.PersistentWindows.Solution/Common/PersistentWindowProcessor.cs @@ -2648,6 +2648,14 @@ namespace PersistentWindows.Common continue; } + if (!toForeground) + { + RECT screenPosition = new RECT(); + User32.GetWindowRect(hwnd, ref screenPosition); + if (screenPosition.Equals(metrics.ScreenPosition)) + continue; + } + IntPtr prevZwnd = metrics.PrevZorderWindow; if (prevZwnd != front_hwnd && (prevZwnd == IntPtr.Zero || prevZwnd != firstBackgroundWindow)) { From cd29b292820b588ce3fb64b120c272089bc70c36 Mon Sep 17 00:00:00 2001 From: Kang Yu Date: Mon, 5 May 2025 18:09:34 -0700 Subject: [PATCH 20/22] simplify DPS code --- .../Common/PersistentWindowProcessor.cs | 16 ++++------------ 1 file changed, 4 insertions(+), 12 deletions(-) diff --git a/Ninjacrab.PersistentWindows.Solution/Common/PersistentWindowProcessor.cs b/Ninjacrab.PersistentWindows.Solution/Common/PersistentWindowProcessor.cs index 7ea75c3..7ebe6cf 100644 --- a/Ninjacrab.PersistentWindows.Solution/Common/PersistentWindowProcessor.cs +++ b/Ninjacrab.PersistentWindows.Solution/Common/PersistentWindowProcessor.cs @@ -522,12 +522,12 @@ namespace PersistentWindows.Common if (!ctrl_key_pressed && !alt_key_pressed) { //restore window to previous background position - SwitchForeBackground(hwnd, secondBackGround:shift_key_pressed); + SwitchForeBackground(hwnd); } else if (ctrl_key_pressed && !alt_key_pressed) { //restore to previous background zorder with current size/pos - SwitchForeBackground(hwnd, strict_dps_check: false, updateBackgroundPos: true, secondBackGround:shift_key_pressed); + SwitchForeBackground(hwnd, strict_dps_check: false, updateBackgroundPos: true); } else if (!ctrl_key_pressed && alt_key_pressed && !shift_key_pressed) { @@ -2613,7 +2613,7 @@ namespace PersistentWindows.Common Log.Event("Bring foreground window {0} to bottom", GetWindowTitle(hwnd)); } - public void SwitchForeBackground(IntPtr hwnd, bool strict_dps_check = true, bool toForeground=false, bool updateBackgroundPos=false, bool secondBackGround = false) + public void SwitchForeBackground(IntPtr hwnd, bool strict_dps_check = true, bool toForeground=false, bool updateBackgroundPos=false) { if (hwnd == IntPtr.Zero || IsTaskBar(hwnd)) return; @@ -2638,8 +2638,6 @@ namespace PersistentWindows.Common if (toForeground && IsTaskBar(front_hwnd)) return; //already foreground - IntPtr firstBackgroundWindow = IntPtr.Zero; - for (; prevIndex >= 0; --prevIndex) { var metrics = monitorApplications[curDisplayKey][hwnd][prevIndex]; @@ -2657,7 +2655,7 @@ namespace PersistentWindows.Common } IntPtr prevZwnd = metrics.PrevZorderWindow; - if (prevZwnd != front_hwnd && (prevZwnd == IntPtr.Zero || prevZwnd != firstBackgroundWindow)) + if (prevZwnd != front_hwnd) { if (toForeground) { @@ -2666,12 +2664,6 @@ namespace PersistentWindows.Common } else { - if (secondBackGround) - { - firstBackgroundWindow = prevZwnd; - secondBackGround = false; - continue; - } if (IsTaskBar(front_hwnd) && IsTaskBar(prevZwnd)) return; //#266, ignore taskbar (as prev-zwindow) change due to window maximize From 6745982d60f6e0ade9fa1552f988f264e098bd57 Mon Sep 17 00:00:00 2001 From: Kang Yu Date: Mon, 5 May 2025 18:12:11 -0700 Subject: [PATCH 21/22] simplify help on DPS, remove Shift + click desktop window --- Help.md | 1 - 1 file changed, 1 deletion(-) diff --git a/Help.md b/Help.md index 67410e3..e7d93ad 100644 --- a/Help.md +++ b/Help.md @@ -60,7 +60,6 @@ * Dual Position Switching functionality: * Click the desktop window to bring the foreground window to its previous background position and Z-order. - * Shift + Click the desktop window to bring the foreground window to its *second* last background position. This is useful if the previous background position is mis-captured due to invoking start menu or other popups. * Ctrl + Click the desktop window to bring the foreground window to its previous Z-order while keeping the current location and size. * To cancel Dual Position Switching: From ae8da1683433ad5ec6a08e892ee02006044bfbd4 Mon Sep 17 00:00:00 2001 From: Kang Yu Date: Thu, 8 May 2025 13:43:36 -0700 Subject: [PATCH 22/22] #403, fix crash due to empty history record --- .../Common/PersistentWindowProcessor.cs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Ninjacrab.PersistentWindows.Solution/Common/PersistentWindowProcessor.cs b/Ninjacrab.PersistentWindows.Solution/Common/PersistentWindowProcessor.cs index 7ebe6cf..fbafe35 100644 --- a/Ninjacrab.PersistentWindows.Solution/Common/PersistentWindowProcessor.cs +++ b/Ninjacrab.PersistentWindows.Solution/Common/PersistentWindowProcessor.cs @@ -1503,7 +1503,9 @@ namespace PersistentWindows.Common lock(captureLock) foreach (var kid in deadAppPos.Keys) { - var appPos = deadAppPos[kid].Last(); + var appPos = deadAppPos[kid].LastOrDefault(); + if (appPos == null) + continue; if (!procName.Equals(appPos.ProcessName)) continue;