diff --git a/main.go b/main.go
index 5e53dcf..05b9560 100644
--- a/main.go
+++ b/main.go
@@ -11,6 +11,7 @@ import (
"os"
"os/signal"
"syscall"
+ "unsafe"
"github.com/jchv/go-webview2"
"github.com/mumur/driver-booster/internal/bridge"
@@ -22,6 +23,51 @@ import (
//go:embed ui/*
var uiFS embed.FS
+var (
+ user32 = syscall.NewLazyDLL("user32.dll")
+ procGetWindowLong = user32.NewProc("GetWindowLongW")
+ procSetWindowLong = user32.NewProc("SetWindowLongW")
+ procSetWindowPos = user32.NewProc("SetWindowPos")
+ procPostMessage = user32.NewProc("PostMessageW")
+ procShowWindow = user32.NewProc("ShowWindow")
+)
+
+const (
+ gwlStyle = -16
+ wsCaption = 0x00C00000
+ wsSysMenu = 0x00080000
+ wsThickFrame = 0x00040000
+ wsMinBox = 0x00020000
+ wsMaxBox = 0x00010000
+ wsVisible = 0x10000000
+ wsPopup = 0x80000000
+
+ swpFrameChanged = 0x0020
+ swpNoMove = 0x0002
+ swpNoSize = 0x0001
+ swpNoZOrder = 0x0004
+
+ wmSysCommand = 0x0112
+ scMinimize = 0xF020
+ scMaximize = 0xF030
+ scRestore = 0xF120
+ scClose = 0xF060
+
+ swMaximize = 3
+ swRestore = 9
+)
+
+func removeWindowFrame(hwnd uintptr) {
+ gwlStyleUintptr := uintptr(0xFFFFFFF0) // GWL_STYLE = -16 as unsigned
+ style, _, _ := procGetWindowLong.Call(hwnd, gwlStyleUintptr)
+ // Remove caption (title bar) but keep thick frame (resizable) and min/max boxes
+ newStyle := (style &^ wsCaption) | wsThickFrame | wsMinBox | wsMaxBox
+ procSetWindowLong.Call(hwnd, gwlStyleUintptr, newStyle)
+ // Force redraw frame
+ procSetWindowPos.Call(hwnd, 0, 0, 0, 0, 0,
+ swpFrameChanged|swpNoMove|swpNoSize|swpNoZOrder)
+}
+
func main() {
// Start embedded HTTP server for UI assets
uiContent, err := fs.Sub(uiFS, "ui")
@@ -74,6 +120,24 @@ func main() {
}
defer w.Destroy()
+ // Remove native title bar to use our custom one
+ hwnd := uintptr(unsafe.Pointer(w.Window()))
+ removeWindowFrame(hwnd)
+
+ // Bind window control functions for custom title bar buttons
+ w.Bind("windowMinimize", func() {
+ procPostMessage.Call(hwnd, wmSysCommand, scMinimize, 0)
+ })
+ w.Bind("windowMaximize", func() {
+ procPostMessage.Call(hwnd, wmSysCommand, scMaximize, 0)
+ })
+ w.Bind("windowRestore", func() {
+ procPostMessage.Call(hwnd, wmSysCommand, scRestore, 0)
+ })
+ w.Bind("windowClose", func() {
+ procPostMessage.Call(hwnd, wmSysCommand, scClose, 0)
+ })
+
// Bind Go functions to JS
w.Bind("goGetSysInfo", func() string {
info := b.SysInfo.Collect()
diff --git a/ui/index.html b/ui/index.html
index 15cb1db..d6deeed 100644
--- a/ui/index.html
+++ b/ui/index.html
@@ -8,8 +8,8 @@
-
-
+
+
@@ -17,12 +17,23 @@
PRO
-
diff --git a/ui/style.css b/ui/style.css
index 7e7ac3d..1729551 100644
--- a/ui/style.css
+++ b/ui/style.css
@@ -67,31 +67,53 @@ body {
/* ---- App Shell ---- */
.app { display:flex; flex-direction:column; height:100vh; background:var(--mica); }
-/* ---- Title Bar (Win11 style) ---- */
+/* ---- Custom Title Bar (frameless window) ---- */
.titlebar {
- display:flex; justify-content:space-between; align-items:center;
- padding:10px 16px;
+ display:flex; align-items:center;
+ padding:0 0 0 12px;
+ height:38px;
background:var(--bg);
border-bottom:1px solid var(--border);
flex-shrink:0;
-webkit-app-region:drag;
+ user-select:none;
}
-.titlebar-left { display:flex; align-items:center; gap:10px; -webkit-app-region:no-drag; }
-.app-title { display:flex; align-items:center; gap:8px; }
-.app-name { font-size:13px; font-weight:600; color:var(--text); letter-spacing:.3px; }
+.titlebar-left { display:flex; align-items:center; gap:8px; -webkit-app-region:no-drag; flex-shrink:0; }
+.titlebar-center { flex:1; display:flex; align-items:center; justify-content:center; }
+.app-title { display:flex; align-items:center; gap:6px; }
+.app-name { font-size:12px; font-weight:600; color:var(--text); letter-spacing:.3px; }
.app-edition {
- font-size:10px; font-weight:600; color:var(--accent);
- background:var(--accent-subtle); padding:1px 6px;
+ font-size:9px; font-weight:600; color:var(--accent);
+ background:var(--accent-subtle); padding:1px 5px;
border-radius:var(--radius-sm); letter-spacing:.5px;
}
-.sys-status { display:flex; align-items:center; gap:6px; font-size:12px; color:var(--text-sec); }
+.sys-status { display:flex; align-items:center; gap:6px; font-size:11px; color:var(--text-dim); }
.status-led {
- width:8px; height:8px; border-radius:50%;
+ width:6px; height:6px; border-radius:50%;
background:var(--green); box-shadow:0 0 6px var(--green);
animation:pulse 2.5s ease-in-out infinite;
}
@keyframes pulse{0%,100%{opacity:1}50%{opacity:.4}}
+/* Window control buttons (Win11 style) */
+.titlebar-controls {
+ display:flex; align-items:stretch;
+ height:38px; flex-shrink:0;
+ -webkit-app-region:no-drag;
+}
+.win-btn {
+ width:46px; height:38px;
+ display:flex; align-items:center; justify-content:center;
+ background:transparent; border:none;
+ color:var(--text-sec); cursor:pointer;
+ transition:background .1s ease;
+ font-family:inherit;
+}
+.win-btn:hover { background:rgba(255,255,255,0.06); color:var(--text); }
+.win-btn:active { background:rgba(255,255,255,0.04); }
+.win-close:hover { background:#c42b1c; color:white; }
+.win-close:active { background:#b52a1c; }
+
/* ---- Toolbar (Win11 Tabs / NavigationView) ---- */
.toolbar {
display:flex; gap:2px; padding:6px 12px;