Jump to content

Sky Slate Blueberry Blackcurrant Watermelon Strawberry Orange Banana Apple Emerald Chocolate
Photo

[module] Dock 1.0        (testing 2.0 b3)


  • Please log in to reply
367 replies to this topic
Laszlo
  • Moderators
  • 4713 posts
  • Last active: Mar 31 2012 03:17 AM
  • Joined: 14 Feb 2005

When I move it, picture becomes garbage.

You should not move it. This is what I said: "prevent moving the docked window, or even remove its title bar". It behaves like a control, which nobody expects to be moved around. You can freely move the parent window. It is true: resizing is more difficult, but can be done.

SetParent can not be made to work generally good… its general usage is equal to 0.

There are many such scripts posted, which work OK. In my main AHK script I have 6 different windows docked with SetParent, another 4 I use occasionally. Just search the Forum and you will find fine working examples. If you failed to make it work, maybe, you did not try hard enough. "Its general usage is" strictly greater than 0.

Here are a few more things you ought to do when using SetParent (disable resize, hide the title bar of Notepad):
Gui Add, Button, X255 Y348 W90 H24, NOTEPAD
Gui Show, x200 y50 w600 h400
WinGet gID, ID, %A_ScriptName%
WinGetPos X, Y, W, H, ahk_id %gID%

Run notepad,,,nPID
WinWait ahk_pid %nPID%
WinSet Style, -0x40000, ahk_pid %nPID%       ; Disable resize
WinMove ahk_pid %nPID%,,0, 400+2-H, 600, 360 ; Client area + Border - Window Height
WinGet nID, ID, ahk_pid %nPID%

DllCall("SetParent", UInt,nID, UInt,gID)
WinActivate ahk_id %gID%
WinActivate ahk_id %nID%


majkinetor
  • Moderators
  • 4512 posts
  • Last active: May 20 2019 07:41 AM
  • Joined: 24 May 2006
2Laszlo
Its buggy, like I said. Minimize maximize and menu is lost. You can refresh it ofc, but there will always be some things, generaly.

Laszlo, you obviously miss the point. This thing you speak about has NOTHING TO DO WITH DOCKING. That is NOT docking.

Docking is the way to connect 2 arbitrary windows so they move minimise and maximize together in any setup.

Dock client will also follow various Dock Host instances around which is not possbile with your method as Unseting Parent and Setting it for new window looks like sht.


I have changed the first page with screens to show you the point.
The GUI now has button that you can click to open Notepad. Open Notepad, move it, open it again, move it... Click 3 notpeads. Dock window will jump to them imediately.

This is fundamental feature of docking not available with poor SetParent method, which is even not recomended to be used as such. U didn't notice "MUST NOT" word from MSDN in red quote by JGR.
Posted Image

majkinetor
  • Moderators
  • 4512 posts
  • Last active: May 20 2019 07:41 AM
  • Joined: 24 May 2006
I updated the first post with some nice xamples.
Posted Image

majkinetor
  • Moderators
  • 4512 posts
  • Last active: May 20 2019 07:41 AM
  • Joined: 24 May 2006
OMG, I just realised that

SetWinDelay -1

creates almost instant chacing of dock host to dock client.... Isn't that great.
Posted Image

Laszlo
  • Moderators
  • 4713 posts
  • Last active: Mar 31 2012 03:17 AM
  • Joined: 14 Feb 2005

Minimize maximize and menu is lost.

You cannot maximize it. In my English XP SP2 minimizing and restoring, or moving the window around does not hide the menu. I wonder, what makes your PC so different. Do you have some custom versions of the Windows system files?

Laszlo, you obviously miss the point. This thing you speak about has NOTHING TO DO WITH DOCKING.

I did not say it was docking:

you can have similar effects in much simpler way

The SetParent method does everything needed to enhance an application with menus, additional buttons, infos, etc., at least in my laptop. In one of my scripts I have more child windows to a single parent, which move, hide or restore together. If an application needs more features, use real docking, as I said:

the real value of the hooks could be seen in more complex examples



toralf
  • Moderators
  • 4035 posts
  • Last active: Aug 20 2014 04:23 PM
  • Joined: 31 Jan 2005
Thanks majkinetor for this modul.
It will come handy when SetParent doesn't do the job.
Ciao
toralf
 
I use the latest AHK version (1.1.15+)
Please ask questions in forum on ahkscript.org. Why?
For online reference please use these Docs.

majkinetor
  • Moderators
  • 4512 posts
  • Last active: May 20 2019 07:41 AM
  • Joined: 24 May 2006
New version of Dock func is availalbe that is much more fluid and handles showing hiding alt tabing etc...

