diff --git a/Flow.Launcher/App.xaml.cs b/Flow.Launcher/App.xaml.cs index b102e384e70..2a68b5d31ea 100644 --- a/Flow.Launcher/App.xaml.cs +++ b/Flow.Launcher/App.xaml.cs @@ -165,9 +165,32 @@ await Stopwatch.NormalAsync("|App.OnStartup|Startup cost", async () => API.SaveAppAllSettings(); Log.Info( "|App.OnStartup|End Flow Launcher startup ---------------------------------------------------- "); + Microsoft.Win32.SystemEvents.PowerModeChanged += SystemEvents_PowerModeChanged; + Microsoft.Win32.SystemEvents.SessionEnding += SystemEvents_SessionEnding; + Microsoft.Win32.SystemEvents.SessionSwitch += SystemEvents_SessionSwitch; }); } - + private void SystemEvents_PowerModeChanged(object sender, Microsoft.Win32.PowerModeChangedEventArgs e) + { + if (e.Mode == Microsoft.Win32.PowerModes.Resume) + { + var mainViewModel = Ioc.Default.GetRequiredService(); + mainViewModel.SystemWakeUpShow(); + } + } + private void SystemEvents_SessionEnding(object sender, Microsoft.Win32.SessionEndingEventArgs e) + { + var mainViewModel = Ioc.Default.GetRequiredService(); + mainViewModel.SystemWakeUpShow(); + } + private void SystemEvents_SessionSwitch(object sender, Microsoft.Win32.SessionSwitchEventArgs e) + { + if (e.Reason == Microsoft.Win32.SessionSwitchReason.SessionUnlock) + { + var mainViewModel = Ioc.Default.GetRequiredService(); + mainViewModel.SystemWakeUpShow(); + } + } #pragma warning restore VSTHRD100 // Avoid async void methods private void AutoStartup() diff --git a/Flow.Launcher/MainWindow.xaml.cs b/Flow.Launcher/MainWindow.xaml.cs index ec8649efcbb..43dfa32f6c0 100644 --- a/Flow.Launcher/MainWindow.xaml.cs +++ b/Flow.Launcher/MainWindow.xaml.cs @@ -2,6 +2,7 @@ using System.ComponentModel; using System.Linq; using System.Media; +using System.Runtime.InteropServices; using System.Threading.Tasks; using System.Windows; using System.Windows.Controls; @@ -20,6 +21,7 @@ using Flow.Launcher.Infrastructure.UserSettings; using Flow.Launcher.Plugin.SharedCommands; using Flow.Launcher.ViewModel; +using Microsoft.Win32; using ModernWpf.Controls; using MouseButtons = System.Windows.Forms.MouseButtons; using NotifyIcon = System.Windows.Forms.NotifyIcon; @@ -31,6 +33,18 @@ public partial class MainWindow { #region Private Fields + //For restore window Freeze + private const int WM_WTSSESSION_CHANGE = 0x02B1; + private const int WTS_SESSION_UNLOCK = 0x8; + private const int NOTIFY_FOR_ALL_SESSIONS = 1; + private const int NOTIFY_FOR_THIS_SESSION = 0; + + [DllImport("wtsapi32.dll")] + private static extern bool WTSRegisterSessionNotification(IntPtr hWnd, int dwFlags); + + [DllImport("wtsapi32.dll")] + private static extern bool WTSUnRegisterSessionNotification(IntPtr hWnd); + // Dependency Injection private readonly Settings _settings; private readonly Theme _theme; @@ -74,8 +88,24 @@ public MainWindow() InitSoundEffects(); DataObject.AddPastingHandler(QueryTextBox, QueryTextBox_OnPaste); - } + + } + private void SystemEvents_SessionEnding(object sender, SessionEndingEventArgs e) + { + _viewModel.SystemWakeUpShow(); + } + private void SystemEvents_PowerModeChanged(object sender, PowerModeChangedEventArgs e) + { + _viewModel.SystemWakeUpShow(); + } + private void SystemEvents_SessionSwitch(object sender, Microsoft.Win32.SessionSwitchEventArgs e) + { + if (e.Reason == Microsoft.Win32.SessionSwitchReason.SessionUnlock) + { + _viewModel.SystemWakeUpShow(); + } + } #endregion #region Window Event @@ -84,13 +114,24 @@ public MainWindow() private void OnSourceInitialized(object sender, EventArgs e) { - var handle = Win32Helper.GetWindowHandle(this, true); - var win = HwndSource.FromHwnd(handle); - win.AddHook(WndProc); - Win32Helper.HideFromAltTab(this); - Win32Helper.DisableControlBox(this); - } + IntPtr handle = new WindowInteropHelper(this).Handle; + var result = WTSRegisterSessionNotification(handle, NOTIFY_FOR_THIS_SESSION); + + if (!result) + { + //Log.Error($"|MainWindow.OnSourceInitialized|WTSRegisterSessionNotification Failed: {Marshal.GetLastWin32Error()}"); + //Debug.WriteLine("Failed"); + } + else + { + //Log.Info("|MainWindow.OnSourceInitialized|WTSRegisterSessionNotification Sucesss"); + //Debug.WriteLine("Sucesss"); + } + HwndSource source = PresentationSource.FromVisual(this) as HwndSource; + source?.AddHook(WndProc); + } + private async void OnLoaded(object sender, RoutedEventArgs _) { // Check first launch @@ -156,11 +197,6 @@ private async void OnLoaded(object sender, RoutedEventArgs _) { if (_viewModel.MainWindowVisibilityStatus) { - if (_settings.UseSound) - { - SoundPlay(); - } - UpdatePosition(false); _viewModel.ResetPreview(); Activate(); @@ -234,6 +270,13 @@ private async void OnLoaded(object sender, RoutedEventArgs _) private async void OnClosing(object sender, CancelEventArgs e) { + // Unregister session notification + var handle = Win32Helper.GetWindowHandle(this, false); + WTSUnRegisterSessionNotification(handle); + SystemEvents.PowerModeChanged -= SystemEvents_PowerModeChanged; + SystemEvents.SessionEnding -= SystemEvents_SessionEnding; + SystemEvents.SessionSwitch -= SystemEvents_SessionSwitch; + _notifyIcon.Visible = false; App.API.SaveAppAllSettings(); e.Cancel = true; @@ -241,7 +284,13 @@ private async void OnClosing(object sender, CancelEventArgs e) Notification.Uninstall(); Environment.Exit(0); } - + protected override void OnClosed(EventArgs e) + { + IntPtr handle = new WindowInteropHelper(this).Handle; + WTSUnRegisterSessionNotification(handle); + + base.OnClosed(e); + } private void OnLocationChanged(object sender, EventArgs e) { if (_animating) @@ -401,41 +450,18 @@ private IntPtr WndProc(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref b } else if (msg == Win32Helper.WM_EXITSIZEMOVE) { - if (_initialHeight != (int)Height) - { - var shadowMargin = 0; - var (_, useDropShadowEffect) = _theme.GetActualValue(); - if (useDropShadowEffect) - { - shadowMargin = 32; - } - - if (!_settings.KeepMaxResults) - { - var itemCount = (Height - (_settings.WindowHeightSize + 14) - shadowMargin) / _settings.ItemHeightSize; - - if (itemCount < 2) - { - _settings.MaxResultsToShow = 2; - } - else - { - _settings.MaxResultsToShow = Convert.ToInt32(Math.Truncate(itemCount)); - } - } - - SizeToContent = SizeToContent.Height; - _viewModel.MainWindowWidth = Width; - } - - if (_initialWidth != (int)Width) - { - SizeToContent = SizeToContent.Height; - } - + // 기존 코드 handled = true; } + // Windows (Win+L) Event + if (msg == WM_WTSSESSION_CHANGE && wParam.ToInt32() == WTS_SESSION_UNLOCK) + { + // 기존 코드 + handled = true; + } + + // 여기에 반환문 추가 return IntPtr.Zero; } @@ -456,7 +482,7 @@ private void InitSoundEffects() } } - private void SoundPlay() + public void SoundPlay() { if (_settings.WMPInstalled) { diff --git a/Flow.Launcher/SettingWindow.xaml.cs b/Flow.Launcher/SettingWindow.xaml.cs index 28140f0245c..75d770a5be0 100644 --- a/Flow.Launcher/SettingWindow.xaml.cs +++ b/Flow.Launcher/SettingWindow.xaml.cs @@ -36,9 +36,9 @@ private void OnLoaded(object sender, RoutedEventArgs e) RefreshMaximizeRestoreButton(); // Fix (workaround) for the window freezes after lock screen (Win+L) or sleep // https://stackoverflow.com/questions/4951058/software-rendering-mode-wpf - HwndSource hwndSource = PresentationSource.FromVisual(this) as HwndSource; - HwndTarget hwndTarget = hwndSource.CompositionTarget; - hwndTarget.RenderMode = RenderMode.SoftwareOnly; // Must use software only render mode here + //HwndSource hwndSource = PresentationSource.FromVisual(this) as HwndSource; + //HwndTarget hwndTarget = hwndSource.CompositionTarget; + //hwndTarget.RenderMode = RenderMode.SoftwareOnly; // Must use software only render mode here InitializePosition(); } diff --git a/Flow.Launcher/ViewModel/MainViewModel.cs b/Flow.Launcher/ViewModel/MainViewModel.cs index 3ce0ba2f0b6..e7ad6e9effc 100644 --- a/Flow.Launcher/ViewModel/MainViewModel.cs +++ b/Flow.Launcher/ViewModel/MainViewModel.cs @@ -4,6 +4,7 @@ using System.Globalization; using System.Windows.Input; using System.Linq; +using System.Runtime.InteropServices; using System.Text; using System.Threading; using System.Threading.Channels; @@ -24,6 +25,8 @@ using Flow.Launcher.Plugin.SharedCommands; using Flow.Launcher.Storage; using Microsoft.VisualStudio.Threading; +using System.Windows.Interop; +using System.Diagnostics; namespace Flow.Launcher.ViewModel { @@ -48,7 +51,20 @@ public partial class MainViewModel : BaseModel, ISavable private ChannelWriter _resultsUpdateChannelWriter; private Task _resultsViewUpdateTask; - + + //For restore window Freeze + [DllImport("user32.dll")] + public static extern bool AllowSetForegroundWindow(int processId); + + [DllImport("user32.dll")] + public static extern bool ShowWindow(IntPtr hWnd, int nCmdShow); + + [DllImport("user32.dll")] + public static extern bool BringWindowToTop(IntPtr hWnd); + + private const int SW_SHOW = 5; + private const int SW_RESTORE = 9; + #endregion #region Constructor @@ -1352,12 +1368,60 @@ public void ToggleFlowLauncher() } } + public void SystemWakeUpShow() + { + Application.Current.Dispatcher.Invoke(() => + { + try + { + if (Application.Current.MainWindow is MainWindow mainWindow) + { + Win32Helper.DWMSetCloakForWindow(mainWindow, true); + mainWindow.ClockPanel.Visibility = Visibility.Visible; + SearchIconVisibility = Visibility.Visible; + + MainWindowOpacity = 0; + MainWindowVisibility = Visibility.Visible; + MainWindowVisibilityStatus = true; + + VisibilityChanged?.Invoke(this, new VisibilityChangedEventArgs { IsVisible = true }); + + mainWindow.Topmost = true; + + // 창 표시 및 활성화 + mainWindow.Show(); + mainWindow.Activate(); + mainWindow.Focus(); + + var hwnd = new WindowInteropHelper(mainWindow).Handle; + Win32Helper.SetForegroundWindow(hwnd); + + Application.Current.Dispatcher.BeginInvoke(DispatcherPriority.Background, new Action(() => + { + mainWindow.Topmost = false; + })); + } + else + { + Log.Error("|MainViewModel.SystemWakeUpShow|MainWindow can't find"); + } + } + catch (Exception ex) + { + Log.Exception("|MainViewModel.SystemWakeUpShow|error", ex); + } + }); + } public void Show() { Application.Current.Dispatcher.Invoke(() => { if (Application.Current.MainWindow is MainWindow mainWindow) { + if (Settings.UseSound) + { + mainWindow.SoundPlay(); + } // 📌 Remove DWM Cloak (Make the window visible normally) Win32Helper.DWMSetCloakForWindow(mainWindow, false);