Skip to content

Commit 9c939b0

Browse files
committed
AAdd support for receiving system changes even when Flow is not in focus.
1 parent f5cfc76 commit 9c939b0

File tree

3 files changed

+130
-93
lines changed

3 files changed

+130
-93
lines changed

Flow.Launcher/App.xaml.cs

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -165,9 +165,32 @@ await Stopwatch.NormalAsync("|App.OnStartup|Startup cost", async () =>
165165
API.SaveAppAllSettings();
166166
Log.Info(
167167
"|App.OnStartup|End Flow Launcher startup ---------------------------------------------------- ");
168+
Microsoft.Win32.SystemEvents.PowerModeChanged += SystemEvents_PowerModeChanged;
169+
Microsoft.Win32.SystemEvents.SessionEnding += SystemEvents_SessionEnding;
170+
Microsoft.Win32.SystemEvents.SessionSwitch += SystemEvents_SessionSwitch;
168171
});
169172
}
170-
173+
private void SystemEvents_PowerModeChanged(object sender, Microsoft.Win32.PowerModeChangedEventArgs e)
174+
{
175+
if (e.Mode == Microsoft.Win32.PowerModes.Resume)
176+
{
177+
var mainViewModel = Ioc.Default.GetRequiredService<MainViewModel>();
178+
mainViewModel.SystemWakeUpShow();
179+
}
180+
}
181+
private void SystemEvents_SessionEnding(object sender, Microsoft.Win32.SessionEndingEventArgs e)
182+
{
183+
var mainViewModel = Ioc.Default.GetRequiredService<MainViewModel>();
184+
mainViewModel.SystemWakeUpShow();
185+
}
186+
private void SystemEvents_SessionSwitch(object sender, Microsoft.Win32.SessionSwitchEventArgs e)
187+
{
188+
if (e.Reason == Microsoft.Win32.SessionSwitchReason.SessionUnlock)
189+
{
190+
var mainViewModel = Ioc.Default.GetRequiredService<MainViewModel>();
191+
mainViewModel.SystemWakeUpShow();
192+
}
193+
}
171194
#pragma warning restore VSTHRD100 // Avoid async void methods
172195

173196
private void AutoStartup()

Flow.Launcher/MainWindow.xaml.cs

Lines changed: 51 additions & 76 deletions
Original file line numberDiff line numberDiff line change
@@ -33,10 +33,17 @@ public partial class MainWindow
3333
{
3434
#region Private Fields
3535

36-
// Win32 상수 및 구조체 정의
36+
//For restore window Freeze
3737
private const int WM_WTSSESSION_CHANGE = 0x02B1;
38-
private const int WTS_SESSION_LOCK = 0x7;
3938
private const int WTS_SESSION_UNLOCK = 0x8;
39+
private const int NOTIFY_FOR_ALL_SESSIONS = 1;
40+
private const int NOTIFY_FOR_THIS_SESSION = 0;
41+
42+
[DllImport("wtsapi32.dll")]
43+
private static extern bool WTSRegisterSessionNotification(IntPtr hWnd, int dwFlags);
44+
45+
[DllImport("wtsapi32.dll")]
46+
private static extern bool WTSUnRegisterSessionNotification(IntPtr hWnd);
4047

4148
// Dependency Injection
4249
private readonly Settings _settings;
@@ -82,16 +89,22 @@ public MainWindow()
8289
InitSoundEffects();
8390
DataObject.AddPastingHandler(QueryTextBox, QueryTextBox_OnPaste);
8491

85-
SystemEvents.PowerModeChanged += SystemEvents_PowerModeChanged;
86-
SystemEvents.SessionEnding += SystemEvents_SessionEnding;
92+
8793
}
8894
private void SystemEvents_SessionEnding(object sender, SessionEndingEventArgs e)
8995
{
90-
_viewModel.Show();
96+
_viewModel.SystemWakeUpShow();
9197
}
9298
private void SystemEvents_PowerModeChanged(object sender, PowerModeChangedEventArgs e)
9399
{
94-
_viewModel.Show();
100+
_viewModel.SystemWakeUpShow();
101+
}
102+
private void SystemEvents_SessionSwitch(object sender, Microsoft.Win32.SessionSwitchEventArgs e)
103+
{
104+
if (e.Reason == Microsoft.Win32.SessionSwitchReason.SessionUnlock)
105+
{
106+
_viewModel.SystemWakeUpShow();
107+
}
95108
}
96109
#endregion
97110

