Last active
February 15, 2025 18:28
-
-
Save mariusrueve/c6b1af96c1d5b5792c150e52c8500288 to your computer and use it in GitHub Desktop.
AHK Active Window Rounded Border (Win11 24H2)
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
; ================================ | |
; Active Window Rounded Border Overlay | |
; For Windows 11 (24H2) | |
; Runs continuously in the background. | |
; Adjust the border color, thickness, and corner roundness below. | |
; ================================ | |
#NoEnv | |
#SingleInstance, Force | |
#Persistent | |
SetBatchLines, -1 | |
SendMode, Input | |
SetWorkingDir, %A_ScriptDir% | |
; ------------- User Settings ------------- | |
borderColor := 0x357EC7 ; Hex color (0xRRGGBB) | |
borderThickness:= 4 ; Border thickness in pixels | |
cornerRadius := 12 ; Corner roundness in pixels | |
updateInterval := 20 ; How often (ms) to check/update active window | |
; ------------- End Settings ------------- | |
; --- Create one overlay GUI that will be re‑shaped to form a hollow border --- | |
Gui, Overlay: +AlwaysOnTop +ToolWindow -Caption +E0x20 ; +E0x20 makes it click‑through. | |
; Set the background color of the overlay (it will only be visible in its “region”) | |
; Convert the numeric color (0xRRGGBB) to a 6‑digit hex string (without “0x”) | |
bgColor := Format("{:06X}", borderColor & 0xFFFFFF) | |
Gui, Overlay: Color, %bgColor% | |
Gui, Overlay: Show, NoActivate, ActiveWindowBorder | |
hOverlay := WinExist("ActiveWindowBorder") | |
; Add layered style so that SetWindowRgn is applied smoothly. | |
WinSet, ExStyle, +0x80000, ahk_id %hOverlay% | |
; Global variables to track the last active window’s position & size. | |
global prevHWND := "", prevAx, prevAy, prevAw, prevAh | |
; Set up a timer to update the overlay border. | |
SetTimer, UpdateBorder, %updateInterval% | |
Return | |
; ------------------------------- | |
; UpdateBorder: Positions/resizes and re‑shapes the overlay border | |
; ------------------------------- | |
UpdateBorder: | |
; Get the currently active window. | |
WinGet, activeHWND, ID, A | |
; (Ignore the overlay itself if it somehow becomes active) | |
if (activeHWND = hOverlay) | |
{ | |
WinGet, activeHWND, ID, A | |
} | |
; If no active window found or if the window is minimized, hide the overlay. | |
if (!activeHWND) { | |
Gui, Overlay: Hide | |
Return | |
} | |
WinGet, style, Style, ahk_id %activeHWND% | |
if (style & 0x20000000) { ; WS_MINIMIZE flag | |
Gui, Overlay: Hide | |
Return | |
} | |
; --- Get the window's true bounds using DWM (works better for Windows 11) --- | |
VarSetCapacity(rect, 16, 0) | |
if (DllCall("dwmapi\DwmGetWindowAttribute", "ptr", activeHWND, "uint", 9, "ptr", &rect, "uint", 16) = 0) | |
{ | |
ax := NumGet(rect, 0, "int") | |
ay := NumGet(rect, 4, "int") | |
right := NumGet(rect, 8, "int") | |
bottom := NumGet(rect, 12, "int") | |
aw := right - ax | |
ah := bottom - ay | |
} | |
else { | |
; Fallback in case DWM fails. | |
WinGetPos, ax, ay, aw, ah, ahk_id %activeHWND% | |
} | |
; Only update if something changed. | |
if (activeHWND = prevHWND && ax = prevAx && ay = prevAy && aw = prevAw && ah = prevAh) | |
Return | |
prevHWND := activeHWND, prevAx := ax, prevAy := ay, prevAw := aw, prevAh := ah | |
; Calculate overlay position and size. | |
; The overlay is expanded by borderThickness on all sides so that its inner edge aligns | |
; exactly with the active window’s border. | |
ox := ax - borderThickness | |
oy := ay - borderThickness | |
ow := aw + (2 * borderThickness) | |
oh := ah + (2 * borderThickness) | |
; (Re)position the overlay window. | |
Gui, Overlay: Show, x%ox% y%oy% w%ow% h%oh% NoActivate | |
; ----- Build a hollow (donut‑shaped) region with rounded corners ----- | |
; Outer region: a rounded rectangle covering the full overlay. | |
hRgnOuter := DllCall("CreateRoundRectRgn", "Int", 0, "Int", 0, "Int", ow, "Int", oh, "Int", cornerRadius*2, "Int", cornerRadius*2, "Ptr") | |
; Inner region: same shape, inset by borderThickness. | |
innerCorner := (cornerRadius > borderThickness) ? (cornerRadius - borderThickness) : 0 | |
hRgnInner := DllCall("CreateRoundRectRgn", "Int", borderThickness, "Int", borderThickness, "Int", ow - borderThickness, "Int", oh - borderThickness, "Int", innerCorner*2, "Int", innerCorner*2, "Ptr") | |
; Create a region for the border by subtracting the inner region from the outer. | |
; First, create an empty region. | |
hRgnBorder := DllCall("CreateRectRgn", "Int", 0, "Int", 0, "Int", 0, "Int", 0, "Ptr") | |
; RGN_DIFF = 4: hRgnBorder = hRgnOuter - hRgnInner. | |
DllCall("CombineRgn", "Ptr", hRgnBorder, "Ptr", hRgnOuter, "Ptr", hRgnInner, "Int", 4) | |
; Apply the computed region to the overlay window. | |
; (After calling SetWindowRgn, the system owns hRgnBorder, so DO NOT free it.) | |
DllCall("SetWindowRgn", "Ptr", hOverlay, "Ptr", hRgnBorder, "Int", True) | |
; Clean up the temporary region handles. | |
DllCall("DeleteObject", "Ptr", hRgnOuter) | |
DllCall("DeleteObject", "Ptr", hRgnInner) | |
Return |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
This is what it looks like with a different border color