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
majkinetor
  • Moderators
  • 4512 posts
  • Last active: May 20 2019 07:41 AM
  • Joined: 24 May 2006

the client window gets behind others, and disappears.

If you put gui always on top it will not desapear. If you don't put it , you must send it to the top of the Z-order. Any of these are not the hook problem.
Posted Image

majkinetor
  • Moderators
  • 4512 posts
  • Last active: May 20 2019 07:41 AM
  • Joined: 24 May 2006
2Laszlo

This helped to me, so now your dock example works without any problems:

Dock_Update:
   WinSet, AlwaysOnTop, on, ahk_id %Dock_ClientId%
   WinSet, AlwaysOnTop, off, ahk_id %Dock_ClientId%
Return

Posted Image

Laszlo
  • Moderators
  • 4713 posts
  • Last active: Mar 31 2012 03:17 AM
  • Joined: 14 Feb 2005
Yes, that works. However, the window movement is not as smooth as before, and there is considerable flickering, when the window is moved under the taskbar. Maybe, it could be better if it can be done with dll calls directly, or some other, less drastic means.

Otherwise, your docking solution is getting to really useful. Just a little more tweaking…

majkinetor
  • Moderators
  • 4512 posts
  • Last active: May 20 2019 07:41 AM
  • Joined: 24 May 2006

Otherwise, your docking solution is getting to really useful. Just a little more tweaking…

Indeed. I too can't wait to put this to full working version 1.0

I uploaded new script on the first page. Check it out. I updated your version and removed F12 as there is no need for that now.

I don't see any flickering here.
Posted Image

majkinetor
  • Moderators
  • 4512 posts
  • Last active: May 20 2019 07:41 AM
  • Joined: 24 May 2006
I tried to remove ALwaysOnTop solution with something faster so I tried this:

;   WinSet, AlwaysOnTop, on, ahk_id %Dock_ClientId%
;   WinSet, AlwaysOnTop, off, ahk_id %Dock_ClientId%
Tooltip % API_SetWindowPos(Dock_ClientId, Dock_HostId, 0, 0, 0, 0, 2 | 1 )

API_SetWindowPos(hWnd, hwndInsertAfter, x, y, cx, cy, uFlags){
	return DllCall("SetWindowPos", "uint", hWnd, "uint", hwndInsertAfter, "int", x, "int", y, "int", cx, "int", cy, "uint", uFlags)
}

but this doesn't work either well. Strange thing is that tooltip always show 1 which means function was succesiful.
Posted Image

majkinetor
  • Moderators
  • 4512 posts
  • Last active: May 20 2019 07:41 AM
  • Joined: 24 May 2006
This is kind a cool

Gui Show
WinSet, Region, 0-0 150-0 50-150, ahk_id %Dock_ClientID%

Posted Image

Laszlo
  • Moderators
  • 4713 posts
  • Last active: Mar 31 2012 03:17 AM
  • Joined: 14 Feb 2005
Maybe my laptop is too slow, but the window pair does not move very smoothly for me. Just thinking… If we had too hooks, one for window movement and resize – which does not need the AlwaysOnTop trick, and one for window activation (object state change, system foreground), which does not need the code for window movement, then the movement could be smoother.

majkinetor
  • Moderators
  • 4512 posts
  • Last active: May 20 2019 07:41 AM
  • Joined: 24 May 2006
Well, just add this code

If Dock_event = 3
   WinSet , AlwaysOnTop....

I updated first post with this.


Its interesting that all atempts to set Z-order for dockClient in hook handler other then using AOT fail - WinSet, Top , SetWinPos, etc...


So, thats it, we have functional final dock version, consuming 0 CPU, and you can dock anything to anything (like Notepad to Explorer)

If you don't see more problems, I will make this 1.0 and use this as a base for more robust wrapper.

BTW, Laszlo, you are the topic master when expressions are in question so it would be good to see what we can do here to enable expressions with A_DockClientWidth/Height (like the last screenshot). We need something fast, if possible without manual parsing, and it is enough to have only basic math operations (+-*/).

2Sean
Do you happen to know is there any kind of COM class in Win doing expressions ?
Posted Image

