;; Window management ----------------------------------------------------------

;; -> init

GroupAdd, WindowsExplorer, ahk_class CabinetWClass
GroupAdd, WindowsExplorer, ahk_class ExploreWClass

Gui, FakeWindow:+LastFound +Owner +Disabled -Caption
Gui, +hwndFakeWindowHwnd
y := A_ScreenHeight - 100
Gui, FakeWindow:Show, x0 y%y% AutoSize NA, FakeWindow

;; -> body

#q::WinSet, Bottom,, A
#a::WinSet, Top,, A
#t::WinSet, AlwaysOnTop, Toggle, A
#y::
WinGet, t, Transparent, A
if (t = OFF)
  WinSet, Transparent, 180, A
else
  WinSet, Transparent, OFF, A
return
#b::WinSet, Bottom,, A
#!m::WinMove, A,, 0, 0

#z::WinMinimize, A
#v::
WinGet, mm, MinMax, A
if (mm = 1)
  WinRestore, A
else
  WinMaximize, A
return

#x:: ; minimize all except current
WinGet, hwnd, id, A
WinGet, s, Style, ahk_id %hwnd%
WinSet, Style, -0x20000, ahk_id %hwnd% ; WS_MINIMIZEBOX
WinMinimizeAll
Sleep, 50
WinSet, Style, % s, ahk_id %hwnd%
WinActivate, ahk_id %hwnd%
WinGet, mm, MinMax, ahk_id %hwnd%
if (mm = -1)
  WinRestore, ahk_id %hwnd%
return

#c:: ; minimize last window
SendInput, !{Tab}
Sleep, 50
WinMinimize, A
return


;; -> body

/*
#!m:: ; fix minimization bug (?)
WinGet, hwnd, id, A
parent := DllCall("GetParent", "uint", hwnd)
WinGet, progman, id, Program Manager ahk_class Progman
DllCall("SetParent", "uint", hwnd, "uint", progman)
DllCall("SetParent", "uint", hwnd, "uint", parent)
return
*/

/*
#c::
GWL_HWNDPARENT := -8
MouseGetPos,,, hwnd
WindowDisabled := hwnd
return
*/

/*
$!Tab::
HandleAltTab:
if (WindowDisabled)
  WinSet, Disable,, ahk_id %WindowDisabled%
SendInput, {LAlt Down}{Tab}
Hotkey, $!Tab, HandleAltTab, Off
Hotkey, $!+Tab, HandleAltShiftTab, Off
while (GetKeyState("LAlt", "P") and not esc := GetKeyState("Esc", "P"))
  Sleep, 1
if (esc)
  SendInput, {Esc}
SendInput, {LAlt Up}
Hotkey, $!Tab, HandleAltTab, On
Hotkey, $!+Tab, HandleAltShiftTab, On
WinSet, Enable,, ahk_id %WindowDisabled%
return

$!+Tab::
HandleAltShiftTab:
if (WindowDisabled)
  WinSet, Disable,, ahk_id %WindowDisabled%
if (WinActive("A") = WindowDisabled)
  SendInput, {LAlt Down}{LShift Down}{Tab}{LShift Up}{Tab}
else
  SendInput, {LAlt Down}{LShift Down}{Tab}{LShift Up}
Hotkey, $!Tab, HandleAltTab, Off
Hotkey, $!+Tab, HandleAltShiftTab, Off
while (GetKeyState("LAlt", "P") and not esc := GetKeyState("Esc", "P"))
  Sleep, 1
if (esc)
  SendInput, {Esc}
SendInput, {LAlt Up}
Hotkey, $!Tab, HandleAltTab, On
Hotkey, $!+Tab, HandleAltShiftTab, On
WinSet, Enable,, ahk_id %WindowDisabled%
return
*/

^RButton::
hwndp := WinActive("A")
MouseGetPos,,, hwnd
if (hwnd = hwndp)
{
  WinSet, Top,, A
  return
}
DllCall("SetForegroundWindow", "UInt", hwnd)
WinSet, AlwaysOnTop, On, ahk_id %hwndp%
WinSet, AlwaysOnTop, Off, ahk_id %hwndp%
return

;; Fix inconsistent z-order after minimization via taskbar --------------------

;; -> library

WindowsWindowMessage(wParam, lParam)
{
  static HSHELL_GETMINRECT := 5
  ; The active window is 0 during minimization (if animated)
  if (wParam = HSHELL_GETMINRECT and WinActive("A") = 0)
  {
    hwnd := NumGet(lParam + 0)
    WinWaitNotActive, ahk_id 0
    Sleep, 20
    InsertAfter(hwnd, "BOTTOM")
  }
}

;; -> init

WindowMessageHandlers.Push("WindowsWindowMessage")

;; Change the position of a given window in the z-order -----------------------

;; -> library

InsertAfter(hwnd = "", position = "BOTTOM")
{
  static SWP_NOSIZE := 0x0001
  static SWP_NOMOVE := 0x0002
  static SWP_ASYNCWINDOWPOS := 0x4000
  static HWND_BOTTOM := 1
  static HWND_NOTOPMOST := -2
  static HWND_TOP := 0
  static HWND_TOPMOST := -1
  if (hwnd = "")
    WinGet, hwnd, id, A
  DllCall("SetWindowPos"
  , "UInt", hwnd
  , "UInt", HWND_%position%
  , "Int", 0
  , "Int", 0
  , "Int", 0
  , "Int", 0
  , "UInt", SWP_NOSIZE | SWP_NOMOVE | SWP_ASYNCWINDOWPOS) 
}