script help: minimize to icon in system tray

Get help with using AutoHotkey (v1.1 and older) and its commands and hotkeys
bittersmile
Posts: 5
Joined: 03 Sep 2019, 11:36

script help: minimize to icon in system tray

20 Aug 2021, 12:00

Dear friends,

Can someone help me with a script? I need to assign a hotkey to hide the current active window to system tray as an icon. As for unhide, it would be best if it can be done from the icon (double click or right click and a menu), but if it is difficult, I cal always unhide all windows.

I searched and found some related scripts, but none of them is exactly what I need. The closest one is this one:
https://www.autohotkey.com/boards/viewtopic.php?t=27339

Since I am not good enough to modify these scripts to suit my need, can someone help me?

Thank you very much.
teadrinker
Posts: 4335
Joined: 29 Mar 2015, 09:41
Contact:

Re: script help: minimize to icon in system tray

20 Aug 2021, 15:25

Try this:

Code: Select all

#NoTrayIcon
DetectHiddenWindows, On
global EVENT_SYSTEM_MINIMIZESTART := 0x0016
     , EVENT_SYSTEM_MINIMIZEEND   := 0x0017
     , EVENT_OBJECT_DESTROY       := 0x8001
     , Windows := []

MinimizeHook := new WinEventHook(EVENT_SYSTEM_MINIMIZESTART, EVENT_SYSTEM_MINIMIZEEND, "HookProc")
DestroyHook  := new WinEventHook(EVENT_OBJECT_DESTROY      , EVENT_OBJECT_DESTROY    , "HookProc")
OnMessage(0x404, "AHK_NOTIFYICON")
OnExit("ShowHidden")
Return

Esc::
Terminate() {
   ExitApp
}

^Space::
AddToListAndMinimize() {
   hWnd := WinExist("A")
   SetTitleMatchMode, RegEx
   if WinActive("ahk_class ^(Progman|WorkerW|Shell_TrayWnd)$")
      Return
   if !Windows.HasKey(hWnd) {
      WinGetTitle, title
      Windows[hwnd] := {title: title, hIcon: GetWindowIcon(hWnd)}
   }
   WinMinimize
}

ShowHidden() {
   for hwnd, v in Windows {
      if !DllCall("IsWindowVisible", "Ptr", hwnd)
         WinShow, ahk_id %hwnd%
      if WinExist("ahk_id" . v.gui)
         RemoveTrayIcon(v.gui)
   }
}

GetWindowIcon(hWnd) {
   static WM_GETICON := 0x007F, ICON_SMALL := 0, GCLP_HICONSM := -34
        , GetClassLong := "GetClassLong" . (A_PtrSize = 4 ? "" : "Ptr")
   SendMessage, WM_GETICON, ICON_SMALL, A_ScreenDPI,, ahk_id %hWnd%
   if !smallIcon := ErrorLevel
      smallIcon := DllCall(GetClassLong, "Ptr", hWnd, "Int", GCLP_HICONSM, "Ptr")
   Return smallIcon
}

AddTrayIcon(hIcon, tip := "")
{
   static NIF_MESSAGE := 1, NIF_ICON := 2, NIF_TIP := 4, NIM_ADD := 0
   flags := NIF_MESSAGE|NIF_ICON|(tip = "" ? 0 : NIF_TIP)
   VarSetCapacity(NOTIFYICONDATA, size := A_PtrSize = 8 ? 848 : A_IsUnicode? 828 : 444, 0)
   Gui, New, +hwndhGui
   NumPut(size         , NOTIFYICONDATA)
   NumPut(hGui         , NOTIFYICONDATA, A_PtrSize)
   NumPut(uID  := 0x404, NOTIFYICONDATA, A_PtrSize*2)
   NumPut(flags        , NOTIFYICONDATA, A_PtrSize*2 + 4)
   NumPut(nMsg := 0x404, NOTIFYICONDATA, A_PtrSize*2 + 8)
   NumPut(hIcon        , NOTIFYICONDATA, A_PtrSize*3 + 8)
   if (tip != "")
      StrPut(tip, &NOTIFYICONDATA + 4*A_PtrSize + 8, "CP0")
   DllCall("shell32\Shell_NotifyIcon", "UInt", NIM_ADD, "Ptr", &NOTIFYICONDATA)
   Return hGui
}

RemoveTrayIcon(hWnd, uID := 0x404)
{
   VarSetCapacity(NOTIFYICONDATA, size := A_PtrSize = 8 ? 848 : A_IsUnicode? 828 : 444, 0)
   NumPut(size, NOTIFYICONDATA)
   NumPut(hWnd, NOTIFYICONDATA, A_PtrSize)
   NumPut(uID , NOTIFYICONDATA, A_PtrSize*2)
   DllCall("shell32\Shell_NotifyIcon", "UInt", NIM_DELETE := 2, "Ptr", &NOTIFYICONDATA)
   Return
}

AHK_NOTIFYICON(wp, lp, msg, hwnd)   ; wp — uID, lp — Message
{
   static WM_LBUTTONDOWN := 0x201, WM_RBUTTONUP := 0x205, maxLenMenuStr := 40
   if !(lp = WM_LBUTTONDOWN || lp = WM_RBUTTONUP)
      Return
   
   for k, v in Windows
      if (v.gui = hwnd && window := k)
         break
   if !window
      Return
   
   Switch lp {
   Case WM_LBUTTONDOWN:
      RemoveTrayIcon(hwnd)
      Gui, %hwnd%: Destroy
      WinShow, ahk_id %window%
      WinActivate, ahk_id %window%
   Case WM_RBUTTONUP:
      title := Windows[window, "title"]
      b := StrLen(title) > maxLenMenuStr
      menuText := "Restore «" . SubStr(title, 1, maxLenMenuStr) . (b ? "..." : "") . "»"
      fn := Func(A_ThisFunc).Bind(0x404, WM_LBUTTONDOWN, 0x404, hwnd)
      Menu, IconMenu, Add , % menuText, % fn
      Menu, IconMenu, Icon, % menuText, % "HICON:*" . Windows[window, "hIcon"]
      Menu, IconMenu, Add , Terminate script and show all windows, Terminate
      Menu, IconMenu, Show
      Menu, IconMenu, DeleteAll
   }
}

HookProc(hWinEventHook, event, hwnd, idObject, idChild, dwEventThread, dwmsEventTime) {
   static OBJID_WINDOW := 0
   if !( idObject = OBJID_WINDOW && Windows.HasKey(hwnd) )
      Return
   Switch event {
   Case EVENT_SYSTEM_MINIMIZESTART:
      WinHide, ahk_id %hWnd%
      Windows[hwnd, "gui"] := AddTrayIcon(Windows[hwnd, "hIcon"], Windows[hwnd, "title"])
   Case EVENT_OBJECT_DESTROY, EVENT_SYSTEM_MINIMIZEEND:
      iconGui := Windows[hwnd, "gui"]
      if WinExist("ahk_id" . iconGui)
         RemoveTrayIcon(iconGui)
      try Gui, %iconGui%: Destroy
      ( event = EVENT_OBJECT_DESTROY && Windows.Delete(hwnd) )
   }
}

class WinEventHook
{  ; Event Constants: https://is.gd/tRT5Wr
   __New(eventMin, eventMax, hookProc, eventInfo := 0, idProcess := 0, idThread := 0, dwFlags := 0) {
      this.pCallback := RegisterCallback(hookProc, "F",, eventInfo)
      this.hHook := DllCall("SetWinEventHook", "UInt", eventMin, "UInt", eventMax, "Ptr", 0, "Ptr", this.pCallback
                                             , "UInt", idProcess, "UInt", idThread, "UInt", dwFlags, "Ptr")
   }
   __Delete() {
      DllCall("UnhookWinEvent", "Ptr", this.hHook)
      DllCall("GlobalFree", "Ptr", this.pCallback, "Ptr")
   }
}
Minimize a window to the tray icon with ^Space, afterward this window can be minimized as usual, it will be hidden in the tray icon.
A minimized window can be restored by clicking the tray icon or from the tray icon menu.
Last edited by teadrinker on 21 Aug 2021, 16:05, edited 1 time in total.
User avatar
Xtra
Posts: 2750
Joined: 02 Oct 2015, 12:15

Re: script help: minimize to icon in system tray

21 Aug 2021, 16:05