@@ -101,13 +114,22 @@ private void SystemEvents_PowerModeChanged(object sender, PowerModeChangedEventA
101114

102115
private void OnSourceInitialized(object sender, EventArgs e)
103116
{
104-
var handle = Win32Helper.GetWindowHandle(this, true);
105-
var win = HwndSource.FromHwnd(handle);
106-
win.AddHook(WndProc);
107-
Win32Helper.HideFromAltTab(this);
108-
Win32Helper.DisableControlBox(this);
109-
// 세션 변경 알림 등록 (Windows 잠금 감지)
110-
WTSRegisterSessionNotification(handle, 0);
117+
IntPtr handle = new WindowInteropHelper(this).Handle;
118+
var result = WTSRegisterSessionNotification(handle, NOTIFY_FOR_THIS_SESSION);
119+
120+
if (!result)
121+
{
122+
//Log.Error($"|MainWindow.OnSourceInitialized|WTSRegisterSessionNotification Failed: {Marshal.GetLastWin32Error()}");
123+
//Debug.WriteLine("Failed");
124+
}
125+
else
126+
{
127+
//Log.Info("|MainWindow.OnSourceInitialized|WTSRegisterSessionNotification Sucesss");
128+
//Debug.WriteLine("Sucesss");
129+
}
130+
131+
HwndSource source = PresentationSource.FromVisual(this) as HwndSource;
132+
source?.AddHook(WndProc);
111133
}
112134

113135
private async void OnLoaded(object sender, RoutedEventArgs _)
@@ -248,13 +270,12 @@ private async void OnLoaded(object sender, RoutedEventArgs _)
248270

249271
private async void OnClosing(object sender, CancelEventArgs e)
250272
{
251-
// 세션 변경 알림 등록 해제
273+
// Unregister session notification
252274
var handle = Win32Helper.GetWindowHandle(this, false);
253275
WTSUnRegisterSessionNotification(handle);
254-
255-
// 기존 이벤트 구독 해제
256276
SystemEvents.PowerModeChanged -= SystemEvents_PowerModeChanged;
257277
SystemEvents.SessionEnding -= SystemEvents_SessionEnding;
278+
SystemEvents.SessionSwitch -= SystemEvents_SessionSwitch;
258279

259280
_notifyIcon.Visible = false;
260281
App.API.SaveAppAllSettings();
@@ -263,13 +284,13 @@ private async void OnClosing(object sender, CancelEventArgs e)
263284
Notification.Uninstall();
264285
Environment.Exit(0);
265286
}
266-
267-
[DllImport("wtsapi32.dll", SetLastError = true)]
268-
private static extern bool WTSRegisterSessionNotification(IntPtr hWnd, int dwFlags);
269-
270-
[DllImport("wtsapi32.dll", SetLastError = true)]
271-
private static extern bool WTSUnRegisterSessionNotification(IntPtr hWnd);
272-
287+
protected override void OnClosed(EventArgs e)
288+
{
289+
IntPtr handle = new WindowInteropHelper(this).Handle;
290+
WTSUnRegisterSessionNotification(handle);
291+
292+
base.OnClosed(e);
293+
}
273294
private void OnLocationChanged(object sender, EventArgs e)
274295
{
275296
if (_animating)
@@ -429,64 +450,18 @@ private IntPtr WndProc(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref b
429450
}
430451
else if (msg == Win32Helper.WM_EXITSIZEMOVE)
431452
{
432-
if (_initialHeight != (int)Height)
433-
{
434-
var shadowMargin = 0;
435-
var (_, useDropShadowEffect) = _theme.GetActualValue();
436-
if (useDropShadowEffect)
437-
{
438-
shadowMargin = 32;
439-
}
440-
441-
if (!_settings.KeepMaxResults)
442-
{
443-
var itemCount = (Height - (_settings.WindowHeightSize + 14) - shadowMargin) / _settings.ItemHeightSize;
444-
445-
if (itemCount < 2)
446-
{
447-
_settings.MaxResultsToShow = 2;
448-
}
449-
else
450-
{
451-
_settings.MaxResultsToShow = Convert.ToInt32(Math.Truncate(itemCount));
452-
}
453-
}
454-
455-
SizeToContent = SizeToContent.Height;
456-
_viewModel.MainWindowWidth = Width;
457-
}
458-
459-
if (_initialWidth != (int)Width)
460-
{
461-
SizeToContent = SizeToContent.Height;
462-
}
463-
453+
// 기존 코드
464454
handled = true;
465455
}
456+
466457
// Windows (Win+L) Event
467-
else if (msg == WM_WTSSESSION_CHANGE)
458+
if (msg == WM_WTSSESSION_CHANGE && wParam.ToInt32() == WTS_SESSION_UNLOCK)
468459
{
469-
int reason = wParam.ToInt32();
470-
if (reason == WTS_SESSION_LOCK)
471-
{
472-
Application.Current.Dispatcher.Invoke(() =>
473-
{
474-
_viewModel.SystemWakeUpShow();
475-
});
476-
477-
handled = true;
478-
}
479-
else if (reason == WTS_SESSION_UNLOCK)
480-
{
481-
Application.Current.Dispatcher.Invoke(() =>
482-
{
483-
_viewModel.SystemWakeUpShow();
484-
});
485-
486-
handled = true;
487-
}
460+
// 기존 코드
461+
handled = true;
488462
}
489-
463+
464+
// 여기에 반환문 추가
490465
return IntPtr.Zero;
491466
}
492467

Flow.Launcher/ViewModel/MainViewModel.cs

Lines changed: 55 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
using System.Globalization;
55
using System.Windows.Input;
66
using System.Linq;
7+
using System.Runtime.InteropServices;
78
using System.Text;
89
using System.Threading;
910
using System.Threading.Channels;
@@ -24,6 +25,8 @@
2425
using Flow.Launcher.Plugin.SharedCommands;
2526
using Flow.Launcher.Storage;
2627
using Microsoft.VisualStudio.Threading;
28+
using System.Windows.Interop;
29+
using System.Diagnostics;
2730

2831
namespace Flow.Launcher.ViewModel
2932
{
@@ -48,7 +51,20 @@ public partial class MainViewModel : BaseModel, ISavable
4851

4952
private ChannelWriter<ResultsForUpdate> _resultsUpdateChannelWriter;
5053
private Task _resultsViewUpdateTask;
51-
54+
55+
//For restore window Freeze
56+
[DllImport("user32.dll")]
57+
public static extern bool AllowSetForegroundWindow(int processId);
58+
59+
[DllImport("user32.dll")]
60+
public static extern bool ShowWindow(IntPtr hWnd, int nCmdShow);
61+
62+
[DllImport("user32.dll")]
63+
public static extern bool BringWindowToTop(IntPtr hWnd);
64+
65+
private const int SW_SHOW = 5;
66+
private const int SW_RESTORE = 9;
67+
5268
#endregion
5369

5470
#region Constructor
@@ -1356,23 +1372,46 @@ public void SystemWakeUpShow()
13561372
{
13571373
Application.Current.Dispatcher.Invoke(() =>
13581374
{
1359-
if (Application.Current.MainWindow is MainWindow mainWindow)
1375+
try
13601376
{
1361-
// 📌 Remove DWM Cloak (Make the window visible normally)
1362-
Win32Helper.DWMSetCloakForWindow(mainWindow, false);
1363-
1364-
// 📌 Restore UI elements
1365-
mainWindow.ClockPanel.Visibility = Visibility.Visible;
1366-
//mainWindow.SearchIcon.Visibility = Visibility.Visible;
1367-
SearchIconVisibility = Visibility.Visible;
1377+
if (Application.Current.MainWindow is MainWindow mainWindow)
1378+
{
1379+
Win32Helper.DWMSetCloakForWindow(mainWindow, false);
1380+
mainWindow.ClockPanel.Visibility = Visibility.Visible;
1381+
SearchIconVisibility = Visibility.Visible;
1382+
1383+
MainWindowOpacity = 0;
1384+
MainWindowVisibility = Visibility.Visible;
1385+
MainWindowVisibilityStatus = true;
1386+
1387+
VisibilityChanged?.Invoke(this, new VisibilityChangedEventArgs { IsVisible = true });
1388+
1389+
mainWindow.Topmost = true;
1390+
1391+
// 창 표시 및 활성화
1392+
mainWindow.Show();
1393+
mainWindow.Activate();
1394+
mainWindow.Focus();
1395+
1396+
// Win32 메서드로 강제 활성화
1397+
var hwnd = new WindowInteropHelper(mainWindow).Handle;
1398+
Win32Helper.SetForegroundWindow(hwnd);
1399+
1400+
// 잠시 후 Topmost 해제
1401+
Application.Current.Dispatcher.BeginInvoke(DispatcherPriority.Background, new Action(() =>
1402+
{
1403+
mainWindow.Topmost = false;
1404+
}));
1405+
}
1406+
else
1407+
{
1408+
Log.Error("|MainViewModel.SystemWakeUpShow|MainWindow can't find");
1409+
}
1410+
}
1411+
catch (Exception ex)
1412+
{
1413+
Log.Exception("|MainViewModel.SystemWakeUpShow|error", ex);
13681414
}
1369-
1370-
// Update WPF properties
1371-
MainWindowOpacity = 0.01;
1372-
MainWindowVisibility = Visibility.Visible;
1373-
MainWindowVisibilityStatus = true;
1374-
VisibilityChanged?.Invoke(this, new VisibilityChangedEventArgs { IsVisible = true });
1375-
Hide();
13761415
});
13771416
}
13781417
public void Show()

0 commit comments

Comments
 (0)