Handling Multiple Monitors in Omnis
This example demonstrates how to detect all available monitors on a user’s computer and correctly position Omnis windows across them.
Although Windows currently uses an MDI Frame (so it effectively reports a single screen), the same code works seamlessly on both macOS and Windows.
What This Code Does
- Detects monitor layout --- ensures that if someone re-orients monitors in macOS System Preferences, the Omnis window still opens entirely on a visible screen.\
- Moves a window to a chosen monitor --- via a menu built from the
detected monitor list:
- Move to main monitor (1600×1600)
- Move to secondary monitor (800×800)
- Ensures proper sizing --- the window will not open larger than the monitor it’s on, accounting for the Omnis toolbar position and menu bar height.\
- Snaps window to monitor size --- resizes windows that are too wide or tall to fit.
This requirement has existed for a long time --- but became much easier once the new APIs arrived in Omnis 11.x.
Parameters & Local Variables
Name Type Purpose
pCacheHeight Boolean If true, forces Omnis to
re-query the menu bar height
(macOS only).
delimiter Character Used in token parsing.
height, width Integer (64-bit) Monitor dimensions.
mainScreenHeight Integer (64-bit) Tracks main screen height.
menuBarHeight Integer (default macOS menu bar height.
24)
offsetX, Integer (64-bit) Screen offsets and adjusted Y
offsetY, omnisY coordinate.
screenList List List of all monitors.
screenString Character Raw string from sys(240).
Getting the List of Screens
# Gets a list of screens on the user's computer.
# On Windows (MDI), there will only be one.
Do $cinst.$getMenuBarHeight(pCacheHeight) Returns menuBarHeight
Do screenList.$define(width,height,offsetX,offSetY,omnisY)
Calculate screenString as sys(240)
Repeat
Do method getNextMonitorToken (screenString,'[cxy_]',width.$ref,delimiter.$ref) Returns screenString
Do method getNextMonitorToken (screenString,'[cxy_]',height.$ref,delimiter.$ref) Returns screenString
Do method getNextMonitorToken (screenString,'[cxy_]',offsetX.$ref,delimiter.$ref) Returns screenString
If delimiter='y'
Calculate offsetX as -offsetX
End If
Do method getNextMonitorToken (screenString,'[cxy_]',offSetY.$ref,delimiter.$ref) Returns screenString
If delimiter='y'
Calculate offSetY as -offSetY
End If
If mainScreenHeight<=0
Calculate mainScreenHeight as height-menuBarHeight
Else
Calculate omnisY as offSetY+height-menuBarHeight
Calculate omnisY as omnisY-mainScreenHeight
Calculate omnisY as omnisY*-1
End If
Do screenList.$add(width,height,offsetX,offSetY,omnisY)
Until screenString=""
Quit method screenList
The getNextMonitorToken Method
# Parses sys(240) into monitor values
Parameters:
pString (Character)
pRegExp (Character)
pValue (Item Ref)
pDelimiter (Character)
Calculate returnString as pString
Calculate length as len(returnString)
Calculate startToken as rxpos(pRegExp,returnString,kTrue,kFalse,matchLen)
Calculate pDelimiter as charat(returnString,startToken)
Calculate returnString as right(returnString,length-startToken)
Calculate endToken as rxpos(pRegExp,returnString,kTrue,kFalse,matchLen)
If endToken=0
Calculate pValue as returnString
Calculate returnString as ''
Else
Calculate pValue as mid(returnString,1,endToken-1)
Calculate returnString as right(returnString,length-endToken)
End If
Quit method returnString
Getting the macOS Menu Bar Height
Do $cinst.$getMenuBarHeight(pCacheHeight) Returns menuBarHeight
If not(pCacheHeight)
If not(I_DOS_MACHINE)
Begin text block
Line:tell application "System Events"
Line:tell process "Omnis"
Line:set menuBar to menu bar 1
Line:set menuBarSize to size of menuBar
Line:set height to item 2 of menuBarSize
Line:return height
Line:end tell
Line:end tell
End text block
Get text block applescript
Do code method Common.$doApplescript (applescript,result) Returns #F
If flag true
If len(result)
Calculate cMenuBarHeight as result
End If
End If
Else
Breakpoint # TODO: Handle Windows equivalent
End If
End If
Quit method cMenuBarHeight
Moving a Window to a Selected Monitor
# Moves a selected window to another monitor and resizes it to fit
Parameters:
pMonitorList (List) -> Monitor to move to
pWindowRef (Ref) -> Window reference
pTopBorder (Int)
pLeftBorder (Int)
If pMonitorList.$colcount=0
Breakpoint "Missing monitor row"
Quit method kFalse
End If
If pWindowRef=''
Breakpoint "Missing window reference"
Quit method kFalse
End If
If isclear(pTopBorder)|isclear(pLeftBorder)
Calculate topBorder as 5
Calculate leftBorder as 5
Else
Calculate topBorder as pTopBorder
Calculate leftBorder as pLeftBorder
End If
Calculate pWindowRef.$top as pMonitorList.omnisY+topBorder
Calculate pWindowRef.$left as pMonitorList.offsetX+leftBorder
If pWindowRef.$width+rightBorderMin+leftBorder>pMonitorList.width
Calculate pWindowRef.$width as pMonitorList.width-rightBorderMin-leftBorder
End If
If pWindowRef.$height+bottomBorderMin+topBorder>pMonitorList.height
Calculate pWindowRef.$height as pMonitorList.height-bottomBorderMin-topBorder
End If
Example: Cascading Windows on a Monitor
If pMonitorList.$colcount<=0
Calculate list as $cinst.$getMonitorlist
Calculate pMonitorList as list.1
End If
Do $cinst.$buildOpenWindowList('Top',kFalse,kTrue) Returns windowList
If windowList.$linecount=0
Quit method kTrue
End If
Do windowList.$first(kFalse,kTrue) Returns #F
While flag true
Set reference windowRef to windowList.iWindowRef
If windowRef.$minimized
Calculate windowRef.$maximized as kTrue
End If
If $cinst.$moveWindowToSelectedMonitor.$cando
Do $cinst.$moveWindowToSelectedMonitor(pMonitorList,windowRef,topBorder,leftBorder)
End If
Calculate topBorder as topBorder+22 ## space to see title
Calculate leftBorder as leftBorder+15
Do windowList.$next(0,kFalse,kTrue) Returns #F
End While
Quit method kTrue
Summary
Once Omnis can identify available monitors and their coordinates, you can:
- Automatically place windows on the correct monitor.
- Resize and snap windows to fit.
- Cascade or reposition open windows intelligently.
This logic makes Omnis far more user-friendly in multi-monitor environments --- and might make a good EuroOmnis topic.
Contributed by: []\Doug Easterbrook --- Omnis User Group]
Version: Omnis 11.x compatible