Compare commits

...

53 commits
5.61 ... master

Author SHA1 Message Date
Kang Yu
ae8da16834 #403, fix crash due to empty history record 2025-05-08 13:43:36 -07:00
Kang Yu
6745982d60 simplify help on DPS, remove Shift + click desktop window 2025-05-05 18:12:11 -07:00
Kang Yu
cd29b29282 simplify DPS code 2025-05-05 18:09:34 -07:00
Kang Yu
3a473bdc10 [dual pos switch] use first diff pos as background match 2025-05-05 17:49:23 -07:00
Kang Yu
3d2ed7395c tag 5.65 2025-05-03 23:26:00 -07:00
Kang Yu
3884c4446f no fast capture if window is marked no restore 2025-05-03 23:23:51 -07:00
Kang Yu
11d0c30ddb disable double restore full screen window due to invisible window issue 2025-05-03 23:12:28 -07:00
Kang Yu
f7eb0abe43 speedup inheritance in case window create event is delayed 2025-05-03 22:24:20 -07:00
Kang Yu
cad1ec393f restore process priority 10 seconds after startup 2025-05-03 17:24:44 -07:00
Kang Yu
4df563f1bb speedup PW startup restore by setting set process priority to high during the first 10 seconds of PW starting 2025-05-03 16:44:10 -07:00
Kang Yu
e8f06c1368 no need to write xml when restore finished, as it is done in session end 2025-05-03 16:15:24 -07:00
Kang Yu
2c06fe1684 #388, fix mismatch killed window for jEdit 2025-05-01 23:43:38 -07:00
Kang Yu
9e85ee5810 #369, fix crash on windows 11 when launching webpage 2025-05-01 17:55:09 -07:00
Kang Yu
4998a104ea tag 5.64 2025-05-01 15:46:41 -07:00
Kang Yu
1fd82f35c8 avoid trigger batch restore in restore single window mode 2025-05-01 15:42:07 -07:00
Kang Yu
e7b141e095 further speedup auto-restore-new-window 2025-05-01 15:01:17 -07:00
Kang Yu
304c654e80 inherit window in stack order (last kill, first inherit) 2025-05-01 14:55:44 -07:00
Kang Yu
9661f8bd79 undo wild match for non-resizable window 2025-05-01 11:30:27 -07:00
Kang Yu
5d26d86e28 speedup auto-restore-new-window, reduce killed window entry by wild matching non-resizable window which will not be restored 2025-05-01 11:16:42 -07:00
Kang Yu
f05d569387 #400, fix wrong mismatch of dialog of different style 2025-05-01 09:57:36 -07:00
Kang Yu
f66dc3afd8 match new window with killed one in LIFO style 2025-04-30 19:47:32 -07:00
Kang Yu
5f666b20d1 avoid wrong matching 2025-04-28 16:36:47 -07:00
Kang Yu
2d695d11bf tag 5.63, update help for command line option change 2025-04-28 14:53:26 -07:00
Kang Yu
8da7d9b4bc turn on -auto_restore_new_window_to_last_capture again 2025-04-28 14:24:18 -07:00
Kang Yu
f7a1f92343 fix wrong tick value for 5 min 2025-04-28 14:16:45 -07:00
Kang Yu
8771c2edd7 disable auto restore from db/xml at pw start if system is up more than 5 min 2025-04-28 14:14:31 -07:00
Kang Yu
f34fffa574 disable auto restore from db if system is up more than 5 min 2025-04-28 14:10:41 -07:00
Kang Yu
cce0f7f52d refix #369, #388, #392: improve algorithm matching new window to killed one. Add command option -pos_match_threshold, using 40 as default value 2025-04-28 13:50:30 -07:00
Kang Yu
8c5d6475ad fix broken -auto_restore_new_window_to_last_capture 2025-04-28 10:58:58 -07:00
Kang Yu
052cb05f53 refix delay activating webpage commander window when curosr is beam (user might be typing) 2025-04-27 22:51:01 -07:00
Kang Yu
40f8f5cefd delay activating webpage commander window when cursor is beam (user might be typing) 2025-04-27 22:11:42 -07:00
Kang Yu
7dc0cbee82 relax title match when inherit killed window 2025-04-27 21:18:07 -07:00
Kang Yu
1a5d9442d2 relax class name and position match when inherit killed window 2025-04-27 21:14:09 -07:00
Kang Yu
d36bf0c56c reduce cpu load on non-window object 2025-04-27 14:56:03 -07:00
Kang Yu
9224d62191 postpone capture to avoid wrong matching to killed window 2025-04-26 22:55:31 -07:00
Kang Yu
e41caba220 improve debug message 2025-04-26 22:29:16 -07:00
Kang Yu
769f35b681 debug print inherited window handle 2025-04-26 18:37:18 -07:00
Kang Yu
2ba0a5395b move inherit killed window out of IsWindowMoved() to CaptureWindow() 2025-04-26 15:25:31 -07:00
Kang Yu
e4be317e77 improve accuracy of matching killed window based on position similarity 2025-04-25 23:39:44 -07:00
Kang Yu
fb5f538b88 improve re-entrance protection using lock 2025-04-18 14:29:29 -07:00
Kang Yu
3b5813bb35 reduce event loggging of regular trimming of position history 2025-04-18 13:20:28 -07:00
Kang Yu
de1b815d57 fix dead-loop in TrimQueue() 2025-04-14 21:20:21 -07:00
Kang Yu
62452f3e0b fix dead-loop in TrimQueue(), causing auto-restore to hang, possibly due to wrong inheritance 2025-04-14 16:25:06 -07:00
Kang Yu
0adf762fa0 fix wrong capture due to improper unfreeze 2025-03-24 10:35:28 -07:00
Kang Yu
05a740a21f unlock unknown display session when any window is moved/resized/minimize/unminimized 2025-03-19 16:01:07 -07:00
Kang Yu
4330c95216 refactor TryInheritWindow(), making it safe to be called for both new and captured window 2025-03-17 20:53:17 -07:00
Kang Yu
23b63d09ea tag 5.62, update help 2025-03-17 16:40:29 -07:00
Kang Yu
6097ab4bc7 turn off auto restore existing window to last capture 2025-03-17 16:36:03 -07:00
Kang Yu
aacaefc205 #369, #388, #392: turn off auto-restore new window off by default 2025-03-17 16:30:49 -07:00
Kang Yu
557a3bbddb #369, #388, #392: newly created window auto-restored to wrong place due to matching to incorrect entry with different window title 2025-03-17 14:29:11 -07:00
Kang Yu
189611ad3a improve event message for inherit window 2025-03-17 14:22:16 -07:00
Kang Yu
86926ffd27 #388, fix missing capture of maximized window 2025-03-16 15:36:56 -07:00
Kang Yu
10dd03498a #389, persist exception when running PW with -ignored_process 2025-03-08 16:44:40 -08:00
9 changed files with 339 additions and 130 deletions

View file

@ -24,8 +24,9 @@
| -fix_offscreen_window=0 | Turn off auto correction of off-screen windows | -fix_offscreen_window=0 | Turn off auto correction of off-screen windows
| -fix_unminimized_window=0 | Turn off auto restore of unminimized windows. Use this switch to avoid undesirable window shifting during window activation, which comes with Event id 9999 : "restore minimized window ...." in event viewer. | -fix_unminimized_window=0 | Turn off auto restore of unminimized windows. Use this switch to avoid undesirable window shifting during window activation, which comes with Event id 9999 : "restore minimized window ...." in event viewer.
|-auto_restore_new_display_session_from_db=0| Disable window restore from DB upon PC startup or switching display for the first time |-auto_restore_new_display_session_from_db=0| Disable window restore from DB upon PC startup or switching display for the first time
|-auto_restore_existing_window_to_last_capture=0 | Turn off auto restore upon PW start |-auto_restore_existing_window_to_last_capture=1 | Turn on auto restore existing window from last capture upon PW start
|-auto_restore_new_window_to_last_capture=0 | Turn off auto restore new window to last killed position |-auto_restore_new_window_to_last_capture=0 | Turn off auto restore new window to last killed position
|-pos_match_threshold 80 | Auto correct new window position to last killed position within range of 80 pixels, default is 40
| auto_restore_missing_windows=1 | When restoring from disk, restore missing windows without prompting the user | auto_restore_missing_windows=1 | When restoring from disk, restore missing windows without prompting the user
| auto_restore_missing_windows=2 | At startup, automatically restore missing windows from disk. The user will be prompted before restoring each missing window | auto_restore_missing_windows=2 | At startup, automatically restore missing windows from disk. The user will be prompted before restoring each missing window
| auto_restore_missing_windows=3 | At startup, automatically restore missing windows from disk without prompting the user | auto_restore_missing_windows=3 | At startup, automatically restore missing windows from disk without prompting the user
@ -59,7 +60,6 @@
* Dual Position Switching functionality: * Dual Position Switching functionality:
* Click the desktop window to bring the foreground window to its previous background position and Z-order. * 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. * 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: * To cancel Dual Position Switching:

View file

@ -37,6 +37,7 @@ namespace PersistentWindows.Common
private static POINT lastCursorPos; private static POINT lastCursorPos;
private POINT lastWheelCursorPos; private POINT lastWheelCursorPos;
private bool handCursor = false; private bool handCursor = false;
private bool ibeamCursor = false;
private int titleHeight; private int titleHeight;
private Color dfltBackColor; private Color dfltBackColor;
private bool promptZkey = true; private bool promptZkey = true;
@ -869,6 +870,7 @@ namespace PersistentWindows.Common
} }
else if (Math.Abs(cursorPos.X - lastCursorPos.X) > 3 || Math.Abs(cursorPos.Y - lastCursorPos.Y) > 3) else if (Math.Abs(cursorPos.X - lastCursorPos.X) > 3 || Math.Abs(cursorPos.Y - lastCursorPos.Y) > 3)
{ {
ibeamCursor = false;
//mouse moving, continue monitor //mouse moving, continue monitor
totalWaitSecondsForWhiteColor = 0; totalWaitSecondsForWhiteColor = 0;
} }
@ -906,12 +908,14 @@ namespace PersistentWindows.Common
} }
else if (hCursor == Cursors.IBeam.Handle) else if (hCursor == Cursors.IBeam.Handle)
{ {
ibeamCursor = true;
Visible = false; Visible = false;
StartAliveTimer(11, 1000); StartAliveTimer(11, 1000);
return; return;
} }
else if (hCursor == Cursors.Cross.Handle || handCursor) else if (hCursor == Cursors.Cross.Handle || handCursor)
{ {
ibeamCursor = false;
StartAliveTimer(7); StartAliveTimer(7);
return; return;
} }
@ -946,6 +950,14 @@ namespace PersistentWindows.Common
regain_focus = false; regain_focus = false;
} }
if (ibeamCursor && hCursor == Cursors.Default.Handle)
//&& Math.Abs(cursorPos.X - lastCursorPos.X) < 3 && Math.Abs(cursorPos.Y - lastCursorPos.Y) < 3)
{
ibeamCursor = false;
StartAliveTimer(11, 1000);
return;
}
// let tiny hotkey window follow cursor position // let tiny hotkey window follow cursor position
ResetHotKeyVirtualDesktop(); ResetHotKeyVirtualDesktop();
ResetHotkeyWindowPos(); ResetHotkeyWindowPos();
@ -968,6 +980,7 @@ namespace PersistentWindows.Common
// hand cursor shape // hand cursor shape
if (!handCursor) if (!handCursor)
{ {
ibeamCursor = false;
handCursor = true; handCursor = true;
Left -= 10; Left -= 10;
} }

View file

@ -26,6 +26,8 @@ namespace PersistentWindows.Common.Models
public bool IsFullScreen { get; set; } public bool IsFullScreen { get; set; }
public bool IsMinimized { get; set; } public bool IsMinimized { get; set; }
public bool IsInvisible { 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 // for restore window position to display session end time
public DateTime CaptureTime { get; set; } public DateTime CaptureTime { get; set; }

View file

@ -34,7 +34,7 @@ namespace PersistentWindows.Common
public int UserForcedRestoreLatency = 0; public int UserForcedRestoreLatency = 0;
private const int CaptureLatency = 3000; // delay in milliseconds from window OS move to capture 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 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 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 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 private const int MaxSnapshots = 38; // 0-9, a-z, ` (for redo last auto restore) and final one for undo last snapshot restore
@ -42,6 +42,8 @@ namespace PersistentWindows.Common
private const int MaxHistoryQueueLength = 41; // ideally bigger than MaxSnapshots + 2 private const int MaxHistoryQueueLength = 41; // ideally bigger than MaxSnapshots + 2
private const int PauseRestoreTaskbar = 3500; //cursor idle time before dragging taskbar private const int PauseRestoreTaskbar = 3500; //cursor idle time before dragging taskbar
private const int MinClassNamePrefix = 8; //allow partial class name matching during inheritance
public int MaxDiffPos = 40; //allow matching window of slightly different position
private bool initialized = false; private bool initialized = false;
@ -104,10 +106,11 @@ namespace PersistentWindows.Common
private Timer restoreTimer; private Timer restoreTimer;
private Timer restoreFinishedTimer; private Timer restoreFinishedTimer;
public bool restoringFromMem = false; // automatic restore from memory or snapshot public bool restoringFromMem = false; // automatic restore from memory or snapshot
private bool restoreSingleWindow = false;
public bool restoringFromDB = false; // manual restore from DB public bool restoringFromDB = false; // manual restore from DB
public bool autoInitialRestoreFromDB = false; public bool autoInitialRestoreFromDB = false;
public bool restoringSnapshot = false; // implies restoringFromMem public bool restoringSnapshot = false; // implies restoringFromMem
private bool restoringFullScreenWindow = false; private Object restoringFullScreenWindow = new object();
public bool showDesktop = false; // show desktop when display changes public bool showDesktop = false; // show desktop when display changes
public int fixZorder = 1; // 1 means restore z-order only for snapshot; 2 means restore z-order for all; 0 means no z-order restore at all public int fixZorder = 1; // 1 means restore z-order only for snapshot; 2 means restore z-order for all; 0 means no z-order restore at all
public int fixZorderMethod = 5; // bit i represent restore method for pass i public int fixZorderMethod = 5; // bit i represent restore method for pass i
@ -158,7 +161,7 @@ namespace PersistentWindows.Common
private static Dictionary<IntPtr, string> windowProcessName = new Dictionary<IntPtr, string>(); private static Dictionary<IntPtr, string> windowProcessName = new Dictionary<IntPtr, string>();
private Process process; private Process process;
private ProcessPriorityClass processPriority; public ProcessPriorityClass processPriority;
private string appDataFolder; private string appDataFolder;
public bool redirectAppDataFolder = false; public bool redirectAppDataFolder = false;
@ -480,6 +483,10 @@ namespace PersistentWindows.Common
} }
else if (fullScreenGamingWindow == IntPtr.Zero) else if (fullScreenGamingWindow == IntPtr.Zero)
{ {
//create window event may be delayed
if (hwnd != IntPtr.Zero && !noRestoreWindows.Contains(hwnd))
CaptureWindow(hwnd, 0, DateTime.Now, curDisplayKey);
StartCaptureTimer(); StartCaptureTimer();
//speed up initial capture //speed up initial capture
@ -515,12 +522,12 @@ namespace PersistentWindows.Common
if (!ctrl_key_pressed && !alt_key_pressed) if (!ctrl_key_pressed && !alt_key_pressed)
{ {
//restore window to previous background position //restore window to previous background position
SwitchForeBackground(hwnd, secondBackGround:shift_key_pressed); SwitchForeBackground(hwnd);
} }
else if (ctrl_key_pressed && !alt_key_pressed) else if (ctrl_key_pressed && !alt_key_pressed)
{ {
//restore to previous background zorder with current size/pos //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) else if (!ctrl_key_pressed && alt_key_pressed && !shift_key_pressed)
{ {
@ -591,8 +598,6 @@ namespace PersistentWindows.Common
public bool Start(bool auto_restore_from_db, bool auto_restore_last_capture_at_startup) public bool Start(bool auto_restore_from_db, bool auto_restore_last_capture_at_startup)
{ {
process = Process.GetCurrentProcess(); process = Process.GetCurrentProcess();
processPriority = process.PriorityClass;
string productName = System.Windows.Forms.Application.ProductName; string productName = System.Windows.Forms.Application.ProductName;
appDataFolder = redirectAppDataFolder ? "." : appDataFolder = redirectAppDataFolder ? "." :
Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), productName); Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), productName);
@ -766,8 +771,6 @@ namespace PersistentWindows.Common
Log.Event("Restore finished in pass {0} with {1} windows recovered for display setting {2}", restorePass, numWindowRestored, curDisplayKey); Log.Event("Restore finished in pass {0} with {1} windows recovered for display setting {2}", restorePass, numWindowRestored, curDisplayKey);
sessionActive = true; sessionActive = true;
WriteDataDump();
if (!wasRestoringSnapshot && !wasRestoringFromDB) if (!wasRestoringSnapshot && !wasRestoringFromDB)
{ {
if (!snapshotTakenTime.ContainsKey(curDisplayKey)) if (!snapshotTakenTime.ContainsKey(curDisplayKey))
@ -862,6 +865,7 @@ namespace PersistentWindows.Common
(s, e) => (s, e) =>
{ {
process.PriorityClass = ProcessPriorityClass.High; process.PriorityClass = ProcessPriorityClass.High;
EndDisplaySession();
WriteDataDump(); WriteDataDump();
Log.Event("Session ending"); Log.Event("Session ending");
}; };
@ -870,6 +874,9 @@ namespace PersistentWindows.Common
this.displaySettingsChangingHandler = this.displaySettingsChangingHandler =
(s, e) => (s, e) =>
{ {
if (fastRestore)
process.PriorityClass = ProcessPriorityClass.High;
if (!freezeCapture) if (!freezeCapture)
{ {
lastDisplayChangeTime = DateTime.Now; lastDisplayChangeTime = DateTime.Now;
@ -892,9 +899,6 @@ namespace PersistentWindows.Common
this.displaySettingsChangedHandler = this.displaySettingsChangedHandler =
(s, e) => (s, e) =>
{ {
if (fastRestore)
process.PriorityClass = ProcessPriorityClass.High;
string displayKey = GetDisplayKey(); string displayKey = GetDisplayKey();
Log.Event("Display settings changed {0}", displayKey); Log.Event("Display settings changed {0}", displayKey);
@ -1068,6 +1072,10 @@ namespace PersistentWindows.Common
normalSessions.Add(item); normalSessions.Add(item);
} }
var ticks = Kernel32.GetTickCount64();
if (ticks > 300000) //system up 5min
return true;
if (db_exist && auto_restore_from_db) if (db_exist && auto_restore_from_db)
{ {
restoringFromDB = true; restoringFromDB = true;
@ -1396,7 +1404,17 @@ namespace PersistentWindows.Common
if (!monitorApplications.ContainsKey(display_key)) if (!monitorApplications.ContainsKey(display_key))
monitorApplications[display_key] = new Dictionary<IntPtr, List<ApplicationDisplayMetrics>>(); monitorApplications[display_key] = new Dictionary<IntPtr, List<ApplicationDisplayMetrics>>();
List<ApplicationDisplayMetrics> app_list = null;
if (monitorApplications[display_key].ContainsKey(hwnd))
{
app_list = monitorApplications[display_key][hwnd];
monitorApplications[display_key].Remove(hwnd);
}
monitorApplications[display_key][hwnd] = deadApps[display_key][kid]; monitorApplications[display_key][hwnd] = deadApps[display_key][kid];
if (app_list != null)
{
monitorApplications[display_key][hwnd].AddRange(app_list);
}
deadApps[display_key].Remove(kid); deadApps[display_key].Remove(kid);
//replace prev zorder reference of dead_hwnd with hwnd in monitorApplication //replace prev zorder reference of dead_hwnd with hwnd in monitorApplication
@ -1427,6 +1445,18 @@ namespace PersistentWindows.Common
return r; return r;
} }
int LenCommonPrefix(string a, string b)
{
int len = Math.Min(a.Length, b.Length);
int r;
for (r = 0; r < len; ++r)
{
if (a[r] != b[r])
break;
}
return r;
}
private IntPtr FindMatchingKilledWindow(IntPtr hwnd) private IntPtr FindMatchingKilledWindow(IntPtr hwnd)
{ {
if (!deadApps.ContainsKey(curDisplayKey)) if (!deadApps.ContainsKey(curDisplayKey))
@ -1458,22 +1488,41 @@ namespace PersistentWindows.Common
if (!string.IsNullOrEmpty(className)) if (!string.IsNullOrEmpty(className))
{ {
IntPtr dflt_kid = IntPtr.Zero; int pos_match_cnt = 0;
int title_match_cnt = 0;
IntPtr title_match_hid = IntPtr.Zero;
IntPtr pos_match_hid = IntPtr.Zero; IntPtr pos_match_hid = IntPtr.Zero;
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;
long style = User32.GetWindowLong(hwnd, User32.GWL_STYLE);
long ext_style = User32.GetWindowLong(hwnd, User32.GWL_EXSTYLE);
var deadAppPos = deadApps[curDisplayKey]; var deadAppPos = deadApps[curDisplayKey];
lock(captureLock) lock(captureLock)
foreach (var kid in deadAppPos.Keys) foreach (var kid in deadAppPos.Keys)
{ {
var appPos = deadAppPos[kid].Last<ApplicationDisplayMetrics>(); var appPos = deadAppPos[kid].LastOrDefault<ApplicationDisplayMetrics>();
if (appPos == null)
if (!className.Equals(appPos.ClassName))
continue; continue;
if (!procName.Equals(appPos.ProcessName)) if (!procName.Equals(appPos.ProcessName))
continue; 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)
continue;
if (LenCommonPrefix(className, appPos.ClassName) < MinClassNamePrefix)
continue;
}
if (IsMinimized(hwnd) != appPos.IsMinimized) if (IsMinimized(hwnd) != appPos.IsMinimized)
continue; continue;
if (User32.IsWindowVisible(hwnd) == appPos.IsInvisible) if (User32.IsWindowVisible(hwnd) == appPos.IsInvisible)
@ -1486,26 +1535,76 @@ namespace PersistentWindows.Common
if (rect.Equals(r) && title.Equals(appPos.Title)) if (rect.Equals(r) && title.Equals(appPos.Title))
return kid; return kid;
if (title.Equals(appPos.Title)) if (rect.Equals(r))
{ {
if (title_match_cnt == 0) pos_match_cnt++;
title_match_hid = kid;
++title_match_cnt;
}
else if (rect.Equals(r))
pos_match_hid = kid; pos_match_hid = kid;
else if (dflt_kid == IntPtr.Zero) }
dflt_kid = kid;
if (r.Diff(rect) < diff_size)
{
diff_size = r.Diff(rect);
similar_pos_cnt++;
similar_pos_hid = kid;
}
if (appPos.CaptureTime > last_killed_time)
{
last_killed_time = appPos.CaptureTime;
last_killed_hid = kid;
}
} }
if (title_match_cnt == 1) if (pos_match_cnt == 1)
return title_match_hid;
if (pos_match_hid != IntPtr.Zero)
return pos_match_hid; return pos_match_hid;
if (dflt_kid != IntPtr.Zero) if (diff_size <= MaxDiffPos)
return dflt_kid; {
Log.Event($"matching window with position diff of {diff_size}");
return similar_pos_hid;
}
if (!monitorApplications.ContainsKey(curDisplayKey))
return IntPtr.Zero;
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])
{
if (IsMinimized(hwnd) != dm.IsMinimized)
continue;
if (User32.IsWindowVisible(hwnd) == dm.IsInvisible)
continue;
if (dm.ProcessName == procName)
{
proc_name_match_cnt++;
if (dm.ClassName == className)
class_name_match_cnt++;
else
class_name_mismatch_cnt++;
}
break;
}
}
//force match last killed pos if hwnd is the first live window of the app
if (proc_name_match_cnt == 0)
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; return IntPtr.Zero;
@ -1686,6 +1785,7 @@ namespace PersistentWindows.Common
//restore fullscreen window only applies if screen resolution has changed since minimize/normalize //restore fullscreen window only applies if screen resolution has changed since minimize/normalize
if (prevDisplayMetrics.CaptureTime < lastDisplayChangeTime) if (prevDisplayMetrics.CaptureTime < lastDisplayChangeTime)
lock(restoringFullScreenWindow)
RestoreFullScreenWindow(hwnd, target_rect); RestoreFullScreenWindow(hwnd, target_rect);
return; return;
} }
@ -1832,6 +1932,13 @@ namespace PersistentWindows.Common
if (!initialized) if (!initialized)
return; return;
if (hwnd == IntPtr.Zero)
return;
if (idObject != 0)
// ignore non-window object (caret etc)
return;
{ {
switch (eventType) switch (eventType)
{ {
@ -1853,12 +1960,6 @@ namespace PersistentWindows.Common
if (eventType == User32Events.EVENT_OBJECT_DESTROY) if (eventType == User32Events.EVENT_OBJECT_DESTROY)
{ {
if (idObject != 0)
{
// ignore non-window object (caret etc)
return;
}
noRestoreWindows.Remove(hwnd); noRestoreWindows.Remove(hwnd);
debugWindows.Remove(hwnd); debugWindows.Remove(hwnd);
if (fullScreenGamingWindows.Contains(hwnd)) if (fullScreenGamingWindows.Contains(hwnd))
@ -1888,7 +1989,9 @@ namespace PersistentWindows.Common
} }
// for matching new window with killed one // 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]; deadApps[display_config][hwnd] = monitorApplications[display_config][hwnd];
@ -1944,6 +2047,9 @@ namespace PersistentWindows.Common
return; return;
} }
if (!CaptureProcessName(hwnd))
return;
if (ignoreProcess.Count > 0) if (ignoreProcess.Count > 0)
{ {
string processName = windowProcessName[hwnd]; string processName = windowProcessName[hwnd];
@ -1951,9 +2057,6 @@ namespace PersistentWindows.Common
return; return;
} }
if (!CaptureProcessName(hwnd))
return;
#if DEBUG #if DEBUG
if (title.Contains("Microsoft Visual Studio") if (title.Contains("Microsoft Visual Studio")
&& (eventType == User32Events.EVENT_OBJECT_LOCATIONCHANGE && (eventType == User32Events.EVENT_OBJECT_LOCATIONCHANGE
@ -2015,7 +2118,7 @@ namespace PersistentWindows.Common
if (eventType == User32Events.EVENT_OBJECT_LOCATIONCHANGE) 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 // restore is not finished as long as window location keeps changing
CancelRestoreFinishedTimer(); CancelRestoreFinishedTimer();
@ -2029,22 +2132,14 @@ namespace PersistentWindows.Common
{ {
case User32Events.EVENT_OBJECT_CREATE: case User32Events.EVENT_OBJECT_CREATE:
{ {
if (idObject != 0)
// ignore non-window object (caret etc)
return;
if (restoringFromDB) if (restoringFromDB)
return; return;
if (freezeCapture || !monitorApplications.ContainsKey(curDisplayKey)) if (freezeCapture || !monitorApplications.ContainsKey(curDisplayKey))
return; return;
//try to inherit from killed window database userMove = true;
if (FindMatchingKilledWindow(hwnd) != IntPtr.Zero) StartCaptureTimer(UserMoveLatency / 4);
{
userMove = true;
StartCaptureTimer(UserMoveLatency / 2);
}
} }
break; break;
@ -2099,6 +2194,9 @@ namespace PersistentWindows.Common
if (fullScreenGamingWindow != IntPtr.Zero) if (fullScreenGamingWindow != IntPtr.Zero)
return; return;
if (User32.IsZoomed(hwnd))
userMove = true;
if (foreGroundWindow == hwnd) if (foreGroundWindow == hwnd)
{ {
StartCaptureTimer(UserMoveLatency); StartCaptureTimer(UserMoveLatency);
@ -2113,6 +2211,12 @@ namespace PersistentWindows.Common
break; break;
case User32Events.EVENT_SYSTEM_MOVESIZESTART: case User32Events.EVENT_SYSTEM_MOVESIZESTART:
if (freezeCapture)
{
Log.Event($"recognize {curDisplayKey} as user session");
freezeCapture = false; //unlock unknown display session as normal
}
if ((User32.GetKeyState(0x11) & 0x8000) != 0 //ctrl key pressed if ((User32.GetKeyState(0x11) & 0x8000) != 0 //ctrl key pressed
&& (User32.GetKeyState(0x10) & 0x8000) != 0) //shift key pressed && (User32.GetKeyState(0x10) & 0x8000) != 0) //shift key pressed
{ {
@ -2126,6 +2230,12 @@ namespace PersistentWindows.Common
lastUnminimizeWindow = hwnd; lastUnminimizeWindow = hwnd;
tidyTabWindows.Remove(hwnd); //no longer hidden by tidytab tidyTabWindows.Remove(hwnd); //no longer hidden by tidytab
if (freezeCapture)
{
Log.Event($"recognize {curDisplayKey} as user session");
freezeCapture = false; //unlock unknown display session as normal
}
if (monitorApplications.ContainsKey(curDisplayKey) && monitorApplications[curDisplayKey].ContainsKey(hwnd)) if (monitorApplications.ContainsKey(curDisplayKey) && monitorApplications[curDisplayKey].ContainsKey(hwnd))
{ {
//treat unminimized window as foreground //treat unminimized window as foreground
@ -2154,6 +2264,14 @@ namespace PersistentWindows.Common
if (enableMinimizeToTray) if (enableMinimizeToTray)
MinimizeToTray.Create(hwnd); MinimizeToTray.Create(hwnd);
/*
if (freezeCapture)
{
Log.Event($"recognize {curDisplayKey} as user session");
freezeCapture = false; //unlock unknown display session as normal
}
*/
goto case User32Events.EVENT_SYSTEM_MOVESIZEEND; goto case User32Events.EVENT_SYSTEM_MOVESIZEEND;
case User32Events.EVENT_SYSTEM_MOVESIZEEND: case User32Events.EVENT_SYSTEM_MOVESIZEEND:
if (eventType == User32Events.EVENT_SYSTEM_MOVESIZEEND) if (eventType == User32Events.EVENT_SYSTEM_MOVESIZEEND)
@ -2187,15 +2305,37 @@ namespace PersistentWindows.Common
private void TrimQueue(string displayKey, IntPtr hwnd) private void TrimQueue(string displayKey, IntPtr hwnd)
{ {
if (monitorApplications[displayKey][hwnd].Count > MaxHistoryQueueLength)
{
// limit length of snapshot capture history
ulong acc_flags = 0;
for (int i = monitorApplications[displayKey][hwnd].Count - 1; i >= 0; --i)
{
ulong snapshot_flags = monitorApplications[displayKey][hwnd][i].SnapShotFlags;
if (snapshot_flags != 0)
{
if ((snapshot_flags | acc_flags) == acc_flags)
{
Log.Event($"trim redundant snapshot record for {windowTitle[hwnd]}");
monitorApplications[displayKey][hwnd].RemoveAt(i);
}
acc_flags |= snapshot_flags;
}
}
}
while (monitorApplications[displayKey][hwnd].Count > MaxHistoryQueueLength) while (monitorApplications[displayKey][hwnd].Count > MaxHistoryQueueLength)
{ {
// limit length of capture history // limit length of non-snapshot capture history
for (int i = 0; i < monitorApplications[displayKey][hwnd].Count; ++i) for (int i = 0; i < monitorApplications[displayKey][hwnd].Count; ++i)
{ {
if (monitorApplications[displayKey][hwnd][i].SnapShotFlags != 0) ulong snapshot_flags = monitorApplications[displayKey][hwnd][i].SnapShotFlags;
continue; //preserve snapshot record if (snapshot_flags != 0)
continue;
Log.Trace($"trim regular record for {windowTitle[hwnd]}");
monitorApplications[displayKey][hwnd].RemoveAt(i); monitorApplications[displayKey][hwnd].RemoveAt(i);
break; //remove one record at one time break; //remove one record in each iteration
} }
} }
} }
@ -2475,7 +2615,7 @@ namespace PersistentWindows.Common
Log.Event("Bring foreground window {0} to bottom", GetWindowTitle(hwnd)); 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)) if (hwnd == IntPtr.Zero || IsTaskBar(hwnd))
return; return;
@ -2500,8 +2640,6 @@ namespace PersistentWindows.Common
if (toForeground && IsTaskBar(front_hwnd)) if (toForeground && IsTaskBar(front_hwnd))
return; //already foreground return; //already foreground
IntPtr firstBackgroundWindow = IntPtr.Zero;
for (; prevIndex >= 0; --prevIndex) for (; prevIndex >= 0; --prevIndex)
{ {
var metrics = monitorApplications[curDisplayKey][hwnd][prevIndex]; var metrics = monitorApplications[curDisplayKey][hwnd][prevIndex];
@ -2510,8 +2648,16 @@ namespace PersistentWindows.Common
continue; continue;
} }
if (!toForeground)
{
RECT screenPosition = new RECT();
User32.GetWindowRect(hwnd, ref screenPosition);
if (screenPosition.Equals(metrics.ScreenPosition))
continue;
}
IntPtr prevZwnd = metrics.PrevZorderWindow; IntPtr prevZwnd = metrics.PrevZorderWindow;
if (prevZwnd != front_hwnd && (prevZwnd == IntPtr.Zero || prevZwnd != firstBackgroundWindow)) if (prevZwnd != front_hwnd)
{ {
if (toForeground) if (toForeground)
{ {
@ -2520,12 +2666,6 @@ namespace PersistentWindows.Common
} }
else else
{ {
if (secondBackGround)
{
firstBackgroundWindow = prevZwnd;
secondBackGround = false;
continue;
}
if (IsTaskBar(front_hwnd) && IsTaskBar(prevZwnd)) if (IsTaskBar(front_hwnd) && IsTaskBar(prevZwnd))
return; //#266, ignore taskbar (as prev-zwindow) change due to window maximize return; //#266, ignore taskbar (as prev-zwindow) change due to window maximize
@ -2601,35 +2741,45 @@ namespace PersistentWindows.Common
ApplicationDisplayMetrics prevDisplayMetrics; ApplicationDisplayMetrics prevDisplayMetrics;
if (IsWindowMoved(displayKey, hWnd, eventType, now, out curDisplayMetrics, out prevDisplayMetrics)) if (IsWindowMoved(displayKey, hWnd, eventType, now, out curDisplayMetrics, out prevDisplayMetrics))
{ {
if (debugWindows.Contains(hWnd))
{
string log = string.Format("Captured {0,-8} at {1} '{2}' fullscreen:{3} minimized:{4}",
curDisplayMetrics,
curDisplayMetrics.ScreenPosition.ToString(),
curDisplayMetrics.Title,
curDisplayMetrics.IsFullScreen,
curDisplayMetrics.IsMinimized
);
Log.Event(log);
string log2 = string.Format(" WindowPlacement.NormalPosition at {0}",
curDisplayMetrics.WindowPlacement.NormalPosition.ToString());
Log.Event(log2);
}
bool new_window = !monitorApplications[displayKey].ContainsKey(hWnd); bool new_window = !monitorApplications[displayKey].ContainsKey(hWnd);
if (eventType != 0 || new_window) if (eventType != 0 || new_window)
curDisplayMetrics.IsValid = true; curDisplayMetrics.IsValid = true;
if (new_window) if (new_window)
{ {
monitorApplications[displayKey].Add(hWnd, new List<ApplicationDisplayMetrics>()); //if (windowProcessName[hWnd] == "mstsc" && curDisplayMetrics.IsMinimized && curDisplayMetrics.IsInvisible && !curDisplayMetrics.IsFullScreen)
if (curDisplayMetrics.IsMinimized && curDisplayMetrics.IsInvisible && !curDisplayMetrics.IsFullScreen)
return false; //postpone capture till window is visible
IntPtr kid = FindMatchingKilledWindow(hWnd);
TryInheritWindow(hWnd, curDisplayMetrics.HWnd, kid, curDisplayMetrics);
if (kid == IntPtr.Zero)
monitorApplications[displayKey].Add(hWnd, new List<ApplicationDisplayMetrics>());
} }
else else
{ {
TrimQueue(displayKey, hWnd); TrimQueue(displayKey, hWnd);
} }
if (debugWindows.Contains(hWnd))
{
string log = string.Format("Captured {0} '{1}' fullscreen:{2} minimized:{3} visible:{4} at {5} {6, -8}",
curDisplayMetrics.HWnd.ToString("X"),
curDisplayMetrics.Title,
curDisplayMetrics.IsFullScreen,
curDisplayMetrics.IsMinimized,
!curDisplayMetrics.IsInvisible,
curDisplayMetrics.ScreenPosition.ToString(),
curDisplayMetrics
);
Log.Event(log);
string log2 = string.Format(" WindowPlacement.NormalPosition at {0}",
curDisplayMetrics.WindowPlacement.NormalPosition.ToString());
Log.Event(log2);
}
monitorApplications[displayKey][hWnd].Add(curDisplayMetrics); monitorApplications[displayKey][hWnd].Add(curDisplayMetrics);
ret = true; ret = true;
} }
@ -3044,6 +3194,46 @@ namespace PersistentWindows.Common
return true; return true;
} }
private bool TryInheritWindow(IntPtr hwnd, IntPtr realHwnd, IntPtr kid, ApplicationDisplayMetrics curDisplayMetrics)
{
if (kid == IntPtr.Zero)
{
ResolveWindowHandleCollision(hwnd);
}
else
{
var prevDisplayMetrics = InheritKilledWindow(hwnd, realHwnd, kid);
if (hwnd != kid)
{
if (prevDisplayMetrics.Title != curDisplayMetrics.Title)
Log.Error($"{hwnd.ToString("X")} Inherit position data from killed window {prevDisplayMetrics.Title} with different title {curDisplayMetrics.Title} {prevDisplayMetrics.HWnd.ToString("X")}");
else
Log.Error($"{hwnd.ToString("X")} Inherit position data from killed window {prevDisplayMetrics.Title} {prevDisplayMetrics.HWnd.ToString("X")}");
ResolveWindowHandleCollision(hwnd);
}
else
Log.Error($"{hwnd.ToString("X")} Inherit position data from existing window 0x{kid.ToString("X")} for {curDisplayMetrics.Title}");
if (initialized && autoRestoreNewWindowToLastCapture)
{
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);
}
}
return true;
}
return false;
}
private bool IsWindowMoved(string displayKey, IntPtr hwnd, User32Events eventType, DateTime time, private bool IsWindowMoved(string displayKey, IntPtr hwnd, User32Events eventType, DateTime time,
out ApplicationDisplayMetrics curDisplayMetrics, out ApplicationDisplayMetrics prevDisplayMetrics) out ApplicationDisplayMetrics curDisplayMetrics, out ApplicationDisplayMetrics prevDisplayMetrics)
{ {
@ -3123,6 +3313,9 @@ namespace PersistentWindows.Common
NeedUpdateWindowPlacement = false, NeedUpdateWindowPlacement = false,
ScreenPosition = screenPosition, ScreenPosition = screenPosition,
Style = User32.GetWindowLong(hwnd, User32.GWL_STYLE),
ExtStyle = User32.GetWindowLong(hwnd, User32.GWL_EXSTYLE),
IsTopMost = IsWindowTopMost(hwnd), IsTopMost = IsWindowTopMost(hwnd),
NeedClearTopMost = false, NeedClearTopMost = false,
@ -3139,27 +3332,6 @@ namespace PersistentWindows.Common
if (noRestoreWindows.Contains(hwnd)) if (noRestoreWindows.Contains(hwnd))
return false; return false;
IntPtr kid = FindMatchingKilledWindow(hwnd);
bool restore_last = false;
if (kid == IntPtr.Zero)
{
ResolveWindowHandleCollision(hwnd);
}
else
{
prevDisplayMetrics = InheritKilledWindow(hwnd, realHwnd, kid);
if (hwnd != kid)
{
Log.Error($"Inherit position data from killed window 0x{kid.ToString("X")} for {curDisplayMetrics.Title}");
ResolveWindowHandleCollision(hwnd);
}
else
Log.Error($"Inherit position data from existing window 0x{kid.ToString("X")} for {curDisplayMetrics.Title}");
if (initialized && autoRestoreNewWindowToLastCapture)
restore_last = true;
}
//newly created window or new display setting //newly created window or new display setting
curDisplayMetrics.WindowId = (uint)realHwnd; curDisplayMetrics.WindowId = (uint)realHwnd;
@ -3181,18 +3353,7 @@ namespace PersistentWindows.Common
if (curDisplayMetrics.IsMinimized && prevDisplayMetrics != null && prevDisplayMetrics.IsMinimized) if (curDisplayMetrics.IsMinimized && prevDisplayMetrics != null && prevDisplayMetrics.IsMinimized)
moved = false; moved = false;
else else
{
moved = true; moved = true;
if (restore_last && prevDisplayMetrics != null && !restoringFromDB && IsResizableWindow(hwnd))
{
Log.Trace($"restore {windowTitle[hwnd]} to last captured position");
restoringFromMem = true;
RestoreApplicationsOnCurrentDisplays(curDisplayKey, hwnd, prevDisplayMetrics.CaptureTime);
restoringFromMem = false;
return false;
}
}
} }
else if (!monitorApplications[displayKey].ContainsKey(hwnd)) else if (!monitorApplications[displayKey].ContainsKey(hwnd))
{ {
@ -3507,11 +3668,6 @@ namespace PersistentWindows.Common
*/ */
} }
if (restoringFullScreenWindow)
return;
restoringFullScreenWindow = true;
bool wrong_screen = false; bool wrong_screen = false;
RECT cur_rect = new RECT(); RECT cur_rect = new RECT();
User32.GetWindowRect(hwnd, ref cur_rect); User32.GetWindowRect(hwnd, ref cur_rect);
@ -3544,10 +3700,9 @@ namespace PersistentWindows.Common
0, 0, 0, UIntPtr.Zero); 0, 0, 0, UIntPtr.Zero);
Log.Error("restore full screen window {0}", GetWindowTitle(hwnd)); Log.Error("restore full screen window {0}", GetWindowTitle(hwnd));
/*
Thread.Sleep(3 * double_clck_interval); Thread.Sleep(3 * double_clck_interval);
restoringFullScreenWindow = false;
style = User32.GetWindowLong(hwnd, User32.GWL_STYLE); style = User32.GetWindowLong(hwnd, User32.GWL_STYLE);
if ((style & (long)WindowStyleFlags.CAPTION) == 0L) if ((style & (long)WindowStyleFlags.CAPTION) == 0L)
{ {
@ -3570,6 +3725,7 @@ namespace PersistentWindows.Common
} }
Log.Error("fail to restore full screen window {0}", GetWindowTitle(hwnd)); Log.Error("fail to restore full screen window {0}", GetWindowTitle(hwnd));
*/
} }
private void RestoreSnapWindow(IntPtr hwnd, RECT target_pos) private void RestoreSnapWindow(IntPtr hwnd, RECT target_pos)
@ -4318,6 +4474,7 @@ namespace PersistentWindows.Common
if (restore_fullscreen) if (restore_fullscreen)
{ {
if (restoreTimes > 0 && sWindow == null) //#246, let other windows restore first if (restoreTimes > 0 && sWindow == null) //#246, let other windows restore first
lock(restoringFullScreenWindow)
RestoreFullScreenWindow(hWnd, rect); RestoreFullScreenWindow(hWnd, rect);
} }
else if (restoreTimes >= MinRestoreTimes - 1) else if (restoreTimes >= MinRestoreTimes - 1)

View file

@ -624,6 +624,9 @@ namespace PersistentWindows.Common.WinApiBridge
[DllImport("kernel32.dll", SetLastError = true)] [DllImport("kernel32.dll", SetLastError = true)]
public static extern bool CloseHandle(IntPtr hHandle); public static extern bool CloseHandle(IntPtr hHandle);
[DllImport("kernel32")]
public static extern UInt64 GetTickCount64();
[DllImport("kernel32.dll", SetLastError = true)] [DllImport("kernel32.dll", SetLastError = true)]
public static extern IntPtr OpenProcess( public static extern IntPtr OpenProcess(
ProcessAccessFlags processAccess, ProcessAccessFlags processAccess,

View file

@ -61,5 +61,11 @@ namespace PersistentWindows.Common.WinApiBridge
{ {
return string.Format("({0}, {1}), {2} x {3}", Left, Top, Width, Height); return string.Format("({0}, {1}), {2} x {3}", Left, Top, Width, Height);
} }
public int Diff(RECT r)
{
int diff = Math.Abs(Left - r.Left) + Math.Abs(Right - r.Right) + Math.Abs(Top - r.Top) + Math.Abs(Bottom - r.Bottom);
return diff / 4;
}
} }
} }

View file

@ -56,6 +56,15 @@ if not errorlevel 1 goto wait_to_finish";
pwp = new PersistentWindowProcessor(); 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; bool splash = true;
int delay_restart = 0; int delay_restart = 0;
int relaunch_delay = 0; int relaunch_delay = 0;
@ -74,9 +83,10 @@ if not errorlevel 1 goto wait_to_finish";
bool offscreen_fix = true; bool offscreen_fix = true;
bool fix_unminimized_window = true; bool fix_unminimized_window = true;
bool enhanced_offscreen_fix = false; bool enhanced_offscreen_fix = false;
bool set_pos_match_threshold = false;
bool auto_restore_missing_windows = false; bool auto_restore_missing_windows = false;
bool auto_restore_from_db_at_startup = false; bool auto_restore_from_db_at_startup = false;
bool auto_restore_last_capture_at_startup = true; bool auto_restore_last_capture_at_startup = false;
bool launch_once_per_process_id = true; bool launch_once_per_process_id = true;
bool check_upgrade = true; bool check_upgrade = true;
bool auto_upgrade = false; bool auto_upgrade = false;
@ -143,6 +153,12 @@ if not errorlevel 1 goto wait_to_finish";
restore_snapshot = SnapshotCharToId(arg[0]); restore_snapshot = SnapshotCharToId(arg[0]);
continue; continue;
} }
else if (set_pos_match_threshold)
{
set_pos_match_threshold = false;
pwp.MaxDiffPos = int.Parse(arg);
continue;
}
switch(arg) switch(arg)
{ {
@ -260,12 +276,15 @@ if not errorlevel 1 goto wait_to_finish";
case "-redraw_desktop": case "-redraw_desktop":
redraw_desktop = true; redraw_desktop = true;
break; break;
case "-auto_restore_existing_window_to_last_capture=0": case "-auto_restore_existing_window_to_last_capture=1":
auto_restore_last_capture_at_startup = false; auto_restore_last_capture_at_startup = true;
break; break;
case "-auto_restore_new_window_to_last_capture=0": case "-auto_restore_new_window_to_last_capture=0":
pwp.autoRestoreNewWindowToLastCapture = false; pwp.autoRestoreNewWindowToLastCapture = false;
break; break;
case "-pos_match_threshold":
set_pos_match_threshold = true;
break;
case "-auto_restore_missing_windows": case "-auto_restore_missing_windows":
case "-auto_restore_missing_windows=1": case "-auto_restore_missing_windows=1":
auto_restore_missing_windows = true; auto_restore_missing_windows = true;

View file

@ -31,5 +31,5 @@ using System.Runtime.InteropServices;
// You can specify all the values or you can default the Build and Revision Numbers // You can specify all the values or you can default the Build and Revision Numbers
// by using the '*' as shown below: // by using the '*' as shown below:
// [assembly: AssemblyVersion("1.0.*")] // [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("5.61.*")] [assembly: AssemblyVersion("5.65.*")]

View file

@ -252,7 +252,16 @@ namespace PersistentWindows.SystrayShell
if (!upgradeDownloaded.ContainsKey(latestVersion)) 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 src_file = $"{Program.ProjectUrl}/releases/download/{latestVersion}/{System.Windows.Forms.Application.ProductName}{latestVersion}.zip";
var dst_file = $"{Program.AppdataFolder}/upgrade.zip"; var dst_file = $"{Program.AppdataFolder}/upgrade.zip";