private void RestoreApplicationsOnCurrentDisplays(string displayKey = null) { lock (displayChangeLock) { DesktopDisplayMetrics metrics = DesktopDisplayMetrics.AcquireMetrics(); if (displayKey == null) { displayKey = metrics.Key; } lastMetrics = DesktopDisplayMetrics.AcquireMetrics(); if (!monitorApplications.ContainsKey(displayKey)) { // no old profile, we're done Log.Info("No old profile found for {0}", displayKey); CaptureApplicationsOnCurrentDisplays(initialCapture: true); return; } Log.Info("Restoring applications for {0}", displayKey); foreach (var window in CaptureWindowsOfInterest()) { string applicationKey = string.Format("{0}-{1}", window.HWnd.ToInt64(), window.Process.ProcessName); if (monitorApplications[displayKey].ContainsKey(applicationKey)) { var app = monitorApplications[displayKey][applicationKey]; // looks like the window is still here for us to restore WindowPlacement windowPlacement = app.WindowPlacement; if (windowPlacement.ShowCmd == ShowWindowCommands.Maximize) { // When restoring maximized windows, it occasionally switches res and when the maximized setting is restored // the window thinks it's maxxed, but does not eat all the real estate. So we'll temporarily unmaximize then // re-apply that windowPlacement.ShowCmd = ShowWindowCommands.Normal; User32.SetWindowPlacement(app.HWnd, ref windowPlacement); windowPlacement.ShowCmd = ShowWindowCommands.Maximize; } int result = 0; var success = User32.SetWindowPlacement(app.HWnd, ref windowPlacement); if (!success) { string error = new Win32Exception(Marshal.GetLastWin32Error()).Message; Log.Error(error); } result = User32.SetWindowLong(app.HWnd, User32.GWL_EXSTYLE, app.ExtendedStyle); result = User32.SetWindowLong(app.HWnd, User32.GWL_STYLE, app.Style); Log.Info("SetWindowPlacement({0} [{1}x{2}]-[{3}x{4}]) - {5}", window.Process.ProcessName, windowPlacement.NormalPosition.Left, windowPlacement.NormalPosition.Top, windowPlacement.NormalPosition.Width, windowPlacement.NormalPosition.Height, success); } } } }
public void Start() { lastMetrics = DesktopDisplayMetrics.AcquireMetrics(); CaptureApplicationsOnCurrentDisplays(initialCapture: true); var thread = new Thread(InternalRun); thread.IsBackground = true; thread.Name = "PersistentWindowProcessor.InternalRun()"; thread.Start(); SystemEvents.DisplaySettingsChanged += (s, e) => { Log.Info("Display settings changed"); BeginRestoreApplicationsOnCurrentDisplays(); }; SystemEvents.PowerModeChanged += (s, e) => { switch (e.Mode) { case PowerModes.Suspend: Log.Info("System Suspending"); BeginCaptureApplicationsOnCurrentDisplays(); break; case PowerModes.Resume: Log.Info("System Resuming"); BeginRestoreApplicationsOnCurrentDisplays(); break; } }; }
private void CaptureApplicationsOnCurrentDisplays(string displayKey = null, bool initialCapture = false) { lock (displayChangeLock) { DesktopDisplayMetrics metrics = DesktopDisplayMetrics.AcquireMetrics(); if (displayKey == null) { displayKey = metrics.Key; } if (!metrics.Equals(lastMetrics)) { // since the resolution doesn't match, lets wait till it's restored Log.Info("Detected changes in display metrics, will capture once windows are restored"); return; } if (!monitorApplications.ContainsKey(displayKey)) { monitorApplications.Add(displayKey, new SortedDictionary <string, ApplicationDisplayMetrics>()); } var appWindows = CaptureWindowsOfInterest(); List <string> changeLog = new List <string>(); List <ApplicationDisplayMetrics> apps = new List <ApplicationDisplayMetrics>(); foreach (var window in appWindows) { ApplicationDisplayMetrics applicationDisplayMetric = null; bool addToChangeLog = AddOrUpdateWindow(displayKey, window, out applicationDisplayMetric); if (addToChangeLog) { apps.Add(applicationDisplayMetric); changeLog.Add(string.Format("CAOCD - Capturing {0,-45} at [{1,4}x{2,4}] size [{3,4}x{4,4}] V:{5} {6} ", applicationDisplayMetric, applicationDisplayMetric.WindowPlacement.NormalPosition.Left, applicationDisplayMetric.WindowPlacement.NormalPosition.Top, applicationDisplayMetric.WindowPlacement.NormalPosition.Width, applicationDisplayMetric.WindowPlacement.NormalPosition.Height, window.Visible, window.Title )); } } // only save the updated if it didn't seem like something moved everything if ((apps.Count > 0 && apps.Count < AppsMovedThreshold) || initialCapture) { foreach (var app in apps) { if (!monitorApplications[displayKey].ContainsKey(app.Key)) { monitorApplications[displayKey].Add(app.Key, app); } else if (!monitorApplications[displayKey][app.Key].EqualPlacement(app)) { monitorApplications[displayKey][app.Key].WindowPlacement = app.WindowPlacement; } } changeLog.Sort(); Log.Info("{0}Capturing applications for {1}", initialCapture ? "Initial " : "", displayKey); Log.Trace("{0} windows recorded{1}{2}", apps.Count, Environment.NewLine, string.Join(Environment.NewLine, changeLog)); } } }
private void RestoreApplicationsOnCurrentDisplays(string displayKey = null) { lock (displayChangeLock) { if (displayKey == null) { DesktopDisplayMetrics metrics = DesktopDisplayMetrics.AcquireMetrics(); displayKey = metrics.Key; } if (!monitorApplications.ContainsKey(displayKey) || monitorApplications[displayKey].Count == 0) { // the display setting has not been captured yet Log.Trace("Unknown display setting {0}", displayKey); return; } Log.Info("Restoring applications for {0}", displayKey); foreach (var window in WindowHelper.CaptureWindowsOfInterest()) { var procName = window.Process.ProcessName; if (procName.Contains("CodeSetup")) // SFA: What's this about??? seems almost too specific! { // prevent hang in SetWindowPlacement() continue; } var applicationKey = ApplicationDisplayMetrics.GetKey(window.HWnd, window.Process.ProcessName); var prevDisplayMetrics = monitorApplications[displayKey][applicationKey]; var windowPlacement = prevDisplayMetrics.WindowPlacement; if (monitorApplications[displayKey].ContainsKey(applicationKey)) { ApplicationDisplayMetrics curDisplayMetrics = null; if (!HasWindowChanged(displayKey, window, out curDisplayMetrics)) { continue; } // SetWindowPlacement will "place" the window on the correct screen based on its normal position. // If the state isn't "normal/restored" the window will appear not to actually move. To solve this // either a quick switch from 'restore' to whatever the target state is, or using another API // to position the window. bool success; if (windowPlacement.ShowCmd != ShowWindowCommands.Normal) { var prevCmd = windowPlacement.ShowCmd; windowPlacement.ShowCmd = ShowWindowCommands.Normal; success = CheckWin32Error(User32.SetWindowPlacement(window.HWnd, ref windowPlacement)); windowPlacement.ShowCmd = prevCmd; Log.Trace("Toggling to normal window state for: ({0} [{1}x{2}]-[{3}x{4}]) - {5}", window.Process.ProcessName, windowPlacement.NormalPosition.Left, windowPlacement.NormalPosition.Top, windowPlacement.NormalPosition.Width, windowPlacement.NormalPosition.Height, success); } // Set final window placement data - sets "normal" position for all windows (used for de-snapping and screen ID'ing) success = CheckWin32Error(User32.SetWindowPlacement(window.HWnd, ref windowPlacement)); Log.Trace("SetWindowPlacement({0} [{1}x{2}]-[{3}x{4}]) - {5}", window.Process.ProcessName, windowPlacement.NormalPosition.Left, windowPlacement.NormalPosition.Top, windowPlacement.NormalPosition.Width, windowPlacement.NormalPosition.Height, success); // For any windows not maximized or minimized, they might be snapped. This will place them back in their current snapped positions. // (Remember: NormalPosition is used when the user wants to *restore* from the snapped position when dragging) if (windowPlacement.ShowCmd != ShowWindowCommands.ShowMinimized && windowPlacement.ShowCmd != ShowWindowCommands.ShowMaximized) { var rect = prevDisplayMetrics.ScreenPosition; success = User32.SetWindowPos( window.HWnd, IntPtr.Zero, rect.Left, rect.Top, rect.Width, rect.Height, (uint)(SetWindowPosFlags.IgnoreZOrder | SetWindowPosFlags.AsynchronousWindowPosition)); Log.Trace("Restoring position of non maximized/minimized window: SetWindowPos({0} [{1}x{2}]-[{3}x{4}]) - {5}", window.Process.ProcessName, rect.Left, rect.Top, rect.Width, rect.Height, success); CheckWin32Error(success); } } } Log.Trace("Restored windows position for display setting {0}", displayKey); } }
private void CaptureApplicationsOnCurrentDisplays(string displayKey = null, bool initialCapture = false) { lock (displayChangeLock) { if (displayKey == null) { DesktopDisplayMetrics metrics = DesktopDisplayMetrics.AcquireMetrics(); displayKey = metrics.Key; } if (!monitorApplications.ContainsKey(displayKey)) { monitorApplications.Add(displayKey, new SortedDictionary <string, ApplicationDisplayMetrics>()); } List <string> updateLogs = new List <string>(); List <ApplicationDisplayMetrics> updateApps = new List <ApplicationDisplayMetrics>(); var appWindows = WindowHelper.CaptureWindowsOfInterest(); foreach (var window in appWindows) { ApplicationDisplayMetrics curDisplayMetrics = null; if (HasWindowChanged(displayKey, window, out curDisplayMetrics)) { updateApps.Add(curDisplayMetrics); string log = string.Format("Captured {0,-8} at ({1}, {2}) of size {3} x {4} V:{5} {6} ", curDisplayMetrics, curDisplayMetrics.ScreenPosition.Left, curDisplayMetrics.ScreenPosition.Top, curDisplayMetrics.ScreenPosition.Width, curDisplayMetrics.ScreenPosition.Height, window.Visible, window.Title ); string log2 = string.Format("\n WindowPlacement.NormalPosition at ({0}, {1}) of size {2} x {3}", curDisplayMetrics.WindowPlacement.NormalPosition.Left, curDisplayMetrics.WindowPlacement.NormalPosition.Top, curDisplayMetrics.WindowPlacement.NormalPosition.Width, curDisplayMetrics.WindowPlacement.NormalPosition.Height ); updateLogs.Add(log + log2); } } Log.Trace("{0}Capturing windows for display setting {1}", initialCapture ? "Initial " : "", displayKey); List <string> commitUpdateLog = new List <string>(); //for (int i = 0; i < maxUpdateCnt; i++) for (int i = 0; i < updateApps.Count; i++) { ApplicationDisplayMetrics curDisplayMetrics = updateApps[i]; commitUpdateLog.Add(updateLogs[i]); if (!monitorApplications[displayKey].ContainsKey(curDisplayMetrics.Key)) { monitorApplications[displayKey].Add(curDisplayMetrics.Key, curDisplayMetrics); } else { /* * // partially update Normal position part of WindowPlacement * WindowPlacement wp = monitorApplications[displayKey][curDisplayMetrics.Key].WindowPlacement; * wp.NormalPosition = curDisplayMetrics.WindowPlacement.NormalPosition; * monitorApplications[displayKey][curDisplayMetrics.Key].WindowPlacement = wp; */ monitorApplications[displayKey][curDisplayMetrics.Key].WindowPlacement = curDisplayMetrics.WindowPlacement; monitorApplications[displayKey][curDisplayMetrics.Key].ScreenPosition = curDisplayMetrics.ScreenPosition; } } //commitUpdateLog.Sort(); Log.Trace("{0}{1}{2} windows captured", string.Join(Environment.NewLine, commitUpdateLog), Environment.NewLine, commitUpdateLog.Count); } }