Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Controling window placement with multiple monitors #811

Closed
totaam opened this issue Feb 15, 2015 · 12 comments
Closed

Controling window placement with multiple monitors #811

totaam opened this issue Feb 15, 2015 · 12 comments

Comments

@totaam
Copy link
Collaborator

totaam commented Feb 15, 2015

Issue migrated from trac ticket # 811

component: client | priority: minor | resolution: invalid

2015-02-15 05:05:02: lukashaase created the issue


Based on my post on the mailinglist [1]:

Motivation

I use xpra on a Windows with one (undocked laptop), two (docking station #1) or three (docking station #2) monitors. In the docking station cases, the primary display is/are always the external monitor and the secondary one the internal laptop display. Since the laptop is actually a convertible tablet, I use it nearly exclusively are notepad (having the display lying on the table with OneNote open).

Although the internal laptop display is not the primary monitor, it is to the left of the other screens and hence, it has position (0,0) of the complete virtual display.

Now I have X window applications (again, proprietary, sorry) which in 90% of the cases place the windows on the secondary monitor. Since I don't even use that display as an actual monitor, it is so annoying to drag all the windows (and the applications really opens a lot of windows) to the actual primary screen. I asked in the forum of the proprietary application [2] and they claim the window manager would have the option to decide on which monitor new windows open etc.

Proposed enhancements

It would be great if some aspects on where new windows are placed in Windows in a multiple monitor setup can be controlled in xpra. Some suggestions which would overcome the problems above:

  • New windows are always opened on the same physical monitor as the window who opened it (or the last active window). This is the most natural solution in my opinion.

  • Specify where to place new windows based on some rules.

  • Exclude certain physical monitors from being used by xpra at all.

[1] https://xpra.org/list/2015-February/001139.html
[2] http://preview.tinyurl.com/m4k2l2f

@totaam
Copy link
Collaborator Author

totaam commented Feb 16, 2015

2015-02-16 04:54:25: antoine commented


The problem is that applications have many ways of requesting where they are placed on screen, from absolute coordinates on creation, gravity relative to their parent window, moving the window before showing it (and there is more than one way of doing that) - or even moving it after showing it (I've seen it done), specifying which screen to be on, etc..

Then when we create the window, we ask your client OS to place it (assuming we don't have any coordinates to use by that point) - and whatever it decides to do, we honour it.

So it isn't easy to start interfering with this process without breaking other well behaved applications and/or window managers.

Please post the -d window client output of when those windows are created so we can see what attributes are set, which will dictate what we can and can't tweak.
The server log with -d window could also be useful, as long as it is limited to the moment of the window creation (otherwise it could be way too big to parse)

@totaam
Copy link
Collaborator Author

totaam commented Feb 18, 2015

2015-02-18 06:14:06: lukashaase commented


I assume it's not easy. I'm also afraid it could break stuff. Particularly, I think about menus, which, in the end, are also windows.
On the other hand, the current placement (placing always on a different minitor) is totally broken and drives me crazy. I don't know too much about X11 to understand if it is a window manager (and hence xpra) problem or the application itself.

In any case, wouldn't be an option to have a switch to turn on/off that behavior? So it can also be tested in a good manner.

What I could think of is a setting "Force window placement on same monitor".
If this flag is set, xpra checks if the coordinate where the new window should be placed is on a different monitor. If this is the case, the placement is overwritten in some way (e.g. subtract/add coordinates in a way so that the window is placed at the same position but on the current monitor).

Here is the output of such a window when it opens on the leftmost display although it should land on the main/middle window:

2015-02-18 06:04:52,615 process_new_common: [425, 0, 0, 781, 657, {'opacity': -1, 'fullscreen': False, 'has-alpha': False, 'xid': '0x1000026', 'modal': False, 'title': 'Library Manager: initializing... ', 'icon-title': 'Cadence Library Manager', 'client-machine': 'server', 'pid': 14494, 'group-leader-xid': 16777256, 'iconic': False, 'window-type': ('NORMAL',), 'size-constraints': {'minimum-size': (300, 427), 'set-initial-position': True}, 'decorations': True, 'maximized': False, 'class-instance': ('Qt-subapplication', 'LibManager')}], OR=False
2015-02-18 06:04:52,615 make_new_window(..) client_window_classes=[<class 'xpra.client.gl.gtk2.gl_client_window.GLClientWindow'>, <class 'xpra.client.gtk2.border_client_window.BorderClientWindow'>], group_leader_window=None
2015-02-18 06:04:52,615 GLClientWindow(..)
2015-02-18 06:04:52,617 <class 'xpra.client.gl.gtk2.gl_client_window.GLClientWindow'>(gtk2.client, None, 425, 0, 0, 781, 657, {'opacity': -1, 'size-constraints': {'minimum-size': (300, 427), 'set-initial-position': True}, 'decorations': True, 'client-machine': 'r6cad-st130soi.stanford.edu', 'pid': 14494, 'group-leader-xid': 16777256, 'iconic': False, 'window-type': ('NORMAL',), 'fullscreen': False, 'has-alpha': False, 'xid': '0x1000026', 'title': 'Library Manager: initializing... ', 'icon-title': 'Cadence Library Manager', 'modal': False, 'maximized': False, 'class-instance': ('Qt-subapplication', 'LibManager')}, False, {}, (0, 0))
2015-02-18 06:04:52,617 set_window_type(['NORMAL']) hints=0
2015-02-18 06:04:52,617 setup_window() screen=-1, nscreens=1
2015-02-18 06:04:52,617 new_backing(781, 657) backing_class=<class 'xpra.client.gl.gtk2.gl_window_backing.GLPixmapBacking'>
2015-02-18 06:04:52,617 make_new_backing(<class 'xpra.client.gl.gtk2.gl_window_backing.GLPixmapBacking'>, 781, 657) effective backing class=<class 'xpra.client.gl.gtk2.gl_window_backing.GLPixmapBacking'>, server alpha=False, window alpha=False
2015-02-18 06:04:52,654 Win32Hooks: window frame size is 4x4
2015-02-18 06:04:52,710 GL do_configure_event(<gtk.gdk.Event at 036881E8: GDK_CONFIGURE x=4, y=757, width=781, height=657>)
2015-02-18 06:04:52,710 GLClientWindow(425 : gtk2.GLWindowBacking(425, (781, 657), None)).do_map_event(<gtk.gdk.Event at 036881E8: GDK_MAP>) OR=False
2015-02-18 06:04:52,711 GL do_configure_event(<gtk.gdk.Event at 036881E8: GDK_CONFIGURE x=4, y=757, width=781, height=657>)

As a different example, here is the output for such a menu, which of course, should be placed exactly where requested:

2015-02-18 06:07:12,286 process_new_common: [429, 2198, 681, 234, 523, {'opacity': -1, 'fullscreen': False, 'has-alpha': False, 'xid': '0xc0000b', 'pid': -1, 'window-type': ('DROPDOWN_MENU', 'POPUP_MENU', 'NORMAL'), 'maximized': False, 'transient-for': 418, 'override-redirect': True}], OR=True
2015-02-18 06:07:12,286 make_new_window(..) client_window_classes=[<class 'xpra.client.gl.gtk2.gl_client_window.GLClientWindow'>, <class 'xpra.client.gtk2.border_client_window.BorderClientWindow'>], group_leader_window=None
2015-02-18 06:07:12,286 GLClientWindow(..)
2015-02-18 06:07:12,286 <class 'xpra.client.gl.gtk2.gl_client_window.GLClientWindow'>(gtk2.client, None, 429, 2198, 681, 234, 523, {'opacity': -1, 'fullscreen': False, 'has-alpha': False, 'xid': '0xc0000b', 'pid': -1, 'window-type': ('DROPDOWN_MENU', 'POPUP_MENU', 'NORMAL'), 'maximized': False, 'transient-for': 418, 'override-redirect': True}, True, {}, (0, 0))
2015-02-18 06:07:12,286 GLClientWindow(429 : None).apply_transient_for(418) window=GLClientWindow(418 : gtk2.GLWindowBacking(418, (725, 193), YUV444P))
2015-02-18 06:07:12,286 set_window_type(['DROPDOWN_MENU', 'POPUP_MENU', 'NORMAL']) hints=9
2015-02-18 06:07:12,286 new_backing(234, 523) backing_class=<class 'xpra.client.gl.gtk2.gl_window_backing.GLPixmapBacking'>
2015-02-18 06:07:12,286 make_new_backing(<class 'xpra.client.gl.gtk2.gl_window_backing.GLPixmapBacking'>, 234, 523) effective backing class=<class 'xpra.client.gl.gtk2.gl_window_backing.GLPixmapBacking'>, server alpha=False, window alpha=False
2015-02-18 06:07:12,308 Win32Hooks: window frame size is 4x4
2015-02-18 06:07:12,326 GL do_configure_event(<gtk.gdk.Event at 036881D0: GDK_CONFIGURE x=2198, y=681, width=234, height=523>)
2015-02-18 06:07:12,326 GLClientWindow(429 : gtk2.GLWindowBacking(429, (234, 523), None)).do_map_event(<gtk.gdk.Event at 036881D0: GDK_MAP>) OR=True
2015-02-18 06:07:12,326 GL do_configure_event(<gtk.gdk.Event at 036881D0: GDK_CONFIGURE x=2198, y=681, width=234, height=523>)

I wait with posting server's "-d window" until it is necessary. Maybe this helps already.

Aside: I also tried ignoring the window with libfakeXinerama.

This is the content on my "~/.:1900-fakexinerama":

# 3 monitors:
3
# DISPLAY1 (677mm x 423mm)
1280 0 1920 1200
# DISPLAY2 (452mm x 271mm)
0 734 1280 768
# DISPLAY3 (677mm x 381mm)
3200 0 1920 1080

I tried several modifications, e.g.:

# 3 monitors:
3
# DISPLAY1 (677mm x 423mm)
1280 0 1920 1200
# DISPLAY2 (452mm x 271mm)
0 0 0 0
# DISPLAY3 (677mm x 381mm)
3200 0 1920 1080

But whatever I do, it's just ignored. (LD_PRELOAD is set appropriately).
Also, this hack would have problems when I dynamically connect/disconnect monitors as it happens for laptops.

@totaam
Copy link
Collaborator Author

totaam commented Feb 18, 2015

2015-02-18 08:50:01: antoine commented


From what I see, your application is requesting: 'set-initial-position': True whilst setting its position as (0,0).
Please post the server log so we can see more details.
Overriding application requested positioning could be tricky, it exists for a purpose..

As you figured out, the menu should be left alone - an important note: it isn't always possible to tell which windows are menus and which ones aren't, not all applications set the right hints.

@totaam
Copy link
Collaborator Author

totaam commented Feb 19, 2015

2015-02-19 00:33:25: afarr commented


With the way that the libfakexinerama file works, would it be possible to set a given display to be default for the positioning of new applications? (Allowing an application that wants to set a position as (0,0) to do so, but at (0,0) relative to that default display, rather than the Overall Desktop (0,0) coordinate?

(Just a thought, as the placement for some windows when I'm set up with multiple displays can be OCD taunting...)

@totaam
Copy link
Collaborator Author

totaam commented Feb 19, 2015

2015-02-19 02:42:41: antoine commented


No, the fakexinerama stuff only allows us to expose monitor layouts, what applications decide to do with this information is completely out of our control.

@totaam
Copy link
Collaborator Author

totaam commented Feb 19, 2015

2015-02-19 04:40:28: lukashaase commented


That's just so hard to believe because the placement is random (meaning: not always the same on just 80% of the time the wrong monitor). So it's random with a terrible bias actually.

I can imagine quite well how tricky this could be, hence the suggestion with a config option and placement on the requested position but the same monitor as the current focus.

It is very hard to capture anything useful because the server log fills MBs in seconds.
I tried: I prepared a situation where, when I double click, the resulting window would open at the wrong monitor 80% of the time and tried to capture exactly the resulting logs.

Here is what appears on the client:

2015-02-19 04:26:32,269 process_new_common: [8, 120, 3221, 900, 690, {'opacity': -1, 'fullscreen': False, 'has-alpha': False, 'xid': '0xc004bf', 'modal': False, 'title': 'Virtuoso\xc2\xae Schematic Editor L Editing: test test_tia_mos schematic', 'icon-title': 'test_tia_mos', 'client-machine': 'server', 'pid': 6019, 'group-leader-xid': 12582961, 'iconic': False, 'window-type': ('NORMAL',), 'size-constraints': {'minimum-size': (100, 100), 'set-initial-position': True}, 'decorations': True, 'maximized': False, 'class-instance': ('Qt-subapplication', 'Virtuoso')}], OR=False
2015-02-19 04:26:32,270 make_new_window(..) client_window_classes=[<class 'xpra.client.gl.gtk2.gl_client_window.GLClientWindow'>, <class 'xpra.client.gtk2.border_client_window.BorderClientWindow'>], group_leader_window=None
2015-02-19 04:26:32,270 GLClientWindow(..)
2015-02-19 04:26:32,270 <class 'xpra.client.gl.gtk2.gl_client_window.GLClientWindow'>(gtk2.client, None, 8, 120, 3221, 900, 690, {'opacity': -1, 'size-constraints': {'minimum-size': (100, 100), 'set-initial-position': True}, 'decorations': True, 'client-machine': 'server', 'pid': 6019, 'group-leader-xid': 12582961, 'iconic': False, 'window-type': ('NORMAL',), 'fullscreen': False, 'has-alpha': False, 'xid': '0xc004bf', 'title': 'Virtuoso\xc2\xae Schematic Editor L Editing: test test_tia_mos schematic', 'icon-title': 'test_tia_mos', 'modal': False, 'maximized': False, 'class-instance': ('Qt-subapplication', 'Virtuoso')}, False, {}, (0, 0))
2015-02-19 04:26:32,270 set_window_type(['NORMAL']) hints=0
2015-02-19 04:26:32,270 setup_window() screen=-1, nscreens=1
2015-02-19 04:26:32,270 new_backing(900, 690) backing_class=<class 'xpra.client.gl.gtk2.gl_window_backing.GLPixmapBacking'>
2015-02-19 04:26:32,270 make_new_backing(<class 'xpra.client.gl.gtk2.gl_window_backing.GLPixmapBacking'>, 900, 690) effective backing class=<class 'xpra.client.gl.gtk2.gl_window_backing.GLPixmapBacking'>, server alpha=False, window alpha=False
2015-02-19 04:26:32,319 Win32Hooks: window frame size is 4x4
2015-02-19 04:26:32,352 GL do_configure_event(<gtk.gdk.Event at 037C16F8: GDK_CONFIGURE x=124, y=3244, width=900, height=690>)
2015-02-19 04:26:32,354 GL do_configure_event(<gtk.gdk.Event at 037C16F8: GDK_CONFIGURE x=124, y=808, width=900, height=690>)
2015-02-19 04:26:32,355 GLClientWindow(8 : gtk2.GLWindowBacking(8, (900, 690), None)).do_map_event(<gtk.gdk.Event at 037C16F8: GDK_MAP>) OR=False
2015-02-19 04:26:32,355 GL do_configure_event(<gtk.gdk.Event at 037C16F8: GDK_CONFIGURE x=124, y=808, width=900, height=690>)

The server part, although it contains only the relevant section (from the moment of clicking to the end when the window opened) is attached as server-window.txt because it is large.

@totaam
Copy link
Collaborator Author

totaam commented Feb 19, 2015

2015-02-19 04:41:05: lukashaase uploaded file server-window.txt (101.6 KiB)

@totaam
Copy link
Collaborator Author

totaam commented Feb 19, 2015

2015-02-19 04:58:54: antoine commented


The client gets a window of size 900x690 located at 120x3221, and honours the request.

From the server log, we can see that the position you get for the window has been requested by the application:

Found a potential client
new window 0xc004bf
XGetClassHint(0xc004bf) classhints: Qt-subapplication, Virtuoso
_update_client_geometry: using initial size=(900, 690) and position=(120, 3221)

And then this is what the server sees when the client honours the request:

client configured window 8 - WindowModel(0xc004bf - "Virtuoso® Schematic Editor L Editing: test test_tia_mos schematic"), at: (124, 808, 900, 690)

So I am very reluctant to second guess what the application requested.

@totaam
Copy link
Collaborator Author

totaam commented Feb 19, 2015

2015-02-19 05:14:10: lukashaase commented


Hmm
What do you mean specifically by that?

@totaam
Copy link
Collaborator Author

totaam commented Feb 19, 2015

2015-02-19 06:18:48: totaam commented


I mean that it isn't xpra's job to override what applications have requested at random.
Either fix the application to not request a specific location, or tell your client OS to not use a display you don't want to use.

@totaam
Copy link
Collaborator Author

totaam commented Feb 19, 2015

2015-02-19 17:32:28: afarr commented


Ahh, yes... this does make sense. I withdraw my request.

@totaam
Copy link
Collaborator Author

totaam commented Apr 14, 2015

Unless there's something I am missing, I don't think we're doing anything wrong here.

@totaam totaam closed this as completed Apr 14, 2015
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant