Tips_gui   >   Misc   >   Multiple Monitors

Multiple Monitors

Getting a window to reopen in the same position with multiple monitors on the Mac platforms is a bit tricky.

$modes.$width and $modes.$height returns the width and height of the main monitor (the one with the applications menu bar), ignoring additional monitors.

$modes.$height is the height not including the 22 pixels used by the applications menu bar. For a monitor set to 1200 pixels high, $modes.$height is 1178 pixels.

sys(104) and sys(105) return the overall total width and overall height of all the monitors provided that the main monitor is the left most monitor in your System Preferences > Displays > Arrangement window and the tops of the extra monitors are not above the top of the main monitor.

If a monitor is located to the left of the main monitor is will not be included in the sys(104) width calculation.
If a monitor goes higher than the top of the main monitor the portion above the main monitor will not be included in the sys(105) height calculation.

Tip

You can move the applications menu bar from one monitor to another by dragging it to the other monitor in System Preferences > Displays > Arrangement

If the resolution is different on the 2 monitors (one is 1200 pixels high, the other is 1024 pixels high) it becomes a bit of a guessing game outside of the main monitor where the top and bottom of the additional monitor really is.

If you have a dual monitor setup you can click the Run Demo button in the StudioTips Browser window to find out the current $modes.$width, $modes.$height, sys(104), and sys(105), for your current monitor arrangement. Move the StudioTips Browser window to each of the monitors. The demo will also tell you the top, left, bottom, and right pixel location of the StudioTips Browser window.

In my applications I store the last size and position of each window instance for each user when they close the window. The next time they open the same window instance I restore it to the last size and position. If the user is on a different work station or goes from a multiple monitor setup to a single monitor the window instance may need to be resized and repositioned to fit on the available monitor space.

The sample code that follows checks the size and location of a window instance to make sure the window instance fits within the available monitor(s) and if not, resizes and repositions the window to fit within the available space. You are free to copy the code to your own application.

checkSizeAndFit

The checkSizeAndFit method simply has a switch/case that checks the platform and call the respective checkSizeAndFit submethod.

; Parameter 1: prWinInst - Item Reference - reference to the window instance.

; Check and Size to the window to fit the available screen area.
Switch sys(6)
   Case 'M','X'
      Do method checkSizeAndFit_MacOS (prWinInst) Returns FlagOK
   Default
      Do method checkSizeAndFit_Default (prWinInst) Returns FlagOK
End Switch

Quit method FlagOK

checkSizeAndFit_Default

The checkSizeAndFit_Default method is used for non-Mac platforms. For non-Mac platforms all Omnis window instances exist within the Omnis application space ($modes) so the method does not need to worry about the size and location of multiple monitors.

; Parameter 1: prWinInst - Item Reference - reference to the window instance.

; On Windows and Linux the Omnis application window is the max space.
Calculate AvailWidth as $modes.$width
Calculate AvailHeight as $modes.$height

Set reference rTopLevelFrame to prWinInst.$toplevelhwnd.$ref

; Adjust window size if it doesn't fit the available space.
If rTopLevelFrame.$width>AvailWidth
   Calculate rTopLevelFrame.$width as AvailWidth
End If
If rTopLevelFrame.$height>AvailHeight
   Calculate rTopLevelFrame.$height as AvailHeight
End If

; Reposition window if it is outside the available width.
If rTopLevelFrame.$left+rTopLevelFrame.$width>AvailWidth
   Calculate rTopLevelFrame.$left as AvailWidth-rTopLevelFrame.$width
End If

; If the window is below the available height, move it up.
If rTopLevelFrame.$top+rTopLevelFrame.$height>AvailHeight
   Calculate rTopLevelFrame.$top as AvailHeight-rTopLevelFrame.$height
End If

; Check to make sure the window is not off the top of the main monitor window.
If rTopLevelFrame.$top<0
   Calculate rTopLevelFrame.$top as 0
End If

; Check to make sure the window is not off the left of the main monitor window.
If rTopLevelFrame.$left<0
   Calculate rTopLevelFrame.$left as 0
End If

Quit method kTrue

checkSizeAndFit_MacOS

The checkSizeAndFit_MacOS method is used for the Mac platform. On the Mac platform the Omnis window instances can exist outside of $modes space so the method needs to find out the size and location of external monitors using AppleScript then size and locate the window instance accordinly.

; Parameter 1: prWinInst - Item Reference - reference to the window instance.

; Overall Omnis application space on the Mac platform
; includes extra monitors to the left of the main monitor.

Calculate Width_MainMonitor as $modes.$width
; Note : main monitor height excludes the system bar (53 pixels)
Calculate Height_MainMonitor as $modes.$height

; Get the right bounds of the screen. May not be the whole deal if external on the left !
Calculate AScript as con('tell Application ',chr(34),'Finder',chr(34),chr(13),' set screensize to bounds of window of desktop',chr(13),' set returnval to item 3 of screensize',chr(13),' result',chr(13),'end tell')
Do $runapplescript(AScript,ScriptResult)
Calculate Width_Overall as ScriptResult

; Get the leftmost coordinate. Tells us if the external monitor is on the left (if negative).
Calculate AScript as con('tell Application ',chr(34),'Finder',chr(34),chr(13),' set screensize to bounds of window of desktop',chr(13),' set returnval to item 1 of screensize',chr(13),' result',chr(13),'end tell')
Do $runapplescript(AScript,ScriptResult)

; This takes account of having an external monitor on the left - if it is on the right then leftmost value is 0
Calculate Width_Overall as Width_Overall-ScriptResult

; If the main monitor width is the same as the overall width, we have no external monitor or its
; the same width and exactly on top or underneath - otherwise calculate the left of the external
Calculate ExternalMonitor_Left as pick(Width_MainMonitor<>Width_Overall,0,pick(ScriptResult=0,ScriptResult,Width_MainMonitor+1))
Calculate ExternalMonitor_Width as pick(Width_MainMonitor<>Width_Overall,Width_MainMonitor,pick(ScriptResult=0,-ScriptResult,Width_Overall-Width_MainMonitor))

; Get the height bounds of the screen.
Calculate AScript as con('tell Application ',chr(34),'Finder',chr(34),chr(13),' set screensize to bounds of window of desktop',chr(13),' set returnval to item 4 of screensize',chr(13),' result',chr(13),'end tell')
Do $runapplescript(AScript,ScriptResult)
; Note : if the external monitor is lower then this gives overall height, if higher then this is only the main mon height.
Calculate Height_Overall as ScriptResult

Calculate AScript as con('tell Application ',chr(34),'Finder',chr(34),chr(13),' set screensize to bounds of window of desktop',chr(13),' set returnval to item 2 of screensize',chr(13),' result',chr(13),'end tell')
Do $runapplescript(AScript,ScriptResult)
; Note : we have no way of knowing if the external monitor opens lower down than the main monitor, only if higher (so top is negative).
Calculate ExternalMonitor_Top as pick(Height_MainMonitor<>Height_Overall,0,ScriptResult)

; Note Omnis takes 53 off any value less than 0 but if we are on an external monitor we can put it back as we don't have the system bar!!
If ExternalMonitor_Top<0
   
   ; This corrects the height_overall where external is higher than main monitor
   Calculate Height_Overall as Height_Overall-ExternalMonitor_Top
   Calculate ExternalMonitor_Top as ExternalMonitor_Top-53
   
End If

; Note - we have no way of knowing if the external monitor is less height than the main monitor - only if it is taller
Calculate ExternalMonitor_Height as pick(Height_MainMonitor<>Height_Overall,Height_MainMonitor,Height_Overall)

; Note : the toolbar can be relevant to either main monitor.

Set reference rTopLevelFrame to prWinInst.$toplevelhwnd.$ref

; Make sure that the window's width is no greater than the overal monitor width
If rTopLevelFrame.$width>Width_Overall
   Calculate rTopLevelFrame.$width as Width_Overall
End If

; Make sure that the window's height is no greater than the overal monitor height less the toolbar
If rTopLevelFrame.$height>Height_Overall-Toolbar_Height
   Calculate rTopLevelFrame.$height as Width_Overall
End If

; If the window's left edge is inside the main monitor, use the main monitor as the available height.
If rTopLevelFrame.$left<=Width_MainMonitor&rTopLevelFrame.$left=0
   
   ; Note : the toolbar can be relevant to either main monitor.
   
   If rTopLevelFrame.$height>Height_MainMonitor
      Calculate rTopLevelFrame.$height as Height_MainMonitor
   End If
   
   ; Make sure the top of the window is not off the top of the main window.
   If rTopLevelFrame.$top<Toolbar_Height
      Calculate rTopLevelFrame.$top as Toolbar_Height
   End If
   
   ; Make sure the bottom of the window is not past the bottom edge of the main monitor.
   If rTopLevelFrame.$top+rTopLevelFrame.$height>Height_MainMonitor-Toolbar_Height
      If Height_MainMonitor-Toolbar_Height>rTopLevelFrame.$height
         Calculate rTopLevelFrame.$top as Height_MainMonitor-Toolbar_Height-rTopLevelFrame.$height
      Else
         Calculate rTopLevelFrame.$top as Toolbar_Height
         Calculate rTopLevelFrame.$height as Height_MainMonitor-Toolbar_Height
      End If
   End If
   
Else
   ; The window's left edge is outside of the main monitor, use ExternalMonitor_Height as the available height.
   
   If rTopLevelFrame.$height>ExternalMonitor_Height
      Calculate rTopLevelFrame.$height as ExternalMonitor_Height
   End If
   
   ; Make sure the top of the window is not off the top of the external window.
   If rTopLevelFrame.$top<ExternalMonitor_Top+Toolbar_Height
      Calculate rTopLevelFrame.$top as ExternalMonitor_Top+Toolbar_Height
   End If
   
   ; Make sure the bottom of the window is not off the bottom edge of the available space.
   If rTopLevelFrame.$top+rTopLevelFrame.$height>ExternalMonitor_Height
      If rTopLevelFrame.$height<(ExternalMonitor_Height-Toolbar_Height)
         Calculate rTopLevelFrame.$top as ExternalMonitor_Height-rTopLevelFrame.$height
      Else
         ; The window is larger than the available space, size it to fit.
         Calculate rTopLevelFrame.$top as Toolbar_Height
         Calculate rTopLevelFrame.$height as ExternalMonitor_Height-Toolbar_Height
      End If
      ; If the extra monitor is smaller than the main monitor it could still be off the bottom of the extra monitor
   End If
   
End If

; Make sure the right edge of the window is within the overall width.
Calculate Right as rTopLevelFrame.$left+rTopLevelFrame.$width
; If rTopLevelFrame.$left+rTopLevelFrame.$width>pick(ExternalMonitor_Left<0,Width_Overall,Width_MainMonitor)

If rTopLevelFrame.$left+rTopLevelFrame.$width>pick(ExternalMonitor_Left<0,Width_Overall,Width_MainMonitor)
   Calculate rTopLevelFrame.$left as pick(ExternalMonitor_Left<0,Width_Overall,Width_MainMonitor)-rTopLevelFrame.$width
End If

; Make sure the left of the window is not off the left edge of the available space.
; ExternalMonitor_Left can be less than zero - if it is greater than 0 then 0 is our low point
If rTopLevelFrame.$left<min(0,ExternalMonitor_Left)
   Calculate rTopLevelFrame.$left as min(0,ExternalMonitor_Left)
End If

Quit method kTrue