Check it out at first page. Just execute script and enjoy.
Posted Image

toralf
  • Moderators
  • 4035 posts
  • Last active: Aug 20 2014 04:23 PM
  • Joined: 31 Jan 2005
The link to download in first post doesn't work.
Ciao
toralf
 
I use the latest AHK version (1.1.15+)
Please ask questions in forum on ahkscript.org. Why?
For online reference please use these Docs.

majkinetor
  • Moderators
  • 4512 posts
  • Last active: May 20 2019 07:41 AM
  • Joined: 24 May 2006
Sorry, didn't know AutoHotKey.Net is case sensitive.
Posted Image

JGR
  • Members
  • 59 posts
  • Last active: Feb 07 2012 08:49 PM
  • Joined: 15 Jun 2006
By trapping events 0x800A and 0x800B as well there is no need for a timer at all...


SetBatchLines, -1
SetWinDelay -1
CoordMode, tooltip, screen
DetectHiddenWindows, On


	Gui, +LastFound +ToolWindow +AlwaysOnTop
	hGui := WinExist()
	Gui, Add, Text, ,Open Notepad
	Gui, Show, AutoSize 

	Dock_HostClass := "Notepad"
	Dock_ClientId := hGui
	Dock("L","B", "A_DockHostWidth", 0 )

return

Dock( H="R",V="T", sizeX="", sizeY="", dx=0, dy=0 ) {
	local hwnd, msg


	hwnd := WinExist("ahk_pid " . DllCall("GetCurrentProcessId","Uint"))
	Dock_msg := 0x550

	HookDll = wineventhook.dll
	
	Dock_pH := H 
	Dock_pV := V
	Dock_dx := dx 
	Dock_dy := dy
	Dock_sizeX := sizeX 
	Dock_sizeY := sizeY

	Dock_hHookDll := API_LoadLibrary(HookDll)

	Dock_hHook0 := Hook(hwnd, Dock_msg, 3)								;   EVENT_SYSTEM_FOREGROUND
	[color=red]Dock_hHook2 := Hook(hwnd, Dock_msg, 10, 11)		;	EVENT_SYSTEM_MOVESIZESTART :=  10	EVENT_SYSTEM_MOVESIZEEND :=  11
	Dock_hHook3 := Hook(hwnd, Dock_msg, 0x800A, 0x800B, "Dock_HookHandler")		;EVENT_OBJECT_STATECHANGE        0x0000800a, EVENT_OBJECT_LOCATIONCHANGE     0x0000800b,[/color]


	return Dock_hHook & Dock_hHookDll
}

API_ShowWindow(hwnd, flag){
   return DllCall("ShowWindow", "UInt", hwnd, "int", flag) 	
}

Dock_Timer:
	critical 
	WinGetClass Dock_cls, ahk_id %Dock_HookHwnd% 

	if (Dock_cls != Dock_HostClass)
		return

	if (Dock_Event = 3) 
		API_ShowWindow(Dock_ClientId, 8)
		
	WinGetPos, Dock_hX, Dock_hY, Dock_hW, Dock_hH,  ahk_id %Dock_HookHwnd%
	WinGetPos, Dock_cX, Dock_cY, Dock_cW, Dock_cH,  ahk_id %Dock_ClientId%
	Dock_H := Dock_cH
	Dock_W := Dock_cW

	
	if (Dock_sizeX)
		StringReplace, Dock_W, Dock_sizeX, A_DockHostWidth, %Dock_hW%


	if (Dock_sizeY)
		StringReplace, Dock_H, Dock_sizeY, A_DockHostHeight, %Dock_hH%

	

	Dock_x := Dock_hX 
	if (Dock_pH = "R")
			Dock_x := Dock_hX + Dock_hW
	else if (Dock_pH = "M") 
		Dock_x := Dock_hX + (Dock_hW//2) - (Dock_cW//2)

	Dock_y := Dock_hY
	if (Dock_pV = "B")
		Dock_y := Dock_hY + Dock_hH
	else if (Dock_pV = "M") 
		Dock_y := Dock_hY + (Dock_hH//2) - (Dock_cH//2)


	Dock_x += Dock_dx, Dock_y += Dock_dy
	WinMove, ahk_id %Dock_ClientId%, ,%Dock_X%, %Dock_Y%, %Dock_W%, %Dock_H%
return


Undock(){
	goSub Dock_Timer
	Unhook(Dock_hHook, Dock_msg)
	API_FreeLibrary(HookDll)
}
	
Dock_HookHandler(wParam, lParam, msg, hwnd) {
	local e

	GetHookParams(lparam, Dock_event, Dock_HookHwnd)	   


	;if (Dock_event = 10)		;movesizse start
		;SetTimer Dock_Timer, 0

	;if (Dock_event = 11)		;movesize end
		;Undock()

	;if (Dock_event = 3)
	GoSub Dock_Timer
}


GetHookParams(lparam, ByRef event, ByRef hwnd="", ByRef idObject="", ByRef idChild="", ByRef dwEventThread="", ByRef dwmsEventTime="") {
	event			:=GetDeRefInteger(lParam+4)
	hwnd			:=GetDeRefInteger(lParam+8)
	idObject		:=GetDeRefInteger(lParam+12)
	idChild			:=GetDeRefInteger(lParam+16)
	dwEventThread	:=GetDeRefInteger(lParam+20)
	dwmsEventTime	:=GetDeRefInteger(lParam+24)
}

Hook(comm_hwnd, comm_msg, s_event, e_event="", function="", wparam=0) { 
	global HookDll 
    
	r := DllCall(HookDll "\reghook", "UInt", comm_hwnd, "UInt", COMM_MSG, "UInt", s_event, "UInt", e_event ? e_event : s_event, "UInt", wparam) 
	if !r 
		return 0 

	if (function)
		OnMessage(COMM_MSG, function) 

	return r 
}

Unhook(handle, com_msg) { 
   OnMessage(com_msg) 
   return DllCall("UnhookWinEvent", "UInt", handle) 
} 

API_LoadLibrary( dll ) { 
   return DllCall("LoadLibrary", "str", dll) 
}

API_FreeLibrary( h ) {
    return DllCall("FreeLibrary", "uint", h) 
}

InsertInteger(pInteger, ByRef pDest, pOffset = 0, pSize = 4)
; The caller must ensure that pDest has sufficient capacity.  To preserve any existing contents in pDest,
; only pSize number of bytes starting at pOffset are altered in it.
{
   Loop %pSize%  ; Copy each byte in the integer into the structure as raw binary data.
      DllCall("RtlFillMemory", UInt, &pDest + pOffset + A_Index-1, UInt, 1, UChar, pInteger >> 8*(A_Index-1) & 0xFF)
}

ExtractInteger(ByRef pSource, pOffset = 0, pIsSigned = false, pSize = 4)
; pSource is a string (buffer) whose memory area contains a raw/binary integer at pOffset.
; The caller should pass true for pSigned to interpret the result as signed vs. unsigned.
; pSize is the size of PSource's integer in bytes (e.g. 4 bytes for a DWORD or Int).
; pSource must be ByRef to avoid corruption during the formal-to-actual copying process
; (since pSource might contain valid data beyond its first binary zero).
{
   Loop %pSize%  ; Build the integer by adding up its bytes.
      result += *(&pSource + pOffset + A_Index-1) << 8*(A_Index-1)
   if (!pIsSigned OR pSize > 4 OR result < 0x80000000)
      return result  ; Signed vs. unsigned doesn't matter in these cases.
   ; Otherwise, convert the value (now known to be 32-bit) to its signed counterpart:
   return -(0xFFFFFFFF - result + 1)
}


GetDeRefInteger(pSource, pIsSigned = false, pSize = 4)
; pSource is an integer pointer to a raw/binary integer
; The caller should pass true for pSigned to interpret the result as signed vs. unsigned.
; pSize is the size of PSource's integer in bytes (e.g. 4 bytes for a DWORD or Int).
{
   Loop %pSize%  ; Build the integer by adding up its bytes.
      result += *(pSource + A_Index-1) << 8*(A_Index-1)
   if (!pIsSigned OR pSize > 4 OR result < 0x80000000)
      return result  ; Signed vs. unsigned doesn't matter in these cases.
   ; Otherwise, convert the value (now known to be 32-bit) to its signed counterpart:
   return -(0xFFFFFFFF - result + 1)
}

SetDeRefInteger(pInteger, pDest, pSize = 4)
; The caller must ensure that *pDest has sufficient capacity and that pDest is a valid dereferencable integer pointer.
; To preserve any existing contents at *pDest, only pSize number of bytes are altered.
{
   Loop %pSize%  ; Copy each byte in the integer into the structure as raw binary data.
      DllCall("RtlFillMemory", UInt, pDest + A_Index-1, UInt, 1, UChar, pInteger >> 8*(A_Index-1) & 0xFF)
}


majkinetor
  • Moderators
  • 4512 posts
  • Last active: May 20 2019 07:41 AM
  • Joined: 24 May 2006
I suspected there are some of these but didn't know what to choose on bunhc of them
EVENT_OBJECT_STATECHANGE
EVENT_OBJECT_LOCATIONCHANGE

I will try tomorrow how it behaves in dock script
Posted Image

Laszlo
  • Moderators
  • 4713 posts
  • Last active: Mar 31 2012 03:17 AM
  • Joined: 14 Feb 2005
I played around with this docking, using the latest dll JGR posted. Both the original script and JGR's version suffers from the problem in my PC that sometimes the docked window does not show up; sometimes it appears, but after Alt-Tab-ing to another window and back the docked window is not shown. Even if the docked window is visible, when I click on it, it gets to a funny state: after the next change of applications, it is not shown.

If I activate the docked window with WinActivate, it becomes visible, but stays in the limbo state, that is, it disappears again at task change. I found that the commands in subroutine F12 makes the docked window to work correctly (until I click on it again). You can do it manually, too: open the script's main window (double click on its tray icon) and close it. Activating Notepad will show the docked window correctly, again.

You can call this subroutine periodically, but we ought to find the cause of the problem. Any guesses?
#SingleInstance Force
#NoEnv
SetBatchLines -1

SetWinDelay -1
OnExit Close
HookDll = wineventhook.dll

   Run notepad,,,nPID
   WinWait ahk_pid %nPID%
   WinGet Dock_HostID, ID, ahk_pid %nPID%

   Gui +LastFound -Caption +ToolWindow +Border
   Dock_ClientID := WinExist()
   Gui Add, Text,,Docked Window
   Gui Show

   Dock("L","B", "A_DockHostWidth", 0)
   GoSub F12
Return

F12::
   WinActivate ahk_id %Dock_HostID%
   GoSub Dock_Update
   Sleep 0
   ListVars
   Sleep 0
   WinHide %A_ScriptFullPath% - AutoHotkey
Return

Close:
   WinClose ahk_id %Dock_HostID%
ExitApp

Dock(H="R",V="T", sizeX="", sizeY="", dx=0, dy=0) {
   Local hwnd, msg

   hwnd := WinExist("ahk_pid " . DllCall("GetCurrentProcessId"))
   Dock_msg := 0x550

   Dock_pH := H
   Dock_pV := V
   Dock_dx := dx
   Dock_dy := dy
   Dock_sizeX := sizeX
   Dock_sizeY := sizeY

   Dock_hHookDll := API_LoadLibrary(HookDll)

   Dock_hHook0 := Hook(hwnd, Dock_msg, 3)      ; EVENT_SYSTEM_FOREGROUND
   Dock_hHook2 := Hook(hwnd, Dock_msg, 10, 11) ; EVENT_SYSTEM_MOVESIZESTART 10   EVENT_SYSTEM_MOVESIZEEND 11
   Dock_hHook3 := Hook(hwnd, Dock_msg, 0x800A, 0x800B, "Dock_HookHandler") ;EVENT_OBJECT_STATECHANGE 0x0000800a, EVENT_OBJECT_LOCATIONCHANGE 0x0000800b

   Return Dock_hHook & Dock_hHookDll
}

API_ShowWindow(hwnd, flag){
   return DllCall("ShowWindow", "UInt", hwnd, "int", flag)
}

Dock_Update:
   If (Dock_HookHwnd != Dock_HostID)
      Return

   API_ShowWindow(Dock_ClientId, 8)

   WinGetPos, Dock_hX, Dock_hY, Dock_hW, Dock_hH,  ahk_id %Dock_HookHwnd%
   WinGetPos, Dock_cX, Dock_cY, Dock_cW, Dock_cH,  ahk_id %Dock_ClientId%
   Dock_H := Dock_cH
   Dock_W := Dock_cW

   If (Dock_sizeX)
      StringReplace, Dock_W, Dock_sizeX, A_DockHostWidth, %Dock_hW%

   If (Dock_sizeY)
      StringReplace, Dock_H, Dock_sizeY, A_DockHostHeight, %Dock_hH%

   Dock_x := Dock_hX
   If (Dock_pH = "R")
         Dock_x := Dock_hX + Dock_hW
   Else If (Dock_pH = "M")
      Dock_x := Dock_hX + (Dock_hW//2) - (Dock_cW//2)

   Dock_y := Dock_hY
   If (Dock_pV = "B")
      Dock_y := Dock_hY + Dock_hH
   Else If (Dock_pV = "M")
      Dock_y := Dock_hY + (Dock_hH//2) - (Dock_cH//2)

   Dock_x += Dock_dx, Dock_y += Dock_dy
   WinMove ahk_id %Dock_ClientId%,,%Dock_X%, %Dock_Y%, %Dock_W%, %Dock_H%
Return

Undock() {
   GoSub Dock_Update
   Unhook(Dock_hHook, Dock_msg)
   API_FreeLibrary(HookDll)
}

Dock_HookHandler(wParam, lParam, msg, hwnd) {
   Global
   GetHookParams(lparam, Dock_event, Dock_HookHwnd)
   GoSub Dock_Update
}

GetHookParams(lparam, ByRef event, ByRef hwnd="", ByRef idObject="", ByRef idChild="", ByRef dwEventThread="", ByRef dwmsEventTime="") {
   DllCall("RtlMoveMemory", UIntP,event        , UInt,lParam+ 4, UInt, 4)
   DllCall("RtlMoveMemory", UIntP,hwnd         , UInt,lParam+ 8, UInt, 4)
   DllCall("RtlMoveMemory", UIntP,idObject     , UInt,lParam+12, UInt, 4)
   DllCall("RtlMoveMemory", UIntP,idChild      , UInt,lParam+16, UInt, 4)
   DllCall("RtlMoveMemory", UIntP,dwEventThread, UInt,lParam+20, UInt, 4)
   DllCall("RtlMoveMemory", UIntP,dwmsEventTime, UInt,lParam+24, UInt, 4)
}

Hook(comm_hwnd, comm_msg, s_event, e_event="", function="", wparam=0) {
   Global HookDll
   r := DllCall(HookDll "\reghook", UInt,comm_hwnd, UInt,COMM_MSG, UInt,s_event, UInt,e_event ? e_event : s_event, UInt,wparam)
   If (function)
      OnMessage(COMM_MSG, function)
   Return r
}

Unhook(handle, com_msg) {
   OnMessage(com_msg)
   Return DllCall("UnhookWinEvent", "UInt", handle)
}

API_LoadLibrary( dll ) {
   Return DllCall("LoadLibrary", "str", dll)
}

API_FreeLibrary( h ) {
   Return DllCall("FreeLibrary", "uint", h)
}

I checked (with TrayTip) that the hook is correctly called, only the docked window is not shown. I guess, the following command does not work well:
API_ShowWindow(Dock_ClientId, 8)
Flag values other than 8 don't work, either.

polyethene
  • Members
  • 5519 posts
  • Last active: May 17 2015 06:39 AM
  • Joined: 26 Oct 2012
Great concept, but what can wineventhook.dll do here that a normal SetTimer+WinMove can't? e.g.

SetWinDelay, -1
SetBatchLines, -1

Critical
Gui, +LastFound -Caption +Resize +ToolWindow ;+AlwaysOnTop
Gui, Add, Edit, x0 y0 w300 h30, This is docking client
Gui, Add, Button, x+0 yp gOnClick, New Notepad
Gui, Show, x-500 y0 h30
gui := WinExist()

OnClick:
Run, notepad, , , pid
SetTitleMatchMode, 2
WinWait, ahk_pid %pid%
If !hook
	SetTimer, CheckMov, 1
hook := WinExist()

CheckMov:
If !WinExist("ahk_id" . hook) {
	Gui, Destroy
	SetTimer, CheckMov, Off
	ExitApp
}
WinGetPos, x, y, w, , ahk_id %hook%
y -= 50
Gui, Show, x%x% y%y% w%w% NA
Return

~*Esc::ExitApp

autohotkey.com/net Site Manager

 

Contact me by email (polyethene at autohotkey.net) or message tidbit


majkinetor
  • Moderators
  • 4512 posts
  • Last active: May 20 2019 07:41 AM
  • Joined: 24 May 2006
2 Titan
Well, the fact that you have 1ms timer which will interupt anything serious script should do besides docking. If you make timer not so fast, the dock will not be dock at all (try 100ms for instance). So, at every milisecond of your any script that should have docked guis will be interuped at every millisecond with 3 commands unless you make all of the thread non interuptable by timers which then introduces new problem with timers U might have that should interupt things.

Well, its not strange many of here don't like extensive use of timers.

Contrary to that, hook is quiet while you do nothing. It reports when something happens in manner "hej, new window is active" or "hej, this one is going to move" so if none of those things happen, you don't do anything.
Posted Image

Laszlo
  • Moderators
  • 4713 posts
  • Last active: Mar 31 2012 03:17 AM
  • Joined: 14 Feb 2005
The last version of the dock script does not use timer but Windows events, therefore the movement is smoother than with AHK timers, and possibly uses less processor power. Otherwise the demos have similar functionality.

However, both versions suffer from the same problem: the client window gets behind others, and disappears. The main advantage of the SetParent method: the children become controls of the parent, and so they move together, none of them gets behind other windows individually.