Page 1 of 1

Get Desktop Metrics In Multi-Display Setup

Posted: Mon Dec 05, 2016 7:22 am
by TI-994A
This cross-platform (Windows, MacOS, Linux) routine determines:
1. the main desktop
2. the mouse position
3. the desktop that the mouse is hovering on, and
4. the desktop that the app is positioned in (based on app window x/y position)

Code: Select all

;===========================================================
;
;   getDesktopInfo() returns various metrics
;   regarding the mouse, app, and desktops
;
;   tested & working with PureBasic v5.73 LTS (x64) on:
;   - MacOS Catalina 10.15.5
;   - Linux Ubuntu 20.04.2 LTS
;   - Windows 8.1 Professional
;
;   by TI-994A - free to use, improve, share...
;
;   5th December 2016
;
;   Updated: 23rd March 2021
;
;===========================================================

Structure xPoint
  x.i
  y.i
EndStructure

Structure desktop
  app.xPoint
  mouse.xPoint
  appDesktop.i
  mouseDesktop.i
  mainDesktop.i
  appWin.i
  desktop.i
EndStructure

;just drop this routine into any application (requires the desktop structure above)
;and simply poll the relevant elements to determine the required desktop metrics
;
Procedure getDesktopInfo(*ds.desktop)
  Protected desktops = ExamineDesktops()
  Protected i, dx, dy, dw, dh
 
  With *ds
   
    \mouse\x = DesktopMouseX()
    \mouse\y = DesktopMouseY()
    \app\x = WindowX(\appWin)
    \app\y = WindowY(\appWin)
   
    For i = 0 To desktops -1
     
      dx = DesktopX(i)
      dy = DesktopY(i)
      dw = DesktopWidth(i)
      dh = DesktopHeight(i)
     
      If \app\x >= dx And \app\x <= dx + dw And
         \app\y >= dy And \app\y <= dy + dh
        \appDesktop = i
      EndIf     
     
      If \mouse\x >= dx And \mouse\x <= dx + dw And
         \mouse\y >= dy And \mouse\y <= dy + dh
        \mouseDesktop = i       
        If dx = 0 And dy = 0
          \mainDesktop = i
        EndIf             
        Break
      EndIf
     
    Next i
   
  EndWith
 
EndProcedure

;demo
;
desktop.desktop

LoadFont(0, "Arial", 16)
SetGadgetFont(#PB_Default, FontID(0))

wFlags = #PB_Window_SystemMenu | #PB_Window_ScreenCentered
mainWin = OpenWindow(#PB_Any, #PB_Ignore, #PB_Ignore,
                     500, 300, "Active Desktops", wFlags)
desktopInfo = TextGadget(#PB_Any, 50, 50, 400, 50, "")
mousePos = TextGadget(#PB_Any, 50, 120, 400, 50, "")
appPos = TextGadget(#PB_Any, 50, 190, 400, 50, "")
AddWindowTimer(mainWin, 0, 100)

Repeat
  Select WaitWindowEvent()
    Case #PB_Event_CloseWindow
      appQuit = #True
     
    Default
      desktop\appWin = mainWin
      getDesktopInfo(@desktop)
      With desktop
        SetGadgetText(desktopInfo, "Desktop " +
                                   Str(\mainDesktop) + " is the main desktop")
        SetGadgetText(mousePos, "The mouse is at " + Str(\mouse\x) + ", " +
                                Str(\mouse\y) + " on desktop " + Str(\mouseDesktop))
        SetGadgetText(appPos, "The app is on desktop " + Str(\appDesktop))
      EndWith
  EndSelect
Until appQuit
Suggestions, improvements, and feedback are welcome! :wink:

Re: Get Desktop Metrics In Multi-Display Setup

Posted: Sat Mar 20, 2021 5:10 pm
by BarryG
Thanks TI-994A, I had a need for this today.

Re: Get Desktop Metrics In Multi-Display Setup

Posted: Sat Mar 20, 2021 5:45 pm
by TI-994A
BarryG wrote:Thanks TI-994A, I had a need for this today.
Thanks for saying so, Barry. Glad it was helpful.

Re: Get Desktop Metrics In Multi-Display Setup

Posted: Sat Mar 20, 2021 8:24 pm
by davido
@TI-994A,

Thank you for sharing.

It appears to work perfectly on Bigsur running on the new m1 system.





Model Name: MacBook Pro
Model Identifier: MacBookPro17,1
Chip: Apple M1
Total Number of Cores: 8 (4 performance and 4 efficiency)
Memory: 8 GB
System Version: macOS 11.2.2 (20D80)
Kernel Version: Darwin 20.3.0

Re: Get Desktop Metrics In Multi-Display Setup

Posted: Mon Mar 22, 2021 2:53 pm
by skywalk
Wow, very concise. Thanks TI-994A 8)
I will tinker with this to align with the Windows 10 assignments for Displays.
My stacked 3 monitor case:

Code: Select all

Windows10               ThisSnippet    
Display3 - 3rd          1
Display2 - 2nd          2
Display1 - Main         0
DesktopName,Width,Height,ResolutionX,ResolutionY,X,Y
\\.\DISPLAY1,1920,1080,1,1,0,0
\\.\DISPLAY4,1920,1080,1,1,-13,-2160
\\.\DISPLAY5,1920,1080,1,1,-13,-1080

Re: Get Desktop Metrics In Multi-Display Setup

Posted: Mon Mar 22, 2021 4:00 pm
by Josh
Thanks TI. I just tested it on Win7. Looks good, but one little thing strikes me as a bit odd:

When I move the window from one screen to the other, the display "The app is on desktop 1" changes to "The app is on desktop 0" exactly when the window is completely on desktop 0. This seems correct and logical to me.

But when I move the window the other way the display "The app is on desktop 0" changes to "The app is on desktop 1" already when the window is only a little bit on desktop 1 AND then I move the mouse (only the mouse) also to deskop 1.

What you might need to know. In my case the desktop 0 is on the right side, so the x-coordinates of desktop 1 are negative.

Re: Get Desktop Metrics In Multi-Display Setup

Posted: Mon Mar 22, 2021 6:04 pm
by skywalk
Yes, the assignment logic has to go through more rigor.
The main desktop is assumed to have a 0,0 coordinate and any additional desktops are relative to that.
In my case, stacked 3 monitors with different DPI so they have ±x, ±y coordinates.

Re: Get Desktop Metrics In Multi-Display Setup

Posted: Tue Mar 23, 2021 11:25 am
by TI-994A
@davido, @skywalk, @Josh, thank you for your kind words and valuable feedback.

The code has been slightly modified to better poll the position of the app window; and it has also been tested on Linux (and MacOS Big Sur on M1, thanks to @davido).

The position of the app window is determined purely by its top-left x,y coordinates, although many other factors could be considered to improve this.

However, on MaOS, with the Separate Space Displays option activated, app windows do not span the extended screens, and are visible only on the display where the windows are dropped, regardless of their top-left locations. This would require some API to determine.