Exemple #1
0
        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);
                    }
                }
            }
        }
Exemple #2
0
        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);
            }
        }