From abb7cb8fb027260cd3c6193e261a6ea9ec7582ca Mon Sep 17 00:00:00 2001
From: GiantForestStudio <119655663+GiantForestStudio@users.noreply.github.com>
Date: Thu, 23 Jul 2026 16:32:45 +0900
Subject: [PATCH] Reassert always-on-top window state
---
src/Program.cs | 55 +++++++++++++++++++++++++++++++--
src/WeeklyUsageIndicator.csproj | 2 +-
2 files changed, 53 insertions(+), 4 deletions(-)
diff --git a/src/Program.cs b/src/Program.cs
index efffbf8..658747f 100644
--- a/src/Program.cs
+++ b/src/Program.cs
@@ -1,6 +1,7 @@
using System.Collections.Concurrent;
using System.Diagnostics;
using System.Drawing.Drawing2D;
+using System.Runtime.InteropServices;
using System.Text.Json;
namespace WeeklyUsageIndicator;
@@ -54,6 +55,7 @@ internal sealed class UsageIndicatorForm : Form
private bool _isRefreshing;
private bool _isHovered;
private bool _isDragging;
+ private bool _keepOnTop = true;
private Point _dragCursorStart;
private Point _dragFormStart;
@@ -137,7 +139,12 @@ private void BuildContextMenu()
Checked = true,
CheckOnClick = true
};
- topMostItem.CheckedChanged += (_, _) => TopMost = topMostItem.Checked;
+ topMostItem.CheckedChanged += (_, _) =>
+ {
+ _keepOnTop = topMostItem.Checked;
+ TopMost = _keepOnTop;
+ ReassertTopMost();
+ };
var copyItem = new ToolStripMenuItem("현재 상태 복사");
copyItem.Click += (_, _) =>
@@ -166,6 +173,12 @@ private void PlaceNearTaskbar()
workingArea.Bottom - Height - 18);
}
+ private void ReassertTopMost()
+ {
+ if (!_keepOnTop || !Visible || !IsHandleCreated) return;
+ _ = NativeWindow.TrySetTopMost(Handle);
+ }
+
private void SyncCodexVisibility()
{
var codexIsRunning = _codexStateReader.IsRunning();
@@ -193,7 +206,11 @@ private void SyncCodexVisibility()
if (!Visible) Show();
Opacity = 1;
- TopMost = true;
+ if (_keepOnTop)
+ {
+ TopMost = true;
+ ReassertTopMost();
+ }
}
private async Task RefreshUsageAsync(bool force = false)
@@ -388,6 +405,38 @@ private static GraphicsPath RoundedRectangle(RectangleF rectangle, float radius)
}
}
+internal static class NativeWindow
+{
+ private static readonly IntPtr HwndTopMost = new(-1);
+ private const uint SwpNoSize = 0x0001;
+ private const uint SwpNoMove = 0x0002;
+ private const uint SwpNoActivate = 0x0010;
+ private const uint SwpShowWindow = 0x0040;
+
+ public static bool TrySetTopMost(IntPtr windowHandle)
+ {
+ return SetWindowPos(
+ windowHandle,
+ HwndTopMost,
+ 0,
+ 0,
+ 0,
+ 0,
+ SwpNoSize | SwpNoMove | SwpNoActivate | SwpShowWindow);
+ }
+
+ [DllImport("user32.dll", SetLastError = true)]
+ [return: MarshalAs(UnmanagedType.Bool)]
+ private static extern bool SetWindowPos(
+ IntPtr windowHandle,
+ IntPtr insertAfter,
+ int x,
+ int y,
+ int width,
+ int height,
+ uint flags);
+}
+
internal sealed class CodexDesktopStateReader
{
public bool IsRunning()
@@ -481,7 +530,7 @@ await CallCoreAsync(
{
name = "weekly-usage-indicator",
title = "Weekly Usage Indicator",
- version = "1.1.0"
+ version = "1.1.1"
},
capabilities = new { experimentalApi = true }
},
diff --git a/src/WeeklyUsageIndicator.csproj b/src/WeeklyUsageIndicator.csproj
index 441ede1..9a46ea5 100644
--- a/src/WeeklyUsageIndicator.csproj
+++ b/src/WeeklyUsageIndicator.csproj
@@ -9,7 +9,7 @@
WeeklyUsageIndicator
WeeklyUsageIndicator
app.manifest
- 1.1.0
+ 1.1.1
true
none
false