This commit is contained in:
Joshua Fuhs 2012-06-29 22:20:15 -04:00
parent 0f5f77b7cb
commit fcc058b397
2 changed files with 172 additions and 43 deletions

View file

@ -237,7 +237,7 @@ Manager_logViewLayout() {
} }
Manager_logWindowInfo( w ) { Manager_logWindowInfo( w ) {
Local v, wndId, isWinFocus, isBugnActive, isFloating, isHidden, isDecorated, isResponsive, wndTitle, wndProc, wndClass, wndStyle, wndX, wndY, wndW, wndH, detect_state Local v, wndId, isWinFocus, isBugnActive, isFloating, isHidden, isDecorated, isResponsive, isGhost, wndTitle, wndProc, wndClass, wndStyle, wndX, wndY, wndW, wndH, detect_state
detect_state := A_DetectHiddenWindows detect_state := A_DetectHiddenWindows
DetectHiddenWindows, On DetectHiddenWindows, On
@ -269,19 +269,25 @@ Manager_logWindowInfo( w ) {
WinGet, wndStyle, Style, ahk_id %w% WinGet, wndStyle, Style, ahk_id %w%
WinGetPos, wndX, wndY, wndW, wndH, ahk_id %w% WinGetPos, wndX, wndY, wndW, wndH, ahk_id %w%
If Manager_isGhost(w)
isGhost := "*"
Else
isGhost := " "
DetectHiddenWindows, %detect_state% DetectHiddenWindows, %detect_state%
; Intentionally don't detect hidden windows here to see what Manager_hungTest does ; Intentionally don't detect hidden windows here to see what Manager_hungTest does
If Manager_hungTest(w) If Manager_isHung(w)
isResponsive := " " isResponsive := " "
Else Else
isResponsive := "*" isResponsive := "*"
Log_bare(w . "`t" . isHidden . " " isWinFocus . " " . isBugnActive . " " . isFloating . " " . isDecorated . " " . isResponsive . " " . Manager_#%w%_monitor . "`t" . Manager_#%w%_tags . "`t" . wndX . "`t" . wndY . "`t" . wndW . "`t" . wndH . "`t" . wndStyle . "`t" . wndProc . " / " . wndClass . " / " . wndTitle) Log_bare(w . "`t" . isHidden . " " isWinFocus . " " . isBugnActive . " " . isFloating . " " . isDecorated . " " . isResponsive . " " . isGhost . " " . Manager_#%w%_monitor . "`t" . Manager_#%w%_tags . "`t" . wndX . "`t" . wndY . "`t" . wndW . "`t" . wndH . "`t" . wndStyle . "`t" . wndProc . " / " . wndClass . " / " . wndTitle)
} }
Manager_logHeader() { Manager_logHeader() {
Log_bare( "ID`t`tH W A F D R M`tTags`tX`tY`tW`tH`tStyle`t`tProc / Class / Title") Log_bare( "ID`t`tH W A F D R G M`tTags`tX`tY`tW`tH`tStyle`t`tProc / Class / Title")
} }
Manager_logViewWindowList() { Manager_logViewWindowList() {
@ -321,6 +327,7 @@ Manager_logHelp() {
Log_bare(" F - Floating") Log_bare(" F - Floating")
Log_bare(" D - Decorated") Log_bare(" D - Decorated")
Log_bare(" R - Responsive") Log_bare(" R - Responsive")
Log_bare(" G - Ghost")
Log_bare(" M - Monitor") Log_bare(" M - Monitor")
Log_bare(" Tags - Bit-mask of the views in which the window is active") Log_bare(" Tags - Bit-mask of the views in which the window is active")
Log_bare(" X - Windows X position") Log_bare(" X - Windows X position")
@ -360,21 +367,44 @@ Manager_loop(index, increment, lowerBound, upperBound) {
; pv - Preferred view ; pv - Preferred view
; wndId - Window to add to the manager. ; wndId - Window to add to the manager.
Manager_manage(pm, pv, wndId) { Manager_manage(pm, pv, wndId) {
Local a, c0, hideTitle, i, isDecorated, isFloating, isManaged, l, m, n, replace, search, tags Local a, c0, hideTitle, i, isDecorated, isFloating, isManaged, l, m, n, replace, search, tags, body
Local wndControlList0, wndId0, wndIds, wndX, wndY, wndWidth, wndHeight, wndProcessName Local wndControlList0, wndId0, wndIds, wndX, wndY, wndWidth, wndHeight, wndProcessName
If Not InStr(Manager_allWndIds, wndId ";") If Not InStr(Manager_allWndIds, wndId ";")
Manager_allWndIds .= wndId ";" Manager_allWndIds .= wndId ";"
Manager_applyRules(wndId, isManaged, m, tags, isFloating, isDecorated, hideTitle)
If (m = 0) body := 0
m := pm If Manager_isGhost( wndId ) {
If (m < 0) Log_dbg_msg(2, "A window has given up the ghost (Ghost wndId: " . wndId . ")")
m := 1 ; Ghosts need special attention.
If (m > Manager_monitorCount) ; If the specified monitor is out of scope, set it to the max. monitor. ; Say a quick prayer and try to reattach it to its body.
m := Manager_monitorCount body := Manager_findHung( wndId )
If (tags = 0) If body {
tags := 1 << (pv - 1) isManaged := InStr(Manager_managedWndIds, body ";")
m := Manager_#%body%_monitor
tags := Manager_#%body%_tags
isDecorated := Manager_#%body%_isDecorated
isFloating := Manager_#%body%_isFloating
hideTitle := InStr(Bar_hideTitleWndIds, body ";")
}
Else {
Log_dbg_msg(1, "No body could be found for ghost wndId: " . wndId)
}
}
; Apply rules if the window is either a normal window or a ghost without a body.
If ( body = 0 ) {
Manager_applyRules(wndId, isManaged, m, tags, isFloating, isDecorated, hideTitle)
If (m = 0)
m := pm
If (m < 0)
m := 1
If (m > Manager_monitorCount) ; If the specified monitor is out of scope, set it to the max. monitor.
m := Manager_monitorCount
If (tags = 0)
tags := 1 << (pv - 1)
}
WinGet, wndProcessName, ProcessName, ahk_id %wndId% WinGet, wndProcessName, ProcessName, ahk_id %wndId%
If (wndProcessName = "chrome.exe") { If (wndProcessName = "chrome.exe") {
@ -395,7 +425,13 @@ Manager_manage(pm, pv, wndId) {
Loop, % Config_viewCount Loop, % Config_viewCount
If (Manager_#%wndId%_tags & 1 << A_Index - 1) { If (Manager_#%wndId%_tags & 1 << A_Index - 1) {
View_addWnd(m, A_Index, wndId) If (body) {
; Try to position near the body.
View_ghostWnd(m, A_Index, body, wndId)
}
Else {
View_addWnd(m, A_Index, wndId)
}
} }
If Not Config_showBorder If Not Config_showBorder
@ -456,19 +492,48 @@ HSHELL_WINDOWDESTROYED := 2
HSHELL_WINDOWACTIVATED := 4 HSHELL_WINDOWACTIVATED := 4
; At least title change. ; At least title change.
HSHELL_REDRAW := 6 HSHELL_REDRAW := 6
; The following two are seen when a hung window recovers.
; lParam notes the ghost process
HSHELL_WINDOWREPLACED := 13
; lParam notes the recovered process
;14
; Full-screen app activated? Root-privileged window activated? ; Full-screen app activated? Root-privileged window activated?
HSHELL_RUDEAPPACTIVATED := 32772 HSHELL_RUDEAPPACTIVATED := 32772
; When a window is signalling an application update. ; When a window is signalling an application update.
WINDOW_NOTICE := 32774 WINDOW_NOTICE := 32774
;
; Reliable messages and their meanings (note that any message may be missed if bug.n is hung):
; 1 - Window shown (shown ID)
; 2 - Window destroyed or hidden, same message for both (destroyed or hidden ID)
; 4 - Window activated via mouse, alt+tab, or hotkey (sometimes 32772, but always one of them)
; 6 - Window title change (ID of redrawn window)
; 13 - Hung window recovers and replaces ghost window (ghost window ID is provided)
; 14 - Hung window recovered (ID of previously hung window)
; 32772 - Window activated via mouse, alt+tab, or hotkey (sometimes 4, but always one of them)
; 32774 - Window is flashing due to some event, one message for each flash
;
; Indications of:
; New windows - cmd/shell may be starting a new window on message 6
; Win+e indicates a new window with message 6 as long as the button
; presses are below a certain frequency.
; Message 1 may indicate a new window started from Windows Explorer
; There doesn't seem to be a reliable way to get all application starts.
; Closed windows - 13 always indicates closed ghost window
; 2 always indicates closed standard window
; Focus change - 4 or 32772 always catch this
; Window event - 6 indicates when title changes which can be used
; in the case of some applications, 32774 works for others
;
Manager_onShellMessage(wParam, lParam) { Manager_onShellMessage(wParam, lParam) {
Local a, isChanged, aWndClass, aWndHeight, aWndId, aWndTitle, aWndWidth, aWndX, aWndY, m, t, wndClass, wndId, wndIds, wndPName, wndTitle, x, y Local a, isChanged, aWndClass, aWndHeight, aWndId, aWndTitle, aWndWidth, aWndX, aWndY, m, t, wndClass, wndId, wndIds, wndPName, wndTitle, x, y
Log_dbg_msg(2, "Manager_onShellMessage(wParam: " . wParam . ", lParam: " . lParam)
SetFormat, Integer, hex SetFormat, Integer, hex
lParam := lParam+0 lParam := lParam+0
SetFormat, Integer, d SetFormat, Integer, d
Log_dbg_msg(2, "Manager_onShellMessage( wParam: " . wParam . ", lParam: " . lParam . " )")
WinGetClass, wndClass, ahk_id %lParam% WinGetClass, wndClass, ahk_id %lParam%
WinGetTitle, wndTitle, ahk_id %lParam% WinGetTitle, wndTitle, ahk_id %lParam%
WinGet, wndPName, ProcessName, ahk_id %lParam% WinGet, wndPName, ProcessName, ahk_id %lParam%
@ -484,6 +549,15 @@ Manager_onShellMessage(wParam, lParam) {
Bar_updateTitle() Bar_updateTitle()
} }
If ( wParam = HSHELL_WINDOWREPLACED ) {
; This shouldn't need a redraw because the window was supposedly replaced.
Manager_unmanage(lParam)
}
If ( wParam = 14 ) {
; Window recovered from being hung. Maybe force a redraw.
}
If (wParam = 1 Or wParam = 2 Or wParam = 4 Or wParam = 6 Or wParam = 32772) And lParam And Not Manager_hideShow And Not Manager_focus { If (wParam = 1 Or wParam = 2 Or wParam = 4 Or wParam = 6 Or wParam = 32772) And lParam And Not Manager_hideShow And Not Manager_focus {
If Not (wParam = 4 Or wParam = 32772) If Not (wParam = 4 Or wParam = 32772)
If Not wndClass And Not (wParam = 2) { If Not wndClass And Not (wParam = 2) {
@ -513,8 +587,6 @@ Manager_onShellMessage(wParam, lParam) {
If wndIds { If wndIds {
If (Config_onActiveHiddenWnds = "view") { If (Config_onActiveHiddenWnds = "view") {
; Grab the first of such windows and make it visible.
; All others get forgotten (until the next round?)
wndId := SubStr(wndIds, 1, InStr(wndIds, ";") - 1) wndId := SubStr(wndIds, 1, InStr(wndIds, ";") - 1)
Loop, % Config_viewCount Loop, % Config_viewCount
If (Manager_#%wndId%_tags & 1 << A_Index - 1) { If (Manager_#%wndId%_tags & 1 << A_Index - 1) {
@ -646,8 +718,11 @@ Manager_sync(ByRef wndIds = "") {
flag := Manager_manage(Manager_aMonitor, Monitor_#%Manager_aMonitor%_aView_#1, wndId%A_Index%) flag := Manager_manage(Manager_aMonitor, Monitor_#%Manager_aMonitor%_aView_#1, wndId%A_Index%)
If flag If flag
a := flag a := flag
} Else } Else If Not Manager_isHung(wndId%A_Index%) {
; This is a window that is already managed but was brought into focus by something. Maybe it
; would be useful to do something with it.
wndIds .= wndId%A_Index% ";" wndIds .= wndId%A_Index% ";"
}
} }
visibleWndIds := visibleWndIds wndId%A_Index% ";" visibleWndIds := visibleWndIds wndId%A_Index% ";"
} }
@ -738,7 +813,7 @@ Manager_unmanage(wndId) {
} }
Manager_winActivate(wndId) { Manager_winActivate(wndId) {
Local wndHeight, wndWidth, wndX, wndY Local wndHeight, wndWidth, wndX, wndY, newWnd
If Config_mouseFollowsFocus { If Config_mouseFollowsFocus {
If wndId { If wndId {
@ -747,16 +822,23 @@ Manager_winActivate(wndId) {
} Else } Else
DllCall("SetCursorPos", "Int", Round(Monitor_#%Manager_aMonitor%_x + Monitor_#%Manager_aMonitor%_width / 2), "Int", Round(Monitor_#%Manager_aMonitor%_y + Monitor_#%Manager_aMonitor%_height / 2)) DllCall("SetCursorPos", "Int", Round(Monitor_#%Manager_aMonitor%_x + Monitor_#%Manager_aMonitor%_width / 2), "Int", Round(Monitor_#%Manager_aMonitor%_y + Monitor_#%Manager_aMonitor%_height / 2))
} }
If Manager_hungTest(wndId) If Manager_isHung(wndId) {
Log_msg("Manager_winActivate: Potentially hung window " . wndId) Log_dbg_msg(2, "Manager_winActivate: Potentially hung window " . wndId)
Else Return 1
}
Else {
WinActivate, ahk_id %wndId% WinActivate, ahk_id %wndId%
WinGet, newWin, ID, A
If (wndId != newWin)
Return 1
}
Bar_updateTitle() Bar_updateTitle()
Return 0
} }
Manager_winMove(wndId, x, y, width, height) { Manager_winMove(wndId, x, y, width, height) {
If Manager_hungTest(wndId) { If Manager_isHung(wndId) {
Log_msg("Manager_winMove: Potentially hung window " . wndId) Log_dbg_msg(2, "Manager_winMove: Potentially hung window " . wndId)
Return 1 Return 1
} }
Else Else
@ -765,7 +847,7 @@ Manager_winMove(wndId, x, y, width, height) {
WM_EXITSIZEMOVE = 0x0232 WM_EXITSIZEMOVE = 0x0232
SendMessage, WM_ENTERSIZEMOVE, , , , ahk_id %wndId% SendMessage, WM_ENTERSIZEMOVE, , , , ahk_id %wndId%
If ErrorLevel { If ErrorLevel {
Log_msg("Manager_winMove: Potentially hung window " . wndId) Log_dbg_msg(2, "Manager_winMove: Potentially hung window " . wndId)
Return 1 Return 1
} }
Else { Else {
@ -776,8 +858,8 @@ Manager_winMove(wndId, x, y, width, height) {
Manager_winHide(wndId) { Manager_winHide(wndId) {
If Manager_hungTest(wndId) { If Manager_isHung(wndId) {
Log_msg("Manager_winHide: Potentially hung window " . wndId) Log_dbg_msg(2, "Manager_winHide: Potentially hung window " . wndId)
Return 1 Return 1
} }
Else { Else {
@ -788,8 +870,8 @@ Manager_winHide(wndId) {
Manager_winShow(wndId) { Manager_winShow(wndId) {
If Manager_hungTest(wndId) { If Manager_isHung(wndId) {
Log_msg("Manager_winShow: Potentially hung window " . wndId) Log_dbg_msg(2, "Manager_winShow: Potentially hung window " . wndId)
Return 1 Return 1
} }
Else { Else {
@ -800,8 +882,8 @@ Manager_winShow(wndId) {
Manager_winClose(wndId) { Manager_winClose(wndId) {
If Manager_hungTest(wndId) { If Manager_isHung(wndId) {
Log_msg("Manager_winClose: Potentially hung window " . wndId) Log_dbg_msg(2, "Manager_winClose: Potentially hung window " . wndId)
Return 1 Return 1
} }
Else { Else {
@ -812,8 +894,8 @@ Manager_winClose(wndId) {
Manager_winSet(type, value, wndId) { Manager_winSet(type, value, wndId) {
If Manager_hungTest(wndId) { If Manager_isHung(wndId) {
Log_msg("Manager_winSet: Potentially hung window " . wndId) Log_dbg_msg(2, "Manager_winSet: Potentially hung window " . wndId)
Return 1 Return 1
} }
Else { Else {
@ -824,7 +906,7 @@ Manager_winSet(type, value, wndId) {
; 0 - Not hung ; 0 - Not hung
; 1 - Hung ; 1 - Hung
Manager_hungTest(wndId) { Manager_isHung(wndId) {
Local result, detect_setting, WM_NULL Local result, detect_setting, WM_NULL
WM_NULL := 0 WM_NULL := 0
detect_setting := A_DetectHiddenWindows detect_setting := A_DetectHiddenWindows
@ -837,4 +919,38 @@ Manager_hungTest(wndId) {
Return 1 Return 1
Else Else
Return 0 Return 0
}
; Given a ghost window, try to find its body.
; This is only known to work on Windows 7
Manager_findHung( ghostWnd ) {
Local expectedTitle, expectedX, expectedY, expectedW, expectedH, wndTitle, wndX, wndY, wndW, wndH, wndIds
;Log_dbg_msg(3, "Manager_findHung(" . ghostWnd . ")")
WinGetTitle, expectedTitle, ahk_id %ghostWnd%
StringReplace, expectedTitle, expectedTitle, " (Not Responding)", ""
WinGetPos, expectedX, expectedY, expectedW, expectedH, ahk_id %ghostWnd%
SetTitleMatchMode, 2
WinGet, wndIds, List, %expectedTitle%
Loop, % wndIds {
If (A_Index = ghostWnd)
Continue
WinGetPos, wndX, wndY, wndW, wndH, % "ahk_id" wndIDs%A_Index%
If (wndX = expectedX) And (wndY = expectedY) And (wndW = expectedW) And (wndH = expectedH)
Return wndIds%A_Index%
}
Return 0
}
Manager_isGhost(wndId) {
Local wndClass, wndProc
WinGet, wndProc, ProcessName, ahk_id %wndId%
WinGetClass, wndClass, ahk_id %wndId%
If (wndProc = "dwm.exe") And (wndClass = "Ghost")
Return 1
Else
Return 0
} }

View file

@ -36,7 +36,7 @@ View_init(m, v) {
} }
View_activateWindow(d) { View_activateWindow(d) {
Local aWndId, i, j, v, wndId, wndId0, wndIds, success, direction Local aWndId, i, j, v, wndId, wndId0, wndIds, failure, direction
Log_dbg_msg(1, "View_activateWindow(" . d . ")") Log_dbg_msg(1, "View_activateWindow(" . d . ")")
@ -51,6 +51,8 @@ View_activateWindow(d) {
StringSplit, wndId, wndIds, `; StringSplit, wndId, wndIds, `;
Log_dbg_bare(2, "wndId count: " . wndId0) Log_dbg_bare(2, "wndId count: " . wndId0)
If (wndId0 > 1) { If (wndId0 > 1) {
If Manager_#%aWndId%_isFloating
Manager_winSet("Bottom", "", aWndId)
Loop, % wndId0 Loop, % wndId0
If (wndId%A_Index% = aWndId) { If (wndId%A_Index% = aWndId) {
i := A_Index i := A_Index
@ -66,14 +68,17 @@ View_activateWindow(d) {
Log_dbg_bare(2, "Next wndId index: " . j) Log_dbg_bare(2, "Next wndId index: " . j)
wndId := wndId%j% wndId := wndId%j%
Manager_winSet("AlwaysOnTop", "On", wndId) Manager_winSet("AlwaysOnTop", "On", wndId)
success := Manager_winSet("AlwaysOnTop", "Off", wndId) Manager_winSet("AlwaysOnTop", "Off", wndId)
If (success = 0) ; This is a lot of extra work in case there are hung windows on the screen.
; We still want to be able to cycle through them.
failure := Manager_winActivate(wndId)
If Not failure {
Break Break
}
j := Manager_loop(j, direction, 1, wndId0) j := Manager_loop(j, direction, 1, wndId0)
} }
If Manager_#%aWndId%_isFloating
Manager_winSet("Bottom", "", aWndId)
Manager_winActivate(wndId)
} }
} }
@ -115,6 +120,14 @@ View_addWnd(m, v, wndId) {
View_#%m%_#%v%_wndIds := wndId ";" View_#%m%_#%v%_wndIds View_#%m%_#%v%_wndIds := wndId ";" View_#%m%_#%v%_wndIds
} }
View_ghostWnd(m, v, bodyWndId, ghostWndId) {
Local search, replace
search := bodyWndId ";"
replace := search ghostWndId ";"
StringReplace, View_#%m%_#%v%_wndIds, View_#%m%_#%v%_wndIds, %search%, %replace%
}
; Remove a window from the view in question. ; Remove a window from the view in question.
View_delWnd(m, v, wndId) { View_delWnd(m, v, wndId) {
StringReplace, View_#%m%_#%v%_wndIds, View_#%m%_#%v%_wndIds, %wndId%`;, StringReplace, View_#%m%_#%v%_wndIds, View_#%m%_#%v%_wndIds, %wndId%`;,
@ -140,7 +153,7 @@ View_getTiledWndIds(m, v, ByRef tiledWndIds) {
StringTrimRight, wndIds, View_#%m%_#%v%_wndIds, 1 StringTrimRight, wndIds, View_#%m%_#%v%_wndIds, 1
Loop, PARSE, wndIds, `; Loop, PARSE, wndIds, `;
{ {
If Not Manager_#%A_LoopField%_isFloating And WinExist("ahk_id " A_LoopField) { If Not Manager_#%A_LoopField%_isFloating And WinExist("ahk_id " A_LoopField) and Not Manager_isHung(A_LoopField) {
n += 1 n += 1
tiledWndIds .= A_LoopField ";" tiledWndIds .= A_LoopField ";"
} }