/* bug.n -- tiling window management Copyright (c) 2010-2019 Joshua Fuhs, joten This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. @license GNU General Public License version 3 ../LICENSE.md or @version 9.1.0 */ View_init(m, v) { Global View_#%m%_#%v%_area_#0 := 0 View_#%m%_#%v%_aWndIds := "0;" View_#%m%_#%v%_layout_#1 := 1 View_#%m%_#%v%_layout_#2 := 1 View_#%m%_#%v%_layoutAxis_#1 := Config_layoutAxis_#1 View_#%m%_#%v%_layoutAxis_#2 := Config_layoutAxis_#2 View_#%m%_#%v%_layoutAxis_#3 := Config_layoutAxis_#3 View_#%m%_#%v%_layoutGapWidth := Config_layoutGapWidth View_#%m%_#%v%_layoutMFact := Config_layoutMFactor View_#%m%_#%v%_layoutMX := 1 View_#%m%_#%v%_layoutMY := 1 View_#%m%_#%v%_layoutSymbol := Config_layoutSymbol_#1 View_#%m%_#%v%_margins := "0;0;0;0" View_#%m%_#%v%_showStackArea := True StringSplit, View_#%m%_#%v%_margin, View_#%m%_#%v%_margins, `; View_#%m%_#%v%_wndIds := "" } View_activateWindow(i, d = 0) { Local aWndId, direction, failure, j, v, wndId, wndId0, wndIds Debug_logMessage("DEBUG[1] View_activateWindow(" . i . ", " . d . ")", 1) If (i = 0) And (d = 0) Return WinGet, aWndId, ID, A Debug_logMessage("DEBUG[2] Active Windows ID: " . aWndId, 2, False) v := Monitor_#%Manager_aMonitor%_aView_#1 Debug_logMessage("DEBUG[2] View (" . v . ") wndIds: " . View_#%Manager_aMonitor%_#%v%_wndIds, 2, False) StringTrimRight, wndIds, View_#%Manager_aMonitor%_#%v%_wndIds, 1 StringSplit, wndId, wndIds, `; Debug_logMessage("DEBUG[2] wndId count: " . wndId0, 2, False) If (i > 0) And (i <= wndId0) And (d = 0) { wndId := wndId%i% Window_set(wndId, "AlwaysOnTop", "On") Window_set(wndId, "AlwaysOnTop", "Off") Window_#%wndId%_isMinimized := False Manager_winActivate(wndId) } Else If (wndId0 > 1) { If Not InStr(Manager_managedWndIds, aWndId . ";") Or Window_#%aWndId%_isFloating Window_set(aWndId, "Bottom", "") Loop, % wndId0 { If (wndId%A_Index% = aWndId) { j := A_Index Break } } Debug_logMessage("DEBUG[2] Current wndId index: " . j, 2, False) If (d > 0) direction = 1 Else direction = -1 i := Manager_loop(j, d, 1, wndId0) Loop, % wndId0 { Debug_logMessage("DEBUG[2] Next wndId index: " . i, 2, False) wndId := wndId%i% If Not Window_#%wndId%_isMinimized { Window_set(wndId, "AlwaysOnTop", "On") Window_set(wndId, "AlwaysOnTop", "Off") ;; If 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 } i := Manager_loop(i, direction, 1, wndId0) } } } View_addWindow(m, v, wndId) { Local i, mSplit, n, replace, search StringReplace, View_#%m%_#%v%_wndIds, View_#%m%_#%v%_wndIds, % wndId ";",, All If Tiler_isActive(m, v) And ((Config_newWndPosition = "masterBottom") Or (Config_newWndPosition = "stackTop")) { n := View_getTiledWndIds(m, v) mSplit := View_#%m%_#%v%_layoutMX * View_#%m%_#%v%_layoutMY If (mSplit = 1 And Config_newWndPosition = "masterBottom") View_#%m%_#%v%_wndIds := wndId ";" . View_#%m%_#%v%_wndIds Else If ((Config_newWndPosition = "masterBottom" And n < mSplit) Or (Config_newWndPosition = "stackTop" And n <= mSplit)) View_#%m%_#%v%_wndIds .= wndId ";" Else { If (Config_newWndPosition = "masterBottom") i := mSplit - 1 Else i := mSplit search := View_tiledWndId%i% ";" replace := search wndId ";" StringReplace, View_#%m%_#%v%_wndIds, View_#%m%_#%v%_wndIds, %search%, %replace% } } Else If (Config_newWndPosition = "bottom") View_#%m%_#%v%_wndIds .= wndId ";" Else View_#%m%_#%v%_wndIds := wndId ";" View_#%m%_#%v%_wndIds } View_arrange(m, v, setLayout = False) { Local fn, h, l, w, x, y Debug_logMessage("DEBUG[1] View_arrange(" . m . ", " . v . ")", 1) l := View_#%m%_#%v%_layout_#1 fn := Config_layoutFunction_#%l% If fn { x := Monitor_#%m%_x + View_#%m%_#%v%_layoutGapWidth + View_#%m%_#%v%_margin4 y := Monitor_#%m%_y + View_#%m%_#%v%_layoutGapWidth + View_#%m%_#%v%_margin1 w := Monitor_#%m%_width - 2 * View_#%m%_#%v%_layoutGapWidth - View_#%m%_#%v%_margin4 - View_#%m%_#%v%_margin2 h := Monitor_#%m%_height - 2 * View_#%m%_#%v%_layoutGapWidth - View_#%m%_#%v%_margin1 - View_#%m%_#%v%_margin3 ;; All window actions are performed on independent windows. A delay won't help. SetWinDelay, 0 If Config_dynamicTiling Or setLayout { View_getTiledWndIds(m, v) If (fn = "monocle") { ;; 'View_getLayoutSymbol_monocle' View_#%m%_#%v%_layoutSymbol := "[" View_tiledWndId0 "]" ;; 'View_arrange_monocle' Tiler_stackTiles(0, 0, 1, View_tiledWndId0, +1, 3, x, y, w, h, 0) } Else ;; (fn = "tile") Tiler_layoutTiles(m, v, x, y, w, h) } Else If (fn = "tile") { Tiler_layoutTiles(m, v, x, y, w, h, "blank") If Config_continuouslyTraceAreas View_traceAreas(True) } SetWinDelay, 10 } Else ;; floating layout (no 'View_arrange_', following is 'View_getLayoutSymbol_')' View_#%m%_#%v%_layoutSymbol := Config_layoutSymbol_#%l% ;Bar_updateLayout(m) } View_getActiveWindow(m, v) { Local listId, listIds, wndId listIds := "aWndIds;wndIds" wndId := 0 Loop, Parse, listIds, `; { listId := A_LoopField Loop, Parse, View_#%m%_#%v%_%listId%, `; { If Not A_LoopField Break Else If Not WinExist("ahk_id" A_LoopField) Or Window_#%A_LoopField%_isMinimized Continue Else { wndId := A_LoopField Break } } If wndId { If (listId = "wndIds") View_setActiveWindow(m, v, wndId) Break } } Return, wndId } View_getTiledWndIds(m, v) { Local n, tiledWndIds, wndIds n := 0 tiledWndIds := "" StringTrimRight, wndIds, View_#%m%_#%v%_wndIds, 1 Loop, PARSE, wndIds, `; { If A_LoopField And Not Window_#%A_LoopField%_isFloating And WinExist("ahk_id " A_LoopField) and Not Window_isHung(A_LoopField) { n += 1 tiledWndIds .= A_LoopField ";" } } View_tiledWndIds := tiledWndIds StringTrimRight, tiledWndIds, tiledWndIds, 1 StringSplit, View_tiledWndId, tiledWndIds, `; Return, n } View_ghostWindow(m, v, bodyWndId, ghostWndId) { Local search, replace search := bodyWndId ";" replace := search ghostWndId ";" StringReplace, View_#%m%_#%v%_wndIds, View_#%m%_#%v%_wndIds, %search%, %replace% } View_moveToIndex(m, v, n, w) { Local wndIds View_#%n%_#%w%_area_#0 := View_#%m%_#%v%_area_#0 View_#%n%_#%w%_aWndIds := View_#%m%_#%v%_aWndIds View_#%n%_#%w%_layout_#1 := View_#%m%_#%v%_layout_#1 View_#%n%_#%w%_layout_#2 := View_#%m%_#%v%_layout_#2 View_#%n%_#%w%_layoutAxis_#1 := View_#%m%_#%v%_layoutAxis_#1 View_#%n%_#%w%_layoutAxis_#2 := View_#%m%_#%v%_layoutAxis_#2 View_#%n%_#%w%_layoutAxis_#3 := View_#%m%_#%v%_layoutAxis_#3 View_#%n%_#%w%_layoutGapWidth := View_#%m%_#%v%_layoutGapWidth View_#%n%_#%w%_layoutMFact := View_#%m%_#%v%_layoutMFact View_#%n%_#%w%_layoutMX := View_#%m%_#%v%_layoutMX View_#%n%_#%w%_layoutMY := View_#%m%_#%v%_layoutMY View_#%n%_#%w%_layoutSymbol := View_#%m%_#%v%_layoutSymbol View_#%n%_#%w%_margins := View_#%m%_#%v%_margins View_#%n%_#%w%_showStackArea := View_#%m%_#%v%_showStackArea View_#%n%_#%w%_wndIds := View_#%m%_#%v%_wndIds StringSplit, View_#%n%_#%w%_margin, View_#%n%_#%w%_margins, `; StringTrimRight, wndIds, View_#%n%_#%w%_wndIds, 1 Loop, PARSE, wndIds, `; { Window_#%A_LoopField%_monitor := n Window_#%A_LoopField%_tags -= 1 << v - 1 Window_#%A_LoopField%_tags += 1 << w - 1 } } ; @TODO: Theoretically, something is wrong here. From the hotkeys this should be manual tiling, but the function says otherwise. View_moveWindow(i=0, d=0) { Local aWndId, m, v WinGet, aWndId, ID, A m := Manager_aMonitor v := Monitor_#%m%_aView_#1 If Tiler_isActive(Manager_aMonitor, v) And InStr(Manager_managedWndIds, aWndId ";") And Not (i = 0 And d = 0) And View_#%m%_#%v%_area_#0 And (i <= View_#%m%_#%v%_area_#0) { If (i = 0) i := Manager_loop(Window_#%aWndId%_area, d, 1, View_#%m%_#%v%_area_#0) Window_move(aWndId, View_#%m%_#%v%_area_#%i%_x, View_#%m%_#%v%_area_#%i%_y, View_#%m%_#%v%_area_#%i%_width, View_#%m%_#%v%_area_#%i%_height) Window_#%aWndId%_area := i Manager_setCursor(aWndId) } } View_resetTileLayout() { Local m, v m := Manager_aMonitor v := Monitor_#%m%_aView_#1 View_#%m%_#%v%_area_#0 := 0 View_#%m%_#%v%_layout_#2 := View_#%m%_#%v%_layout_#1 View_#%m%_#%v%_layout_#1 := 1 View_#%m%_#%v%_layoutAxis_#1 := Config_layoutAxis_#1 View_#%m%_#%v%_layoutAxis_#2 := Config_layoutAxis_#2 View_#%m%_#%v%_layoutAxis_#3 := Config_layoutAxis_#3 View_#%m%_#%v%_layoutGapWidth := Config_layoutGapWidth View_#%m%_#%v%_layoutMFact := Config_layoutMFactor View_#%m%_#%v%_layoutMX := 1 View_#%m%_#%v%_layoutMY := 1 View_#%m%_#%v%_layoutSymbol := Config_layoutSymbol_#1 View_#%m%_#%v%_margins := "0;0;0;0" View_#%m%_#%v%_showStackArea := True StringSplit, View_#%m%_#%v%_margin, View_#%m%_#%v%_margins, `; If Tiler_isActive(m, v) View_arrange(m, v) } View_setActiveWindow(m, v, wndId) { Global If wndId { StringReplace, View_#%m%_#%v%_aWndIds, View_#%m%_#%v%_aWndIds, % wndId ";", All View_#%m%_#%v%_aWndIds := wndId ";" View_#%m%_#%v%_aWndIds } } View_setGapWidth(i, d = 0) { Local v v := Monitor_#%Manager_aMonitor%_aView_#1 If (i = 0) And (d != 0) i := View_#%Manager_aMonitor%_#%v%_layoutGapWidth i += d If (i >= 0 And i < Monitor_#%Manager_aMonitor%_height And i < Monitor_#%Manager_aMonitor%_width) { i := Ceil(i / 2) * 2 View_#%Manager_aMonitor%_#%v%_layoutGapWidth := i Return, 1 } Else Return, 0 } View_setLayout(i, d = 0) { Local v v := Monitor_#%Manager_aMonitor%_aView_#1 If (i = -1) i := View_#%Manager_aMonitor%_#%v%_layout_#2 Else If (i = 0) i := View_#%Manager_aMonitor%_#%v%_layout_#1 i := Manager_loop(i, d, 1, Config_layoutCount) If (i > 0) And (i <= Config_layoutCount) { If Not (i = View_#%Manager_aMonitor%_#%v%_layout_#1) { View_#%Manager_aMonitor%_#%v%_layout_#2 := View_#%Manager_aMonitor%_#%v%_layout_#1 View_#%Manager_aMonitor%_#%v%_layout_#1 := i } View_arrange(Manager_aMonitor, v, True) } } View_setLayoutProperty(name, i, d, opt = 0) { Local a, l, v a := False v := Monitor_#%Manager_aMonitor%_aView_#1 l := View_#%Manager_aMonitor%_#%v%_layout_#1 If Tiler_isActive(Manager_aMonitor, v) { If (name = "Axis") a := Tiler_setAxis(Manager_aMonitor, v, opt, d) Else If (name = "MFactor") { If (opt = 0) opt := 1 a := Tiler_setMFactor(Manager_aMonitor, v, i, d, opt) } Else If (name = "MX") a := Tiler_setMX(Manager_aMonitor, v, d) Else If (name = "MY") a := Tiler_setMY(Manager_aMonitor, v, d) } If (name = "GapWidth") And (Tiler_isActive(Manager_aMonitor, v) Or (Config_layoutFunction_#%l% = "monocle")) a := View_setGapWidth(i, d) If a View_arrange(Manager_aMonitor, v) } View_shuffleWindow(i, d = 0) { Local aWndId, j, replace, v Debug_logMessage("DEBUG[2] View_shuffleWindow(" . i . ", " . d . ")", 2) v := Monitor_#%Manager_aMonitor%_aView_#1 If Tiler_isActive(Manager_aMonitor, v) { View_getTiledWndIds(Manager_aMonitor, v) WinGet, aWndId, ID, A If InStr(View_tiledWndIds, aWndId ";") And (View_tiledWndId0 > 1) { Loop, % View_tiledWndId0 { If (View_tiledWndId%A_Index% = aWndId) { j := A_Index Break } } If (i = 0) i := j Else If (i = 1 And j = 1) i := 2 i := Manager_loop(i, d, 1, View_tiledWndId0) Debug_logMessage("DEBUG[2] View_shuffleWindow: " . j . " -> " . i, 2) If (i != j) { If (i < j) replace := aWndId ";" View_tiledWndId%i% ";" Else replace := View_tiledWndId%i% ";" aWndId ";" StringReplace, View_#%Manager_aMonitor%_#%v%_wndIds, View_#%Manager_aMonitor%_#%v%_wndIds, % aWndId ";", StringReplace, View_#%Manager_aMonitor%_#%v%_wndIds, View_#%Manager_aMonitor%_#%v%_wndIds, % View_tiledWndId%i% ";", %replace% View_arrange(Manager_aMonitor, v) Manager_setCursor(aWndId) } } } } View_toggleFloatingWindow(wndId = 0) { Local l, v If (wndId = 0) WinGet, wndId, ID, A v := Monitor_#%Manager_aMonitor%_aView_#1 l := View_#%Manager_aMonitor%_#%v%_layout_#1 Debug_logMessage("DEBUG[2] View_toggleFloatingWindow; wndId: " . wndId, 2) If (Config_layoutFunction_#%l% And InStr(Manager_managedWndIds, wndId ";")) { Window_#%wndId%_isFloating := Not Window_#%wndId%_isFloating View_arrange(Manager_aMonitor, v) Bar_updateTitle() } } View_toggleMargins() { Local v If Not (Config_viewMargins = "0;0;0;0") { v := Monitor_#%Manager_aMonitor%_aView_#1 Debug_logMessage("DEBUG[3] View_toggleMargins(" . View_#%Manager_aMonitor%_#%v%_margin1 . ", " . View_#%Manager_aMonitor%_#%v%_margin2 . ", " . View_#%Manager_aMonitor%_#%v%_margin3 . ", " . View_#%Manager_aMonitor%_#%v%_margin4 . ")", 3) If (View_#%Manager_aMonitor%_#%v%_margins = "0;0;0;0") View_#%Manager_aMonitor%_#%v%_margins := Config_viewMargins Else View_#%Manager_aMonitor%_#%v%_margins := "0;0;0;0" StringSplit, View_#%Manager_aMonitor%_#%v%_margin, View_#%Manager_aMonitor%_#%v%_margins, `; View_arrange(Manager_aMonitor, v) } } View_toggleStackArea() { Local v v := Monitor_#%Manager_aMonitor%_aView_#1 If Tiler_isActive(Manager_aMonitor, v) And Not Config_dynamicTiling { Tiler_toggleStackArea(Manager_aMonitor, v) View_arrange(Manager_aMonitor, v) } } View_traceAreas(continuously = False) { Local v v := Monitor_#%Manager_aMonitor%_aView_#1 If Tiler_isActive(Manager_aMonitor, v) And Not Config_dynamicTiling Tiler_traceAreas(Manager_aMonitor, v, continuously) }