mirror of
https://github.com/kangyu-california/PersistentWindows.git
synced 2025-05-11 04:55:39 +02:00
feature-enhancment from #321, automatically inherit data from killed window
This commit is contained in:
parent
e5f7371829
commit
42a6165603
3 changed files with 99 additions and 61 deletions
|
@ -5,14 +5,6 @@ using PersistentWindows.Common.Diagnostics;
|
||||||
|
|
||||||
namespace PersistentWindows.Common.Models
|
namespace PersistentWindows.Common.Models
|
||||||
{
|
{
|
||||||
public class DeadAppPosition
|
|
||||||
{
|
|
||||||
public string ClassName { get; set; }
|
|
||||||
public string Title { get; set; }
|
|
||||||
public string ProcessPath { get; set; }
|
|
||||||
public RECT ScreenPosition { get; set; }
|
|
||||||
}
|
|
||||||
|
|
||||||
public class ApplicationDisplayMetrics
|
public class ApplicationDisplayMetrics
|
||||||
{
|
{
|
||||||
// for LiteDB use only
|
// for LiteDB use only
|
||||||
|
|
|
@ -43,10 +43,12 @@ namespace PersistentWindows.Common
|
||||||
|
|
||||||
// window position database
|
// window position database
|
||||||
private Dictionary<string, Dictionary<IntPtr, List<ApplicationDisplayMetrics>>> monitorApplications
|
private Dictionary<string, Dictionary<IntPtr, List<ApplicationDisplayMetrics>>> monitorApplications
|
||||||
= new Dictionary<string, Dictionary<IntPtr, List<ApplicationDisplayMetrics>>>(); //in-memory database
|
= new Dictionary<string, Dictionary<IntPtr, List<ApplicationDisplayMetrics>>>(); //in-memory database of live windows
|
||||||
|
private Dictionary<string, Dictionary<Int64, List<ApplicationDisplayMetrics>>> deadApps
|
||||||
|
= new Dictionary<string, Dictionary<Int64, List<ApplicationDisplayMetrics>>>(); //database of killed windows
|
||||||
|
private Int64 lastKilledWindowId = 0; //monotonically increasing unique id for every killed window
|
||||||
private string persistDbName = null; //on-disk database name
|
private string persistDbName = null; //on-disk database name
|
||||||
private Dictionary<string, POINT> lastCursorPos = new Dictionary<string, POINT>();
|
private Dictionary<string, POINT> lastCursorPos = new Dictionary<string, POINT>();
|
||||||
private Dictionary<string, List<DeadAppPosition>> deadApps = new Dictionary<string, List<DeadAppPosition>>();
|
|
||||||
private HashSet<IntPtr> allUserMoveWindows = new HashSet<IntPtr>();
|
private HashSet<IntPtr> allUserMoveWindows = new HashSet<IntPtr>();
|
||||||
private HashSet<IntPtr> unResponsiveWindows = new HashSet<IntPtr>();
|
private HashSet<IntPtr> unResponsiveWindows = new HashSet<IntPtr>();
|
||||||
private HashSet<IntPtr> noRecordWindows = new HashSet<IntPtr>();
|
private HashSet<IntPtr> noRecordWindows = new HashSet<IntPtr>();
|
||||||
|
@ -1012,42 +1014,82 @@ namespace PersistentWindows.Common
|
||||||
User32.MoveWindow(hwnd, target_rect.Left + target_rect.Width / 4, target_rect.Top + target_rect.Height / 4, target_rect.Width / 2, target_rect.Height / 2, true);
|
User32.MoveWindow(hwnd, target_rect.Left + target_rect.Width / 4, target_rect.Top + target_rect.Height / 4, target_rect.Width / 2, target_rect.Height / 2, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool RecallLastKilledPosition(IntPtr hwnd)
|
public bool RecallLastPositionKilledWindow(IntPtr hwnd)
|
||||||
{
|
{
|
||||||
if (deadApps.ContainsKey(curDisplayKey))
|
Int64 kid = FindMatchingKilledWindow(hwnd);
|
||||||
|
if (kid < 0)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
var d = deadApps[curDisplayKey][kid].Last<ApplicationDisplayMetrics>();
|
||||||
|
var r = d.ScreenPosition;
|
||||||
|
|
||||||
|
User32.MoveWindow(hwnd, r.Left, r.Top, r.Width, r.Height, true);
|
||||||
|
User32.SetForegroundWindow(hwnd);
|
||||||
|
Log.Error("Recover last closing location \"{0}\"", GetWindowTitle(hwnd));
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void RecallLastPosition(IntPtr hwnd)
|
||||||
|
{
|
||||||
|
int cnt = monitorApplications[curDisplayKey][hwnd].Count;
|
||||||
|
if (cnt < 2)
|
||||||
|
return;
|
||||||
|
var d = monitorApplications[curDisplayKey][hwnd][cnt - 1];
|
||||||
|
var r = d.ScreenPosition;
|
||||||
|
User32.MoveWindow(hwnd, r.Left, r.Top, r.Width, r.Height, true);
|
||||||
|
User32.SetForegroundWindow(hwnd);
|
||||||
|
Log.Error("Restore last location \"{0}\"", GetWindowTitle(hwnd));
|
||||||
|
}
|
||||||
|
|
||||||
|
private void InheritKilledWindow(IntPtr hwnd, Int64 kid)
|
||||||
|
{
|
||||||
|
foreach (var display_key in deadApps.Keys)
|
||||||
{
|
{
|
||||||
var deadAppPos = deadApps[curDisplayKey];
|
if (deadApps[display_key].ContainsKey(kid))
|
||||||
string className = GetWindowClassName(hwnd);
|
|
||||||
if (!string.IsNullOrEmpty(className))
|
|
||||||
{
|
{
|
||||||
uint processId = 0;
|
if (!monitorApplications.ContainsKey(display_key))
|
||||||
uint threadId = User32.GetWindowThreadProcessId(hwnd, out processId);
|
monitorApplications[display_key] = new Dictionary<IntPtr, List<ApplicationDisplayMetrics>>();
|
||||||
string procPath = GetProcExePath(processId);
|
monitorApplications[display_key][hwnd] = deadApps[display_key][kid];
|
||||||
string title = GetWindowTitle(hwnd);
|
deadApps[display_key].Remove(kid);
|
||||||
int idx = deadAppPos.Count;
|
}
|
||||||
foreach (var appPos in deadAppPos.Reverse<DeadAppPosition>())
|
}
|
||||||
{
|
}
|
||||||
--idx;
|
|
||||||
|
|
||||||
if (!className.Equals(appPos.ClassName))
|
private Int64 FindMatchingKilledWindow(IntPtr hwnd)
|
||||||
continue;
|
{
|
||||||
if (!title.Equals(appPos.Title))
|
if (!deadApps.ContainsKey(curDisplayKey))
|
||||||
continue;
|
return -1;
|
||||||
if (!procPath.Equals(appPos.ProcessPath))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
// found match
|
var deadAppPos = deadApps[curDisplayKey];
|
||||||
RECT r = appPos.ScreenPosition;
|
string className = GetWindowClassName(hwnd);
|
||||||
User32.MoveWindow(hwnd, r.Left, r.Top, r.Width, r.Height, true);
|
if (!string.IsNullOrEmpty(className))
|
||||||
User32.SetForegroundWindow(hwnd);
|
{
|
||||||
Log.Error("Recover last closing location\"{0}\"", GetWindowTitle(hwnd));
|
string procName = windowProcessName[hwnd];
|
||||||
//deadApps[curDisplayKey].RemoveAt(idx);
|
string title = GetWindowTitle(hwnd);
|
||||||
return true;
|
foreach (var kid in deadAppPos.Keys)
|
||||||
}
|
{
|
||||||
|
var appPos = deadAppPos[kid].Last<ApplicationDisplayMetrics>();
|
||||||
|
|
||||||
|
if (!className.Equals(appPos.ClassName))
|
||||||
|
continue;
|
||||||
|
if (!procName.Equals(appPos.ProcessName))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
// match position first
|
||||||
|
RECT r = appPos.ScreenPosition;
|
||||||
|
RECT rect = new RECT();
|
||||||
|
User32.GetWindowRect(hwnd, ref rect);
|
||||||
|
if (rect.Equals(r))
|
||||||
|
return kid;
|
||||||
|
|
||||||
|
// lastly match title
|
||||||
|
if (title.Equals(appPos.Title))
|
||||||
|
return kid;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void FixOffScreenWindow(IntPtr hwnd)
|
private void FixOffScreenWindow(IntPtr hwnd)
|
||||||
|
@ -1059,7 +1101,7 @@ namespace PersistentWindows.Common
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (RecallLastKilledPosition(hwnd))
|
if (RecallLastPositionKilledWindow(hwnd))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
RECT rect = new RECT();
|
RECT rect = new RECT();
|
||||||
|
@ -1374,51 +1416,51 @@ namespace PersistentWindows.Common
|
||||||
}
|
}
|
||||||
|
|
||||||
noRestoreWindows.Remove(hwnd);
|
noRestoreWindows.Remove(hwnd);
|
||||||
windowProcessName.Remove(hwnd);
|
|
||||||
debugWindows.Remove(hwnd);
|
debugWindows.Remove(hwnd);
|
||||||
if (fullScreenGamingWindows.Contains(hwnd))
|
if (fullScreenGamingWindows.Contains(hwnd))
|
||||||
{
|
{
|
||||||
fullScreenGamingWindows.Remove(hwnd);
|
fullScreenGamingWindows.Remove(hwnd);
|
||||||
exitFullScreenGaming = true;
|
exitFullScreenGaming = true;
|
||||||
}
|
}
|
||||||
windowTitle.Remove(hwnd);
|
|
||||||
dualPosSwitchWindows.Remove(hwnd);
|
dualPosSwitchWindows.Remove(hwnd);
|
||||||
|
|
||||||
foreach (var key in monitorApplications.Keys)
|
foreach (var display_config in monitorApplications.Keys)
|
||||||
{
|
{
|
||||||
if (!monitorApplications[key].ContainsKey(hwnd))
|
if (!monitorApplications[display_config].ContainsKey(hwnd))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (monitorApplications[key][hwnd].Count > 0)
|
if (monitorApplications[display_config][hwnd].Count > 0)
|
||||||
{
|
{
|
||||||
// save window size of closed app to restore off-screen window later
|
// save window size of closed app to restore off-screen window later
|
||||||
if (!deadApps.ContainsKey(key))
|
if (!deadApps.ContainsKey(display_config))
|
||||||
{
|
{
|
||||||
deadApps.Add(key, new List<DeadAppPosition>());
|
deadApps.Add(display_config, new Dictionary<Int64, List<ApplicationDisplayMetrics>>());
|
||||||
}
|
}
|
||||||
var appPos = new DeadAppPosition();
|
|
||||||
var lastMetric = monitorApplications[key][hwnd].Last();
|
|
||||||
appPos.ClassName = lastMetric.ClassName;
|
|
||||||
appPos.Title = lastMetric.Title;
|
|
||||||
appPos.ScreenPosition = lastMetric.ScreenPosition;
|
|
||||||
string procPath = GetProcExePath(lastMetric.ProcessId);
|
|
||||||
appPos.ProcessPath = procPath;
|
|
||||||
deadApps[key].Add(appPos);
|
|
||||||
|
|
||||||
windowTitle.Remove((IntPtr)lastMetric.WindowId);
|
// for matching new window with killed one
|
||||||
|
monitorApplications[display_config][hwnd].Last().ProcessName = windowProcessName[hwnd];
|
||||||
|
|
||||||
//limit list size
|
deadApps[display_config][lastKilledWindowId] = monitorApplications[display_config][hwnd];
|
||||||
while (deadApps[key].Count > 50)
|
|
||||||
|
windowTitle.Remove((IntPtr)monitorApplications[display_config][hwnd].Last().WindowId);
|
||||||
|
|
||||||
|
//limit deadApp size
|
||||||
|
foreach (var kid in deadApps[display_config].Keys)
|
||||||
{
|
{
|
||||||
deadApps[key].RemoveAt(0);
|
if (lastKilledWindowId - kid > 50)
|
||||||
|
deadApps[display_config].Remove(kid);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
monitorApplications[key].Remove(hwnd);
|
monitorApplications[display_config].Remove(hwnd);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool found = windowTitle.Remove(hwnd);
|
++lastKilledWindowId;
|
||||||
|
|
||||||
|
windowProcessName.Remove(hwnd);
|
||||||
|
|
||||||
|
bool found = windowTitle.Remove(hwnd);
|
||||||
if (sessionActive && found)
|
if (sessionActive && found)
|
||||||
{
|
{
|
||||||
StartCaptureTimer(); //update z-order
|
StartCaptureTimer(); //update z-order
|
||||||
|
@ -2572,6 +2614,10 @@ namespace PersistentWindows.Common
|
||||||
if (noRestoreWindows.Contains(hwnd))
|
if (noRestoreWindows.Contains(hwnd))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
Int64 kid = FindMatchingKilledWindow(hwnd);
|
||||||
|
if (kid >= 0)
|
||||||
|
InheritKilledWindow(hwnd, kid);
|
||||||
|
|
||||||
//newly created window or new display setting
|
//newly created window or new display setting
|
||||||
curDisplayMetrics.WindowId = (uint)realHwnd;
|
curDisplayMetrics.WindowId = (uint)realHwnd;
|
||||||
|
|
||||||
|
|
|
@ -655,7 +655,7 @@ namespace PersistentWindows.SystrayShell
|
||||||
|
|
||||||
static public void RecallLastKilledPosition()
|
static public void RecallLastKilledPosition()
|
||||||
{
|
{
|
||||||
pwp.RecallLastKilledPosition(PersistentWindowProcessor.GetForegroundWindow());
|
pwp.RecallLastPosition(PersistentWindowProcessor.GetForegroundWindow());
|
||||||
}
|
}
|
||||||
|
|
||||||
static public void CenterWindow()
|
static public void CenterWindow()
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue