Recent

Author Topic: [SOLVED] How to obtain desktop width in multi-monitor setup?  (Read 14713 times)

jwdietrich

  • Hero Member
  • *****
  • Posts: 1278
    • formatio reticularis
[SOLVED] How to obtain desktop width in multi-monitor setup?
« on: December 19, 2016, 02:33:27 pm »
On a multi-monitor system screen.width delivers the width of one monitor only (probably the form's monitor). What is the recommended way to get the width of the total desktop area if multiple monitors are attached to the system?

Obviously, the task is more complex than to calculate 2 * screen.width, since the attached monitors may have different resolutions and their arrangement may be variable, too.
« Last Edit: December 21, 2016, 08:31:20 pm by jwdietrich »
function GetRandomNumber: integer; // xkcd.com
begin
  GetRandomNumber := 4; // chosen by fair dice roll. Guaranteed to be random.
end;

http://www.formatio-reticularis.de

Lazarus 4.2.0 | FPC 3.2.2 | PPC, Intel, ARM | macOS, Windows, Linux

ASerge

  • Hero Member
  • *****
  • Posts: 2492
Re: How to obtain desktop width in multi-monitor setup?
« Reply #1 on: December 19, 2016, 02:44:42 pm »
Subject: ...desktop width...
answer: DesktopWidth (for Screen variable)

balazsszekely

  • Guest
Re: How to obtain desktop width in multi-monitor setup?
« Reply #2 on: December 19, 2016, 03:00:22 pm »
If you're interested in each monitor separately:
Code: Pascal  [Select][+][-]
  1. var
  2.   I: Integer;
  3. begin
  4.   for I := 0 to Screen.MonitorCount - 1 do
  5.     ListBox1.Items.Add(IntToStr(Screen.Monitors[I].Width) +  '  ' + IntToStr(Screen.Monitors[I].Height));
  6. end;

jwdietrich

  • Hero Member
  • *****
  • Posts: 1278
    • formatio reticularis
Re: How to obtain desktop width in multi-monitor setup?
« Reply #3 on: December 19, 2016, 09:09:42 pm »
Thanks for your suggestions. Unfortunately, the issue seems to be more complex than expected, at least on the Mac.

@ASerge:
In macOS Screen.DesktopWidth unfortunately delivers the same value as Screen.Width.

@GetMem:
Your example generally works. On the Mac, however, (and probably with Windows, too), it is also possible to arrange monitors vertically. I have expanded your code in form of the following function, which checks for the arrangement of monitors and only adds their widths, if they are horizontally arranged:

Code: Pascal  [Select][+][-]
  1. function ExtendedScreenWidth: longint;
  2. var
  3.   width, lastRight: longint;
  4.   i: integer;
  5. begin
  6.   width := 0;
  7.   lastRight := -1;
  8.   for i := 0 to Screen.MonitorCount - 1 do
  9.   if Screen.Monitors[i].Left > lastRight then
  10.   begin
  11.     width := width + Screen.Monitors[i].Width;
  12.     lastRight := Screen.Monitors[i].Left;
  13.   end;
  14.   result := width;
  15. end;

Now, having this solved with your help I have still another problem:

I wanted to know the width of the desktop area in order to be able to programmatically distribute the windows of my application over the total virtual screen area in a multi-monitor setup. Unfortunately, if I set the left property of a window to a value right of the width property of the first monitor (in order to place it on the second screen) this seems to be automatically corrected by the LCL (at least on macOS), so that the window is positioned on the first monitor again. To be more concrete, I have two monitors with a width of 1280 pixels each. This sums up to a total width of 2560 pixels. If I set the left property of my window to e.g. 2000 pixels this is "corrected", so that it becomes 720. Of course it is possible to manually move the windows across the total desktop area.

Could this "automatic correction" be a bug, and how is it possible to circumvent it?
function GetRandomNumber: integer; // xkcd.com
begin
  GetRandomNumber := 4; // chosen by fair dice roll. Guaranteed to be random.
end;

http://www.formatio-reticularis.de

Lazarus 4.2.0 | FPC 3.2.2 | PPC, Intel, ARM | macOS, Windows, Linux

balazsszekely

  • Guest
Re: How to obtain desktop width in multi-monitor setup?
« Reply #4 on: December 19, 2016, 10:25:13 pm »
@jwdietrich
If your primary monitor is on the right, then the secondary monitor on the left has negative coordinates(however strange it might seems). You should always set the left/top of your form relative to the left/top of the monitor you want to place it.  TMonitor object contains all the info you need(coordinates, is primary or not, etc...)

jwdietrich

  • Hero Member
  • *****
  • Posts: 1278
    • formatio reticularis
Re: How to obtain desktop width in multi-monitor setup?
« Reply #5 on: December 20, 2016, 06:03:15 pm »
@jwdietrich
If your primary monitor is on the right, then the secondary monitor on the left has negative coordinates(however strange it might seems). You should always set the left/top of your form relative to the left/top of the monitor you want to place it.  TMonitor object contains all the info you need(coordinates, is primary or not, etc...)

Thanks for your explanations.

I have now checked the same problem on a Windows machine with dual monitor setup. Here, Screen.DesktopWidth seems to correctly represent the total desktop area. Therefore, the behaviour in the Carbon widgetset seems to be a bug.

Secondly, I have checked, according to your suggestion, which monitor is the primary one. On my Windows machine, Screen.Monitors[1] is the primary monitor, and it is on the left of the secondary monitor represented by Screen.Monitors[0]. Therefore, since both monitors here have a width of 1920 pixels, my window should be displayed on the right monitor, if I set its left property to 3477. It is still displayed, however, on the left monitor, similar to my experiences with macOS.

Unfortunately, it is even impossible to set the monitor property of my form, since it is read only.
« Last Edit: December 20, 2016, 06:15:41 pm by jwdietrich »
function GetRandomNumber: integer; // xkcd.com
begin
  GetRandomNumber := 4; // chosen by fair dice roll. Guaranteed to be random.
end;

http://www.formatio-reticularis.de

Lazarus 4.2.0 | FPC 3.2.2 | PPC, Intel, ARM | macOS, Windows, Linux

Thaddy

  • Hero Member
  • *****
  • Posts: 19129
  • Glad to be alive.
Re: How to obtain desktop width in multi-monitor setup?
« Reply #6 on: December 20, 2016, 06:34:48 pm »
Unfortunately, it is even impossible to set the monitor property of my form, since it is read only.

Why do you want to do that?
objects are fine constructs. You can even initialize them with constructors.

jwdietrich

  • Hero Member
  • *****
  • Posts: 1278
    • formatio reticularis
Re: How to obtain desktop width in multi-monitor setup?
« Reply #7 on: December 20, 2016, 09:03:53 pm »
Unfortunately, it is even impossible to set the monitor property of my form, since it is read only.

Why do you want to do that?

Well, that is a good question. Since I am unable to position my forms freely within the desktop area, I reflected if it is possible to take a less elegant way by setting the monitor property and then determining the left property of the window. But unfortunately, this way is obstructed, too.

BTW, I have submitted a bug report for the Mac issue regarding the DesktopWidth property. This seems to be a minor problem, however, compared with the other issues.
function GetRandomNumber: integer; // xkcd.com
begin
  GetRandomNumber := 4; // chosen by fair dice roll. Guaranteed to be random.
end;

http://www.formatio-reticularis.de

Lazarus 4.2.0 | FPC 3.2.2 | PPC, Intel, ARM | macOS, Windows, Linux

balazsszekely

  • Guest
Re: How to obtain desktop width in multi-monitor setup?
« Reply #8 on: December 20, 2016, 09:48:44 pm »
@jwdietrich
Quote
In my Windows machine, Screen.Monitors[1] is the primary monitor, and it is on the left of the secondary monitor represented by Screen.Monitors[0]
Yes, exactly. Then you should set your form like this:
Screen.Monitors[0].Left + 100.

jwdietrich

  • Hero Member
  • *****
  • Posts: 1278
    • formatio reticularis
Re: How to obtain desktop width in multi-monitor setup?
« Reply #9 on: December 21, 2016, 11:56:50 am »
@jwdietrich
Quote
In my Windows machine, Screen.Monitors[1] is the primary monitor, and it is on the left of the secondary monitor represented by Screen.Monitors[0]
Yes, exactly. Then you should set your form like this:
Screen.Monitors[0].Left + 100.

Unfortunately, this doesn't work as well (tested on both macOS and Windows). If I set the left property of my form to 100 it is correctly placed 100 pixels from the left margin of the leftmost monitor, but if I set it to Screen.Monitors[0].Left + 100 then it is placed on the right margin of the left monitor (referred to as Screen.Monitors[1]).

I am afraid that this is another bug in the LCL.
function GetRandomNumber: integer; // xkcd.com
begin
  GetRandomNumber := 4; // chosen by fair dice roll. Guaranteed to be random.
end;

http://www.formatio-reticularis.de

Lazarus 4.2.0 | FPC 3.2.2 | PPC, Intel, ARM | macOS, Windows, Linux

balazsszekely

  • Guest
Re: How to obtain desktop width in multi-monitor setup?
« Reply #10 on: December 21, 2016, 12:04:10 pm »
I just tested with Lazarus trunk/FPC 3.0.0/Windows 7
Primary monitor on the left, secondary on the right:
Both:
Code: Pascal  [Select][+][-]
  1.   Self.Left := Screen.Monitors[1].Left + 100;
and
Code: Pascal  [Select][+][-]
  1. Self.Left := 2400;
move the form to the secondary monitor. With Lazarus trunk works fine. What is your version?


rvk

  • Hero Member
  • *****
  • Posts: 7014
Re: How to obtain desktop width in multi-monitor setup?
« Reply #11 on: December 21, 2016, 01:01:00 pm »
I just tested this on Lazarus 1.6 / FPC 3.0.0 on Windows 10.

My primary monitor is on the left and has number 2 in Windows-settings.
My second monitor is on the right and has number 1 in Windows-settings.

Pressing button 1 moves the form to the secondary monitor (on the right) which is monitor[0].
Pressing button 2 moves the form to the primary monitor (on the left) which is monitor[1].
So this is not a bug in Lazarus/FPC on Windows (not sure about Mac).
(What exactly does this for you on Windows and Mac and what version do you have on both of these?)

Code: Pascal  [Select][+][-]
  1. procedure TForm1.Button1Click(Sender: TObject);
  2. begin
  3.   if Screen.MonitorCount > 0 then
  4.     Self.Left := Screen.Monitors[0].Left + 100;
  5. end;
  6.  
  7. procedure TForm1.Button2Click(Sender: TObject);
  8. begin
  9.   if Screen.MonitorCount > 1 then
  10.     Self.Left := Screen.Monitors[1].Left + 100;
  11. end;

Thaddy

  • Hero Member
  • *****
  • Posts: 19129
  • Glad to be alive.
Re: How to obtain desktop width in multi-monitor setup?
« Reply #12 on: December 21, 2016, 01:02:26 pm »
Are your monitors the same size, Rvk?
objects are fine constructs. You can even initialize them with constructors.

rvk

  • Hero Member
  • *****
  • Posts: 7014
Re: How to obtain desktop width in multi-monitor setup?
« Reply #13 on: December 21, 2016, 01:09:01 pm »
Are your monitors the same size, Rvk?
Nope. Although both should be 24" the left is slightly bigger @1920x1200 and the right is @1920x1080.

I think the reason the left is #2 and right is #1 under Windows is because left is DVI and right is HDMI.

But for me the Screen.monitor works perfectly on Lazarus 1.6 through trunk. It's just that you need to be aware of how Screen.Monitors is filled.

jwdietrich

  • Hero Member
  • *****
  • Posts: 1278
    • formatio reticularis
Re: How to obtain desktop width in multi-monitor setup?
« Reply #14 on: December 21, 2016, 01:39:27 pm »
Thanks for sharing your interesting experiences. I use Lazarus 1.6.2 with FPC 3.0.0 on both Mac OS X and Windows.

I have just some pressure in time, but I will test your examples this evening. Maybe the problem is that my primary monitor is on the right.
function GetRandomNumber: integer; // xkcd.com
begin
  GetRandomNumber := 4; // chosen by fair dice roll. Guaranteed to be random.
end;

http://www.formatio-reticularis.de

Lazarus 4.2.0 | FPC 3.2.2 | PPC, Intel, ARM | macOS, Windows, Linux

 

TinyPortal © 2005-2018