Laszlo
  • Moderators
  • 4713 posts
  • Last active: Mar 31 2012 03:17 AM
  • Joined: 14 Feb 2005
The last version seems to work OK, and fast enough. (Checking Dock_event = 3 was clever!) I made a few changes. Keep the ones you see fit.

- There is no need any more for API_ShowWindow(Dock_ClientId, 8) in the Dock_Update subroutine.
- It is a little cleaner to list explicitly the global variables a function needs, albeit longer.
- We don't need to load the hook dll repeatedly.
- It is enough to determine the script's process ID only once.
- The return value of the function Dock was better the logic AND of the handles, which is 0 if any one of them is 0. (Bitwise AND can be 0 otherwise, too.)
- Undock does not need GoSub Dock_Update
- I made the calling syntax of the dock function faster and more flexible, but also more complex (beginners choose one of a few listed options). There are 10 parameters: (xhw,xw,xd, yhh,yh,yd, whw,wd, hhh,hd)
--- The x coordinate of the top, left corner of the client window is computed as
HostX + xhw*HostWidth + xw*ClientWidth + xd, with the parameters xhw, xw and xd
--- The y coordinate of the top, left corner of the client window is computed as
HostY + yhh*HostHeight + yh*ClientHeight + yd, with the parameters yhh, yh and yd
--- The width ClientWidth of the client window is computed as whw*HostWidth + wd, with the parameters whw and wd.
--- The height ClientHeight of the client window is computed as hhh*HostHeight + hd, with the parameters hhh and hd.
#SingleInstance Force
#NoEnv
SetBatchLines -1

SetWinDelay -1
OnExit Close
HookDll = wineventhook.dll

   Run notepad,,,nPID
   WinWait ahk_pid %nPID%
   Dock_HostID := Dock_HookHwnd := WinExist("ahk_pid " . nPID)

   Gui +LastFound -Caption +ToolWindow +Border
   Dock_ClientID := WinExist()
   Gui Add, Text,,Docked Window
   Gui Show
  ; dx = (HostWidth*, ClientWidth*, Offset)
  ; dy = (HostHeight*,ClientHeight*,Offset)
  ;  w = (HostWidth*, Constant)
  ;  h = (HostHeight*,Constant)
  ;Dock(0,0,0, 1,0,-2, 1,0, 0,30)     ; below, full width
  ;Dock(.5,-.5,0, 1,0,10, .5,0, 0,30) ; below, centered, half width
  ;Dock(0,-1,-10, 0,0,0, 0,63, 1,0)   ; left, top
  ;Dock(1,0,10, 0,0,50, 0,63, 1,-50)  ; right, bottom
   Dock(0,0,0, 0,-1,-5, 0,120, 0,30)  ; above, left, fixed width

Dock_Update:
   If (Dock_HookHwnd != Dock_HostID)
      Return
   WinGetPos hX, hY, hW, hH, ahk_id %Dock_HookHwnd%
   W := whw*hW + wd, H := hhh*hH + hd
   WinMove ahk_id %Dock_ClientId%,,hX + xhw*hW + xw*W + xd, hY + yhh*hH + yh*H + yd, W, H

   If (Dock_event = 3) {
      WinSet AlwaysOnTop, On,  ahk_id %Dock_ClientId%
      WinSet AlwaysOnTop, Off, ahk_id %Dock_ClientId%
   }
Return

Close:
   Undock()
   WinClose ahk_id %Dock_HostID%
ExitApp

Dock(_xhw,_xw,_xd, _yhh,_yh,_yd, _whw,_wd, _hhh,_hd) {
   Global HookDll, xhw,xw,xd, yhh,yh,yd, whw,wd, hhh,hd
   Static hwnd, Dock_hHookDll, Dock_msg := 0x550
   If Dock_hHookDll=
      Dock_hHookDll := API_LoadLibrary(HookDll)
   If hwnd=
      hwnd := WinExist("ahk_pid " . DllCall("GetCurrentProcessId"))

   xhw:=_xhw, xw:=_xw, xd:=_xd, yhh:=_yhh, yh:=_yh, yd:=_yd, whw:=_whw, wd:=_wd, hhh:=_hhh, hd:=_hd

   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_hHook3 && Dock_hHook2 && Dock_hHook0 && Dock_hHookDll
}

