How to programmatically Tile / Cascade windows ?
http://www.autohotke...p?p=84807#84807Foreword: If you are one those not been using the Tile / Cascade facility available in the taskbar, then try it now.
Minimize all windows and open two instances of windows explorer. Right-click on an empty area on the Taskbar and select Tile Windows Horizontally.. See the result!... Close those windows! This topic is about doing it from a script.
The search does not reveal much posts on the topic.
Tile Windows Vertically, how? Too difficult?
Tile Windows Horizontally/ Vertically With Only Left Click
There are two seperate functions: TileWindows and CascadeWindows in user32.dll which does the job, and even more.
Simple is the simple solution: You can bind any of these DllCalls to a Hotkey!
Tile windows vertically : DllCall( "TileWindows", uInt,0, Int,0, Int,0, Int,0, Int,0 )
Tile windows horizontally : DllCall( "TileWindows", uInt,0, Int,1, Int,0, Int,0, Int,0 )
Cascade windows : DllCall( "CascadeWindows", uInt,0, Int,4, Int,0, Int,0, Int,0 )
Take a look at the MSDN reference (if you are a techie), or just skip it and continue reading.Taken from MSDN:
TileWindows Function
The TileWindows function tiles the specified child windows of the specified parent window.
WORD TileWindows(
HWND hwndParent,
UINT wHow,
RECT *lpRect,
UINT cKids,
const HWND *lpKids
);
hwndParent : [in] Handle to the parent window. If this parameter is NULL, the desktop window is assumed.
wHow : [in] Specifies tiling flags. This parameter can be one of the following values—optionally combined with MDITILE_SKIPDISABLED to prevent disabled multiple-document interface (MDI) child windows from being tiled. MDITILE_HORIZONTAL Tiles windows horizontally.
MDITILE_VERTICAL Tiles windows vertically.lpRect : [in] Pointer to a RECT structure that specifies the rectangular area, in client coordinates, within which the windows are arranged. If this parameter is NULL, the client area of the parent window is used.
cKids : [in] Specifies the number of elements in the array specified by the lpKids parameter. This parameter is ignored if lpKids is NULL.
lpKids : [in] Pointer to an array of handles to the child windows to arrange. If this parameter is NULL, all child windows of the specified parent window (or of the desktop window) are arranged.
Return Value
If the function succeeds, the return value is the number of windows arranged.
If the function fails, the return value is zero. To get extended error information, call GetLastError.[/list]Remarks : Calling TileWindows causes all maximized windows to be restored to their previous size.
CascadeWindows Function
The CascadeWindows function cascades the specified child windows of the specified parent window.
WORD CascadeWindows(
HWND hwndParent,
UINT wHow,
const RECT *lpRect,
UINT cKids,
const HWND *lpKids
);
wHow : [in] Specifies a cascade flag. This parameter can be one or more of the following values. MDITILE_SKIPDISABLED: Prevents disabled multiple-document interface (MDI) child windows from being cascaded.
MDITILE_ZORDER: Windows 2000/XP: Arranges the windows in Z order. If this value is not specified, the windows are arranged using the order specified in the lpKids array.
For other parameters, refer: TileWindows (above)[/list]Remarks :
By default, CascadeWindows arranges the windows in the order provided by the lpKids array, but preserves the Z-Order. If you specify the MDITILE_ZORDER flag, CascadeWindows arranges the windows in Z order.
Calling CascadeWindows causes all maximized windows to be restored to their previous size.
Minimum DLL Version : user32.dll, Minimum operating systems : Windows 95, Windows NT 4.0
You can also set the area where the windows should be Tiled / Cascaded. You can also pass the list of windows handles, and limit the tiling/cascading to a set of windows. But those parameters have to passed as pointers to an Array and a Structure. With some patience, I was able to understand InsertInteger() provided in the help file ( DllCall ), but I do not have the knowledge to explain it.
Instead,
I provide here the WinArrange.ahk written as a wrapper for those two functions. You may just include the wrapper in your script and call the WinArrange() function with much ease. Simply put, you call the WinArrange(), and it takes care of creating the RECT structure and the array of window handles.WinArrange( TC=1, aStr="", VH=0x1, Rect="", hWnd=0x0 ) { CreateArray( aRect, Rect ) ; Create a RECT structure. IfEqual, Rect,, SetEnv, lpRect, 0 ; determining whether lpRect is NULL IfNotEqual,Rect,, SetEnv, lpRect, % &aRect ; or a pointer to the RECT Structure. cKids := CreateArray( aKids, aStr ) ; Create an Array of window handles. IfEqual, aStr,, SetEnv, lpKids, 0 ; determining whether lpKids is NULL IfNotEqual,aStr,, SetEnv, lpKids, % &aKids ; or a pointer to the array of handles. If ( TC= 1 ) { ; then the windows have to be Tiled Return DllCall("TileWindows",Int,hWnd,UInt,VH,UInt,lpRect,Int,cKids,Int,lpKids) } Else { ; the windows have to be Cascaded IfNotEqual, VH, 4, SetEnv,VH,0 ; If VH is 4, windows will be cascaded in ZORDER Return DllCall("CascadeWindows",Int,hWnd,UInt,VH,UInt,lpRect,Int,cKids,Int,lpKids) } } CreateArray( ByRef Arr, aStr="", Size=4 ) { ; complicated variant of InsertInteger() IfEqual, aStr,, Return 0 ; aStr will be a pipe delimited string of integer values. StringReplace, aStr, aStr, |, |, All UseErrorlevel ; Calculating the no. of pipes. aFields := errorLevel + 1 ; errorlevel is no. of pipes, +1 results in no of fields. VarSetCapacity( Arr, ( aFields*Size ), 0 ) ; Initialise var length and zero fill it. Loop, Parse, aStr, | { Loop %Size% DllCall( "RtlFillMemory", UInt, &Arr+[color=red](0 pOffset)[/color]+A_Index-1 ; Thanks to Laszlo , UInt,1, UChar, A_LoopField >> 8*(A_Index-1) & 0xFF ) pOffset += %Size% } Return aFields }
Here is an example that demonstrates the use of above wrapper. You can Copy / Paste & Try it but you require to download the wrapper first : Download : WinArrange.ahk
The following script opens two instances of Windows Explorer to allow ease copy/move tasks between folder/drives. You can control those two windows with the WinArrange() function provided in the wrapper. Exiting the script will close the windows.#Persistent OnExit, ExitRoutine TILE := 1 ; for Param 1 CASCADE := 2 ; for Param 1 VERTICAL := 0 ; for Param 3 HORIZONTAL := 1 ; for Param 3 ZORDER := 4 ; for Param 3 CLIENTAREA := "200|25|1000|700" ; for Param 4 ; ALLWINDOWS (Param 2), ARRAYORDER (Param 3), FULLSCREEN (Param 4) ; are undeclared variables simulating NULL content. Run C:\,,MAX Sleep, 500 hWnd1 := WinExist("A") Run D:\,,MAX Sleep, 500 hWnd2 := WinExist("A") ARRAY := hWnd1 "|" hWnd2 WinArrange( TILE, ARRAY, VERTICAL, CLIENTAREA ) Return ; Auto-Execute section ends! ------------------------------------ ^#F2::WinArrange( CASCADE, ARRAY, ZORDER, CLIENTAREA ) ^#F3::WinArrange( TILE, ARRAY, HORIZONTAL, CLIENTAREA ) ^#F4::WinArrange( TILE, ARRAY, HORIZONTAL, FULLSCREEN ) ^#F5::WinArrange( TILE, ARRAY, VERTICAL, CLIENTAREA ) ^#F6::WinArrange( TILE, ARRAY, VERTICAL, FULLSCREEN ) ^#NumpadADD:: Loop, Parse, ARRAY, | WinActivate, ahk_id %A_LoopField% Return ^#NumpadSub:: Loop, Parse, ARRAY, | WinMinimize, ahk_id %A_LoopField% Return ExitRoutine: Loop, Parse, ARRAY, | WinClose, ahk_id %A_LoopField% ExitApp Return #Include WinArrange.ahk ; ---------------------------------------------
I have used anly two windows in the above example. With WinGet, Var, List creating a list of window handles is very easy. Combining it with ahk_class will give you many probabilities in arranging windows.
I am able see instances where these functions could prove useful.
One may have many instances of Internet Explorer and with the Cascade Windows facility, you can Cascade only the IE windows!
Reading the IE titlebar would allow easy window selection.
You might be alt-tab`ing hard between your script, .ini & other includes.
You can tile only those windows opened by notepad/other editor with a hotkey and view all those files in one go!
I guess, I am tired... Let me see if I can post a part 2 with more examples.

[How To] Programmatically Tile / Cascade windows
![[How To] Programmatically Tile / Cascade windows: post #1](http://autohotkey.com/board/public/style_images/ortem/icon_share.png)
all windows or cascade them. I'd like to have a little more control
though, but don't know if it can be done:
1. tile only selected windows
Say there are 5 windows on the desktop. I'd like to tile just 2 of them (select with Control-LMB) ie. the 2 selected windows gets tiled on top of the other windows.
2. Cascade all windows based on a selected windows
size
Say there're 5 windows on the desktop. I resize one of them (thus it becomes the topmost window) and cascade all windows. All windows sizes will be the same size as the selected one, but cascaded behind it.
Thanks.
![[How To] Programmatically Tile / Cascade windows: post #2](http://autohotkey.com/board/public/style_images/ortem/icon_share.png)
1. tile only selected windows
Say there are 5 windows on the desktop. I'd like to tile just 2 of them (select with Control-LMB) ie. the 2 selected windows gets tiled on top of the other windows.
I do not get the idea. The exact facility is already available in XP atleast.
You may select any number of Windows from taskbar with Ctrl+LButton and right click and select Tile windows from Context menu
2. Cascade all windows based on a selected windows
size
Say there're 5 windows on the desktop. I resize one of them (thus it becomes the topmost window) and cascade all windows. All windows sizes will be the same size as the selected one, but cascaded behind it.
For custom cascading, we will have to use WinMove on every other window on Desktop..
![[How To] Programmatically Tile / Cascade windows: post #3](http://autohotkey.com/board/public/style_images/ortem/icon_share.png)
![[How To] Programmatically Tile / Cascade windows: post #4](http://autohotkey.com/board/public/style_images/ortem/icon_share.png)
I have a script with child windows
I do not understand. Even edit/text controls are child windows.. Can you please elaborate?
![[How To] Programmatically Tile / Cascade windows: post #5](http://autohotkey.com/board/public/style_images/ortem/icon_share.png)
I have a script with child windows
I do not understand. Even edit/text controls are child windows.. Can you please elaborate?
Oh sorry, what I mean is, I have several GUI's with the "+ParentAnotherGUI" option. So they're basically inside the Main GUI. Is it possible to tile or cascade them using your function? I tried it but I can't seem to get it to work.
![[How To] Programmatically Tile / Cascade windows: post #6](http://autohotkey.com/board/public/style_images/ortem/icon_share.png)
WinPosTile(hParent, cIndex, cCount, ByRef x, ByRef y, ByRef w, Byref h) ; [color=#FF0000]hParent=handle of the parent GUI, cIndex=index of the[/color] { ; [color=#FF0000]child window, cCount=number of child windows[/color] cols := Ceil(Sqrt(cCount)), rows := Ceil(Sqrt(cCount)) if (cols*(rows-1) >= cCount) rows-- WinGetPos,,, wGrid, hGrid, ahk_id %hParent% pos_Cols := ( C := Mod( cIndex, cols ) ) ? C : cols, pos_Rows := Ceil( cIndex / cols ) ; thanks to SKAN for this tip wGrid := wGrid / cols, hGrid := hGrid / rows w := wGrid, h := hGrid, x := (wGrid/2) - (w/2) + (wGrid*(pos_Cols-1)), y := (hGrid/2)-(h/2) + (hGrid*(pos_Rows-1)) } WinPosCascade(hParent, cIndex, cCount, ByRef x, ByRef y, ByRef w, ByRef h, Offset="25") ; [color=#FF0000]Parameters same as above function[/color] { WinGetPos,,, wParent, hParent, ahk_id %hParent% w := wParent - (Offset*(cCount-1)), h := (hParent-100) - (Offset*(cCount-1)), x := Offset * (cCount - cIndex), y := Offset * (cCount - cIndex) return } WinTile() { global SubID, hWork ; [color=#FF0000]SubID is an array containing the Hwnd of the child windows, hWork is the Hwnd of the parent window[/color] i := SubID.MaxIndex() for k, v in SubID { WinPosTile(hWork, k, i, x, y, w, h) WinMove, ahk_id %v%,, %x%, %y%, %w%, %h% } } WinCascade() ; [color=#FF0000]SubID is an array containing the Hwnd of the child windows, hWork is the Hwnd of the parent window[/color] { global SubID, hWork i := SubID.MaxIndex() for k, v in SubID { WinPosCascade(hWork, k, i, x, y, w, h) WinMove, ahk_id %v%,, %x%, %y%, %w%, %h% } }
![[How To] Programmatically Tile / Cascade windows: post #8](http://autohotkey.com/board/public/style_images/ortem/icon_share.png)

![[How To] Programmatically Tile / Cascade windows: post #9](http://autohotkey.com/board/public/style_images/ortem/icon_share.png)
Hello,
Can you copy and paste the wrapper along with the cascade and tile scripts into one .ahk file? I want to ask before I test it. Also I am using Win7 OS
Thanks,
Jason
![[How To] Programmatically Tile / Cascade windows: post #10](http://autohotkey.com/board/public/style_images/ortem/icon_share.png)
DllCall( "RtlFillMemory", UInt, &Arr+[color=red](0 pOffset)[/color]+A_Index-1 ; Thanks to Laszlo
I'm getting an error when I run this. Unsupported Method. Any ideas?
Win7 32bit. AHK 1.1.19-ish
![[How To] Programmatically Tile / Cascade windows: post #11](http://autohotkey.com/board/public/style_images/ortem/icon_share.png)