Jump to content

Recommended Posts

Posted

I'm trying to auto-generate some system tray menu items based on the number of monitors a person has in their setup, but I'm having trouble. The way I have it set up, the auto-generated system tray items have to be in the same case in the switch statement. Inside that switch statement, I'm running a function that has an integer as the second variable that represents which monitor the function should use. As far as I can tell, I'd need to be able to let the program know which tray item got selected from inside the case, but after a couple hours searching and trying different things to do that I've come up short.

Included is all parts of the script related to things you can do from the system tray in the current version of the script so that the code can be run as-is for testing. In short, it resizes and moves an open window with the exact name as is specified with the $sTargetWindowName variable so that the titlebar and borders are off-screen, so as to emulate "borderless windowed" functionality in applications without said functionality built in (e.g. certain games where losing focus on the window in fullscreen by interacting with other windows disconnects you from a server you're on). The toolbar menu and options in question simply let the user choose which monitor the "borderless-ized" window goes onto.

#NoTrayIcon
#include-Once
#include <WinAPIGdi.au3>;for _GetMonitors()
#include <WinAPISys.au3>;for _GetMonitors()
#include <TrayConstants.au3>;for $TRAY_ICONSTATE_SHOW

AutoItSetOption("TrayMenuMode", 3)
AutoItSetOption("TrayAutoPause", 0)
AutoItSetOption( "WinTitleMatchMode", 3)

Global $aMonitors[1][5]
$aMonitors[0][0] = 0

;MAIN
;==================================================================================================
Global $sTargetWindowName = "Example Window"
_TrayMenu()
;==================================================================================================

Func _TrayMenu()
    If $aMonitors[0][0] == 0 Then
        _GetMonitors()
    EndIf
    
    Local $idBorderlessize = TrayCreateMenu ("Borderless-ize")
    Local $BorderlessizeMonitor[$aMonitors[0][0]]
    For $i=0 to $aMonitors[0][0] - 1
        Local $Msg = "Monitor " & $i + 1
        $BorderlessizeMonitor[$i] = TrayCreateItem ($Msg, $idBorderlessize)
    Next
    TrayCreateItem("")
    
    Local $idPreferences = TrayCreateItem("Preferences")
    Local $idAbout = TrayCreateItem("About")
    TrayCreateItem ("")
    
    Local $idExit = TrayCreateItem ("Exit")
    
    TraySetState ($TRAY_ICONSTATE_SHOW)
    
    While 1
        Switch TrayGetMsg()
            Case $BorderlessizeMonitor[0] To $BorderlessizeMonitor[$aMonitors[0][0] - 1]
                ;figure out how to get which menu item got pressed so it can be passed to the _Borderlessize function as the second parameter.
                _Borderlessize($sTargetWindowName, 1)
            Case $idPreferences
                ;will allow users to set preferences such as the default monitor, which windows they'd like to manipulate, etc.
            Case $idAbout
                ;will open a messagebox 
            Case $idExit
                ExitLoop
        EndSwitch
    WEnd
EndFunc;==> _TrayMenu


;Moves and resizes the specified window in a way that emulates windowed borderless on the specified monitor, hence "Borderless-ize"
;If no monitor is specified, monitor that window is on is used.
Func _Borderlessize($sWindow = "", $Monitor = 0)
    If $aMonitors[0][0] == 0 Then
        _GetMonitors()
    EndIf
    Local $Msg = ""
    If @NumParams = 1 Then
        Local $iM = _WinOnMonitor($sWindow)
        If $iM = -1 Then
            $Msg &= $sWindow & " is not open."
            MsgBox(0, "", $Msg)
            Return
        ElseIf $iM = 0 Then
            $Msg &= $sWindow & " is not on any display monitors." & @CRLF & @CRLF
            $Msg &= "Please make sure the top left corner of the" & @CRLF & "window is visible and try again."
            MsgBox(0, "", $Msg)
            Return
        EndIf
    Else
        $iM = $Monitor
    EndIf
    Local $ixBorder = _WinAPI_GetSystemMetrics(32)
    Local $iyBorder = _WinAPI_GetSystemMetrics(33)
    Local $iMenu = _WinAPI_GetSystemMetrics(15) + 5 
        ;the +5 is for the 5 extra pixels of height unaccounted for by getting the titlebar height and border thickness. 
        ;I wish I didn't have to hard-code this in, but that's not what I'm here for. I'll make a separate post for this.
    Local $iX = $aMonitors[$iM][1] - $ixBorder
    Local $iY = $aMonitors[$iM][2] - $iMenu - $iyBorder
    Local $iW = $aMonitors[$iM][3] + ($ixBorder * 2)
    Local $iH = $aMonitors[$iM][4]+ ($iyBorder*2) + $iMenu
    WinSetState($sWindow, "", @SW_RESTORE)
    WinMove($sWindow, "", $iX, $iY, $iW, $iH)
EndFunc ;==> _Borderlessize


;Loads the $aMonitors array with information about the display monitors such as size and position.
Func _GetMonitors()
    $aMonitors = _WinAPI_EnumDisplayMonitors()
    If IsArray($aMonitors) Then
        ReDim $aMonitors[$aMonitors[0][0] + 1][5]
        For $ix = 1 To $aMonitors[0][0]
            $aPos = _WinAPI_GetPosFromRect($aMonitors[$ix][1])
            For $j = 0 To 3
                $aMonitors[$ix][$j + 1] = $aPos[$j]
            Next
        Next
    EndIf
EndFunc ;==> _GetMonitors

This is my first time using the forums, so I'm not sure if I included too much of the code. If I did, my apologies.

Posted (edited)

This should work for you :

Local $iMsg
  While True
    $iMsg = TrayGetMsg()
    Switch $iMsg
      Case $BorderlessizeMonitor[0] To $BorderlessizeMonitor[$aMonitors[0][0] - 1]
        ;figure out how to get which menu item got pressed so it can be passed to the _Borderlessize function as the second parameter.
        _Borderlessize($sTargetWindowName, $iMsg - $BorderlessizeMonitor[0] + 1)
    ; .....
    EndSwitch
  WEnd

One other solution is to go onEventMode, then you can use @TRAY_ID to know which item was selected.

Edited by Nine
Posted
19 hours ago, Nine said:

One other solution is to go onEventMode, then you can use @TRAY_ID to know which item was selected.

I had tried the first solution a couple times, it always went screwy. I assume it's because at any one moment in the loop, the program is *either* getting the tray message or running the switch, and because the tray message can include things like "moused over" or "double clicked", it was a roll of the dice as to whether the switch statement would actually be using the right tray message. Either way, it didn't work.

The second solution was exactly what I was looking for, and I managed to get exactly what I wanted after a couple more hours of research, trial, and error. @Tray_ID doesn't return the text of the tray item like I had originally thought, but rather returns the controlID (which is a number created when the tray item is created), which caused some (literal) headaches.

This meant I had to create an array that would store the controlID on creation, and the value that I wanted to pass to _Borderlessize based on which controlID was pressed (I called this array $aBorderlessizeIds). I also made each auto-generated tray item point to the same function when I used TrayItemSetOnEvent, which I called _TrayBorderlessize. Once we get to _TrayBorderlessize, it's just a matter of using _ArraySearch to figure out which row in the array has the same controlID as returned by @Tray_ID, and then using the ArraySearch value to grab the number I wanted from the $aBorderlessizeIds array.

Here's the code, with everything not related to the autogeneration of menu items cut out:

Global $aBorderlessizeIds[1][1]

Func _TrayMenu()
    If $aMonitors[0][0] == 0 Then
        _GetMonitors()
    EndIf
    
    Local $idBorderlessize = TrayCreateMenu ("Borderless-ize")
    Local $idBorderlessizeItem = 0
    ReDim $aBorderlessizeIds[$aMonitors[0][0]][2]
    Local $i = 0
    For $i=0 to $aMonitors[0][0] - 1
        Local $Msg = "Monitor " & $i + 1
        $idBorderlessizeItem = TrayCreateItem ($Msg, $idBorderlessize)
        $aBorderlessizeIds[$i][0] = Int($idBorderlessizeItem)
        $aBorderlessizeIds[$i][1] = $i +1
        TrayItemSetOnEvent(-1, "_TrayBorderlessize")
EndFunc;==> _TrayMenu

Func _TrayBorderlessize()
    Local $Index = Int(_ArraySearch($aBorderlessizeIds, @TRAY_ID, 0, 0, 0, 0, 1, 0))
    _Borderlessize($sTargetWindowName, $aBorderlessizeIds[$Index][1])
EndFunc;==> _TrayBorderlessize

 

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
×
×
  • Create New...