diff --git a/src/RdpManager/WindowBorder.cs b/src/RdpManager/WindowBorder.cs
index 52ecfd7..67b4f81 100644
--- a/src/RdpManager/WindowBorder.cs
+++ b/src/RdpManager/WindowBorder.cs
@@ -56,17 +56,27 @@ public static void Apply(Window window)
catch { /* starszy DWM bez tego atrybutu — bez znaczenia */ }
}
- /// Nakłada TERAZ i utrzymuje: przy każdej aktywacji okna oraz raz po pełnym wyrenderowaniu
- /// (ApplicationIdle — już po tym, jak WPF-UI skończy malować krawędź).
+ /// Nakłada TERAZ i utrzymuje: synchronicznie z hooka WM_NCACTIVATE (ogranicza błysk),
+ /// z handlera Activated + odroczonych dobić (ostatnie słowo po repaintach WPF-UI) oraz raz po
+ /// pełnym wyrenderowaniu.
public static void Keep(Window window)
{
if (window == null) return;
Apply(window);
// WM_NCACTIVATE: Windows/WPF-UI przemalowują krawędź (non-client) przy (de)aktywacji — m.in. gdy
- // zamknie się okno potomne (np. „O aplikacji") i główne wraca na wierzch. Hookujemy tę wiadomość i
- // przywracamy wybraną obwódkę SYNCHRONICZNIE, w tym samym cyklu repaint (bez odroczenia = bez błysku
- // kobaltu). Hook jest statyczny (bez domknięcia per-okno) i zwalnia się z HwndSource okna — brak wycieku.
+ // zamknie się okno potomne (np. „O aplikacji") i główne wraca na wierzch. Zapis synchroniczny w tym
+ // hooku ogranicza błysk, a odroczone dobicie w BorderHook domyka cykl. Hook jest statyczny (bez
+ // domknięcia per-okno) i zwalnia się z HwndSource okna — brak wycieku.
HwndSource.FromHwnd(new WindowInteropHelper(window).Handle)?.AddHook(BorderHook);
+ // Handler Activated — sprawdzona ścieżka sprzed #183: WPF-UI maluje akcent PO Activated, więc
+ // dobicie odroczone stąd ląduje jako ostatnie. #183 usunął to w całości (zostawiając tylko zapis
+ // synchroniczny z hooka, który leci PRZED repaintem WPF-UI) — obwódka zostawała kobaltowa NA STAŁE.
+ window.Activated += (_, __) =>
+ {
+ Apply(window);
+ window.Dispatcher.BeginInvoke(new Action(() => Apply(window)),
+ System.Windows.Threading.DispatcherPriority.ApplicationIdle);
+ };
// Dobij raz po pełnym wyrenderowaniu (WPF-UI kończy malować krawędź po Loaded) — asekuracja pierwszej klatki.
window.Dispatcher.BeginInvoke(new Action(() => Apply(window)),
System.Windows.Threading.DispatcherPriority.ApplicationIdle);
@@ -74,18 +84,32 @@ public static void Keep(Window window)
private const int WM_NCACTIVATE = 0x0086;
- // Przy każdym WM_NCACTIVATE ponownie nakłada bieżącą specyfikację obwódki — zanim klatka trafi na ekran.
+ // Przy każdym WM_NCACTIVATE ponownie nakłada bieżącą specyfikację obwódki: raz SYNCHRONICZNIE
+ // (ogranicza błysk — zanim klatka trafi na ekran) i raz ODROCZONO (ApplicationIdle).
+ // Odroczone dobicie jest KONIECZNE: WPF-UI przemalowuje krawędź na akcent PÓŹNIEJ w tym samym
+ // cyklu aktywacji (po zdarzeniu Activated), więc sam synchroniczny zapis przegrywa „ostatnie
+ // słowo" i obwódka ZOSTAWAŁA kobaltowa na stałe (regresja z #183, która to dobicie usunęła).
private static IntPtr BorderHook(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled)
{
if (msg == WM_NCACTIVATE && hwnd != IntPtr.Zero)
{
- uint val = SpecToColorRef(_spec);
- try { DwmSetWindowAttribute(hwnd, DWMWA_BORDER_COLOR, ref val, sizeof(uint)); }
- catch { /* starszy DWM bez atrybutu — bez znaczenia */ }
+ WriteBorder(hwnd);
+ var h = hwnd; // kopia do domknięcia (hwnd to parametr ref-świata WndProc)
+ Application.Current?.Dispatcher.BeginInvoke(new Action(() => WriteBorder(h)),
+ System.Windows.Threading.DispatcherPriority.ApplicationIdle);
}
return IntPtr.Zero;
}
+ // Zapis bieżącej specyfikacji wprost na hwnd (okno mogło już nie mieć obiektu Window — np. w trakcie
+ // zamykania; nieaktualny uchwyt jest nieszkodliwy, DWM zwróci błąd, który ignorujemy).
+ private static void WriteBorder(IntPtr hwnd)
+ {
+ uint val = SpecToColorRef(_spec);
+ try { DwmSetWindowAttribute(hwnd, DWMWA_BORDER_COLOR, ref val, sizeof(uint)); }
+ catch { /* starszy DWM bez atrybutu — bez znaczenia */ }
+ }
+
// "" → brak; "System"/"default" → systemowy akcent; "#RRGGBB" → COLORREF (0x00BBGGRR); błędny → brak.
private static uint SpecToColorRef(string spec)
{