Dock_HookHandler(wParam, lParam, msg, hwnd) {
   Global Dock_event, Dock_HookHwnd
   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
}

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

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

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

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

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


majkinetor
  • Moderators
  • 4512 posts
  • Last active: May 20 2019 07:41 AM
  • Joined: 24 May 2006
I have no objections to such changes. I intended to do all that myself, the script above is created out of great number of trials and mistakes so it is nor optmised nor done like it should be.

I will test a lil more your version and update the above code with it, if it works OK.


Thx for improvements.

- Undock does not need GoSub Dock_Update

I think it does , but that was before. Without it, dock window sometimes doesn't position correctly.
Posted Image

majkinetor
  • Moderators
  • 4512 posts
  • Last active: May 20 2019 07:41 AM
  • Joined: 24 May 2006
Yeah, works great, I like the syntax too.

One thing needs to be done: to hook application termination and to call appropriate user function so it can shutdown the gui or do whatever he likes with it.

Dock(....., "OnHostTerminate")

OnHostTerminate:
    Msgbox I am off too
    ExitApp
return


Also, ability to specify host classes would be great to have. Like, monitor all ahk_class Notepad windows (jumping on active one, which original model has)
Posted Image

majkinetor
  • Moderators
  • 4512 posts
  • Last active: May 20 2019 07:41 AM
  • Joined: 24 May 2006
New version

2Laszlo
After some usage, I think your interface doesn't provide more benefits then original except allowing expressions (Dock parameters). Its just different, and I like the idea as long as we can extend it a liltle.

- ability to let the Dock client keep its original width & height (should be trivial) without repeating its w & h in Dock call. For instance, its not possible now to create default values for Dock function as Client W & H must be known at call.

- ability to anchor X & Y, so for instance, dock can always keep its width & height but stay at bottom right when resizing. (should be trivial too)




Also, we should start to think about multiple dock clients and host classes. (not trivial)
Posted Image

Laszlo
  • Moderators
  • 4713 posts
  • Last active: Mar 31 2012 03:17 AM
  • Joined: 14 Feb 2005
If the client window does not move with the host, it is not docking, is it? Still, if it is visible, when the host is, the client can be useful for status messages, or building a private task bar of selected applications. It is easily achieved with two more parameters (coefficients of HostX and HostY), but 10 parameters look already too many and confusing, so adding two more makes the function scary. I would add instead another function: Link(X,Y,W,H), with fixed coordinates for the client. It does not even have to inquire the position of the host.
WinGetPos X, Y, W, H, ahk_id %Dock_ClientId%
give the necessary values explicitly.
; .. ..
   WinGetPos X, Y, W, H, ahk_id %Dock_ClientId%
   Link(A_ScreenWidth-W,0,W,H)        ; pin window to upper right corner of screen
   WinGetPos X, Y,,,ahk_id %Dock_HostID%
   WinMove ahk_id %Dock_HostID%,,X+1,Y
   WinMove ahk_id %Dock_HostID%,,X,Y ; instead of calling Dock_Update
Return
; .. ..

Link_Update:
   If (Dock_HookHwnd = Dock_HostID && Dock_event = 3) {
      WinSet AlwaysOnTop, On,  ahk_id %Dock_ClientId%
      WinSet AlwaysOnTop, Off, ahk_id %Dock_ClientId%
   }
Return

Link(x, y, w, h) {
   Global HookDll, Dock_ClientId
   Static hwnd, Dock_hHookDll, Dock_msg := 0x550
   If Dock_hHookDll=
      Dock_hHookDll := API_LoadLibrary(HookDll)
   If hwnd=
      hwnd := WinExist("ahk_pid " . DllCall("GetCurrentProcessId"))

   WinMove ahk_id %Dock_ClientId%,,x, y, w, h

   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, "Link_HookHandler") ;EVENT_OBJECT_STATECHANGE 0x0000800a, EVENT_OBJECT_LOCATIONCHANGE 0x0000800b

   Return Dock_hHook3 && Dock_hHook2 && Dock_hHook0 && Dock_hHookDll
}

