mirror of
https://github.com/kangyu-california/PersistentWindows.git
synced 2025-05-11 04:55:39 +02:00
Compare commits
53 commits
Author | SHA1 | Date | |
---|---|---|---|
|
ae8da16834 | ||
|
6745982d60 | ||
|
cd29b29282 | ||
|
3a473bdc10 | ||
|
3d2ed7395c | ||
|
3884c4446f | ||
|
11d0c30ddb | ||
|
f7eb0abe43 | ||
|
cad1ec393f | ||
|
4df563f1bb | ||
|
e8f06c1368 | ||
|
2c06fe1684 | ||
|
9e85ee5810 | ||
|
4998a104ea | ||
|
1fd82f35c8 | ||
|
e7b141e095 | ||
|
304c654e80 | ||
|
9661f8bd79 | ||
|
5d26d86e28 | ||
|
f05d569387 | ||
|
f66dc3afd8 | ||
|
5f666b20d1 | ||
|
2d695d11bf | ||
|
8da7d9b4bc | ||
|
f7a1f92343 | ||
|
8771c2edd7 | ||
|
f34fffa574 | ||
|
cce0f7f52d | ||
|
8c5d6475ad | ||
|
052cb05f53 | ||
|
40f8f5cefd | ||
|
7dc0cbee82 | ||
|
1a5d9442d2 | ||
|
d36bf0c56c | ||
|
9224d62191 | ||
|
e41caba220 | ||
|
769f35b681 | ||
|
2ba0a5395b | ||
|
e4be317e77 | ||
|
fb5f538b88 | ||
|
3b5813bb35 | ||
|
de1b815d57 | ||
|
62452f3e0b | ||
|
0adf762fa0 | ||
|
05a740a21f | ||
|
4330c95216 | ||
|
23b63d09ea | ||
|
6097ab4bc7 | ||
|
aacaefc205 | ||
|
557a3bbddb | ||
|
189611ad3a | ||
|
86926ffd27 | ||
|
10dd03498a |
9 changed files with 339 additions and 130 deletions
4
Help.md
4
Help.md
|
@ -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:
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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; }
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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.*")]
|
||||||
|
|
||||||
|
|
|
@ -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";
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue