[SOLVED] How to obtain desktop width in multi-monitor setup? lazarus / 31-LCL ---------------------------------------------------------------------- jwdietrich · 2016-12-19 13:33 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. ---------------------------------------------------------------------- ASerge · 2016-12-19 13:44 Subject: ...desktop width... answer: DesktopWidth (for Screen variable) ---------------------------------------------------------------------- balazsszekely · 2016-12-19 14:00 If you're interested in each monitor separately: Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i var  I: Integer;begin  for I := 0 to Screen.MonitorCount - 1 do    ListBox1.Items.Add(IntToStr(Screen.Monitors[I].Width) +  '  ' + IntToStr(Screen.Monitors[I].Height));end; ---------------------------------------------------------------------- jwdietrich · 2016-12-19 20:09 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][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i function ExtendedScreenWidth: longint;var  width, lastRight: longint;  i: integer;begin  width := 0;  lastRight := -1;  for i := 0 to Screen.MonitorCount - 1 do  if Screen.Monitors[i].Left > lastRight then  begin    width := width + Screen.Monitors[i].Width;    lastRight := Screen.Monitors[i].Left;  end;  result := width;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? ---------------------------------------------------------------------- balazsszekely · 2016-12-19 21:25 @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 · 2016-12-20 17:03 Quote from: GetMem 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...) 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. ---------------------------------------------------------------------- Thaddy · 2016-12-20 17:34 Quote from: jwdietrich on December 20, 2016, 06:03:15 pmUnfortunately, it is even impossible to set the monitor property of my form, since it is read only. Why do you want to do that? ---------------------------------------------------------------------- jwdietrich · 2016-12-20 20:03 Quote from: Thaddy on December 20, 2016, 06:34:48 pmQuote from: jwdietrich on December 20, 2016, 06:03:15 pmUnfortunately, 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. ---------------------------------------------------------------------- balazsszekely · 2016-12-20 20:48 @jwdietrich QuoteIn 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 · 2016-12-21 10:56 Quote from: GetMem on December 20, 2016, 09:48:44 pm@jwdietrich QuoteIn 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. ---------------------------------------------------------------------- balazsszekely · 2016-12-21 11:04 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][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i   Self.Left := Screen.Monitors[1].Left + 100;and Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i Self.Left := 2400;move the form to the secondary monitor. With Lazarus trunk works fine. What is your version? ---------------------------------------------------------------------- rvk · 2016-12-21 12:01 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][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i procedure TForm1.Button1Click(Sender: TObject);begin  if Screen.MonitorCount > 0 then    Self.Left := Screen.Monitors[0].Left + 100;end; procedure TForm1.Button2Click(Sender: TObject);begin  if Screen.MonitorCount > 1 then    Self.Left := Screen.Monitors[1].Left + 100;end; ---------------------------------------------------------------------- Thaddy · 2016-12-21 12:02 Are your monitors the same size, Rvk? ---------------------------------------------------------------------- rvk · 2016-12-21 12:09 Quote from: Thaddy on December 21, 2016, 01:02:26 pmAre 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 · 2016-12-21 12:39 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. ---------------------------------------------------------------------- rvk · 2016-12-21 13:15 Quote from: jwdietrich on December 21, 2016, 01:39:27 pmMaybe the problem is that my primary monitor is on the right. I just tried that too and works fine for me on Windows: When making the right monitor (#1) the primary-monitor: Pressing button 1 moves the form to the primary monitor (on the right) which is monitor[0]. Pressing button 2 moves the form to the secondary monitor (on the left) which is monitor[1]. I even tried swapping places in the settings (left to right and right to left) and it still worked. (Let's see what you experience later on) ---------------------------------------------------------------------- jwdietrich · 2016-12-21 19:29 Quote from: rvk on December 21, 2016, 02:15:24 pmQuote from: jwdietrich on December 21, 2016, 01:39:27 pmMaybe the problem is that my primary monitor is on the right. I just tried that too and works fine for me on Windows: When making the right monitor (#1) the primary-monitor: Pressing button 1 moves the form to the primary monitor (on the right) which is monitor[0]. Pressing button 2 moves the form to the secondary monitor (on the left) which is monitor[1]. I even tried swapping places in the settings (left to right and right to left) and it still worked. (Let's see what you experience later on) I tested your simple example programs, and it works well, even on Mac OS X. There must be a problem in my own code, which is in a very large application with multiple forms. It is now my own job to find the reason. Sorry for bothering you with these questions. After all, this discussion lead to the discovery of a bug in the Carbon widget set, which may be an element of a small compensation. Thanks again.