I’m creating a control that needs to know the AvailableHeight of the screen its window is on. I guess in most multi-monitor setups all the screens have the same height, but it’d be nice to cover all the bases.
That’s definitely not a valid assumption - laptop users are very common users of second screens, and they very rarely are the same dimensions as the built-in display.
You’ll have to make a judgement call by checking the bounds of each window to see which screen is the best choice for your purposes. Remember that a window can be present on multiple displays at once.
Good point.
Another good point
Ventura
MacStudio
Xojo 2023.v1
I use two displays. Perhaps it is some setting, but I actually cannot get my Windows to span two displays. They are either on one or the other but whatever
Anyway perhaps to figure out on which display screen your window is on this might work.
Var numDisplays As Integer
numDisplays = DesktopDisplay.DisplayCount
Var lastDisplayIndex As Integer = numDisplays - 1 // Zero based
Var leftDisplay() As Integer
leftDisplay.ResizeTo(lastDisplayIndex)
For nIndex As Integer = 0 To lastDisplayIndex
leftDisplay(nIndex) = DesktopDisplay.DisplayAt(nIndex).Left
Next nIndex
Var winBounds As Rect
winBounds = Self.Bounds
Var leftWindow As Integer
leftWindow = winBounds.Left
Now the integer array leftDisplay() will contain the position in some global space of the left edge of the attached displays. The main display’s Left edge will always be zero. The other displays are relative to that. In my case I have two displays. The main display DesktopDisplay.DisplayAt(0) has a Left value of zero. My second display is positioned to the left of the main. It is DesktopDisplay.DisplayAt(1). DesktopDisplay.DisplayAt(1).Left is -2560. The fact it is negative means that its left edge in this global space is to the left of the left edge of the main display.
Now for the window as opposed to the displays, you can find its left edge in the global space in the variable leftWindow as determined by the code above. In this simple case of two displays side by side, it is clear that if the leftWindow is negative then it is on the second display. If left Window is positive, it is somewhere on the main display so many pixels from the left edge of the display.
But in more complex situations with three screen or whatever, I think that you can grok the general logic as to where the left edge of the window is and where the left edges of all the displays are and use that to figure out which display the window is on. I would just effectively define the window as being on the display that contains its left edge.
Now there can be more unusual positions of the displays. I presume if the user has arranged a second display to be directly above the main display that their Left values would both be zero. There is also available and analogous DesktopDisplay.DisplayAt(0).Top so you could use the Top information to deal with more unusual configurations of the displays.
By the way, ChatGPT was happy to provide code for this that was total gibberish.
You are correct: there are setting to allow that.
Worst: same apply to Windows computer with more than one screens…
At last, my i5 MacBook Pro 13" have two external screen connected (and the internal one display nothing, but the image is generated/exists).
API2 function. The x and y you pass in will make a difference. Often people will use the top left of the window, however, that is easily moved outside of any screen. I will often use the middle of the screen. top + (height /2), left + (width/2), which is harder to confuse. Obviously that can still go wrong.
This also takes account of the menubar height.
Public Function WhichScreen(x As Integer, y As Integer) As Integer
Var oDisplay As DesktopDisplay
For iDisplay As Integer = 0 To DesktopDisplay.LastDisplayIndex
oDisplay = DesktopDisplay.DisplayAt( iDisplay )
If x >= oDisplay.AvailableLeft And x <= oDisplay.AvailableWidth + oDisplay.AvailableLeft And _
y >= oDisplay.AvailableTop And y <= oDisplay.AvailableHeight + oDisplay.AvailableTop Then
Return iDisplay
End If
Next
End Function
I just converted some math, slapped in proper Xojo and made some tests. Seems ok.
The rationale: get 2 rectangles, window and display, find the intersection area, if any, the display with “more” overlapped window inside it wins.
Public Function AreaWindowOnDisplay(w As DesktopWindow, displayNumber As Integer) As Int64
// Return the area that the Window w occupy on display DisplayNumber
Var wlx, wly, wrx, wry, dlx, dly, drx, dry, ixlength, iylength As Integer
Var d As DesktopDisplay = DesktopDisplay.DisplayAt(displayNumber)
wlx = w.Left
wly = w.Top
wrx = wlx + w.Width
wry = wly + w.Height
dlx = d.Left
dly = d.Top
drx = dlx + d.Width
dry = dly + d.Height
ixlength = min(wrx, drx) - max(wlx, dlx)
iylength = min(wry, dry) - max(wly, dly)
If ixlength>0 and iylength>0 Then Return ixlength*iylength
Return 0
End Function
Public Function FindWindowDisplay(w As DesktopWindow) As Integer
// Loops through displays looking for which one contains more Window w contents
Var OverlappedDisplay As Integer = 0
Var CandidateArea As Int64 = AreaWindowOnDisplay(w, 0)
For i As Integer = 1 to DesktopDisplay.LastDisplayIndex
var area As Int64 = AreaWindowOnDisplay(w, i)
If area > CandidateArea Then
CandidateArea = area
OverlappedDisplay = i
End
Next
Return OverlappedDisplay
End Function
@Ian_Kennedy ah, I didn’t know that Screen.AvailableLeft gives a global coordinate - makes total sense now.
@Robert_Livingston and @Ian_Kennedy both pointed me in the right direction, but @Rick_A 's solution is the most robust, so marked it as The Solution - thanks to all!
Be care of screen scaling on Windows. If you main screen is 100% and your second is not 100%, eg 125% or 175%, you can get some odd values returned from xojo. I’m not sure if they have fixed this yet. I had to use mbs to get better results.
It’s your choice, but it can be wrong.
My setup is like Robert: the secondary screen is at the left of the main one.
If I drag my current Safari window, which is on the main screen, by its rightmost corner and move it at left, to a distance of 3/4 of the main screen (e.g. I just want to see one quarter of the right area of the window, leaving space for another window), the window will be “much more” in the second screen (as coordinates are concerned), but, since the mouse hasn’t left the main screen, Mac OS will still display the small part that stays on the main screen (and hide the window from the 2nd screen).
I don’t get what you say. Mouse is not a concern here. Also it is not a question of choice, but logic.
This is something needing more tests and observation, but I couldn’t see problems with my setup using the last Xojo, if someone with multiple monitors and different scales can find something using the last Xojo, it could be interesting. If some misbehavior is found some adjusts must be done, probably changing from absolute values to percentages taking scales in consideration.
It was from around 2019, i added a bug fix request ages ago.
We try align a floating window to fill the screen and the x,y,width and height values from Screen were wrong. MBS had the correct values.
Also you had to use a windows dll call “SetWindowPos” to have it position correctly as Xojo adjusted the values.
Again, might of been fixed a long time ago,
That looks like a real bug. Probably gone.
My feeling is that it just works, because the multiplicative nature of the area while transferring contents to other quadrants, it increases and decreases proportionally on each quadrant, and at 50% it will jump the significance anyway to the other square.
This doesn’t imply I’m wrong.
You use it to move the window.
There are ways to find immediately on which screen a given window is considered, on Mac, as the MBS plugins have a way: Monkeybread Xojo plugin - NSWindowMBS class
(check the screen property).
Credits to Norman to having reminded me of that.
Of course they do but I plan to share my project with the community at some point and so am trying to write it without plugins. And I need both MacOS and Windows.
Never said that, but also did not get a prove of what I provided does not solve for free the problem.
On Windows it worked, on Mac it should.
Have you tested it before starting to grump about your desire to pay for a more complex solution?
That would not be a good guess. I’m running three monitors right now. Two are old HP ZR24w’s. Those are tricked out so they can be swirled into portrait orientation. I have one on an older Mini configured that way, and one on the right side of a landscape monitor - two monitors on an M2 Mini. I have them set up so I can read documents without scrolling.
Though what is created on one monitor usually stays on that monitor, it can’t be relied upon. I can easily drag something from the LandScape monitor to the Portrait monitor or vice versa.