[4.9.23] Windows7, MultiMonitor, Display is created on the wrong screen
Dennis

EDIT: DO NOT BOTHER READING THIS THREAD. THE ISSUE IS ALREADY FIXED IN THE LATEST SVN REVISION.

{"name":"602361","src":"\/\/djungxnpq2nug.cloudfront.net\/image\/cache\/1\/b\/1bf7917daae0f76487527aec963c23d7.png","w":686,"h":287,"tn":"\/\/djungxnpq2nug.cloudfront.net\/image\/cache\/1\/b\/1bf7917daae0f76487527aec963c23d7"}602361

I run a two screen system with Windows 7. The screens are arranged as seen in the image above. Pressing "identify" in the hardware configuration gives the numbers seen in the upper left corners.

However, the second screen is configured as the "primary screen" and all applications open their windows on that screen, except for the ones using Allegro. They always open the display (via al_create_display) on the wrong (1 but not primary) screen.

Thomas Fjellstrom

The code should be letting windows do the positioning (As long as you aren't trying to force it yourself), but I didn't write that code so I don't know for sure.

Elias

Looks like a bug to me. And rather annoying as well, I hate it when in X11 programs think they are smarter than the window manager. And the same seems to happen here under Windows. If nobody shows up who knows how to fix it right now, can you enter it to the bug tracker? Then it won't be forgotten to fix it.

Dennis

Done.

append (found some more information while debugging it)
It seems as though windows is treating the entire area as one virtual screen space into which it positions the monitors.

The origin (0,0) of the virtual screen space seems to be mapped to the upper left corner of the primary display.

That way, my secondary displays(first adapter but not primary display) upper left corner ends up being at (-1280, 0).

To fix that, the system initialization code (I couldn't find it yet) would have to set the default display adapter for new displays (currently 0) to the adapter which reports (0,0) as the upper left corner in "win_get_monitor_info".

screenshot to illustrate the issue (ignore the green comments in the code, that was just a lazy fix (which works to open the window on the primary display but doesn't center the new window)):
{"name":"602362","src":"\/\/djungxnpq2nug.cloudfront.net\/image\/cache\/2\/a\/2a822c6d71b8c6f5bbbdccdaffb31bbc.png","w":1310,"h":844,"tn":"\/\/djungxnpq2nug.cloudfront.net\/image\/cache\/2\/a\/2a822c6d71b8c6f5bbbdccdaffb31bbc"}602362

append 2:
Ok, I've created a patch which seems to fix the issue on my system (see attachment). http://www.allegro.cc/files/attachment/602363 (is a unified diff file)

wonsungi

I was able to reproduce Dennis' bug, and I confirm his patch works on my system.

On a related note, how can you force an Allegro program to open in the active monitor? For example, if the folder containing the Allegro exe is on monitor 2, the Allegro program opens on monitor 2; if on monitor 1, the Allegro program also opens on monitor 1.

Picasa Photo viewer works like this. It is very handy to select which monitor a full screen application will open in by first moving the containing folder to that monitor.

Thomas Fjellstrom

edit: nevermind. I misread.

I don't think theres a way to get the "active" monitor. If allegro isn't already doing that it may be a bug.

Arthur Kalliokoski

I don't think theres a way to get the "active" monitor.

Active monitor? You mean the monitor that's displaying the program that has current focus?

Thomas Fjellstrom

Active monitor? You mean the monitor that's displaying the program that has current focus?

That or the one with the mouse. Either way, I don't know if allegro has a way to give you that info at the moment.

Evert

So what happens if we don't specify any display at all and just let the OS pick what it thinks is the best display for the window to pop-up? Does that do what's expected?

And yes... that will possibly not be compatible with the solution to the problem that the OP posted in this thread.
For what it's worth, I don't think the OS X port lets you decide to pop up on the "current" display either, but I hardly ever do multi-display stuff with that (not having a second display doesn't help there).

Arthur Kalliokoski

I think a nice touch would be that if an Allegro program is started from a console, then the graphical window would open on the other monitor. It's a pain switching back and forth to view the windows in their entirety if they have any size to them.

Dennis

Just posting to tell that this issue is fixed. The patch has already been applied to the SVN and Trent fixed it up further so it's still possible to override the default display adapter manually.

If the display adapter is set to -1 (or not at all) now, Windows will always open the window centered on the primary display (regardless of it's display adapter index number).

Chris Katko

How long would this take to apply to a pre-compiled version of Allegro 5? I use the pre-compiled version and just realized this affects me now (I just got a second monitor).

Trent Gamblin

The patch Dennis posted is kind of... incomplete and wrong. What actually got committed to svn is different. So you'd be better of just starting from SVN IMO. It's no buggier than the latest release (If anything, it's better).

Michał Cichoń

For me the reason of such behavior (see first Denis post) lie in the implementation of monitor enumeration.

Brief look at the implementation...

Ok, there is a problem. Simple example: three attached monitors 1, 2 and 3. Second is turned off.

al_get_num_video_adapters() returns 2. al_get_monitor_info(0) return info for 1. al_get_monitor_info(1) return info for 2. al_get_monitor_info(2) return info for 3.

I will run some tests on multi-monitor machine to make sure what results using EnumDisplayDevices() I got.

Edit:
Implementation assume that one adapter can handle one monitor, which is not true.

Edit2:
Maybe we could use EnumDisplayMonitors() instead of EnumDisplayDevices(). In result we got information about region of activity and primary flag.

Trent Gamblin

Do you have a use case right now where it's broken? Cause if it ain't broke...

Michał Cichoń

A little investigation.

I did trough following steps:
- switch with dual-display, report
- switch to 'show only on first', report
- switch to 'show only on second', report
- switch to extended, report

Four session has been found.

Conclusions:
- for dual-display EnumDisplayDevices() return more than one monitor
- for dual-display EnumDisplayDevices() will return adapter without monitor
- inactive monitors may be attached to many devices (I guess this is because internal state is not updated until monitor is being activated)
- active monitor is attached to only one device
- primary monitor is not the first one (but may be)
- EnumDisplayMonitors() give what we want, without bothering about details
- GetSystemMetrics() give correct result - number of active monitors (it is simpler than using EnumDisplayDevices())

I propose to switch the implementation into pair GetSystemMetrics()/EnumDisplayMonitors(). Also al_get_primary_adapter() should be added, because adapter with zero index doesn't have to be primary one.



  --- SESSION ---



-- GetSystemMetrics --

Monitors:   1                                   


-- EnumDisplayDevices --

Monitors:   1                                    Attached to desktop

Monitors:   5                                    All


-- EnumDisplayDevices --

Device:     \\.\DISPLAY1                         NVIDIA GeForce 8600M GT  
  Rect:     (0, 0), (1920, 1080)
  State:    Attached to Desktop, Primary Device
  Monitor:  \\.\DISPLAY1\Monitor0                Generic PnP Monitor
    State:  Active, Attached

  Monitor:  \\.\DISPLAY1\Monitor1                Generic PnP Monitor
    State:  Active, Attached

Device:     \\.\DISPLAY2                         NVIDIA GeForce 8600M GT  
  State:    <empty>

Device:     \\.\DISPLAYV1                        RDPDD Chained DD
  State:    Mirroring Driver

Device:     \\.\DISPLAYV2                        RDP Encoder Mirror Driver
  State:    Mirroring Driver, TS Compatible

Device:     \\.\DISPLAYV3                        RDP Reflector Display Driver
  State:    Mirroring Driver, TS Compatible


-- EnumDisplayMonitors --

Monitor:    \\.\DISPLAY1                        
  Rect:     (0, 0), (1920, 1080)
  State:    Primary



  --- SESSION ---



-- GetSystemMetrics --

Monitors:   1                                   


-- EnumDisplayDevices --

Monitors:   1                                    Attached to desktop

Monitors:   5                                    All


-- EnumDisplayDevices --

Device:     \\.\DISPLAY1                         NVIDIA GeForce 8600M GT  
  Rect:     (0, 0), (1920, 1200)
  State:    Attached to Desktop, Primary Device
  Monitor:  \\.\DISPLAY1\Monitor0                Generic PnP Monitor
    State:  Active, Attached

Device:     \\.\DISPLAY2                         NVIDIA GeForce 8600M GT  
  State:    <empty>
  Monitor:  \\.\DISPLAY2\Monitor0                Generic PnP Monitor
    State:  Attached

Device:     \\.\DISPLAYV1                        RDPDD Chained DD
  State:    Mirroring Driver

Device:     \\.\DISPLAYV2                        RDP Encoder Mirror Driver
  State:    Mirroring Driver, TS Compatible

Device:     \\.\DISPLAYV3                        RDP Reflector Display Driver
  State:    Mirroring Driver, TS Compatible


-- EnumDisplayMonitors --

Monitor:    \\.\DISPLAY1                        
  Rect:     (0, 0), (1920, 1200)
  State:    Primary



  --- SESSION ---



-- GetSystemMetrics --

Monitors:   1                                   


-- EnumDisplayDevices --

Monitors:   1                                    Attached to desktop

Monitors:   5                                    All


-- EnumDisplayDevices --

Device:     \\.\DISPLAY1                         NVIDIA GeForce 8600M GT  
  Rect:     (0, 0), (1920, 1080)
  State:    Attached to Desktop, Primary Device
  Monitor:  \\.\DISPLAY1\Monitor0                Generic PnP Monitor
    State:  Active, Attached

  Monitor:  \\.\DISPLAY1\Monitor1                Generic PnP Monitor
    State:  Attached

Device:     \\.\DISPLAY2                         NVIDIA GeForce 8600M GT  
  State:    <empty>
  Monitor:  \\.\DISPLAY2\Monitor0                Generic PnP Monitor
    State:  Attached

Device:     \\.\DISPLAYV1                        RDPDD Chained DD
  State:    Mirroring Driver

Device:     \\.\DISPLAYV2                        RDP Encoder Mirror Driver
  State:    Mirroring Driver, TS Compatible

Device:     \\.\DISPLAYV3                        RDP Reflector Display Driver
  State:    Mirroring Driver, TS Compatible


-- EnumDisplayMonitors --

Monitor:    \\.\DISPLAY1                        
  Rect:     (0, 0), (1920, 1080)
  State:    Primary



  --- SESSION ---



-- GetSystemMetrics --

Monitors:   2                                   


-- EnumDisplayDevices --

Monitors:   2                                    Attached to desktop

Monitors:   5                                    All


-- EnumDisplayDevices --

Device:     \\.\DISPLAY1                         NVIDIA GeForce 8600M GT  
  Rect:     (-1920, 0), (0, 1200)
  State:    Attached to Desktop
  Monitor:  \\.\DISPLAY1\Monitor0                Generic PnP Monitor
    State:  Active, Attached

Device:     \\.\DISPLAY2                         NVIDIA GeForce 8600M GT  
  Rect:     (0, 0), (1920, 1080)
  State:    Attached to Desktop, Primary Device
  Monitor:  \\.\DISPLAY2\Monitor0                Generic PnP Monitor
    State:  Active, Attached

Device:     \\.\DISPLAYV1                        RDPDD Chained DD
  State:    Mirroring Driver

Device:     \\.\DISPLAYV2                        RDP Encoder Mirror Driver
  State:    Mirroring Driver, TS Compatible

Device:     \\.\DISPLAYV3                        RDP Reflector Display Driver
  State:    Mirroring Driver, TS Compatible


-- EnumDisplayMonitors --

Monitor:    \\.\DISPLAY1                        
  Rect:     (-1920, 0), (0, 1200)
  State:    <empty>

Monitor:    \\.\DISPLAY2                        
  Rect:     (0, 0), (1920, 1080)
  State:    Primary

Trent Gamblin

Conclusions:
- for dual-display EnumDisplayDevices() return more than one monitor
- for dual-display EnumDisplayDevices() will return adapter without monitor
- inactive monitors may be attached to many devices (I guess this is because internal state is not updated until monitor is being activated)
- active monitor is attached to only one device
- primary monitor is not the first one (but may be)
- EnumDisplayMonitors() give what we want, without bothering about details
- GetSystemMetrics() give correct result - number of active monitors (it is simpler than using EnumDisplayDevices())

I propose to switch the implementation into pair GetSystemMetrics()/EnumDisplayMonitors(). Also al_get_primary_adapter() should be added, because adapter with zero index doesn't have to be primary one.

Ok. Can you open a bug on Sourceforge? And since you already have some code, attach it there? Unless you plan on fixing it yourself. Also I think the new function is a good idea too.

EDIT:

What about the initial value for the current adapter? I assume that can be found without installing a display driver, on all platforms, rather than using 0?

Michał Cichoń

I can prepare a patch, which address those issues.

Primary adapter can be detected without initializing display driver. This is simple result of monitor enumeration. That's true for Windows. Mac OS should handle this easily and Linux... Who knows, there is X11 under the hood.

I will put xxx_get_primary_adapter in system driver vtable.

Committing changes is an another issue, due to feature freeze. I will probably release a patch and unofficial build with it.

Evert

Mac OS should handle this easily

You mean the first element returned by [NSScreen screens]? Currently, I think, the default is the return value of [NSScreen mainScreen], which gives you the one that "the user currently interacts with".
Is it clear (and is there consensus) on what the correct behaviour is?

Thomas Fjellstrom

Primary for OSX would be which ever monitor the dock and menu are both on.

Evert

Primary for OSX would be which ever monitor the dock and menu are both on.

Ok, that's the first entry that's returned by [NSScreen screens] (which makes sense, for "primary" to be "the first"). In other words, it's always the first screen reported.
But going back to using [NSScreen mainScreen], I guess it's been discussed in a previous thread here, but what should the initially default screen be? Should it be "the first display", or should it be "the currently active display"? On OS X right now it's the latter, which I think makes sense, but does that make sense to everyone and is it consistent across platforms (in particular, Windows)? Or do users expect different default behaviour on different platforms?

Thomas Fjellstrom

I think you probably want an app to launch on the "currently active" screen. At least I generally do. If I start an app while on my secondary screen, I tend to want it to pop up there since thats where I have my focus.

But I think the only way to start an app on a secondary screen on osx is with some kind of icon or bundle on the desktop.

Evert

But I think the only way to start an app on a secondary screen on osx is with some kind of icon or bundle on the desktop.

I don't think so. Finder or commandline should do as well.

Thomas Fjellstrom
Evert said:

I don't think so. Finder or commandline should do as well.

Ah, ok. I suppose that'd work too. Wasn't thinking.

Elias

In X11 an app by default is started on the same monitor i start it from. I.e. if I type "./my_game" into a console and that console is on the right monitor, that's where the window is created. That is, that's how it worked under Ubuntu 10.04 with NVidia's TwinView - only setup I tried multiple monitors on.

Thomas Fjellstrom

Thats entirely up to the window manager, at least if the user didn't force the position.

Elias

Yes, but if we add a function to return the primary monitor, should it be the one where the WM would run the app?

Thomas Fjellstrom
Elias said:

Yes, but if we add a function to return the primary monitor, should it be the one where the WM would run the app?

I guess it depends if we mean "primary" or "active". If its primary, it aught to be the actual primary monitor, the one at 0x0.

Evert

I guess it depends if we mean "primary" or "active". If its primary, it aught to be the actual primary monitor, the one at 0x0.

I think we should avoid the use of the name "primary". For one thing, if that's really what the user wants, he/she could just select the first screen (afterall, that's what "primary" means) and be done with it. This is already the current behaviour on OS X (since screen 0 is always the one with the Dock and the menu bar, which starts at 0,0) and, as I understand it, Linux.
What we would need then is a function that tells the user what the "active" or "default" display is where the OS will show a window, which is what [NSScreen mainScreen] returns on OS X.

For the sake of clarity I think we should maybe avoid the use of "primary" to refer to anything other than the first display (for which we don't need a function to tell us what it is, since it's the first one). It seems to me that this is mainly a Windows problem, where the first display is the one that is "on the left" rather than the one containing the taskbar (in other words, different operating systems mean different things by "primary display"). In which case, perhaps we need to have the following:

  • A function to get the "active" (current, default, whatever) screen, which is where the window will appear unless we explicitly tell it to go elsewhere. Not sure how easy it is to get that on X11, but maybe this could just be a "magic" identifier of -1 to say "we don't care".

  • A function to get the screen that has the taskbar (dock) on it. On OS X, this is just the first screen (index 0). No idea on how to get this information on X11 though.

With those two functions, I think we have all we need. I don't think we should force our own ordering on screens (for instance, force "0" to be the display containing the taskbar (dock) on every operating system, since I see that become messy and confusing in the future) beside that: whether screen "0" is "the one on the left" or "the one that contains the taskbar" depends on the platform.

Thomas Fjellstrom
Evert said:

What we would need then is a function that tells the user what the "active" or "default" display is where the OS will show a window, which is what [NSScreen mainScreen] returns on OS X.

Except that changes when the user moves their mouse, and I'm not sure X even has such a concept. It probably doesn't. AFAIK Its completely up to X WMs.

Quote:

No idea on how to get this information on X11 though.

Which taskbar? I can have many. Some WMs don't have any.

append:

Quote:

whether screen "0" is "the one on the left" or "the one that contains the taskbar" depends on the platform.

Indeed. X can have "the one that contains the taskbar" on the right or left. It can place secondary screens on either side of 0x0. And it all depends on how the user sets up their config.

Evert

Except that changes when the user moves their mouse,

No. It changes when the user changes the key window. In other words, it's the screen that the currently active window is on. The location of the mouse has nothing to do with it (obviously, OS X doesn't have focus-follows-mouse, which I still find annoying). But in the current context, that's irrelevant: what matters is that it's the screen that the display will appear on if we go with the default.

Quote:

and I'm not sure X even has such a concept. It probably doesn't. AFAIK Its completely up to X WMs.

There is absolutely no way to ask where the window is going to show up if we don't specify anything?
In which case, we probably should go with a generic "-1" to indicate we don't care and "pick the default". We could still add a function that tells you what the "main" display is (the one with the taskbar on Windows, equivalent to the first one on OS X, probably equivalent to the first one on X11).

Quote:

Which taskbar? I can have many. Some WMs don't have any.

Sure. You probably understand what I meant though.

gnolam
Evert said:

It seems to me that this is mainly a Windows problem, where the first display is the one that is "on the left" rather than the one containing the taskbar

What?

Thomas Fjellstrom
Evert said:

Sure. You probably understand what I meant though.

X doesn't though ;) The closest thing to a primary monitor is the one at 0x0, and the closest thing to a default is the one that contains a window that has focus.

I think in the end thats what the "default" monitor has to be at any given time. The monitor with a window on it that has focus.

Evert
Quote:

What?

See first post.
The complaint is that Allegro identifies the "first" screen as the one on the left rather than the one containing the taskbar. In OS X, the "first" screen would be the one with the dock and the menu bar on it (in other words, the one on the right in the picture) and the second one would be the one on the left.
It seems though (from Dennis' second post) that Windows does, in fact, put the origin of the coordinate system on the screen with the taskbar, as in OS X. It just doesn't report it as the "first" display.
Either way, it's a problem with the Windows port of Allegro, not a general problem.

The closest thing to a primary monitor is the one at 0x0, and the closest thing to a default is the one that contains a window that has focus.

That's exactly what it is on OS X. And, looking at the earlier discussion again, it seems that this is what it is in Windows as well.
So it seems we actually have a platform-neutral way of identifying different displays, it's just that Windows enumerates them in the "wrong" order.

Michał Cichoń

How about such results?

2 adapters found...
Main adapter is 0
Active adapter is 1
Adapter 0: (0, 0) - (1920, 1200)
   Available fullscreen display modes:
   Mode   0:  640 x  480, 60 Hz
   Mode   1:  720 x  480, 60 Hz
   ...
   Mode  25: 1920 x 1200, 60 Hz
Adapter 1: (1920, 0) - (3360, 900)
   Available fullscreen display modes:
   Mode   0: 1440 x  900, 60 Hz
   Mode   1: 1440 x  900, 75 Hz
   ...
   Mode  53: 1280 x 1024, 75 Hz

New functions:

int al_get_main_adapter(void);
int al_get_active_adapter(void);

First one return index of main adapter (one with task bar). Second one return active one. For example if you launch your application on second monitor then it will be considered as active. If active adapter couldn't be determined there is a fall back to main adapter.

During Allegro initialization active adapter is set as default adapter.

Edit:
I attached patch to this post. Please confirm me than Mac implementation is working and Linux version compile without problems. (Linux implementation isn't done, but I created stubs in mmon_interface).

Evert

First one return index of main adapter (one with task bar).

This would only ever be different from 0 only on Windows, as I understand it?

Quote:

If active adapter couldn't be determined there is a fall back to main adapter.

During Allegro initialization active adapter is set as default adapter.

Yes, although I still think we should allow a "magic value" of -1 when setting the current active adapter for those cases where you can't determine the "active" one and still want the OS to select whatever it thinks the default should be (which may be the case on X11).

EDIT: I can try if the OS X patch compiles later, but I don't have a second monitor to test it with.

Thomas Fjellstrom
Evert said:

This would only ever be different from 0 only on Windows, as I understand it?

No, the monitor at 0x0 can be listed at any point in the Xrandr output. I assume if you put a secondary to the left on OSX it might appear first in its output too.

Michał Cichoń
Evert said:

This would only ever be different from 0 only on Windows, as I understand it?

I don't know how other platforms will behave. I have linux on VM and still, there is only one monitor in there.
We have MacMinis and they have only one video output (unless I didn't spot HDMI yet). So I may try to confirm that on Thursday.

Evert said:

Yes, although I still think we should allow a "magic value" of -1 when setting the current active adapter for those cases where you can't determine the "active" one and still want the OS to select whatever it thinks the default should be (which may be the case on X11).

This will alter display initialization code. I can do that for Windows and this is relatively simple thing to do. Other platforms are... hm... sill mysterious to me. :)

This feature doesn't collide with patch, so may be considered separately.
I think first we should run some test to confirm results are satisfactory. If not we will back to -1 idea.

Matthew Leverton
Evert said:

It seems to me that this is mainly a Windows problem, where the first display is the one that is "on the left" rather than the one containing the taskbar

I cannot speak for how Allegro works with the Windows API, but Windows treats the primary display as the one marked as "Use this device as the primary monitor." It doesn't matter which is to the left or right or up or down or has the task bar, etc.

Evert

I assume if you put a secondary to the left on OSX it might appear first in its output too.

No. That's the point I was making:

Quote:

screens

Returns an array of NSScreen objects representing all of the screens available on the system.
+ (NSArray *)screens
Return Value

An array of the NSScreen objects available on the current system or nil if the screen information could not be obtained from the window system.
Discussion

The screen at index 0 in the returned array corresponds to the primary screen of the user’s system. This is the screen that contains the menu bar and whose origin is at the point (0, 0). In the case of mirroring, the first screen is the largest drawable display; if all screens are the same size, it is the screen with the highest pixel depth. This primary screen may not be the same as the one returned by the mainScreen method, which returns the screen with the active window.

The array should not be cached. Screens can be added, removed, or dynamically reconfigured at any time. When the display configuration is changed, the default notification center sends a NSApplicationDidChangeScreenParametersNotification notification.

Michał Cichoń

I implemented OSX function according to this documentation.

The question is, what about NSApplicationDidChangeScreenParametersNotification? Maybe Allegro should notify user about changing display layout? There is also similar message generated by Windows.

Evert

Maybe Allegro should notify user about changing display layout?

Maybe. We have an event for when the orientation of the display changes (only on the iOS port, I think).
Querying the status of different adapters after things change should work properly though (since we indeed don't cache the results).

I think that's a separate issue though, and also one that we don't necessarily need to fix for 5.0 (since we can easily add event types afterwards).

EDIT:
I finally had time to look at the patch. On OS X, it's not going to work; [NSScreen mainScreen] returns an NSScreen, not the index in the screens array corresponding to the currently active display, which is what the function should return.
I still think there needs to be a magic "-1" to indicate that "we don't care" and let the OS pick whatever it thinks the default screen should be, rather than explicitly asking for the default and setting that. This to accomodate situations where that information is not readily available.

Michał Cichoń

OK. I added that magic "-1" value to my TODO list.

I will try to fix OSX version tomorrow.

Thread #605265. Printed from Allegro.cc