Below are three ways of approaching the task of
"attaching an overlay window to another window". The easiest and most straightforward way of implementing this is simply endlessly polling for the dimensions of your main window and readjusting the overlay window accordingly. In essence, all examples hinge on this method, though there are some subtle differences. While an infinite loop might yield the smoothest results, babysitting one in a larger script might prove challenging, not to mention the spike in CPU usage if not managed properly.
Code: Select all
#NoEnv
SetBatchLines -1
SetWinDelay -1
Run % "notepad", , , pid
WinWait % "ahk_pid" pid
hNotepad := WinExist("ahk_pid" pid)
Gui New, % "+HwndhGui +Owner" hNotepad
Gui Show, w100 h100
Loop
{
if !WinExist("ahk_id" hNotepad)
ExitApp
WinGetPos x, y, , , % "ahk_id" hNotepad
WinMove % "ahk_id " hGui, , x, y
}
The second approach utilizes timers. Again same as the loops, they are relatively simple to setup, though not necessarily to manage. Resource usage is lower than that of loops, however, you might find the overlay window lagging behind when the main window is subject to both extremely jerky and gentle motions.
Code: Select all
#NoEnv
SetBatchLines -1
SetWinDelay -1
Run % "notepad", , , pid
WinWait % "ahk_pid" pid
hNotepad := WinExist("ahk_pid" pid)
Gui New, % "+HwndhGui +Owner" hNotepad
Gui Show, w100 h100
SetTimer MoveWindow, 1
MoveWindow:
if !WinExist("ahk_id" hNotepad)
ExitApp
WinGetPos x, y, , , % "ahk_id" hNotepad
WinMove % "ahk_id " hGui, , x, y
Return
Lastly, a
WinEventHook, though arguably requiring more effort upfront to setup, is the most resource efficient and borders the loop in terms of responsiveness. Error handling and unhooking omitted for brevity in this example.
Code: Select all
#NoEnv
SetBatchLines -1
SetWinDelay -1
Run % "notepad", , , pid
WinWait % "ahk_pid" pid
hNotepad := WinExist("ahk_pid" pid)
DllCall("SetWinEventHook"
, "UInt", 0x800B ; EVENT_OBJECT_LOCATIONCHANGE
, "UInt", 0x800B ; EVENT_OBJECT_LOCATIONCHANGE
, "Ptr", 0
, "Ptr", RegisterCallback("WinEventProc")
, "UInt", pid
, "UInt", 0
, "UInt", 0x0001 ; WINEVENT_OUTOFCONTEXT | WINEVENT_SKIPOWNTHREAD
, "Ptr")
Gui New, % "+HwndhGui +Owner" hNotepad
Gui Show, w100 h100
WinWaitClose % "ahk_pid" pid
ExitApp
WinEventProc(hWinEventHook, event, hwnd, idObject, idChild, idEventThread, dwmsEventTime) {
global hNotepad, hGui
if (hwnd = hNotepad)
{
WinGetPos x, y, , , % "ahk_id" hNotepad
WinMove % "ahk_id " hGui, , x, y
}
}
At any rate, whichever method you decide to go for, don't forget to adjust
A_WinDelay and
A_BatchLines accordingly. I have disabled them altogether in all of the above examples.