Skip to content

Commit 79da928

Browse files
committed
Do not fill twice & Add lock for stability
1 parent f337d88 commit 79da928

File tree

2 files changed

+95
-30
lines changed

2 files changed

+95
-30
lines changed

Flow.Launcher.Infrastructure/QuickSwitch/QuickSwitch.cs

Lines changed: 82 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
using System;
2+
using System.Collections.Generic;
23
using System.IO;
34
using System.Runtime.InteropServices;
45
using System.Threading;
@@ -48,6 +49,13 @@ public static class QuickSwitch
4849

4950
private static DispatcherTimer _dragMoveTimer = null;
5051

52+
// A list of all file dialog windows that are auto switched already
53+
private static readonly List<HWND> _autoSwitchedDialogs = new();
54+
55+
private static readonly object _autoSwitchedDialogsLock = new();
56+
57+
private static readonly SemaphoreSlim _navigationLock = new(1, 1);
58+
5159
private static HWND _mainWindowHandle = HWND.Null;
5260

5361
private static HWND _dialogWindowHandle = HWND.Null;
@@ -199,14 +207,16 @@ private static void NavigateDialogPath(Action action = null)
199207
return;
200208
}
201209

210+
Log.Debug(ClassName, $"Path: {path}");
202211
JumpToPath(path, action);
203212
}
204213

205-
public static bool JumpToPath(string path, Action action = null)
214+
[System.Diagnostics.CodeAnalysis.SuppressMessage("Usage", "VSTHRD101:Avoid unsupported async delegates", Justification = "<Pending>")]
215+
public static void JumpToPath(string path, Action action = null)
206216
{
207-
if (!CheckPath(path, out var isFile)) return false;
217+
if (!CheckPath(path, out var isFile)) return;
208218

209-
var t = new Thread(() =>
219+
var t = new Thread(async () =>
210220
{
211221
// Jump after flow launcher window vanished (after JumpAction returned true)
212222
// and the dialog had been in the foreground.
@@ -217,20 +227,47 @@ public static bool JumpToPath(string path, Action action = null)
217227
};
218228

219229
// Assume that the dialog is in the foreground now
220-
if (isFile)
230+
await _navigationLock.WaitAsync();
231+
try
232+
{
233+
var dialog = Win32Helper.GetForegroundWindowHWND();
234+
235+
bool result;
236+
if (isFile)
237+
{
238+
result = Win32Helper.FileJump(path, dialog);
239+
}
240+
else
241+
{
242+
result = Win32Helper.DirJump(path, dialog);
243+
}
244+
245+
if (result)
246+
{
247+
lock (_autoSwitchedDialogsLock)
248+
{
249+
_autoSwitchedDialogs.Add(dialog);
250+
}
251+
}
252+
else
253+
{
254+
Log.Error(ClassName, "Failed to jump to path");
255+
}
256+
}
257+
catch (System.Exception e)
221258
{
222-
Win32Helper.FileJump(path, Win32Helper.GetForegroundWindow());
259+
Log.Exception(ClassName, "Failed to jump to path", e);
223260
}
224-
else
261+
finally
225262
{
226-
Win32Helper.DirJump(path, Win32Helper.GetForegroundWindow());
263+
_navigationLock.Release();
227264
}
228-
265+
229266
// Invoke action if provided
230267
action?.Invoke();
231268
});
232269
t.Start();
233-
return true;
270+
return;
234271

235272
static bool CheckPath(string path, out bool file)
236273
{
@@ -278,6 +315,8 @@ uint dwmsEventTime
278315
// File dialog window
279316
if (GetWindowClassName(hwnd) == DialogWindowClassName)
280317
{
318+
Log.Debug(ClassName, $"Hwnd: {hwnd}");
319+
281320
lock (_dialogWindowHandleLock)
282321
{
283322
_dialogWindowHandle = hwnd;
@@ -286,24 +325,43 @@ uint dwmsEventTime
286325
// Navigate to path
287326
if (_settings.AutoQuickSwitch)
288327
{
289-
Win32Helper.SetForegroundWindow(hwnd);
290-
NavigateDialogPath(() =>
328+
// Check if we have already switched for this dialog
329+
bool alreadySwitched;
330+
lock (_dialogWindowHandleLock)
331+
{
332+
alreadySwitched = _autoSwitchedDialogs.Contains(hwnd);
333+
}
334+
335+
// Just show quick switch window
336+
if (alreadySwitched)
291337
{
292-
// Show quick switch window after path is navigated
293338
if (_settings.ShowQuickSwitchWindow)
294339
{
295340
ShowQuickSwitchWindow?.Invoke(_dialogWindowHandle.Value);
296341
_dragMoveTimer?.Start();
297342
}
298-
});
299-
return;
343+
}
344+
// Show quick switch window after navigating the path
345+
else
346+
{
347+
NavigateDialogPath(() =>
348+
{
349+
if (_settings.ShowQuickSwitchWindow)
350+
{
351+
ShowQuickSwitchWindow?.Invoke(_dialogWindowHandle.Value);
352+
_dragMoveTimer?.Start();
353+
}
354+
});
355+
}
300356
}
301-
302-
// Show quick switch window
303-
if (_settings.ShowQuickSwitchWindow)
357+
else
304358
{
305-
ShowQuickSwitchWindow?.Invoke(_dialogWindowHandle.Value);
306-
_dragMoveTimer?.Start();
359+
// Show quick switch window
360+
if (_settings.ShowQuickSwitchWindow)
361+
{
362+
ShowQuickSwitchWindow?.Invoke(_dialogWindowHandle.Value);
363+
_dragMoveTimer?.Start();
364+
}
307365
}
308366
}
309367
// Quick switch window
@@ -413,10 +471,15 @@ uint dwmsEventTime
413471
// If the dialog window is destroyed, set _dialogWindowHandle to null
414472
if (_dialogWindowHandle != HWND.Null && _dialogWindowHandle == hwnd)
415473
{
474+
Log.Debug(ClassName, $"Dialog Hwnd: {hwnd}");
416475
lock (_dialogWindowHandleLock)
417476
{
418477
_dialogWindowHandle = HWND.Null;
419478
}
479+
lock (_autoSwitchedDialogsLock)
480+
{
481+
_autoSwitchedDialogs.Remove(hwnd);
482+
}
420483
ResetQuickSwitchWindow?.Invoke();
421484
_dragMoveTimer?.Stop();
422485
}

Flow.Launcher.Infrastructure/Win32Helper.cs

Lines changed: 13 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -116,7 +116,12 @@ public static unsafe string GetWallpaperPath()
116116

117117
public static nint GetForegroundWindow()
118118
{
119-
return PInvoke.GetForegroundWindow().Value;
119+
return GetForegroundWindowHWND().Value;
120+
}
121+
122+
internal static HWND GetForegroundWindowHWND()
123+
{
124+
return PInvoke.GetForegroundWindow();
120125
}
121126

122127
public static bool SetForegroundWindow(Window window)
@@ -621,21 +626,18 @@ public static void OpenImeSettings()
621626

622627
private static readonly InputSimulator _inputSimulator = new();
623628

624-
public static bool FileJump(string filePath, nint dialog, bool altD = true)
629+
internal static bool FileJump(string filePath, HWND dialogHandle, bool altD = true)
625630
{
626-
return DirFileJump(Path.GetDirectoryName(filePath), filePath, dialog, altD);
631+
return DirFileJump(Path.GetDirectoryName(filePath), filePath, dialogHandle, altD);
627632
}
628633

629-
public static bool DirJump(string dirPath, nint dialog, bool altD = true)
634+
internal static bool DirJump(string dirPath, HWND dialogHandle, bool altD = true)
630635
{
631-
return DirFileJump(dirPath, null, dialog, altD);
636+
return DirFileJump(dirPath, null, dialogHandle, altD);
632637
}
633638

634-
private static bool DirFileJump(string dirPath, string filePath, nint dialog, bool altD = true, bool editFileName = false)
639+
private static bool DirFileJump(string dirPath, string filePath, HWND dialogHandle, bool altD = true, bool editFileName = false)
635640
{
636-
// Get the handle of the dialog window
637-
var dialogHandle = new HWND(dialog);
638-
639641
// Directly edit file name input box.
640642
if (editFileName)
641643
{
@@ -654,7 +656,7 @@ private static bool DirFileJump(string dirPath, string filePath, nint dialog, bo
654656

655657
// Get the handle of the path input box and then set the text.
656658
// The window with class name "ComboBoxEx32" is not visible when the path input box is not with the keyboard focus.
657-
var controlHandle = PInvoke.FindWindowEx(new(dialogHandle), HWND.Null, "WorkerW", null);
659+
var controlHandle = PInvoke.FindWindowEx(dialogHandle, HWND.Null, "WorkerW", null);
658660
controlHandle = PInvoke.FindWindowEx(controlHandle, HWND.Null, "ReBarWindow32", null);
659661
controlHandle = PInvoke.FindWindowEx(controlHandle, HWND.Null, "Address Band Root", null);
660662
controlHandle = PInvoke.FindWindowEx(controlHandle, HWND.Null, "msctls_progress32", null);
@@ -689,7 +691,7 @@ private static bool DirFileJump(string dirPath, string filePath, nint dialog, bo
689691
if (!string.IsNullOrEmpty(filePath))
690692
{
691693
// After navigating to the path, we then set the file name.
692-
return DirFileJump(null, Path.GetFileName(filePath), dialog, altD, true);
694+
return DirFileJump(null, Path.GetFileName(filePath), dialogHandle, altD, true);
693695
}
694696

695697
return true;

0 commit comments

Comments
 (0)