Pre-push merge

This commit is contained in:
Joshua Fuhs 2012-12-03 22:43:16 -05:00
commit b2272226e0
6 changed files with 548 additions and 169 deletions

View file

@ -90,8 +90,12 @@ Config_init()
;; Configuration management ;; Configuration management
Config_autoSaveSession := False Config_autoSaveSession := False
; @todo: To be removed?
If Not Config_filePath ; The file path, to which the configuration and session is saved. This target directory must be writable by the user (%A_ScriptDir% is the diretory, in which "Main.ahk" or the executable of bug.n is saved).
Config_filePath := A_ScriptDir "\Config.ini"
Config_maintenanceInterval := 5000
Config_restore("Config") Config_restoreConfig(Config_filePath)
Config_getSystemSettings() Config_getSystemSettings()
Config_initColors() Config_initColors()
Loop, % Config_layoutCount Loop, % Config_layoutCount
@ -241,24 +245,40 @@ Config_redirectHotkey(key)
} }
} }
Config_restore(section, m = 0) Config_restoreLayout(filename, m)
{
Local i, var, val
If Not FileExist(filename)
Return
Loop, READ, %filename%
If (SubStr(A_LoopReadLine, 1, 10 + StrLen(m)) = "Monitor_#" m "_" Or SubStr(A_LoopReadLine, 1, 8 + StrLen(m)) = "View_#" m "_#") {
i := InStr(A_LoopReadLine, "=")
var := SubStr(A_LoopReadLine, 1, i - 1)
val := SubStr(A_LoopReadLine, i + 1)
%var% := val
}
}
Config_restoreConfig(filename)
{ {
Local cmd, i, key, type, val, var Local cmd, i, key, type, val, var
If FileExist(Config_filePath) If Not FileExist(filename)
{ Return
If (section = "Config")
{ Loop, READ, %filename%
Loop, READ, %Config_filePath%
{
If (SubStr(A_LoopReadLine, 1, 7) = "Config_") If (SubStr(A_LoopReadLine, 1, 7) = "Config_")
{ {
;Log_msg("Processing line: " . A_LoopReadLine)
i := InStr(A_LoopReadLine, "=") i := InStr(A_LoopReadLine, "=")
var := SubStr(A_LoopReadLine, 1, i - 1) var := SubStr(A_LoopReadLine, 1, i - 1)
val := SubStr(A_LoopReadLine, i + 1) val := SubStr(A_LoopReadLine, i + 1)
type := SubStr(var, 1, 13) type := SubStr(var, 1, 13)
If (type = "Config_hotkey") If (type = "Config_hotkey")
{ {
Debug_logMessage("Processing configured hotkey: " . A_LoopReadLine, 0)
i := InStr(val, "::") i := InStr(val, "::")
key := SubStr(val, 1, i - 1) key := SubStr(val, 1, i - 1)
cmd := SubStr(val, i + 2) cmd := SubStr(val, i + 2)
@ -266,6 +286,7 @@ Config_restore(section, m = 0)
Hotkey, %key%, Off Hotkey, %key%, Off
Else Else
{ {
Debug_logMessage(" Hotkey: " . key . " -> " . cmd, 0)
Config_hotkeyCount += 1 Config_hotkeyCount += 1
Config_hotkey_#%Config_hotkeyCount%_key := key Config_hotkey_#%Config_hotkeyCount%_key := key
Config_hotkey_#%Config_hotkeyCount%_command := cmd Config_hotkey_#%Config_hotkeyCount%_command := cmd
@ -287,38 +308,29 @@ Config_restore(section, m = 0)
%var% := val %var% := val
} }
} }
}
Else If (section = "Monitor") Config_UI_saveSession()
{ {
Loop, READ, %Config_filePath% Config_saveSession(Config_filePath, Config_filePath)
{
If (SubStr(A_LoopReadLine, 1, 10 + StrLen(m)) = "Monitor_#" m "_" Or SubStr(A_LoopReadLine, 1, 8 + StrLen(m)) = "View_#" m "_#")
{
i := InStr(A_LoopReadLine, "=")
var := SubStr(A_LoopReadLine, 1, i - 1)
val := SubStr(A_LoopReadLine, i + 1)
%var% := val
}
}
}
}
} }
Config_saveSession() Config_saveSession(original, target)
{ {
Local m, text Local m, text, tmpfilename
text := ";; bug.n -- tiling window management`n;; @version " VERSION "`n`n" tmpfilename := target . ".tmp"
If FileExist(Config_filePath) FileDelete, %tmpfilename%
text := "; bug.n - tiling window management`n; @version " VERSION "`n`n"
If FileExist(original)
{ {
Loop, READ, %Config_filePath% Loop, READ, %original%
{ {
If (SubStr(A_LoopReadLine, 1, 7) = "Config_") If (SubStr(A_LoopReadLine, 1, 7) = "Config_")
text .= A_LoopReadLine "`n" text .= A_LoopReadLine "`n"
} }
text .= "`n" text .= "`n"
} }
FileDelete, %Config_filePath%
Loop, % Manager_monitorCount Loop, % Manager_monitorCount
{ {
@ -352,7 +364,16 @@ Config_saveSession()
} }
} }
FileAppend, %text%, %Config_filePath% ;; The FileMove below is an all-or-nothing replacement of the file.
;; We don't want to leave this half-finished.
FileAppend, %text%, %tmpfilename%
If ErrorLevel
{
If FileExist(tmpfilename)
FileDelete, %tmpfilename%
}
Else
FileMove, %tmpfilename%, %target%, 1
} }
;; Key definitions ;; Key definitions
@ -443,7 +464,7 @@ Config_saveSession()
;; Administration ;; Administration
#^e::Run, edit %Config_filePath% #^e::Run, edit %Config_filePath%
#^s::Config_saveSession() #^s::Config_UI_saveSession()
#^r::Main_reload() #^r::Main_reload()
#^+r::Reload #^+r::Reload
#^q::ExitApp #^q::ExitApp

View file

@ -27,7 +27,6 @@ Debug_initLog(filename, level = 0, truncateFile = True)
If truncateFile If truncateFile
If FileExist(Debug_logFilename) If FileExist(Debug_logFilename)
FileDelete, %Debug_logFilename% FileDelete, %Debug_logFilename%
Debug_logMessage("Log initialized.", 0)
} }
Debug_logHelp() Debug_logHelp()

View file

@ -36,13 +36,18 @@ SetWinDelay, 10
Main_dataDir = %1% Main_dataDir = %1%
Else Else
Main_dataDir = %A_ScriptDir% Main_dataDir = %A_ScriptDir%
Debug_initLog(Main_dataDir "\log.txt", 0, False)
Config_filePath := Main_dataDir "\config.ini" Main_setup()
Debug_initLog(Main_appDir "\log.txt", 0, False)
Debug_logMessage("====== Initializing ======")
Config_filePath := Main_appDir "\Config.ini"
Config_init() Config_init()
Menu, Tray, Tip, %NAME% %VERSION% Menu, Tray, Tip, %NAME% %VERSION%
IfExist %A_ScriptDir%\logo.ico IfExist %A_ScriptDir%\images\kfm.ico
Menu, Tray, Icon, %A_ScriptDir%\logo.ico Menu, Tray, Icon, %A_ScriptDir%\images\kfm.ico
Menu, Tray, NoStandard Menu, Tray, NoStandard
Menu, Tray, Add, Toggle bar, Main_toggleBar Menu, Tray, Add, Toggle bar, Main_toggleBar
Menu, Tray, Add, Help, Main_help Menu, Tray, Add, Help, Main_help
@ -51,16 +56,17 @@ SetWinDelay, 10
ResourceMonitor_init() ResourceMonitor_init()
Manager_init() Manager_init()
Debug_logMessage("====== Running ======", 0)
Return ;; end of the auto-execute section Return ;; end of the auto-execute section
;; Function & label definitions ;; Function & label definitions
Main_cleanup: Main_cleanup:
Debug_logMessage("Cleaning up", 0) Debug_logMessage("====== Cleaning up ======", 0)
If Config_autoSaveSession If Config_autoSaveSession
Config_saveSession() Config_saveSession(Config_filePath, Config_filePath)
Manager_cleanup() Manager_cleanup()
ResourceMonitor_cleanup() ResourceMonitor_cleanup()
Debug_logMessage("Exiting bug.n", 0) Debug_logMessage("====== Exiting bug.n ======", 0)
ExitApp ExitApp
Main_evalCommand(command) Main_evalCommand(command)
@ -121,28 +127,93 @@ Main_quit:
ExitApp ExitApp
Return Return
; Create bug.n-specific directories.
Main_makeDir(dirName) {
IfNotExist, %dirName%
{
FileCreateDir, %dirName%
If ErrorLevel
{
MsgBox, Error (%ErrorLevel%) when creating '%dirName%'. Aborting.
ExitApp
}
}
Else
{
FileGetAttrib, attrib, %dirName%
IfNotInString, attrib, D
{
MsgBox, The file path '%dirName%' already exists and is not a directory. Aborting.
ExitApp
}
}
}
Main_setup() {
Local winAppDir
Main_appDir := ""
Main_logFile := ""
Main_dataDir := ""
Main_autoLayout := ""
Main_autoWindowState := ""
EnvGet, winAppDir, APPDATA
Main_appDir := winAppDir . "\bug.n"
Main_logFile := Main_appDir . "\bugn_log.txt"
Main_dataDir := Main_appDir . "\data"
Main_autoLayout := Main_dataDir . "\_Layout.ini"
Main_autoWindowState := Main_dataDir . "\_WindowState.ini"
Main_makeDir(Main_appDir)
Main_makeDir(Main_dataDir)
}
Main_reload() Main_reload()
{ {
Local i, m Local i, ncm, ncmSize
Manager_resetWindowBorder()
;; Reset border color, padding and witdh.
If Config_selBorderColor
DllCall("SetSysColors", "Int", 1, "Int*", 10, "UInt*", Manager_normBorderColor)
If (Config_borderWidth > 0) Or (Config_borderPadding >= 0 And A_OSVersion = WIN_VISTA)
{
ncmSize := VarSetCapacity(ncm, 4 * (A_OSVersion = WIN_VISTA ? 11 : 10) + 5 * (28 + 32 * (A_IsUnicode ? 2 : 1)), 0)
NumPut(ncmSize, ncm, 0, "UInt")
DllCall("SystemParametersInfo", "UInt", 0x0029, "UInt", ncmSize, "UInt", &ncm, "UInt", 0)
If (Config_borderWidth > 0)
NumPut(Manager_borderWidth, ncm, 4, "Int")
If (Config_borderPadding >= 0 And A_OSVersion = WIN_VISTA)
NumPut(Manager_borderPadding, ncm, 40 + 5 * (28 + 32 * (A_IsUnicode ? 2 : 1)), "Int")
DllCall("SystemParametersInfo", "UInt", 0x002a, "UInt", ncmSize, "UInt", &ncm, "UInt", 0)
}
DllCall("Shell32.dll\SHAppBarMessage", "UInt", (ABM_REMOVE := 0x1), "UInt", &Bar_appBarData) DllCall("Shell32.dll\SHAppBarMessage", "UInt", (ABM_REMOVE := 0x1), "UInt", &Bar_appBarData)
;; SKAN: Crazy Scripting : Quick Launcher for Portable Apps (http://www.autohotkey.com/forum/topic22398.html) ;; SKAN: Crazy Scripting : Quick Launcher for Portable Apps (http://www.autohotkey.com/forum/topic22398.html)
Config_init() Config_init()
Manager_setWindowBorder() ; Windows UI
If Config_selBorderColor {
SetFormat, Integer, hex
Manager_normBorderColor := DllCall("GetSysColor", "Int", 10)
SetFormat, Integer, d
DllCall("SetSysColors", "Int", 1, "Int*", 10, "UInt*", Config_selBorderColor)
}
If (Config_borderWidth > 0) Or (Config_borderPadding >= 0 And A_OSVersion = WIN_VISTA) {
ncmSize := VarSetCapacity(ncm, 4 * (A_OSVersion = WIN_VISTA ? 11 : 10) + 5 * (28 + 32 * (A_IsUnicode ? 2 : 1)), 0)
NumPut(ncmSize, ncm, 0, "UInt")
DllCall("SystemParametersInfo", "UInt", 0x0029, "UInt", ncmSize, "UInt", &ncm, "UInt", 0)
Manager_borderWidth := NumGet(ncm, 4, "Int")
Manager_borderPadding := NumGet(ncm, 40 + 5 * (28 + 32 * (A_IsUnicode ? 2 : 1)), "Int")
If (Config_borderWidth > 0)
NumPut(Config_borderWidth, ncm, 4, "Int")
If (Config_borderPadding >= 0 And A_OSVersion = WIN_VISTA)
NumPut(Config_borderPadding, ncm, 40 + 5 * (28 + 32 * (A_IsUnicode ? 2 : 1)), "Int")
DllCall("SystemParametersInfo", "UInt", 0x002a, "UInt", ncmSize, "UInt", &ncm, "UInt", 0)
}
Bar_getHeight() Bar_getHeight()
SysGet, m, MonitorCount
If Not (m = Manager_monitorCount)
{
MsgBox, 48, bug.n: Reload, The number of monitors changed. You should restart bug.n (by default with the hotkey Win+Ctrl+Shift+R).
If (m < Manager_monitorCount)
{
Manager_monitorCount := m
Manager_aMonitor := 1
}
}
Loop, % Manager_monitorCount Loop, % Manager_monitorCount
{ {
Monitor_getWorkArea(A_Index) Monitor_getWorkArea(A_Index)

View file

@ -24,6 +24,10 @@ Manager_init()
Manager_setWindowBorder() Manager_setWindowBorder()
Bar_getHeight() Bar_getHeight()
; axes, dimensions, percentage, flipped, gapWidth
Manager_layoutDirty := 0
; New/closed windows, active changed,
Manager_windowsDirty := 0
Manager_aMonitor := 1 Manager_aMonitor := 1
Manager_taskBarMonitor := "" Manager_taskBarMonitor := ""
Manager_showTaskBar := True Manager_showTaskBar := True
@ -52,9 +56,41 @@ Manager_init()
} }
Manager_registerShellHook() Manager_registerShellHook()
SetTimer, Manager_maintenance_label, %Config_maintenanceInterval%
SetTimer, Bar_loop, %Config_readinInterval% SetTimer, Bar_loop, %Config_readinInterval%
} }
; Asynchronous management of various WM properties.
; We want to make sure that we can recover the layout and windows in the event of
; unexpected problems.
; Periodically check for changes to these things and save them somewhere (not over
; user-defined files).
Manager_maintenance_label:
Manager_maintenance()
Return
Manager_maintenance() {
Local tmp
;Debug_logMessage("Manager_maintenance", 2)
; @todo: Check for changes to the layout.
;If Manager_layoutDirty {
;Debug_logMessage("Saving layout state: " . Main_autoLayout, 0)
Config_saveSession(Config_filaPath, Main_autoLayout)
Manager_layoutDirty := 0
;}
; @todo: Manager_sync?
; @todo: Check for changes to windows.
;If Manager_windowsDirty {
;Debug_logMessage("Saving window state: " . Main_autoWindowState, 0)
Manager_saveWindowState(Main_autoWindowState, Manager_monitorCount, Config_viewCount)
Manager_windowsDirty := 0
;}
}
Manager_activateMonitor(d) Manager_activateMonitor(d)
{ {
Local aView, aWndHeight, aWndId, aWndWidth, aWndX, aWndY, v, wndId Local aView, aWndHeight, aWndId, aWndWidth, aWndX, aWndY, v, wndId
@ -304,6 +340,45 @@ Manager_loop(index, increment, lowerBound, upperBound)
Return, index Return, index
} }
Manager__setWinProperties(wndId, isManaged, m, tags, isDecorated, isFloating, hideTitle )
{
Local a
If Not Instr(Manager_allWndIds, wndId ";")
Manager_allWndIds .= wndId ";"
If (isManaged)
{
Manager_managedWndIds .= wndId ";"
Monitor_moveWindow(m, wndId)
Manager_#%wndId%_tags := tags
Manager_#%wndId%_isDecorated := isDecorated
Manager_#%wndId%_isFloating := isFloating
If Not Config_showBorder
Manager_winSet("Style", "-0x40000", wndId)
If Not Manager_#%wndId%_isDecorated
Manager_winSet("Style", "-0xC00000", wndId)
a := Manager_#%wndId%_tags & (1 << (Monitor_#%m%_aView_#1 - 1))
If a
{
Manager_aMonitor := m
Manager_winActivate(wndId)
}
Else
{
Manager_hideShow := True
Manager_winHide(wndId)
Manager_hideShow := False
}
}
If hideTitle
Bar_hideTitleWndIds .= wndId . ";"
Return, a
}
;; Accept a window to be added to the system for management. ;; Accept a window to be added to the system for management.
;; Provide a monitor and view preference, but don't override the config. ;; Provide a monitor and view preference, but don't override the config.
Manager_manage(preferredMonitor, preferredView, wndId) Manager_manage(preferredMonitor, preferredView, wndId)
@ -311,8 +386,9 @@ Manager_manage(preferredMonitor, preferredView, wndId)
Local a, action, c0, hideTitle, i, isDecorated, isFloating, isManaged, l, m, n, replace, search, tags, body Local a, action, 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 ";") ; Manage any window only once.
Manager_allWndIds .= wndId ";" If InStr(Manager_managedWndIds, wndId ";")
Return
body := 0 body := 0
If Manager_isGhost(wndId) If Manager_isGhost(wndId)
@ -335,7 +411,7 @@ Manager_manage(preferredMonitor, preferredView, wndId)
} }
} }
;; Apply rules, if the window is either a normal window or a ghost without a body. ;; Apply rules if the window is either a normal window or a ghost without a body.
If (body = 0) If (body = 0)
{ {
Manager_applyRules(wndId, isManaged, m, tags, isFloating, isDecorated, hideTitle, action) Manager_applyRules(wndId, isManaged, m, tags, isFloating, isDecorated, hideTitle, action)
@ -349,6 +425,7 @@ Manager_manage(preferredMonitor, preferredView, wndId)
tags := 1 << (preferredView - 1) tags := 1 << (preferredView - 1)
} }
; @todo: Remove this application-specific code.
WinGet, wndProcessName, ProcessName, ahk_id %wndId% WinGet, wndProcessName, ProcessName, ahk_id %wndId%
If (wndProcessName = "chrome.exe") If (wndProcessName = "chrome.exe")
{ {
@ -358,24 +435,14 @@ Manager_manage(preferredMonitor, preferredView, wndId)
isManaged := False isManaged := False
} }
If isManaged a := Manager__setWinProperties( wndId, isManaged, m, tags, isDecorated, isFloating, hideTitle)
{
If (action = "Close" Or action = "Maximize")
Manager_win%action%(wndId)
Monitor_moveWindow(m, wndId)
Manager_managedWndIds .= wndId ";"
Manager_#%wndId%_monitor := m
Manager_#%wndId%_tags := tags
Manager_#%wndId%_isDecorated := isDecorated
Manager_#%wndId%_isFloating := isFloating
; Do view placement.
If isManaged {
Loop, % Config_viewCount Loop, % Config_viewCount
{ If (Manager_#%wndId%_tags & (1 << (A_Index - 1))) {
If (Manager_#%wndId%_tags & 1 << A_Index - 1) If (body) {
{ ; Try to position near the body.
If (body)
{ ;; Try to position near the body.
View_ghostWindow(m, A_Index, body, wndId) View_ghostWindow(m, A_Index, body, wndId)
} }
Else Else
@ -383,30 +450,6 @@ Manager_manage(preferredMonitor, preferredView, wndId)
} }
} }
If Not Config_showBorder
Manager_winSet("Style", "-0x40000", wndId)
If Not Manager_#%wndId%_isDecorated
Manager_winSet("Style", "-0xC00000", wndId)
a := Manager_#%wndId%_tags & 1 << Monitor_#%m%_aView_#1 - 1
If a
{
Manager_aMonitor := m
Manager_winActivate(wndId)
}
Else
{
Manager_hideShow := True
Manager_winHide(wndId)
Manager_hideShow := False
}
}
If hideTitle And Not InStr(Bar_hideTitleWndIds, wndId)
Bar_hideTitleWndIds .= wndId . ";"
Else If Not hideTitle
StringReplace, Bar_hideTitleWndIds, Bar_hideTitleWndIds, %wndId%`;,
Return, a Return, a
} }
@ -441,14 +484,21 @@ Manager_moveWindow()
} }
HSHELL_WINDOWCREATED := 1 HSHELL_WINDOWCREATED := 1
HSHELL_WINDOWDESTROYED := 2 ;; Seems to get sent sometimes when windows are deactivated. ;; Seems to get sent sometimes when windows are deactivated.
HSHELL_WINDOWACTIVATED := 4 ;; At least title change. HSHELL_WINDOWDESTROYED := 2
HSHELL_WINDOWACTIVATED := 4
;; At least title change.
HSHELL_REDRAW := 6 HSHELL_REDRAW := 6
;; The following two are seen when a hung window recovers. ;; The following two are seen when a hung window recovers.
HSHELL_WINDOWREPLACED := 13 ;; lParam notes the ghost process ;; lParam notes the ghost process
;14 ;; lParam notes the recovered process HSHELL_WINDOWREPLACED := 13
HSHELL_RUDEAPPACTIVATED := 32772 ;; Full-screen app activated? Root-privileged window activated? ;; lParam notes the recovered process
WINDOW_NOTICE := 32774 ;; When a window is signalling an application update. ;;14
;; Full-screen app activated? Root-privileged window activated?
HSHELL_RUDEAPPACTIVATED := 32772
;; When a window is signalling an application update.
WINDOW_NOTICE := 32774
/* /*
Reliable messages and their meanings (note that any message may be missed if bug.n is hung): Reliable messages and their meanings (note that any message may be missed if bug.n is hung):
1 - Window shown (shown ID) 1 - Window shown (shown ID)
@ -463,7 +513,8 @@ WINDOW_NOTICE := 32774 ;; When a window is signalling an applicatio
Indications of: Indications of:
New windows New windows
cmd/shell may be starting a new window on message 6 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. 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. 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. There doesn't seem to be a reliable way to get all application starts.
Closed windows Closed windows
@ -474,10 +525,10 @@ WINDOW_NOTICE := 32774 ;; When a window is signalling an applicatio
Window event Window event
6 indicates when title changes which can be used 6 indicates when title changes which can be used
in the case of some applications, 32774 works for others in the case of some applications, 32774 works for others
Windows events can't always be caught.
*/ */
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 aWndClass, aWndHeight, aWndId, aWndTitle, aWndWidth, aWndX, aWndY, isChanged, m, t, wndClass, wndId, wndIds, wndPName, wndTitle, x, y
SetFormat, Integer, hex SetFormat, Integer, hex
lParam := lParam+0 lParam := lParam+0
@ -492,19 +543,15 @@ Manager_onShellMessage(wParam, lParam)
WinGet, aWndId, ID, A WinGet, aWndId, ID, A
WinGetClass, aWndClass, ahk_id %aWndId% WinGetClass, aWndClass, ahk_id %aWndId%
WinGetTitle, aWndTitle, ahk_id %aWndId% WinGetTitle, aWndTitle, ahk_id %aWndId%
If ((wParam = 4 Or wParam = 32772) And lParam = 0 And aWndClass = "Progman" And aWndTitle = "Program Manager") If ((wParam = 4 Or wParam = 32772) And lParam = 0 And aWndClass = "Progman" And aWndTitle = "Program Manager") {
{
If (Manager_monitorCount > 1)
{
MouseGetPos, x, y MouseGetPos, x, y
m := Monitor_get(x, y) m := Monitor_get(x, y)
If m If m
Manager_aMonitor := m Manager_aMonitor := m
}
Bar_updateTitle() Bar_updateTitle()
} }
If (wParam = 13) If (wParam = HSHELL_WINDOWREPLACED)
{ ;; This shouldn't need a redraw because the window was supposedly replaced. { ;; This shouldn't need a redraw because the window was supposedly replaced.
Manager_unmanage(lParam) Manager_unmanage(lParam)
} }
@ -512,6 +559,13 @@ Manager_onShellMessage(wParam, lParam)
; { ;; Window recovered from being hung. Maybe force a redraw. ; { ;; Window recovered from being hung. Maybe force a redraw.
; } ; }
;; @todo: There are two problems with the use of Manager_hideShow:
;; 1) If Manager_hideShow is set when we hit this block, we won't take some actions that should eventually be taken.
;; This _may_ explain why some windows never get picked up when spamming Win+e
;; 2) There is a race condition between the time that Manager_hideShow is checked and any other action which we are
;; trying to protect against. If another process (hotkey) enters a hideShow block after Manager_hideShow has
;; been checked here, bad things could happen. I've personally observed that windows may be permanently hidden.
;; Look into the use of AHK synchronization primitives.
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 wndClass And Not (wParam = 2 Or wParam = 4 Or wParam = 32772) If Not wndClass And Not (wParam = 2 Or wParam = 4 Or wParam = 32772)
@ -543,7 +597,7 @@ Manager_onShellMessage(wParam, lParam)
If wndIds If wndIds
{ ;; If there are new (unrecognized) windows, which are hidden ... { ;; If there are new (unrecognized) windows, which are hidden ...
If (Config_onActiveHiddenWnds = "view") If (Config_onActiveHiddenWnds = "view")
{ ;; ... change the view, to shw the first hidden window { ;; ... change the view to show the first hidden window
wndId := SubStr(wndIds, 1, InStr(wndIds, ";") - 1) wndId := SubStr(wndIds, 1, InStr(wndIds, ";") - 1)
Loop, % Config_viewCount Loop, % Config_viewCount
{ {
@ -727,6 +781,8 @@ Manager_sizeWindow()
SendMessage, WM_SYSCOMMAND, SC_SIZE, , , ahk_id %aWndId% SendMessage, WM_SYSCOMMAND, SC_SIZE, , , ahk_id %aWndId%
} }
;; @todo: This constantly tries to re-add windows that are never going to be manageable.
;; Manager_manage should probably ignore all windows that are already in Manager_allWndIds.
Manager_sync(ByRef wndIds = "") Manager_sync(ByRef wndIds = "")
{ {
Local a, flag, shownWndIds, v, visibleWndIds, wndId Local a, flag, shownWndIds, v, visibleWndIds, wndId
@ -758,7 +814,8 @@ Manager_sync(ByRef wndIds = "")
visibleWndIds := visibleWndIds wndId%A_Index% ";" visibleWndIds := visibleWndIds wndId%A_Index% ";"
} }
;; Check, if a window, that is known to be visible, is actually not visible ;; @todo-future: Find out why this unmanage code exists and if it's still needed.
;; check, if a window, that is known to be visible, is actually not visible
StringTrimRight, shownWndIds, shownWndIds, 1 StringTrimRight, shownWndIds, shownWndIds, 1
Loop, PARSE, shownWndIds, `; Loop, PARSE, shownWndIds, `;
{ {
@ -773,11 +830,217 @@ Manager_sync(ByRef wndIds = "")
Return, a Return, a
} }
;; No windows are known to the system yet.
;; Try to do something smart with the initial layout. Manager_saveWindowState(filename, nm, nv)
{
Local allWndId, allWndIds, process, title, text, monitor, wndId, view, isManaged, isTitleHidden
text := "; bug.n - tiling window management`n; @version " VERSION "`n`n"
tmpfname := filename . ".tmp"
FileDelete, %tmpfname%
; Dump window ID and process name. If these two don't match an existing process, we won't try
; to recover that window.
StringTrimRight, allWndIds, Manager_allWndIds, 1
StringSplit, allWndId, allWndIds, `;
DetectHiddenWindows, On
Loop, % allWndId0
{
wndId := allWndId%A_Index%
WinGet, process, ProcessName, ahk_id %wndId%
; Include title for informative reasons.
WinGetTitle, title, ahk_id %wndId%
; wndId;process;Tags;Floating;Decorated;HideTitle;Managed;Title
If ( InStr(Manager_managedWndIds, wndId . ";") > 0 )
{
isManaged := 1
}
else
{
isManaged := 0
}
If ( InStr(Bar_hideTitleWndIds, wndId . ";") > 0 )
isTitleHidden := 1
Else
isTitleHidden := 0
text .= "Window " . wndId . ";" . process . ";" . Manager_#%wndId%_monitor . ";" . Manager_#%wndId%_tags . ";" . Manager_#%wndId%_isFloating . ";" . Manager_#%wndId%_isDecorated . ";" . isTitleHidden . ";" . isManaged . ";" . title . "`n"
}
DetectHiddenWindows, Off
text .= "`n"
; @todo: Dump window arrangements on every view. If some views or monitors have disappeared, leave their
; corresponding windows alone.
Loop, % nm
{
monitor := A_Index
Loop, % nv
{
view := A_Index
; @todo: Dump all view window lists
text .= "View_#" . monitor . "_#" . view . "_wndIds=" . View_#%monitor%_#%view%_wndIds . "`n"
}
}
FileAppend, %text%, %tmpfname%
If ErrorLevel
{
If FileExist(tmpfname)
FileDelete, %tmpfname%
}
Else
FileMove, %tmpfname%, %filename%, 1
}
;; Restore previously saved window state.
;; If the state is completely different, this function won't do much. However, if restoring from a crash
;; or simply restarting bug.n, it should completely recover the window state.
Manager__restoreWindowState(filename)
{
Local vidx, widx, i, j, m, v, candidate_set, view_set, excluded_view_set, view_m0, view_v0, view_list0, wnds0, items0, wndProc, view_var, isManaged, isFloating, isDecorated, hideTitle
If Not FileExist(filename)
Return
widx := 1
vidx := 1
view_set := ""
excluded_view_set := ""
;; Read all interesting things from the file.
Loop, READ, %filename%
{
If (SubStr(A_LoopReadLine, 1, 5) = "View_")
{
i := InStr(A_LoopReadLine, "#")
j := InStr(A_LoopReadLine, "_", false, i)
m := SubStr(A_LoopReadLine, i + 1, j - i - 1)
i := InStr(A_LoopReadLine, "#", false, j)
j := InStr(A_LoopReadLine, "_", false, i)
v := SubStr(A_LoopReadLine, i + 1, j - i - 1)
i := InStr(A_LoopReadLine, "=", j + 1)
If (m <= Manager_monitorCount) And ( v <= Config_viewCount )
{
view_list%vidx% := SubStr(A_LoopReadLine, i + 1)
view_m%vidx% := m
view_v%vidx% := v
view_set := view_set . view_list%vidx%
vidx := vidx + 1
}
Else
{
excluded_view_set := excluded_view_set . view_list%vidx%
Debug_logMessage("View (" . m . ", " . v . ") is no longer available (" . vidx . ")", 0)
}
}
Else If (SubStr(A_LoopReadLine, 1, 7) = "Window ") {
wnds%widx% := SubStr(A_LoopReadLine, 8)
widx := widx + 1
}
}
;Debug_logMessage("view_set: " . view_set, 1)
;Debug_logMessage("excluded_view_set: " . excluded_view_set, 1)
candidate_set := ""
; Scan through all defined windows. Create a candidate set of windows based on whether the properties of existing windows match.
Loop, % (widx - 1)
{
StringSplit, items, wnds%A_Index%, `;
If ( items0 < 9 )
{
Debug_logMessage("Window '" . wnds%A_Index% . "' could not be processed due to parse error", 0)
Continue
}
i := 1
i := items%i%
j := 2
DetectHiddenWindows, On
WinGet, wndProc, ProcessName, ahk_id %i%
DetectHiddenWindows, Off
If Not ( items%j% = wndProc )
{
Debug_logMessage("Window ahk_id " . i . " process '" . wndProc . "' doesn't match expected '" . items%j% . "', forgetting this window", 0)
Continue
}
j := 8
isManaged := items%j%
; If Managed
If ( items%j% )
{
If ( InStr(view_set, i) = 0)
{
If ( InStr(excluded_view_set, i) )
{
Debug_logMessage("Window ahk_id " . i . " is being ignored because it no longer belongs to an active view", 0)
}
Else
{
Debug_logMessage("Window ahk_id " . i . " is being ignored because it doesn't exist in any views", 0)
}
Continue
}
}
; Set up the window.
j := 3
m := items%j%
j := 4
v := items%j%
j := 5
isFloating := items%j%
j := 6
isDecorated := items%j%
j := 7
hideTitle := items%j%
Manager__setWinProperties(i, isManaged, m, v, isDecorated, isFloating, hideTitle )
;Manager_winHide(i)
candidate_set := candidate_set . i . ";"
}
;Debug_logMessage("candidate_set: " . candidate_set, 1)
; Set up all views. Must filter the window list by those from the candidate set.
Loop, % (vidx - 1)
{
StringSplit, items, view_list%A_Index%, `;
view_set := ""
Loop, % items0 - 1
{
If ( InStr(candidate_set, items%A_Index% ) > 0 )
view_set := view_set . items%A_Index% . ";"
}
view_var := "View_#" . view_m%A_Index% . "_#" . view_v%A_Index% . "_wndIds"
%view_var% := view_set
}
}
; No windows are known to the system yet.
; Try to do something smart with the initial layout.
Manager_initial_sync() Manager_initial_sync()
{ {
Local m, wnd, wndH, wndId, wndId0, wndIds, wndW, wndX, wndY Local wndId0, wnd, wndX, wndY, wndW, wndH, x, y, m, len
;; Initialize lists ;; Initialize lists
;; Note that these variables make this function non-reentrant. ;; Note that these variables make this function non-reentrant.
@ -786,7 +1049,11 @@ Manager_initial_sync()
Manager_initial_sync_m#%A_Index%_wndList := "" Manager_initial_sync_m#%A_Index%_wndList := ""
} }
;; Check all visible windows against the known windows ;; Use saved window placement settings to first determine
;; which monitor/view a window should be attached to.
Manager__restoreWindowState(Main_autoWindowState)
;; Check all remaining visible windows against the known windows
WinGet, wndId, List, , , WinGet, wndId, List, , ,
Loop, % wndId Loop, % wndId
{ {
@ -796,12 +1063,14 @@ Manager_initial_sync()
;; Which monitor is it on? ;; Which monitor is it on?
wnd := wndId%A_Index% wnd := wndId%A_Index%
WinGetPos, wndX, wndY, wndW, wndH, ahk_id %wnd% WinGetPos, wndX, wndY, wndW, wndH, ahk_id %wnd%
m := Monitor_get(wndX + wndW/2, wndY + wndH/2)
x := wndX + wndW/2
y := wndY + wndH/2
m := Monitor_get(x, y)
If m > 0 If m > 0
Manager_initial_sync_m#%m%_wndList .= wndId%A_Index% ";" Manager_initial_sync_m#%m%_wndList .= wndId%A_Index% ";"
;; @todo: What percentage of the monitor area is it occupying? (Suggest layout)
;; @todo: What part of the monitor is it on? (Ordering of windows)
} }
Loop, % Manager_monitorCount Loop, % Manager_monitorCount
@ -832,6 +1101,8 @@ Manager_unmanage(wndId)
{ {
Local a Local a
;; Do our best to make sure that any unmanaged windows are left visible.
Manager_winShow(wndId)
a := Manager_#%wndId%_tags & 1 << Monitor_#%Manager_aMonitor%_aView_#1 - 1 a := Manager_#%wndId%_tags & 1 << Monitor_#%Manager_aMonitor%_aView_#1 - 1
Loop, % Config_viewCount Loop, % Config_viewCount
{ {

View file

@ -29,7 +29,7 @@ Monitor_init(m)
{ {
View_init(m, A_Index) View_init(m, A_Index)
} }
Config_restore("Monitor", m) Config_restoreLayout(Main_autoLayout, m)
Monitor_getWorkArea(m) Monitor_getWorkArea(m)
Bar_init(m) Bar_init(m)
} }
@ -209,23 +209,9 @@ Monitor_getWorkArea(m)
Monitor_moveWindow(m, wndId) Monitor_moveWindow(m, wndId)
{ {
Local fX, fY, monitor, wndHeight, wndWidth, wndX, wndY Global
Manager_#%wndId%_monitor := m Manager_#%wndId%_monitor := m
If Manager_#%wndId%_isFloating
{
WinGetPos, wndX, wndY, wndWidth, wndHeight, ahk_id %wndId%
monitor := Monitor_get(wndX+wndWidth/2, wndY+wndHeight/2)
If Not (m = monitor)
{ ;; Move the window to the target monitor and scale it, if it does not fit on the monitor.
fX := Monitor_#%m%_width / Monitor_#%monitor%_width
fY := Monitor_#%m%_height / Monitor_#%monitor%_height
If (wndX-Monitor_#%monitor%_x+wndWidth > Monitor_#%m%_width) Or (wndY-Monitor_#%monitor%_y+wndHeight > Monitor_#%m%_height)
Manager_winMove(wndId, Monitor_#%m%_x+fX*(wndX-Monitor_#%monitor%_x), Monitor_#%m%_y+fY*(wndY-Monitor_#%monitor%_y), fX*wndWidth, fY*wndHeight)
Else
Manager_winMove(wndId, Monitor_#%m%_x+(wndX-Monitor_#%monitor%_x), Monitor_#%m%_y+(wndY-Monitor_#%monitor%_y), wndWidth, wndHeight)
}
}
} }
Monitor_setWindowTag(t) Monitor_setWindowTag(t)

31
test/UserInputTiming.ahk Normal file
View file

@ -0,0 +1,31 @@
/*
* Measure the minimum delay between button presses.
*
* Minimum observed delay: 80ms (2012/11/23)
*/
Start_Day:=A_YDay
Last_Time:= (((((((A_YDay - Start_Day) * 24 ) + A_Hour ) * 60) + A_Min) * 60) + A_Sec) * 1000 + A_MSec
Min_Delay:=1000000
MsgBox, ms base: %Last_Time%
Return
r::
Cur_Time := (((((((A_YDay - Start_Day) * 24 ) + A_Hour ) * 60) + A_Min) * 60) + A_Sec) * 1000 + A_MSec
Difference := Cur_Time - Last_Time
If (Difference < Min_Delay)
Min_Delay := Difference
Last_Time := Cur_Time
Return
q::
MsgBox, Min_Delay: %Min_Delay%
ExitApp