teadrinker wrote:
20 Aug 2021, 15:25
Try this:
:thumbup:
ufunk
Posts: 54
Joined: 17 Jan 2020, 13:45

Re: script help: minimize to icon in system tray

26 Oct 2021, 06:45

Thank you very much, I also searched for such a script for a long time :)
ufunk
Posts: 54
Joined: 17 Jan 2020, 13:45

Re: script help: minimize to icon in system tray

31 Dec 2021, 12:14

Hi,
minimize a window to tray and unhide it from tray works great. But after the first unhide from tray, I just have the wish that the window minimizes as usual when I press minimize in title bar of the window. The current behaviour is that the window minimizes to tray when I press minimize in title bar. My wish is that the window should only minimize to tray when I press the hotkey for it (^Space).
Could someone help me with that? Implementing this change is beyond my ahk skills.

For clarity, here is a picture of the minimize button in the title bar I am referring to:
Image
teadrinker
Posts: 4335
Joined: 29 Mar 2015, 09:41
Contact:

Re: script help: minimize to icon in system tray

01 Jan 2022, 13:29

@ufunk

Code: Select all

#NoTrayIcon
DetectHiddenWindows, On
global EVENT_SYSTEM_MINIMIZEEND := 0x0017
     , EVENT_OBJECT_DESTROY     := 0x8001
     , Windows := []

MinimizeHook := new WinEventHook(EVENT_SYSTEM_MINIMIZEEND, EVENT_SYSTEM_MINIMIZEEND, "HookProc")
DestroyHook  := new WinEventHook(EVENT_OBJECT_DESTROY    , EVENT_OBJECT_DESTROY    , "HookProc")
OnMessage(0x404, "AHK_NOTIFYICON")
OnExit("ShowHidden")
Return

^Space::
AddToListAndMinimize() {
   hWnd := WinExist("A")
   SetTitleMatchMode, RegEx
   if WinActive("ahk_class ^(Progman|WorkerW|Shell_TrayWnd)$")
      Return
   if !Windows.HasKey(hWnd) {
      WinGetTitle, title
      Windows[hwnd] := {title: title, hIcon: GetWindowIcon(hWnd)}
   }
   WinMinimize
   WinHide
   Windows[hwnd, "gui"] := AddTrayIcon(Windows[hwnd, "hIcon"], Windows[hwnd, "title"])
}

ShowHidden() {
   for hwnd, v in Windows {
      if !DllCall("IsWindowVisible", "Ptr", hwnd)
         WinShow, ahk_id %hwnd%
      if WinExist("ahk_id" . v.gui)
         RemoveTrayIcon(v.gui)
   }
}

GetWindowIcon(hWnd) {
   static WM_GETICON := 0x007F, ICON_SMALL := 0, GCLP_HICONSM := -34
        , GetClassLong := "GetClassLong" . (A_PtrSize = 4 ? "" : "Ptr")
   SendMessage, WM_GETICON, ICON_SMALL, A_ScreenDPI,, ahk_id %hWnd%
   if !smallIcon := ErrorLevel
      smallIcon := DllCall(GetClassLong, "Ptr", hWnd, "Int", GCLP_HICONSM, "Ptr")
   Return smallIcon
}

AddTrayIcon(hIcon, tip := "")
{
   static NIF_MESSAGE := 1, NIF_ICON := 2, NIF_TIP := 4, NIM_ADD := 0
   flags := NIF_MESSAGE|NIF_ICON|(tip = "" ? 0 : NIF_TIP)
   VarSetCapacity(NOTIFYICONDATA, size := 396, 0)
   Gui, New, +hwndhGui
   NumPut(size         , NOTIFYICONDATA)
   NumPut(hGui         , NOTIFYICONDATA, A_PtrSize)
   NumPut(uID  := 0x404, NOTIFYICONDATA, A_PtrSize*2)
   NumPut(flags        , NOTIFYICONDATA, A_PtrSize*2 + 4)
   NumPut(nMsg := 0x404, NOTIFYICONDATA, A_PtrSize*2 + 8)
   NumPut(hIcon        , NOTIFYICONDATA, A_PtrSize*3 + 8)
   if (tip != "")
      StrPut(tip, &NOTIFYICONDATA + 4*A_PtrSize + 8, "CP0")
   DllCall("shell32\Shell_NotifyIcon", "UInt", NIM_ADD, "Ptr", &NOTIFYICONDATA)
   Return hGui
}

RemoveTrayIcon(hWnd, uID := 0x404)
{
   VarSetCapacity(NOTIFYICONDATA, size := 24, 0)
   NumPut(size, NOTIFYICONDATA)
   NumPut(hWnd, NOTIFYICONDATA, A_PtrSize)
   NumPut(uID , NOTIFYICONDATA, A_PtrSize*2)
   DllCall("shell32\Shell_NotifyIcon", "UInt", NIM_DELETE := 2, "Ptr", &NOTIFYICONDATA)
   Return
}

AHK_NOTIFYICON(wp, lp, msg, hwnd)   ; wp — uID, lp — Message
{
   static WM_LBUTTONDOWN := 0x201, WM_RBUTTONUP := 0x205, maxLenMenuStr := 40
   if !(lp = WM_LBUTTONDOWN || lp = WM_RBUTTONUP)
      Return
   
   for k, v in Windows
      if (v.gui = hwnd && window := k)
         break
   if !window
      Return
   
   Switch lp {
   Case WM_LBUTTONDOWN:
      RemoveTrayIcon(hwnd)
      Gui, %hwnd%: Destroy
      WinShow, ahk_id %window%
      WinActivate, ahk_id %window%
   Case WM_RBUTTONUP:
      title := Windows[window, "title"]
      b := StrLen(title) > maxLenMenuStr
      menuText := "Restore «" . SubStr(title, 1, maxLenMenuStr) . (b ? "..." : "") . "»"
      fn := Func(A_ThisFunc).Bind(0x404, WM_LBUTTONDOWN, 0x404, hwnd)
      Menu, IconMenu, Add , % menuText, % fn
      Menu, IconMenu, Icon, % menuText, % "HICON:*" . Windows[window, "hIcon"]
      Menu, IconMenu, Add , Show all windows, ShowHidden
      Menu, IconMenu, Show
      Menu, IconMenu, DeleteAll
   }
}

HookProc(hWinEventHook, event, hwnd, idObject, idChild, dwEventThread, dwmsEventTime) {
   static OBJID_WINDOW := 0
   if !( idObject = OBJID_WINDOW && Windows.HasKey(hwnd) )
      Return
   iconGui := Windows[hwnd, "gui"]
   if WinExist("ahk_id" . iconGui) {
      RemoveTrayIcon(iconGui)
      Gui, %iconGui%: Destroy
   }
   ( event = EVENT_OBJECT_DESTROY && Windows.Delete(hwnd) )
}

class WinEventHook
{  ; Event Constants: https://is.gd/tRT5Wr
   __New(eventMin, eventMax, hookProc, eventInfo := 0, idProcess := 0, idThread := 0, dwFlags := 0) {
      this.pCallback := RegisterCallback(hookProc, "F",, eventInfo)
      this.hHook := DllCall("SetWinEventHook", "UInt", eventMin, "UInt", eventMax, "Ptr", 0, "Ptr", this.pCallback
                                             , "UInt", idProcess, "UInt", idThread, "UInt", dwFlags, "Ptr")
   }
   __Delete() {
      DllCall("UnhookWinEvent", "Ptr", this.hHook)
      DllCall("GlobalFree", "Ptr", this.pCallback, "Ptr")
   }
}
ufunk
Posts: 54
Joined: 17 Jan 2020, 13:45

Re: script help: minimize to icon in system tray

01 Jan 2022, 16:31

This is breathtaking and works like a charm. Thank you a lot for your inputs in such a fruitful way. I appreciate that.
poopux
Posts: 9
Joined: 21 Mar 2024, 08:48

Re: script help: minimize to icon in system tray

21 Mar 2024, 09:08

I like the script, yet, how do I restore the window that has been hidden? I only see the option to restore via the tray. Is there a possible to use a hotkey for restore, too?
teadrinker
Posts: 4335
Joined: 29 Mar 2015, 09:41
Contact:

Re: script help: minimize to icon in system tray

21 Mar 2024, 11:50

poopux wrote: how do I restore the window that has been hidden?
The script can hide many windows. Which one are you talking about?
poopux
Posts: 9
Joined: 21 Mar 2024, 08:48

