2012-12-04 02:52:43 +00:00
/*
bug . n - - tiling window management
2015-01-25 12:07:37 +00:00
Copyright ( c ) 2010 - 2015 Joshua Fuhs , joten
2012-12-05 12:39:51 +00:00
2012-12-04 02:52:43 +00:00
This program is distributed in the hope that it will be useful ,
but WITHOUT ANY WARRANTY ; without even the implied warranty of
2015-01-25 12:07:37 +00:00
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
2012-12-04 02:52:43 +00:00
GNU General Public License for more details .
2012-12-05 12:39:51 +00:00
2015-01-25 12:07:37 +00:00
@license GNU General Public License version 3
. . / LICENSE . md or < http : / / www . gnu . org / licenses / >
2012-12-05 12:39:51 +00:00
2015-01-25 13:04:17 +00:00
@version 9.0 . 0
2012-12-04 02:52:43 +00:00
* /
2012-12-05 12:39:51 +00:00
Manager_init ( )
2012-12-04 02:52:43 +00:00
{
2012-12-05 23:55:38 +00:00
Local doRestore
2013-03-29 22:49:55 +00:00
2015-01-25 19:39:09 +00:00
Manager_setWindowBorders ( )
2012-11-27 03:13:38 +00:00
Bar_getHeight ( )
; axes, dimensions, percentage, flipped, gapWidth
Manager_layoutDirty := 0
2012-12-05 12:39:51 +00:00
; New/closed windows, active changed,
2012-11-27 03:13:38 +00:00
Manager_windowsDirty := 0
Manager_aMonitor := 1
2013-03-29 22:49:55 +00:00
2012-12-05 23:55:38 +00:00
doRestore := 0
If ( Config_autoSaveSession = " ask " )
{
MsgBox , 0x4 , , Would you like to restore an auto - saved session ?
IfMsgBox Yes
doRestore := 1
}
Else If ( Config_autoSaveSession = " auto " )
{
doRestore := 1
}
2013-03-29 22:49:55 +00:00
2012-11-27 03:13:38 +00:00
SysGet , Manager_monitorCount , MonitorCount
Loop , % Manager_monitorCount
2012-12-04 02:52:43 +00:00
{
2012-12-05 23:55:38 +00:00
Monitor_init ( A_Index , doRestore )
2012-12-04 02:52:43 +00:00
}
2012-11-27 03:13:38 +00:00
Bar_initCmdGui ( )
If Not Config_showTaskBar
Monitor_toggleTaskBar ( )
2012-12-05 12:39:51 +00:00
2012-12-04 02:52:43 +00:00
Manager_focus := False
Manager_hideShow := False
Bar_hideTitleWndIds := " "
Manager_allWndIds := " "
Manager_managedWndIds := " "
2012-12-05 23:55:38 +00:00
Manager_initial_sync ( doRestore )
2013-03-29 22:49:55 +00:00
2012-11-27 03:13:38 +00:00
Bar_updateStatus ( )
Bar_updateTitle ( )
2012-12-05 12:39:51 +00:00
Loop , % Manager_monitorCount
2012-12-04 02:52:43 +00:00
{
2012-11-27 03:13:38 +00:00
View_arrange ( A_Index , Monitor_# %A_Index% _aView_#1 )
Bar_updateView ( A_Index , Monitor_# %A_Index% _aView_#1 )
}
2012-12-05 12:39:51 +00:00
2012-11-27 03:13:38 +00:00
Manager_registerShellHook ( )
2015-01-25 21:26:17 +00:00
SetTimer , Manager_doMaintenance , %Config_maintenanceInterval%
2012-11-27 03:13:38 +00:00
SetTimer , Bar_loop , %Config_readinInterval%
2011-07-27 17:43:34 +00:00
}
2015-01-28 19:12:57 +00:00
Manager_activateMonitor ( i , d = 0 ) {
2012-12-04 02:52:43 +00:00
Local aView , aWndHeight , aWndId , aWndWidth , aWndX , aWndY , v , wndId
2012-12-05 12:39:51 +00:00
2015-01-28 19:12:57 +00:00
If ( Manager_monitorCount > 1 ) {
2012-11-27 03:13:38 +00:00
aView := Monitor_# %Manager_aMonitor% _aView_#1
2012-12-04 02:52:43 +00:00
aWndId := View_getActiveWindow ( Manager_aMonitor , aView )
2015-01-28 19:12:57 +00:00
If aWndId {
2012-12-04 02:52:43 +00:00
WinGetPos , aWndX , aWndY , aWndWidth , aWndHeight , ahk_id %aWndId%
If ( Monitor_get ( aWndX + aWndWidth / 2 , aWndY + aWndHeight / 2 ) = Manager_aMonitor )
View_# %Manager_aMonitor% _# %aView% _aWndId := aWndId
2012-11-27 03:13:38 +00:00
}
2012-12-05 12:39:51 +00:00
2014-10-29 17:15:11 +00:00
;; Manually set the active monitor.
2015-01-28 19:12:57 +00:00
If ( i = 0 )
i := Manager_aMonitor
Manager_aMonitor := Manager_loop ( i , d , 1 , Manager_monitorCount )
2012-11-27 03:13:38 +00:00
v := Monitor_# %Manager_aMonitor% _aView_#1
wndId := View_# %Manager_aMonitor% _# %v% _aWndId
2015-01-28 19:12:57 +00:00
If Not ( wndId And WinExist ( " ahk_id " wndId ) ) {
2012-11-27 03:13:38 +00:00
If View_# %Manager_aMonitor% _# %v% _wndIds
2015-01-28 19:12:57 +00:00
wndId := SubStr ( View_# %Manager_aMonitor% _# %v% _wndIds , 1 , InStr ( View_# %Manager_aMonitor% _# %v% _wndIds , " ; " ) - 1 )
2012-11-27 03:13:38 +00:00
Else
wndId := 0
}
2015-01-28 19:12:57 +00:00
Debug_logMessage ( " DEBUG[1] Manager_activateMonitor: Manager_aMonitor: " Manager_aMonitor " , i: " i " , d: " d " , wndId: " wndId , 1 )
2012-11-27 03:13:38 +00:00
Manager_winActivate ( wndId )
}
2012-06-26 16:52:44 +00:00
}
2015-02-01 19:02:08 +00:00
Manager_applyRules ( wndId , ByRef isManaged , ByRef m , ByRef tags , ByRef isFloating , ByRef isDecorated , ByRef hideTitle , ByRef action ) {
2015-02-01 19:10:54 +00:00
Local i , mouseX , mouseY , wndClass , wndHeight , wndTitle , wndWidth , wndX , wndY
2012-12-04 02:52:43 +00:00
Local rule0 , rule1 , rule2 , rule3 , rule4 , rule5 , rule6 , rule7 , rule8 , rule9 , rule10
2012-12-05 12:39:51 +00:00
2012-11-27 03:13:38 +00:00
isManaged := True
m := 0
tags := 0
isFloating := False
isDecorated := False
hideTitle := False
2012-12-04 02:52:43 +00:00
action := " "
2012-12-05 12:39:51 +00:00
2012-11-27 03:13:38 +00:00
WinGetClass , wndClass , ahk_id %wndId%
WinGetTitle , wndTitle , ahk_id %wndId%
WinGetPos , wndX , wndY , wndWidth , wndHeight , ahk_id %wndId%
2015-02-01 19:10:54 +00:00
If ( wndClass Or wndTitle ) And Not ( wndX < - 4999 ) And Not ( wndY < - 4999 ) {
2015-02-01 19:02:08 +00:00
Loop , % Config_ruleCount {
2015-02-01 19:10:54 +00:00
;; The rules are traversed in reverse order.
i := Config_ruleCount - A_Index + 1
StringSplit , rule , Config_rule_# %i% , `;
2015-02-01 19:02:08 +00:00
If RegExMatch ( wndClass . " ; " . wndTitle , rule1 . " ; " . rule2 ) And ( rule3 = " " Or %rule3% ( wndId ) ) {
2012-11-27 03:13:38 +00:00
isManaged := rule4
m := rule5
tags := rule6
isFloating := rule7
isDecorated := rule8
hideTitle := rule9
2012-12-04 02:52:43 +00:00
action := rule10
2015-02-01 19:10:54 +00:00
;; The first matching rule is returned, i. e. the last in the original rder of Config_rule.
Break
2012-11-27 03:13:38 +00:00
}
}
2015-02-05 19:57:59 +00:00
Debug_logMessage ( " DEBUG[6] Manager_applyRules: class: " wndClass " , title: " wndTitle " , wndId: " wndId " , action: " action , 6 )
2015-02-01 19:02:08 +00:00
} Else {
2012-11-27 03:13:38 +00:00
isManaged := False
If wndTitle
hideTitle := True
}
2012-06-28 03:34:19 +00:00
}
2012-12-05 12:39:51 +00:00
Manager_cleanup ( )
2012-11-27 03:13:38 +00:00
{
Local aWndId , m , ncmSize , ncm , wndIds
2012-12-05 12:39:51 +00:00
2012-11-27 03:13:38 +00:00
WinGet , aWndId , ID , A
2012-12-05 12:39:51 +00:00
2015-01-25 19:39:09 +00:00
Manager_restoreWindowBorders ( )
2012-12-05 12:39:51 +00:00
2012-12-04 02:52:43 +00:00
;; Show borders and title bars.
2012-11-27 03:13:38 +00:00
StringTrimRight , wndIds , Manager_managedWndIds , 1
Manager_hideShow := True
Loop , PARSE , wndIds , `;
{
2015-01-25 18:16:30 +00:00
Window_show ( A_LoopField )
2012-11-27 03:13:38 +00:00
If Not Config_showBorder
2015-01-25 18:16:30 +00:00
Window_set ( A_LoopField , " Style " , " +0x40000 " )
Window_set ( A_LoopField , " Style " , " +0xC00000 " )
2012-11-27 03:13:38 +00:00
}
2012-12-05 12:39:51 +00:00
2012-12-04 02:52:43 +00:00
;; Show the task bar.
2012-11-27 03:13:38 +00:00
WinShow , Start ahk_class Button
WinShow , ahk_class Shell_TrayWnd
Manager_hideShow := False
2012-12-05 12:39:51 +00:00
2015-01-25 19:39:09 +00:00
;; Restore window positions and sizes.
2012-12-05 12:39:51 +00:00
Loop , % Manager_monitorCount
2012-11-27 03:13:38 +00:00
{
m := A_Index
Monitor_# %m% _showBar := False
2015-01-31 00:45:36 +00:00
Monitor_# %m% _showTaskBar := True
2012-11-27 03:13:38 +00:00
Monitor_getWorkArea ( m )
2012-12-05 12:39:51 +00:00
Loop , % Config_viewCount
2012-12-04 02:52:43 +00:00
{
2014-03-09 21:45:28 +00:00
View_arrange ( m , A_Index , True )
2012-12-04 02:52:43 +00:00
}
2012-11-27 03:13:38 +00:00
}
2015-01-25 18:16:30 +00:00
Window_set ( aWndId , " AlwaysOnTop " , " On " )
Window_set ( aWndId , " AlwaysOnTop " , " Off " )
2012-12-05 12:39:51 +00:00
2012-11-27 03:13:38 +00:00
DllCall ( " Shell32.dll\SHAppBarMessage " , " UInt " , ( ABM_REMOVE := 0x1 ) , " UInt " , & Bar_appBarData )
2012-12-04 02:52:43 +00:00
;; SKAN: Crazy Scripting : Quick Launcher for Portable Apps (http://www.autohotkey.com/forum/topic22398.html)
2012-06-22 23:56:13 +00:00
}
2015-01-25 17:07:51 +00:00
Manager_closeWindow ( ) {
2015-01-28 18:42:07 +00:00
Local aView , aWndId , wndId0 , wndIds
2015-01-25 17:07:51 +00:00
2012-11-27 03:13:38 +00:00
WinGet , aWndId , ID , A
2015-01-25 17:07:51 +00:00
If Window_isProg ( aWndId ) {
2012-12-05 00:36:38 +00:00
;; Prior to closing, find the next window that should have focus.
;; If there is no such window, choose the bar on the same monitor.
2015-01-25 17:07:51 +00:00
aView := Monitor_# %Manager_aMonitor% _aView_#1
2015-01-28 18:42:07 +00:00
StringTrimRight , wndIds , View_# %Manager_aMonitor% _# %aView% _wndIds , 1
StringSplit , wndId , wndIds , `;
If ( wndId0 > = 2 )
View_activateWindow ( 0 , + 1 )
Else
2012-12-05 00:36:38 +00:00
Manager_winActivate ( 0 )
2015-01-25 18:16:30 +00:00
Window_close ( aWndId )
2012-12-05 00:36:38 +00:00
}
2012-06-22 23:56:13 +00:00
}
2015-01-25 21:26:17 +00:00
; 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_doMaintenance:
Critical
;; @TODO: Manager_sync?
If Not ( Config_autoSaveSession = " off " ) And Not ( Config_autoSaveSession = " False " )
Manager_saveState ( )
Return
2012-12-05 12:39:51 +00:00
Manager_getWindowInfo ( )
2012-11-27 03:13:38 +00:00
{
2015-02-14 12:52:49 +00:00
Local aWndClass , aWndHeight , aWndId , aWndMinMax , aWndPId , aWndPName , aWndStyle , aWndTitle , aWndWidth , aWndX , aWndY , rule , text , v
2012-12-05 12:39:51 +00:00
2012-11-27 03:13:38 +00:00
WinGet , aWndId , ID , A
WinGetClass , aWndClass , ahk_id %aWndId%
WinGetTitle , aWndTitle , ahk_id %aWndId%
2015-02-14 12:52:49 +00:00
WinGet , aWndPName , ProcessName , ahk_id %aWndId%
WinGet , aWndPId , PID , ahk_id %aWndId%
2012-11-27 03:13:38 +00:00
WinGet , aWndStyle , Style , ahk_id %aWndId%
2014-10-02 13:46:12 +00:00
WinGet , aWndMinMax , MinMax , ahk_id %aWndId%
2012-11-27 03:13:38 +00:00
WinGetPos , aWndX , aWndY , aWndWidth , aWndHeight , ahk_id %aWndId%
text := " ID: " aWndId " `n class:`t " aWndClass " `n title:`t " aWndTitle
2015-02-01 19:02:08 +00:00
rule := " Config_rule= " aWndClass " ; " aWndTitle " ; "
2014-10-02 13:46:12 +00:00
If InStr ( Manager_managedWndIds , aWndId " ; " )
rule .= " ;1 "
Else
rule .= " ;0 "
2015-01-25 18:38:10 +00:00
rule .= " ; " Window_# %aWndId% _monitor " ; " Window_# %aWndId% _tags " ; " Window_# %aWndId% _isFloating " ; " Window_# %aWndId% _isDecorated
2014-10-02 13:46:12 +00:00
If InStr ( Bar_hiddenWndIds , aWndId ) {
2012-11-27 03:13:38 +00:00
text .= " (hidden) "
2014-10-02 13:46:12 +00:00
rule .= " ;1; "
} Else
rule .= " ;0; "
If ( aWndMinMax = 1 )
2015-01-25 18:16:30 +00:00
rule .= " maximize "
2015-02-14 12:52:49 +00:00
text .= " `n process:`t " aWndPName " [ " aWndPId " ]`nstyle:`t " aWndStyle " `n metrics:`tx: " aWndX " , y: " aWndY " , width: " aWndWidth " , height: " aWndHeight " `n tags:`t " Window_# %aWndId% _tags
2015-01-25 18:38:10 +00:00
If Window_# %aWndId% _isFloating
2012-11-27 03:13:38 +00:00
text .= " (floating) "
2014-10-02 13:46:12 +00:00
text .= " `n `n " rule
2012-11-27 03:13:38 +00:00
MsgBox , 260 , bug . n : Window Information , % text " `n `n Copy text to clipboard? "
IfMsgBox Yes
Clipboard := text
2012-06-28 03:34:19 +00:00
}
2012-12-05 12:39:51 +00:00
Manager_getWindowList ( )
2012-11-27 03:13:38 +00:00
{
Local text , v , aWndId , wndIds , aWndTitle
2012-12-05 12:39:51 +00:00
2012-11-27 03:13:38 +00:00
v := Monitor_# %Manager_aMonitor% _aView_#1
aWndId := View_# %Manager_aMonitor% _# %v% _aWndId
WinGetTitle , aWndTitle , ahk_id %aWndId%
text := " Active Window`n " aWndId " :`t " aWndTitle
2012-12-05 12:39:51 +00:00
2012-11-27 03:13:38 +00:00
StringTrimRight , wndIds , View_# %Manager_aMonitor% _# %v% _wndIds , 1
text .= " `n `n Window List "
Loop , PARSE , wndIds , `;
{
WinGetTitle , wndTitle , ahk_id %A_LoopField%
text .= " `n " A_LoopField " :`t " wndTitle
}
2012-12-05 12:39:51 +00:00
2012-11-27 03:13:38 +00:00
MsgBox , 260 , bug . n : Window List , % text " `n `n Copy text to clipboard? "
IfMsgBox Yes
Clipboard := text
2012-06-26 16:52:44 +00:00
}
2012-12-05 12:39:51 +00:00
Manager_lockWorkStation ( )
2012-11-27 03:13:38 +00:00
{
Global Config_shellMsgDelay
2012-12-05 12:39:51 +00:00
2012-11-27 03:13:38 +00:00
RegWrite , REG_DWORD , HKEY_CURRENT_USER , Software \Microsoft \Windows \CurrentVersion \Policies \System , DisableLockWorkstation , 0
Sleep , % Config_shellMsgDelay
DllCall ( " LockWorkStation " )
Sleep , % 4 * Config_shellMsgDelay
RegWrite , REG_DWORD , HKEY_CURRENT_USER , Software \Microsoft \Windows \CurrentVersion \Policies \System , DisableLockWorkstation , 1
2012-06-06 19:14:40 +00:00
}
2012-12-04 02:52:43 +00:00
;; Unambiguous: Re-use WIN+L as a hotkey in bug.n (http://www.autohotkey.com/community/viewtopic.php?p=500903&sid=eb3c7a119259b4015ff045ef80b94a81#p500903)
2012-06-06 19:14:40 +00:00
2015-01-28 22:45:58 +00:00
Manager_loop ( index , increment , lowerBound , upperBound ) {
If ( upperBound < = 0 ) Or ( upperBound < lowerBound ) Or ( upperBound = 0 )
Return , 0
numberOfIndexes := upperBound - lowerBound + 1
lowerBoundBasedIndex := index - lowerBound
lowerBoundBasedIndex := Mod ( lowerBoundBasedIndex + increment , numberOfIndexes )
If ( lowerBoundBasedIndex < 0 )
lowerBoundBasedIndex + = numberOfIndexes
Return , lowerBound + lowerBoundBasedIndex
2011-07-27 17:43:34 +00:00
}
2012-12-05 15:08:29 +00:00
Manager__setWinProperties ( wndId , isManaged , m , tags , isDecorated , isFloating , hideTitle , action = " " )
2012-11-27 03:13:38 +00:00
{
Local a
2012-11-25 13:56:35 +00:00
2012-11-27 03:13:38 +00:00
If Not Instr ( Manager_allWndIds , wndId " ; " )
Manager_allWndIds .= wndId " ; "
2012-11-25 13:56:35 +00:00
2012-12-05 12:39:51 +00:00
If ( isManaged )
2012-12-04 03:40:52 +00:00
{
2015-01-25 18:16:30 +00:00
If ( action = " close " Or action = " maximize " )
Window_ %action% ( wndId )
2012-12-05 15:08:29 +00:00
2012-11-27 03:13:38 +00:00
Manager_managedWndIds .= wndId " ; "
Monitor_moveWindow ( m , wndId )
2015-01-25 18:38:10 +00:00
Window_# %wndId% _tags := tags
Window_# %wndId% _isDecorated := isDecorated
Window_# %wndId% _isFloating := isFloating
Window_# %wndId% _area := 0
2012-12-05 12:39:51 +00:00
2012-11-27 03:13:38 +00:00
If Not Config_showBorder
2015-01-25 18:16:30 +00:00
Window_set ( wndId , " Style " , " -0x40000 " )
2015-01-25 18:38:10 +00:00
If Not Window_# %wndId% _isDecorated
2015-01-25 18:16:30 +00:00
Window_set ( wndId , " Style " , " -0xC00000 " )
2012-11-25 13:56:35 +00:00
2015-01-25 18:38:10 +00:00
a := Window_# %wndId% _tags & ( 1 << ( Monitor_# %m% _aView_#1 - 1 ) )
2012-12-05 12:39:51 +00:00
If a
2012-12-04 03:40:52 +00:00
{
2014-10-29 17:15:11 +00:00
;; A newly created window defines the active monitor, if it is visible.
2012-11-27 03:13:38 +00:00
Manager_aMonitor := m
Manager_winActivate ( wndId )
2012-12-05 12:39:51 +00:00
}
Else
2012-12-04 03:40:52 +00:00
{
2012-11-27 03:13:38 +00:00
Manager_hideShow := True
2015-01-25 18:16:30 +00:00
Window_hide ( wndId )
2012-11-27 03:13:38 +00:00
Manager_hideShow := False
}
}
If hideTitle
Bar_hideTitleWndIds .= wndId . " ; "
2012-12-05 12:39:51 +00:00
2012-11-27 03:13:38 +00:00
Return , a
2012-11-25 13:56:35 +00:00
}
2012-12-04 02:52:43 +00:00
;; Accept a window to be added to the system for management.
;; Provide a monitor and view preference, but don't override the config.
2012-12-05 12:39:51 +00:00
Manager_manage ( preferredMonitor , preferredView , wndId )
2012-12-04 02:52:43 +00:00
{
Local a , action , c0 , hideTitle , i , isDecorated , isFloating , isManaged , l , m , n , replace , search , tags , body
2015-02-14 12:52:49 +00:00
Local wndControlList0 , wndId0 , wndIds , wndX , wndY , wndWidth , wndHeight
2012-12-05 12:39:51 +00:00
2015-02-13 20:59:31 +00:00
;; Manage any window only once.
If InStr ( Manager_allWndIds , wndId " ; " )
2012-11-27 03:13:38 +00:00
Return
2012-12-05 12:39:51 +00:00
2012-11-27 03:13:38 +00:00
body := 0
2015-01-25 18:16:30 +00:00
If Window_isGhost ( wndId )
2012-12-04 02:52:43 +00:00
{
Debug_logMessage ( " DEBUG[2] A window has given up the ghost (Ghost wndId: " . wndId . " ) " , 2 )
2015-01-25 18:16:30 +00:00
body := Window_findHung ( wndId )
2012-12-05 12:39:51 +00:00
If body
2012-12-04 02:52:43 +00:00
{
2012-11-27 03:13:38 +00:00
isManaged := InStr ( Manager_managedWndIds , body " ; " )
2015-01-25 18:38:10 +00:00
m := Window_# %body% _monitor
tags := Window_# %body% _tags
isDecorated := Window_# %body% _isDecorated
isFloating := Window_# %body% _isFloating
2012-11-27 03:13:38 +00:00
hideTitle := InStr ( Bar_hideTitleWndIds , body " ; " )
2012-12-04 02:52:43 +00:00
action := " "
2012-11-27 03:13:38 +00:00
}
2012-12-05 12:39:51 +00:00
Else
2012-12-04 02:52:43 +00:00
{
Debug_logMessage ( " DEBUG[1] No body could be found for ghost wndId: " . wndId , 1 )
2012-11-27 03:13:38 +00:00
}
}
2012-12-05 12:39:51 +00:00
2012-12-04 02:52:43 +00:00
;; Apply rules if the window is either a normal window or a ghost without a body.
2012-12-05 12:39:51 +00:00
If ( body = 0 )
2012-12-04 02:52:43 +00:00
{
Manager_applyRules ( wndId , isManaged , m , tags , isFloating , isDecorated , hideTitle , action )
2012-11-27 03:13:38 +00:00
If ( m = 0 )
2012-12-04 02:52:43 +00:00
m := preferredMonitor
2012-11-27 03:13:38 +00:00
If ( m < 0 )
m := 1
2012-12-04 02:52:43 +00:00
If ( m > Manager_monitorCount ) ;; If the specified monitor is out of scope, set it to the max. monitor.
2012-11-27 03:13:38 +00:00
m := Manager_monitorCount
If ( tags = 0 )
2012-12-04 02:52:43 +00:00
tags := 1 << ( preferredView - 1 )
2012-11-27 03:13:38 +00:00
}
2012-12-05 12:39:51 +00:00
2015-02-12 19:35:41 +00:00
If Window_isElevated ( wndId )
isManaged := 0
2012-12-05 15:08:29 +00:00
a := Manager__setWinProperties ( wndId , isManaged , m , tags , isDecorated , isFloating , hideTitle , action )
2012-12-05 12:39:51 +00:00
2012-11-27 03:13:38 +00:00
; Do view placement.
If isManaged {
Loop , % Config_viewCount
2015-01-25 18:38:10 +00:00
If ( Window_# %wndId% _tags & ( 1 << ( A_Index - 1 ) ) ) {
2012-11-27 03:13:38 +00:00
If ( body ) {
; Try to position near the body.
2012-12-04 02:52:43 +00:00
View_ghostWindow ( m , A_Index , body , wndId )
2012-11-27 03:13:38 +00:00
}
2012-12-05 12:39:51 +00:00
Else
2012-12-04 02:52:43 +00:00
View_addWindow ( m , A_Index , wndId )
2012-11-27 03:13:38 +00:00
}
}
2012-12-05 12:39:51 +00:00
2012-11-27 03:13:38 +00:00
Return , a
2011-07-27 17:43:34 +00:00
}
2015-01-25 19:28:40 +00:00
Manager_maximizeWindow ( ) {
Local aWndId
2012-12-05 12:39:51 +00:00
2012-11-27 03:13:38 +00:00
WinGet , aWndId , ID , A
2015-01-25 19:28:40 +00:00
If Not Window_# %aWndId% _isFloating
View_toggleFloatingWindow ( aWndId )
2015-01-25 18:16:30 +00:00
Window_set ( aWndId , " Top " , " " )
2012-12-05 12:39:51 +00:00
2015-01-25 18:16:30 +00:00
Window_move ( aWndId , Monitor_# %Manager_aMonitor% _x , Monitor_# %Manager_aMonitor% _y , Monitor_# %Manager_aMonitor% _width , Monitor_# %Manager_aMonitor% _height )
2011-07-27 17:43:34 +00:00
}
2015-01-25 19:28:40 +00:00
Manager_moveWindow ( ) {
Local aWndId , SC_MOVE , WM_SYSCOMMAND
2012-12-05 12:39:51 +00:00
2012-11-27 03:13:38 +00:00
WinGet , aWndId , ID , A
2015-01-25 19:28:40 +00:00
If Not Window_# %aWndId% _isFloating
View_toggleFloatingWindow ( aWndId )
2015-01-25 18:16:30 +00:00
Window_set ( aWndId , " Top " , " " )
2012-12-05 12:39:51 +00:00
2012-11-27 03:13:38 +00:00
WM_SYSCOMMAND = 0x112
2012-12-04 02:52:43 +00:00
SC_MOVE = 0xF010
2012-11-27 03:13:38 +00:00
SendMessage , WM_SYSCOMMAND , SC_MOVE , , , ahk_id %aWndId%
2011-07-27 17:43:34 +00:00
}
2015-01-25 21:26:17 +00:00
Manager_onDisplayChange ( a , wParam , uMsg , lParam ) {
Debug_logMessage ( " DEBUG[1] Manager_onDisplayChange( a: " . a . " , uMsg: " . uMsg . " , wParam: " . wParam . " , lParam: " . lParam . " ) " , 1 )
MsgBox , 0x4 , , Would you like to reset the monitor configuration ?
IfMsgBox Yes
Manager_resetMonitorConfiguration ( )
}
2012-12-04 02:52:43 +00:00
/*
2015-02-14 20:34:27 +00:00
Reliable messages : 1 , 2 , 4 , 6 , 13 , 14 , 32772 , 32774. Any message may be missed , if bug . n is hung .
Indications of a . . .
new window :
6: Cmd / shell may be starting a new window .
6: Win + E indicates a new window , as long as the button presses are below a certain frequency .
1: Maybe a new window started from Windows Explorer .
2012-12-04 02:52:43 +00:00
There doesn 't seem to be a reliable way to get all application starts .
2015-02-14 20:34:27 +00:00
closed window :
13: Always indicates closed ghost window .
2: Always indicates closed standard window . ( ? )
focus change :
4: Always catch this !
32772: Always catch this !
window event :
6: Title changes , which can be used in the case of some applications , . . .
32774: . . . works for others .
2012-12-04 02:52:43 +00:00
Windows events can 't always be caught .
* /
2011-07-27 17:43:34 +00:00
Manager_onShellMessage ( wParam , lParam ) {
2015-02-14 12:52:49 +00:00
Local a , isChanged , aWndClass , aWndHeight , aWndId , aWndTitle , aWndWidth , aWndX , aWndY , i , m , t , wndClass , wndId , wndId0 , wndIds , wndTitle , x , y
2015-02-14 20:34:27 +00:00
;; HSHELL_* become global.
HSHELL_WINDOWCREATED := 1 ;; A window is shown (shown ID).
HSHELL_WINDOWDESTROYED := 2 ;; Seems to get sent sometimes when windows are deactivated. A window destroyed or hidden, same message for both (destroyed or hidden ID).
HSHELL_ACTIVATESHELLWINDOW := 3
HSHELL_WINDOWACTIVATED := 4 ;; At least the title changes. A window is activated via mouse, Alt+Tab or hotkey (sometimes 32772, but always one of them).
HSHELL_GETMINRECT := 5
HSHELL_REDRAW := 6 ;; A window title changes (ID of redrawn window).
HSHELL_TASKMAN := 7
HSHELL_LANGUAGE := 8
HSHELL_SYSMENU := 9
HSHELL_ENDTASK := 10
HSHELL_ACCESSIBILITYSTATE := 11
HSHELL_APPCOMMAND := 12
;; The following two are seen when a hung window recovers.
HSHELL_WINDOWREPLACED := 13 ;; lParam notes the ghost process. A hung window recovers and replaces the ghost window (ghost window ID).
HSHELL_WINDOWREPLACING := 14 ;; lParam notes the recovered process. A hung window recovered (ID of previously hung window).
HSHELL_HIGHBIT := 32768 ;; 0x8000
HSHELL_FLASH := 32774 ;; (HSHELL_REDRAW|HSHELL_HIGHBIT); when a window is signalling an application update. The window is flashing due to some event, one message for each flash.
HSHELL_RUDEAPPACTIVATED := 32772 ;; (HSHELL_WINDOWACTIVATED|HSHELL_HIGHBIT); full-screen app activated? Root-privileged window activated? The window activated via mouse, Alt+Tab or hotkey (sometimes 4, but always one of them).
2012-12-05 12:39:51 +00:00
2012-11-27 03:13:38 +00:00
SetFormat , Integer , hex
lParam := lParam + 0
SetFormat , Integer , d
2012-12-05 12:39:51 +00:00
2012-12-04 02:52:43 +00:00
Debug_logMessage ( " DEBUG[2] Manager_onShellMessage( wParam: " . wParam . " , lParam: " . lParam . " ) " , 2 )
2012-12-05 12:39:51 +00:00
2012-11-27 03:13:38 +00:00
WinGetClass , wndClass , ahk_id %lParam%
WinGetTitle , wndTitle , ahk_id %lParam%
2015-02-13 20:59:31 +00:00
If Not wndClass And Not wndTitle {
;; If there is no window class or title, it is assumed that the window is not identifiable.
;; The problem was, that i. a. claws-mail triggers Manager_sync, but the application window
;; would not be ready for being managed, i. e. class and title were not available. Therefore more
;; attempts were needed.
Return
}
2012-12-05 12:39:51 +00:00
2012-11-27 03:13:38 +00:00
WinGet , aWndId , ID , A
WinGetClass , aWndClass , ahk_id %aWndId%
WinGetTitle , aWndTitle , ahk_id %aWndId%
2015-02-08 19:24:17 +00:00
If ( ( wParam = 4 Or wParam = 32772 ) And ( aWndClass = " WorkerW " And aWndTitle = " " Or lParam = 0 And aWndClass = " Progman " And aWndTitle = " Program Manager " ) )
{
2012-11-27 03:13:38 +00:00
MouseGetPos , x , y
m := Monitor_get ( x , y )
2014-10-29 17:15:11 +00:00
;; The current position of the mouse cursor defines the active monitor, if the desktop has been activated.
2012-11-27 03:13:38 +00:00
If m
Manager_aMonitor := m
Bar_updateTitle ( )
}
2012-12-05 12:39:51 +00:00
2015-02-08 19:24:17 +00:00
If ( wParam = HSHELL_WINDOWREPLACED )
{ ;; This shouldn't need a redraw because the window was supposedly replaced.
2012-11-27 03:13:38 +00:00
Manager_unmanage ( lParam )
}
2015-02-08 19:24:17 +00:00
; If (wParam = 14)
; { ;; Window recovered from being hung. Maybe force a redraw.
; }
2012-12-05 12:39:51 +00:00
2015-02-08 19:24:17 +00:00
;; @todo: There are two problems with the use of Manager_hideShow:
2012-12-04 02:52:43 +00:00
;; 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
2012-12-05 12:39:51 +00:00
;; 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
2012-12-04 02:52:43 +00:00
;; 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.
2015-02-08 19:24:17 +00:00
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
{
2012-11-27 03:13:38 +00:00
isChanged := Manager_sync ( wndIds )
If wndIds
isChanged := False
2012-12-05 12:39:51 +00:00
2015-02-08 19:24:17 +00:00
If isChanged
{
2014-03-03 10:56:37 +00:00
If Config_dynamicTiling
View_arrange ( Manager_aMonitor , Monitor_# %Manager_aMonitor% _aView_#1 )
2012-11-27 03:13:38 +00:00
Bar_updateView ( Manager_aMonitor , Monitor_# %Manager_aMonitor% _aView_#1 )
}
2012-12-05 12:39:51 +00:00
2015-02-08 19:24:17 +00:00
If ( Manager_monitorCount > 1 )
{
2012-12-04 02:52:43 +00:00
WinGet , aWndId , ID , A
2012-11-27 03:13:38 +00:00
WinGetPos , aWndX , aWndY , aWndWidth , aWndHeight , ahk_id %aWndId%
m := Monitor_get ( aWndX + aWndWidth / 2 , aWndY + aWndHeight / 2 )
2012-12-04 02:52:43 +00:00
Debug_logMessage ( " DEBUG[1] Manager_onShellMessage: Manager_monitorCount: " Manager_monitorCount " , Manager_aMonitor: " Manager_aMonitor " , m: " m " , aWndId: " aWndId , 1 )
2014-10-29 17:15:11 +00:00
;; The currently active window defines the active monitor.
2012-12-05 00:36:38 +00:00
If m
Manager_aMonitor := m
2012-11-27 03:13:38 +00:00
}
2012-12-05 12:39:51 +00:00
2015-02-08 19:24:17 +00:00
If wndIds
{ ;; If there are new (unrecognized) windows, which are hidden ...
If ( Config_onActiveHiddenWnds = " view " )
{ ;; ... change the view to show the first hidden window
2012-11-27 03:13:38 +00:00
wndId := SubStr ( wndIds , 1 , InStr ( wndIds , " ; " ) - 1 )
2015-02-08 19:24:17 +00:00
Loop , % Config_viewCount
{
If ( Window_# %wndId% _tags & 1 << A_Index - 1 )
{
2012-12-04 02:52:43 +00:00
Debug_logMessage ( " DEBUG[3] Switching views because " . wndId . " is considered hidden and active " , 3 )
2014-10-29 17:15:11 +00:00
;; A newly created window defines the active monitor, if it is visible.
2015-01-25 18:38:10 +00:00
Manager_aMonitor := Window_# %wndId% _monitor
2012-11-27 03:13:38 +00:00
Monitor_activateView ( A_Index )
Break
}
2012-12-04 02:52:43 +00:00
}
2015-02-08 19:24:17 +00:00
}
Else
{ ;; ... re-hide them
2012-11-27 03:13:38 +00:00
StringTrimRight , wndIds , wndIds , 1
StringSplit , wndId , wndIds , `;
2015-02-08 19:24:17 +00:00
If ( Config_onActiveHiddenWnds = " hide " )
{
2012-12-05 12:39:51 +00:00
Loop , % wndId0
2015-02-08 19:24:17 +00:00
{
2015-01-25 18:16:30 +00:00
Window_hide ( wndId %A_Index% )
2015-02-08 19:24:17 +00:00
}
}
Else If ( Config_onActiveHiddenWnds = " tag " )
{
2012-12-04 02:52:43 +00:00
;; ... or tag all of them for the current view.
2012-11-27 03:13:38 +00:00
t := Monitor_# %Manager_aMonitor% _aView_#1
2015-02-08 19:24:17 +00:00
Loop , % wndId0
{
2012-11-27 03:13:38 +00:00
wndId := wndId %A_Index%
View_# %Manager_aMonitor% _# %t% _wndIds := wndId " ; " View_# %Manager_aMonitor% _# %t% _wndIds
View_# %Manager_aMonitor% _# %t% _aWndId := wndId
2015-01-25 18:38:10 +00:00
Window_# %wndId% _tags + = 1 << t - 1
2012-11-27 03:13:38 +00:00
}
Bar_updateView ( Manager_aMonitor , t )
2014-03-03 10:56:37 +00:00
If Config_dynamicTiling
View_arrange ( Manager_aMonitor , t )
2012-11-27 03:13:38 +00:00
}
}
}
2012-12-05 12:39:51 +00:00
2015-02-01 13:39:46 +00:00
;; This is a workaround for a redrawing problem of the bug.n bar, which
;; seems to get lost, when windows are created or destroyed under the
;; following conditions.
If ( Manager_monitorCount > 1 ) And ( Config_verticalBarPos = " tray " ) {
Loop , % ( Manager_monitorCount - 1 ) {
i := A_Index + 1
Bar_updateLayout ( i )
Bar_updateStatic ( i )
Loop , % Config_viewCount
Bar_updateView ( i , A_Index )
}
Bar_updateStatus ( )
Bar_updateTitle ( )
} Else
Bar_updateTitle ( )
2012-11-27 03:13:38 +00:00
}
2011-07-27 17:43:34 +00:00
}
2014-10-31 16:01:30 +00:00
Manager_registerShellHook ( ) {
WM_DISPLAYCHANGE := 126 ;; This message is sent when the display resolution has changed.
2012-11-27 03:13:38 +00:00
Gui , + LastFound
hWnd := WinExist ( )
2014-10-31 16:01:30 +00:00
WinGetClass , wndClass , ahk_id %hWnd%
WinGetTitle , wndTitle , ahk_id %hWnd%
2012-12-04 02:52:43 +00:00
DllCall ( " RegisterShellHookWindow " , " UInt " , hWnd ) ;; Minimum operating systems: Windows 2000 (http://msdn.microsoft.com/en-us/library/ms644989(VS.85).aspx)
2014-10-31 16:01:30 +00:00
Debug_logMessage ( " DEBUG[1] Manager_registerShellHook; hWnd: " . hWnd . " , wndClass: " . wndClass . " , wndTitle: " . wndTitle , 1 )
2012-11-27 03:13:38 +00:00
msgNum := DllCall ( " RegisterWindowMessage " , " Str " , " SHELLHOOK " )
OnMessage ( msgNum , " Manager_onShellMessage " )
2014-10-31 16:01:30 +00:00
OnMessage ( WM_DISPLAYCHANGE , " Manager_onDisplayChange " )
2011-07-27 17:43:34 +00:00
}
2012-12-04 02:52:43 +00:00
;; SKAN: How to Hook on to Shell to receive its messages? (http://www.autohotkey.com/forum/viewtopic.php?p=123323#123323)
2014-10-31 16:01:30 +00:00
Manager_resetMonitorConfiguration ( ) {
Local GuiN , hWnd , i , m , wndClass , wndIds , wndTitle
m := Manager_monitorCount
SysGet , Manager_monitorCount , MonitorCount
If ( Manager_monitorCount < m ) {
Loop , % m - Manager_monitorCount {
i := Manager_monitorCount + A_Index
GuiN := ( i - 1 ) + 1
Gui , %GuiN% : Destroy
Loop , % Config_viewCount {
If View_# %i% _# %A_Index% _wndIds {
View_#1_# %A_Index% _wndIds := View_# %i% _# %A_Index% _wndIds View_#1_# %A_Index% _wndIds
StringTrimRight , wndIds , View_# %i% _# %A_Index% _wndIds , 1
Loop , PARSE , wndIds , `;
{
Loop , % Config_viewCount {
StringReplace , View_# %i% _# %A_Index% _wndIds , View_# %i% _# %A_Index% _wndIds , %A_LoopField% `; ,
View_# %i% _# %A_Index% _aWndId := 0
}
Monitor_moveWindow ( 1 , A_LoopField )
}
2014-10-06 11:59:59 +00:00
2014-10-31 16:01:30 +00:00
;; Manually set the active monitor.
Manager_aMonitor := 1
}
}
}
m := Manager_monitorCount
} Else If ( Manager_monitorCount > m ) {
Loop , % Manager_monitorCount - m
Monitor_init ( m + A_Index , True )
}
Loop , % m {
Monitor_getWorkArea ( A_Index )
Bar_init ( A_Index )
}
Manager_saveState ( )
Loop , % Manager_monitorCount {
View_arrange ( A_Index , Monitor_# %A_Index% _aView_#1 )
Bar_updateView ( A_Index , Monitor_# %A_Index% _aView_#1 )
}
Manager__restoreWindowState ( Main_autoWindowState )
Bar_updateStatus ( )
Bar_updateTitle ( )
Gui , + LastFound
hWnd := WinExist ( )
WinGetClass , wndClass , ahk_id %hWnd%
WinGetTitle , wndTitle , ahk_id %hWnd%
DllCall ( " RegisterShellHookWindow " , " UInt " , hWnd ) ;; Minimum operating systems: Windows 2000 (http://msdn.microsoft.com/en-us/library/ms644989(VS.85).aspx)
Debug_logMessage ( " DEBUG[1] Manager_registerShellHook; hWnd: " . hWnd . " , wndClass: " . wndClass . " , wndTitle: " . wndTitle , 1 )
2014-10-06 11:59:59 +00:00
}
2015-01-25 19:39:09 +00:00
Manager_restoreWindowBorders ( )
2012-12-04 02:52:43 +00:00
{
Local ncm , ncmSize
2012-12-05 12:39:51 +00:00
2012-12-04 02:52:43 +00:00
If Config_selBorderColor
DllCall ( " SetSysColors " , " Int " , 1 , " Int* " , 10 , " UInt* " , Manager_normBorderColor )
2012-12-05 12:39:51 +00:00
If ( Config_borderWidth > 0 ) Or ( Config_borderPadding > = 0 And A_OSVersion = WIN_VISTA )
2012-12-04 02:52:43 +00:00
{
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 )
}
}
2011-07-27 17:43:34 +00:00
2015-01-25 21:26:17 +00:00
;; 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 ) {
2015-02-14 12:52:49 +00:00
Local vidx , widx , i , j , m , v , candidate_set , view_set , excluded_view_set , view_m0 , view_v0 , view_list0 , wnds0 , items0 , wndPName , view_var , isManaged , isFloating , isDecorated , hideTitle
2015-01-25 21:26:17 +00:00
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
2015-02-14 12:52:49 +00:00
WinGet , wndPName , ProcessName , ahk_id %i%
2015-01-25 21:26:17 +00:00
DetectHiddenWindows , Off
2015-02-14 12:52:49 +00:00
If Not ( items %j% = wndPName ) {
Debug_logMessage ( " Window ahk_id " . i . " process ' " . wndPName . " ' doesn't match expected ' " . items %j% . " ', forgetting this window " , 0 )
2015-01-25 21:26:17 +00:00
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 )
;Window_hide(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
}
}
Manager_saveState ( ) {
Critical
Global Config_filePath , Config_viewCount , Main_autoLayout , Main_autoWindowState , Manager_layoutDirty , Manager_monitorCount , Manager_windowsDirty
Debug_logMessage ( " DEBUG[2] Manager_saveState " , 2 )
;; @TODO: Check for changes to the layout.
;If Manager_layoutDirty {
Debug_logMessage ( " DEBUG[2] Manager_saveState: " Main_autoLayout , 2 )
Config_saveSession ( Config_filePath , Main_autoLayout )
Manager_layoutDirty := 0
;}
;; @TODO: Check for changes to windows.
;If Manager_windowsDirty {
Debug_logMessage ( " DEBUG[2] Manager_saveState: " Main_autoWindowState , 2 )
Manager_saveWindowState ( Main_autoWindowState , Manager_monitorCount , Config_viewCount )
Manager_windowsDirty := 0
;}
}
Manager_saveWindowState ( filename , nm , nv ) {
2015-02-14 12:52:49 +00:00
Local allWndId0 , allWndIds , wndPName , title , text , monitor , wndId , view , isManaged , isTitleHidden
2015-01-25 21:26:17 +00:00
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%
2015-02-14 12:52:49 +00:00
WinGet , wndPName , ProcessName , ahk_id %wndId%
2015-01-25 21:26:17 +00:00
; Include title for informative reasons.
WinGetTitle , title , ahk_id %wndId%
2015-02-14 12:52:49 +00:00
; wndId;processName;Tags;Floating;Decorated;HideTitle;Managed;Title
2015-01-25 21:26:17 +00:00
2015-02-13 20:59:31 +00:00
isManaged := InStr ( Manager_managedWndIds , wndId . " ; " )
isTitleHidden := InStr ( Bar_hideTitleWndIds , wndId . " ; " )
2015-01-25 21:26:17 +00:00
2015-02-14 12:52:49 +00:00
text .= " Window " . wndId . " ; " . wndPName . " ; " . Window_# %wndId% _monitor . " ; " . Window_# %wndId% _tags . " ; " . Window_# %wndId% _isFloating . " ; " . Window_# %wndId% _isDecorated . " ; " . isTitleHidden . " ; " . isManaged . " ; " . title . " `n "
2015-01-25 21:26:17 +00:00
}
DetectHiddenWindows , Off
text .= " `n "
;; 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
;; 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
}
2015-02-05 19:57:59 +00:00
Manager_setCursor ( wndId ) {
2015-01-27 23:02:37 +00:00
Local wndHeight , wndWidth , wndX , wndY
If Config_mouseFollowsFocus {
If wndId {
WinGetPos , wndX , wndY , wndWidth , wndHeight , ahk_id %wndId%
DllCall ( " SetCursorPos " , " Int " , Round ( wndX + wndWidth / 2 ) , " Int " , Round ( wndY + wndHeight / 2 ) )
} 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 ) )
}
}
2015-01-28 19:49:03 +00:00
Manager_setViewMonitor ( i , d = 0 ) {
Local aView , aWndId , v , wndIds
2012-12-05 12:39:51 +00:00
2015-01-28 19:49:03 +00:00
aView := Monitor_# %Manager_aMonitor% _aView_#1
If ( Manager_monitorCount > 1 ) And View_# %Manager_aMonitor% _# %aView% _wndIds {
If ( i = 0 )
i := Manager_aMonitor
i := Manager_loop ( i , d , 1 , Manager_monitorCount )
v := Monitor_# %i% _aView_#1
View_# %i% _# %v% _wndIds := View_# %Manager_aMonitor% _# %aView% _wndIds View_# %i% _# %v% _wndIds
2012-12-05 12:39:51 +00:00
2015-01-28 19:49:03 +00:00
StringTrimRight , wndIds , View_# %Manager_aMonitor% _# %aView% _wndIds , 1
Loop , PARSE , wndIds , `;
{
Loop , % Config_viewCount {
StringReplace , View_# %Manager_aMonitor% _# %A_Index% _wndIds , View_# %Manager_aMonitor% _# %A_Index% _wndIds , %A_LoopField% `; ,
View_# %Manager_aMonitor% _# %A_Index% _aWndId := 0
2012-12-04 02:52:43 +00:00
}
2012-12-05 12:39:51 +00:00
2015-01-28 19:49:03 +00:00
Monitor_moveWindow ( i , A_LoopField )
Window_# %A_LoopField% _tags := 1 << v - 1
}
View_arrange ( Manager_aMonitor , aView )
Loop , % Config_viewCount {
Bar_updateView ( Manager_aMonitor , A_Index )
2012-11-27 03:13:38 +00:00
}
2015-01-28 19:49:03 +00:00
;; Manually set the active monitor.
Manager_aMonitor := i
View_arrange ( i , v )
WinGet , aWndId , ID , A
Manager_winActivate ( aWndId )
Bar_updateView ( i , v )
2012-11-27 03:13:38 +00:00
}
2011-07-27 17:43:34 +00:00
}
2015-01-25 19:39:09 +00:00
Manager_setWindowBorders ( )
2012-12-04 02:52:43 +00:00
{
Local ncm , ncmSize
2012-12-05 12:39:51 +00:00
If Config_selBorderColor
2012-12-04 02:52:43 +00:00
{
SetFormat , Integer , hex
Manager_normBorderColor := DllCall ( " GetSysColor " , " Int " , 10 )
SetFormat , Integer , d
DllCall ( " SetSysColors " , " Int " , 1 , " Int* " , 10 , " UInt* " , Config_selBorderColor )
}
2012-12-05 12:39:51 +00:00
If ( Config_borderWidth > 0 ) Or ( Config_borderPadding > = 0 And A_OSVersion = WIN_VISTA )
2012-12-04 02:52:43 +00:00
{
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 )
}
}
2015-01-28 19:49:03 +00:00
Manager_setWindowMonitor ( i , d = 0 ) {
2012-11-27 03:13:38 +00:00
Local aWndId , v
2012-12-05 12:39:51 +00:00
2012-11-27 03:13:38 +00:00
WinGet , aWndId , ID , A
2015-01-28 19:26:43 +00:00
If ( Manager_monitorCount > 1 And InStr ( Manager_managedWndIds , aWndId " ; " ) ) {
Loop , % Config_viewCount {
2012-12-05 12:39:51 +00:00
StringReplace , View_# %Manager_aMonitor% _# %A_Index% _wndIds , View_# %Manager_aMonitor% _# %A_Index% _wndIds , %aWndId% `; ,
2012-11-27 03:13:38 +00:00
If ( aWndId = View_# %Manager_aMonitor% _# %A_Index% _aWndId )
View_# %Manager_aMonitor% _# %A_Index% _aWndId := 0
Bar_updateView ( Manager_aMonitor , A_Index )
}
2014-03-03 10:56:37 +00:00
If Config_dynamicTiling
View_arrange ( Manager_aMonitor , Monitor_# %Manager_aMonitor% _aView_#1 )
2012-12-05 12:39:51 +00:00
2014-10-29 17:15:11 +00:00
;; Manually set the active monitor.
2015-01-28 19:26:43 +00:00
If ( i = 0 )
i := Manager_aMonitor
Manager_aMonitor := Manager_loop ( i , d , 1 , Manager_monitorCount )
2012-11-27 03:13:38 +00:00
Monitor_moveWindow ( Manager_aMonitor , aWndId )
v := Monitor_# %Manager_aMonitor% _aView_#1
2015-01-25 18:38:10 +00:00
Window_# %aWndId% _tags := 1 << v - 1
2012-11-27 03:13:38 +00:00
View_# %Manager_aMonitor% _# %v% _wndIds := aWndId " ; " View_# %Manager_aMonitor% _# %v% _wndIds
View_# %Manager_aMonitor% _# %v% _aWndId := aWndId
2014-03-03 10:56:37 +00:00
If Config_dynamicTiling
View_arrange ( Manager_aMonitor , v )
2012-12-04 02:52:43 +00:00
Manager_winActivate ( aWndId )
2012-11-27 03:13:38 +00:00
Bar_updateView ( Manager_aMonitor , v )
}
2011-07-27 17:43:34 +00:00
}
2015-01-25 19:28:40 +00:00
Manager_sizeWindow ( ) {
Local aWndId , SC_SIZE , WM_SYSCOMMAND
2012-12-05 12:39:51 +00:00
2012-11-27 03:13:38 +00:00
WinGet , aWndId , ID , A
2015-01-25 19:28:40 +00:00
If Not Window_# %aWndId% _isFloating
View_toggleFloatingWindow ( aWndId )
2015-01-25 18:16:30 +00:00
Window_set ( aWndId , " Top " , " " )
2012-12-05 12:39:51 +00:00
2012-11-27 03:13:38 +00:00
WM_SYSCOMMAND = 0x112
2012-12-04 02:52:43 +00:00
SC_SIZE = 0xF000
2012-11-27 03:13:38 +00:00
SendMessage , WM_SYSCOMMAND , SC_SIZE , , , ahk_id %aWndId%
2011-07-27 17:43:34 +00:00
}
2015-01-25 21:26:17 +00:00
;; No windows are known to the system yet.
;; Try to do something smart with the initial layout.
Manager_initial_sync ( doRestore ) {
2015-01-28 18:42:07 +00:00
Local wndId , wndId0 , wnd , wndX , wndY , wndW , wndH , x , y , m , len
2015-01-25 21:26:17 +00:00
;; Initialize lists
;; Note that these variables make this function non-reentrant.
Loop , % Manager_monitorCount
Manager_initial_sync_m# %A_Index% _wndList := " "
;; Use saved window placement settings to first determine
;; which monitor/view a window should be attached to.
If doRestore
Manager__restoreWindowState ( Main_autoWindowState )
;; Check all remaining visible windows against the known windows
WinGet , wndId , List , , ,
Loop , % wndId {
;; Based on some analysis here, determine which monitors and layouts would best
;; serve existing windows. Do not override configuration settings.
;; Which monitor is it on?
wnd := wndId %A_Index%
WinGetPos , wndX , wndY , wndW , wndH , ahk_id %wnd%
x := wndX + wndW / 2
y := wndY + wndH / 2
m := Monitor_get ( x , y )
If m > 0
Manager_initial_sync_m# %m% _wndList .= wndId %A_Index% " ; "
}
Loop , % Manager_monitorCount {
m := A_Index
StringTrimRight , wndIds , Manager_initial_sync_m# %m% _wndList , 1
StringSplit , wndId , wndIds , `;
Loop , % wndId0
Manager_manage ( m , 1 , wndId %A_Index% )
}
}
2015-02-08 19:24:17 +00:00
;; @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.
;; The problem was, that i. a. claws-mail triggers Manager_sync, but the application window
;; would not be ready for being managed, i. e. class and title were not available. Therefore more
;; attempts were needed.
;; Perhaps this method can be refined by not adding any window to Manager_allWndIds, but only
;; those, which have at least a title or class.
Manager_sync ( ByRef wndIds = " " )
{
2012-11-27 03:13:38 +00:00
Local a , flag , shownWndIds , v , visibleWndIds , wndId
2012-12-05 12:39:51 +00:00
2015-02-08 19:24:17 +00:00
Loop , % Manager_monitorCount
{
2012-11-27 03:13:38 +00:00
v := Monitor_# %A_Index% _aView_#1
shownWndIds .= View_# %A_Index% _# %v% _wndIds
}
2012-12-04 02:52:43 +00:00
;; Check all visible windows against the known windows
2012-12-05 12:39:51 +00:00
WinGet , wndId , List , , ,
2015-02-08 19:24:17 +00:00
Loop , % wndId
{
If Not InStr ( shownWndIds , wndId %A_Index% " ; " )
{
If Not InStr ( Manager_managedWndIds , wndId %A_Index% " ; " )
{
2012-11-27 03:13:38 +00:00
flag := Manager_manage ( Manager_aMonitor , Monitor_# %Manager_aMonitor% _aView_#1 , wndId %A_Index% )
If flag
a := flag
2015-02-08 19:24:17 +00:00
}
Else If Not Window_isHung ( wndId %A_Index% )
{
2012-12-04 02:52:43 +00:00
;; 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.
2012-11-27 03:13:38 +00:00
wndIds .= wndId %A_Index% " ; "
}
}
visibleWndIds := visibleWndIds wndId %A_Index% " ; "
}
2012-12-05 12:39:51 +00:00
2015-02-08 19:24:17 +00:00
;; @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
2012-11-27 03:13:38 +00:00
StringTrimRight , shownWndIds , shownWndIds , 1
Loop , PARSE , shownWndIds , `;
{
2015-02-08 19:24:17 +00:00
If Not InStr ( visibleWndIds , A_LoopField )
{
2012-11-27 03:13:38 +00:00
flag := Manager_unmanage ( A_LoopField )
If flag
a := flag
}
}
2012-12-05 12:39:51 +00:00
2012-11-27 03:13:38 +00:00
Return , a
2011-07-27 17:43:34 +00:00
}
2014-10-31 15:20:31 +00:00
Manager_unmanage ( wndId ) {
Local a , aView , wndId0 , wndIds
;; Find the next window that should have focus.
;; If there is no such window, choose the bar on the same monitor.
aView := Monitor_# %Manager_aMonitor% _aView_#1
2015-01-28 18:42:07 +00:00
StringTrimRight , wndIds , View_# %Manager_aMonitor% _# %aView% _wndIds , 1
2014-10-31 15:20:31 +00:00
StringSplit , wndId , wndIds , `;
2015-01-28 18:42:07 +00:00
If ( wndId0 > = 2 )
View_activateWindow ( 0 , + 1 )
2014-10-31 15:20:31 +00:00
Else
2015-01-28 18:42:07 +00:00
Manager_winActivate ( 0 )
2012-12-05 12:39:51 +00:00
2012-12-04 02:52:43 +00:00
;; Do our best to make sure that any unmanaged windows are left visible.
2015-01-25 18:16:30 +00:00
Window_show ( wndId )
2015-01-28 18:42:07 +00:00
a := Window_# %wndId% _tags & 1 << aView - 1
Loop , % Config_viewCount {
If ( Window_# %wndId% _tags & 1 << A_Index - 1 ) {
2012-12-05 12:39:51 +00:00
StringReplace , View_# %Manager_aMonitor% _# %A_Index% _wndIds , View_# %Manager_aMonitor% _# %A_Index% _wndIds , %wndId% `; ,
2012-11-27 03:13:38 +00:00
Bar_updateView ( Manager_aMonitor , A_Index )
}
2012-12-04 02:52:43 +00:00
}
2015-01-25 18:38:10 +00:00
Window_# %wndId% _monitor :=
Window_# %wndId% _tags :=
Window_# %wndId% _isDecorated :=
Window_# %wndId% _isFloating :=
Window_# %wndId% _area :=
2012-12-05 12:39:51 +00:00
StringReplace , Bar_hideTitleWndIds , Bar_hideTitleWndIds , %wndId% `; ,
StringReplace , Manager_allWndIds , Manager_allWndIds , %wndId% `; ,
2012-11-27 03:13:38 +00:00
StringReplace , Manager_managedWndIds , Manager_managedWndIds , %wndId% `; , , All
2012-12-05 12:39:51 +00:00
2012-11-27 03:13:38 +00:00
Return , a
2011-07-27 17:43:34 +00:00
}
2015-01-25 17:07:51 +00:00
Manager_winActivate ( wndId ) {
2015-02-05 19:57:59 +00:00
Manager_setCursor ( wndId )
2015-01-25 17:07:51 +00:00
Debug_logMessage ( " DEBUG[1] Activating window: " wndId , 1 )
If Not wndId {
If ( A_OSVersion = " WIN_8 " )
WinGet , wndId , ID , ahk_class WorkerW
Else
WinGet , wndId , ID , Program Manager ahk_class Progman
Debug_logMessage ( " DEBUG[1] Activating Desktop: " wndId , 1 )
2012-11-27 03:13:38 +00:00
}
2012-06-28 03:34:19 +00:00
2015-01-25 17:07:51 +00:00
If Window_activate ( wndId )
Return , 1
Else {
Bar_updateTitle ( )
2012-11-27 03:13:38 +00:00
Return 0
}
2012-06-30 02:20:15 +00:00
}