Link_HookHandler(wParam, lParam, msg, hwnd) {
   Global Dock_event, Dock_HookHwnd
   GetHookParams(lparam, Dock_event, Dock_HookHwnd)
   GoSub Link_Update
}
If you want to keep the original width and height of the client window (which might look ugly), we can have special values for the corresponding parameters, like "W" and "H" in the Dock function. (In Link() this does not save much work, unless more complicated parameter structure is introduced.)
; .. ..
   Dock(0,0,0, 0,-1,-5, 0,"W", 0,"H") ; above, left, fixed width
; .. ..
Dock(_xhw,_xw,_xd, _yhh,_yh,_yd, _whw,_wd, _hhh,_hd) {
   Global HookDll, xhw,xw,xd, yhh,yh,yd, whw,wd, hhh,hd, Dock_ClientId
   Static hwnd, Dock_hHookDll, Dock_msg := 0x550
   If Dock_hHookDll=
      Dock_hHookDll := API_LoadLibrary(HookDll)
   If hwnd=
      hwnd := WinExist("ahk_pid " . DllCall("GetCurrentProcessId"))

   WinGetPos,,,W, H, ahk_id %Dock_ClientId%
   wd := _wd = "W" ? W : _wd
   hd := _hd = "H" ? H : _hd
   xhw:=_xhw, xw:=_xw, xd:=_xd, yhh:=_yhh, yh:=_yh, yd:=_yd, whw:=_whw, hhh:=_hhh

   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_hHook3 && Dock_hHook2 && Dock_hHook0 && Dock_hHookDll
}


majkinetor
  • Moderators
  • 4512 posts
  • Last active: May 20 2019 07:41 AM
  • Joined: 24 May 2006

If the client window does not move with the host, it is not docking, is it?

Why do you tell this ? OF course its not.

Still, if it is visible, when the host is, the client can be useful for status messages, or building a private task bar of selected applications. It is easily achieved with two more parameters

Both applications are useful. Thats why we need handler so the one can choose what is going to happen when dock host dies.

It is easily achieved with two more parameters (coefficients of HostX and HostY), but 10 parameters look already too many and confusing, so adding two more makes the function scary.

I think number of parameters function has isn't important. We can easily transmit parameters via string thus omiting those not used by user. Also, if it has 20 parameters its not important. U call this function once now only, its not problem to determine paramters correctly.
Along this line, I wanted to note is that docking scenarios will be more or less the same for all users. There are like 10-20 docking setups ppl will use all the time, those that need more can create their own preset itself. So, we can create new function that will call Dock.

DockIndirect( "preset" )

THis func can hold list of presets like "topleft" "rightbottom" "fancy" "bottom midle". IT can also load them from ini file, we can keep presets here.

If you want to keep the original width and height of the client window (which might look ugly)

U can't say that. Its up to the user. Check out LilBuilder. I have dock client that is made like it is and I don't want to resize it, just dock it.

I don't understand quite purpose of Link function. I will try to concentrate more later.
Posted Image

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

If the client window does not move with the host, it is not docking, is it?

Why do you tell this ?

To justify the new function named Link, instead of overloading the Dock function.

I think number of parameters function has isn't important.

It also adds two more multiplications for handling each event. On my slow laptop any speedup is welcome.

We can easily transmit parameters via string thus omitting those not used by user.

True, but using variables in those string parameters (commonly read from an ini file or the registry) makes the parameters horrible looking.

There are like 10-20 docking setups ppl will use all the time, those that need more can create their own preset itself. So, we can create new function that will call Dock.

Yes, like DockLeft(), DockBottomCenter(), etc. This is similar to cut and paste the right sequence of parameters or DockIndirect( "preset" ). Use what you like.

If you want to keep the original width and height of the client window (which might look ugly)

U can't say that. Its up to the user.

If he is not careful, mismatched size windows might look bad. Just wanted to note that keeping the touching sides of equal length often looks nicer. Of course, not always.

I don't understand quite purpose of Link function.

If the client window does not move, the handler is much simpler. With the corresponding Link function the user can save code space and processor power. It only assures that the client is visible, when the host is.