Re: script help: minimize to icon in system tray

21 Mar 2024, 14:19

any window. Once a window is hidden in the tray by pressing CTRL + Space it can only be recovered by clicking on the icon in the tray. I would also like to recover it with a hotkey.
Hide a window by hotkey and restore it with a hotkey.

Thanks
poopux
teadrinker
Posts: 4335
Joined: 29 Mar 2015, 09:41
Contact:

Re: script help: minimize to icon in system tray

21 Mar 2024, 14:53

Imagine you already have 10 hidden windows. Which of them should appear after pressing a hotkey? Any of them?
poopux
Posts: 9
Joined: 21 Mar 2024, 08:48

Re: script help: minimize to icon in system tray

22 Mar 2024, 05:31

One by one. Last in, first out.
teadrinker
Posts: 4335
Joined: 29 Mar 2015, 09:41
Contact:

Re: script help: minimize to icon in system tray

22 Mar 2024, 11:14

Ctrl + R to restore:

Code: Select all

#Requires AutoHotkey v1

#NoTrayIcon
DetectHiddenWindows, On
global EVENT_SYSTEM_MINIMIZEEND := 0x0017
     , EVENT_OBJECT_DESTROY     := 0x8001
     , Windows := [], orderList := []

MinimizeHook := new WinEventHook(EVENT_SYSTEM_MINIMIZEEND, EVENT_SYSTEM_MINIMIZEEND, "HookProc")
DestroyHook  := new WinEventHook(EVENT_OBJECT_DESTROY    , EVENT_OBJECT_DESTROY    , "HookProc")
OnMessage(0x404, "AHK_NOTIFYICON")
OnExit("ShowHidden")
Return

^Space::
AddToListAndMinimize() {
   hWnd := WinExist("A")
   SetTitleMatchMode, RegEx
   if WinActive("ahk_class ^(Progman|WorkerW|Shell_TrayWnd)$")
      Return
   if !Windows.HasKey(hWnd) {
      WinGetTitle, title
      Windows[hwnd] := {title: title, hIcon: GetWindowIcon(hWnd)}
   }
   WinMinimize
   WinHide
   Windows[hwnd, "gui"] := AddTrayIcon(Windows[hwnd, "hIcon"], Windows[hwnd, "title"])
   orderList.Push(hwnd)
}

^r::
RestoreLast() {
   AHK_NOTIFYICON(0x404, WM_LBUTTONDOWN := 0x201, 0x404, Windows[orderList.Pop()].gui)
}

ShowHidden() {
   for hwnd, v in Windows {
      if !DllCall("IsWindowVisible", "Ptr", hwnd)
         WinShow, ahk_id %hwnd%
      if WinExist("ahk_id" . v.gui)
         RemoveTrayIcon(v.gui)
   }
   orderList := []
}

GetWindowIcon(hWnd) {
   static WM_GETICON := 0x007F, ICON_SMALL := 0, GCLP_HICONSM := -34
        , GetClassLong := "GetClassLong" . (A_PtrSize = 4 ? "" : "Ptr")
   SendMessage, WM_GETICON, ICON_SMALL, A_ScreenDPI,, ahk_id %hWnd%
   if !smallIcon := ErrorLevel
      smallIcon := DllCall(GetClassLong, "Ptr", hWnd, "Int", GCLP_HICONSM, "Ptr")
   Return smallIcon
}

AddTrayIcon(hIcon, tip := "")
{
   static NIF_MESSAGE := 1, NIF_ICON := 2, NIF_TIP := 4, NIM_ADD := 0
   flags := NIF_MESSAGE|NIF_ICON|(tip = "" ? 0 : NIF_TIP)
   VarSetCapacity(NOTIFYICONDATA, size := 396, 0)
   Gui, New, +hwndhGui
   NumPut(size         , NOTIFYICONDATA)
   NumPut(hGui         , NOTIFYICONDATA, A_PtrSize)
   NumPut(uID  := 0x404, NOTIFYICONDATA, A_PtrSize*2)
   NumPut(flags        , NOTIFYICONDATA, A_PtrSize*2 + 4)
   NumPut(nMsg := 0x404, NOTIFYICONDATA, A_PtrSize*2 + 8)
   NumPut(hIcon        , NOTIFYICONDATA, A_PtrSize*3 + 8)
   if (tip != "")
      StrPut(tip, &NOTIFYICONDATA + 4*A_PtrSize + 8, "CP0")
   DllCall("shell32\Shell_NotifyIcon", "UInt", NIM_ADD, "Ptr", &NOTIFYICONDATA)
   Return hGui
}

RemoveTrayIcon(hWnd, uID := 0x404)
{
   VarSetCapacity(NOTIFYICONDATA, size := 24, 0)
   NumPut(size, NOTIFYICONDATA)
   NumPut(hWnd, NOTIFYICONDATA, A_PtrSize)
   NumPut(uID , NOTIFYICONDATA, A_PtrSize*2)
   DllCall("shell32\Shell_NotifyIcon", "UInt", NIM_DELETE := 2, "Ptr", &NOTIFYICONDATA)
}

AHK_NOTIFYICON(wp, lp, msg, hwnd)   ; wp — uID, lp — Message
{
   static WM_LBUTTONDOWN := 0x201, WM_RBUTTONUP := 0x205, maxLenMenuStr := 40
   if !(lp = WM_LBUTTONDOWN || lp = WM_RBUTTONUP)
      Return
   
   for k, v in Windows
      if (v.gui = hwnd && window := k)
         break
   if !window
      Return
   
   Switch lp {
   Case WM_LBUTTONDOWN:
      RemoveTrayIcon(hwnd)
      Gui, %hwnd%: Destroy
      WinShow, ahk_id %window%
      WinActivate, ahk_id %window%
   Case WM_RBUTTONUP:
      title := Windows[window, "title"]
      b := StrLen(title) > maxLenMenuStr
      menuText := "Restore «" . SubStr(title, 1, maxLenMenuStr) . (b ? "..." : "") . "»"
      fn := Func(A_ThisFunc).Bind(0x404, WM_LBUTTONDOWN, 0x404, hwnd)
      Menu, IconMenu, Add , % menuText, % fn
      Menu, IconMenu, Icon, % menuText, % "HICON:*" . Windows[window, "hIcon"]
      Menu, IconMenu, Add , Show all windows, ShowHidden
      Menu, IconMenu, Show
      Menu, IconMenu, DeleteAll
   }
}

HookProc(hWinEventHook, event, hwnd, idObject, idChild, dwEventThread, dwmsEventTime) {
   static OBJID_WINDOW := 0
   if !( idObject = OBJID_WINDOW && Windows.HasKey(hwnd) )
      Return
   iconGui := Windows[hwnd, "gui"]
   if WinExist("ahk_id" . iconGui) {
      RemoveTrayIcon(iconGui)
      Gui, %iconGui%: Destroy
   }
   for k, v in orderList {
      if (v = hwnd) {
         orderList.RemoveAt(k)
         break
      }
   }
   ( event = EVENT_OBJECT_DESTROY && Windows.Delete(hwnd) )
}

class WinEventHook
{  ; Event Constants: https://is.gd/tRT5Wr
   __New(eventMin, eventMax, hookProc, eventInfo := 0, idProcess := 0, idThread := 0, dwFlags := 0) {
      this.pCallback := RegisterCallback(hookProc, "F",, eventInfo)
      this.hHook := DllCall("SetWinEventHook", "UInt", eventMin, "UInt", eventMax, "Ptr", 0, "Ptr", this.pCallback
                                             , "UInt", idProcess, "UInt", idThread, "UInt", dwFlags, "Ptr")
   }
   __Delete() {
      DllCall("UnhookWinEvent", "Ptr", this.hHook)
      DllCall("GlobalFree", "Ptr", this.pCallback, "Ptr")
   }
}
poopux
Posts: 9
Joined: 21 Mar 2024, 08:48

Re: script help: minimize to icon in system tray

23 Mar 2024, 04:08

Thank you very much! I will give it a try and revert.
poopux
Posts: 9
Joined: 21 Mar 2024, 08:48

Re: script help: minimize to icon in system tray

24 Mar 2024, 10:50

works like a charm, thank you!!

Return to “Ask for Help (v1)”

Who is online

Users browsing this forum: Bing [Bot] and 69 guests