Server on Centos7 r20582 Client both Python and HTML on Windows r20582 Can't reproduce outside Xpra.
While looking for a good test case for #1974 I found this.
Install java and run:
java -jar windowDrift.jar
The window has set initial bounds (100,y=100,width=450,height=300) that don't change through the java code or user input but the window moves from these bounds. The only change in code is the window toggles visibility every 5 seconds.
sh-4.2$ java -jar windowDrift.jar Window bounds: java.awt.Rectangle[x=100,y=100,width=450,height=300] Window bounds: java.awt.Rectangle[x=92,y=69,width=450,height=300] Window bounds: java.awt.Rectangle[x=84,y=38,width=450,height=300] Window bounds: java.awt.Rectangle[x=84,y=38,width=450,height=300] Window bounds: java.awt.Rectangle[x=76,y=7,width=450,height=300] Window bounds: java.awt.Rectangle[x=76,y=7,width=450,height=300]
Expected output:
Window bounds: java.awt.Rectangle[x=100,y=100,width=450,height=300] Window bounds: java.awt.Rectangle[x=100,y=100,width=450,height=300] Window bounds: java.awt.Rectangle[x=100,y=100,width=450,height=300] Window bounds: java.awt.Rectangle[x=100,y=100,width=450,height=300] Window bounds: java.awt.Rectangle[x=100,y=100,width=450,height=300] Window bounds: java.awt.Rectangle[x=100,y=100,width=450,height=300] Window bounds: java.awt.Rectangle[x=100,y=100,width=450,height=300] Window bounds: java.awt.Rectangle[x=100,y=100,width=450,height=300]
Sample jar and source
-d geometry,metadata
log output (edited):
Window.read_initial_X11_properties() WM_PROTOCOLS=['WM_DELETE_WINDOW', 'WM_TAKE_FOCUS'] WM_CLASS=('sun-awt-X11-XFramePeer', 'MainWindow') wm_hints.input = 0 WM_NORMAL_HINTS={u'position': (100, 100), u'win_gravity': 1, u'size': (440, 270)} initial X11 position and size: requested((100, 100, 440, 270), \ {u'position': (100, 100), 'gravity': 1, u'size': (440, 270)})=(100, 100, 440, 270) setup() hints={u'position': (100, 100), 'gravity': 1, u'size': (440, 270)} size=440x270 updateprop(geometry, (100, 100, 440, 270)) unchanged setup() resizing windows to 440x270
client @31.600 process_new_common: [2, 100, 100, 440, 270, {\ b'size-constraints': {b'position': (100, 100), b'gravity': 1, b'size': (440, 270)}, \ b'window-type': (b'NORMAL',), b'xid': b'0xe00007', b'decorations': 1, b'title': b' ', \ b'icon-title': b'Java', b'class-instance': (b'sun-awt-X11-XFramePeer', b'MainWindow'), \ b'client-machine': b'desktop', b'pid': 5660, b'set-initial-position': True }], \ metadata={ b'size-constraints': {b'position': (100, 100), b'gravity': 1, b'size': (440, 270)}, \ b'window-type': (b'NORMAL',), b'xid': b'0xe00007', \ b'decorations': 1, b'title': b' ', b'icon-title': b'Java', \ b'class-instance': (b'sun-awt-X11-XFramePeer', b'MainWindow'), \ b'client-machine': b'desktop', b'pid': 5660, b'set-initial-position': True}, \ OR=False
Property changed on 0xe00007: WM_NORMAL_HINTS WM_NORMAL_HINTS={u'position': (100, 100), u'win_gravity': 1, u'size': (450, 263)} updateprop(size-hints, {u'position': (100, 100), 'gravity': 1, u'size': (450, 263)}) \ previous value={u'position': (100, 100), 'gravity': 1, u'size': (440, 270)} XpraServer._window_resized_signaled(WindowModel(0xe00007),(<GParamBoxed 'geometry'>,)) \ geometry=(100, 100, 450, 263), desktop manager geometry=[100, 100, 440, 270]
we ignore the update on the corral window since it is not visible yet:
WindowModel.do_xpra_configure_event: corral window is not visible _do_update_client_geometry: allocated 440x270 (from <function window_size at 0x7ff7083ce6e0>) _do_update_client_geometry: size({u'position': (100, 100), 'gravity': 1, u'size': (450, 263)})=440x270 _do_update_client_geometry: position=100x100 (from <function window_position at 0x7ff7083ce848>) updateprop(geometry, (100, 100, 440, 270)) unchanged
anyway, we process the resize (450x263) on the client window:
do_child_configure_request_event(<X11:ConfigureRequest {\ 'delivered_to': u'0x40003c', 'send_event': '0', 'type': '23', 'detail': '0', \ 'height': '263', 'width': '450', 'window': u'0xe00007', 'above': '0', 'y': '0', 'x': '0', \ 'serial': '0xb48', 'border_width': '0', 'value_mask': '12', 'display': ':15'}>) \ client=0xe00007, corral=0x40003c, value_mask=Width|Height, \ size-hints={u'position': (100, 100), 'gravity': 1, u'size': (450, 263)} updateprop(requested-size, (450, 263)) previous value=(440, 270) updateprop(geometry, (100, 100, 450, 263)) previous value=(100, 100, 440, 270)
client @31.610 setup_window() position=(100, 100), set_initial_position=True, OR=False, decorated=True client @31.610 setup_window() window frame sizes={'frame': (0, 0, 37, 0), 'offset': (0, 37)} client @31.611 setup_window() adjusted initial position=(100, 63)
and it sends back a configure packet to the server with this size (440x270):
_process_configure_window([2, 100, 100, 440, 270, {\ 'encoding.scrolling': True, 'encoding.transparency': False, \ 'encodings.rgb_formats': ('YUV420P', 'YUV422P', 'YUV444P', 'GBRP', 'BGRA', 'BGRX', 'RGBA', 'RGBX', 'RGB', 'BGR'), \ 'encoding.full_csc_modes': {'mpeg1': ('YUV420P',), 'mpeg2': ('YUV420P',), '...',)}, \ 'encoding.bit-depth': 24 }, 0, {}, False, 2, (1776, 1368), ('mod2',)]) old window geometry: (100, 100, 450, 263)
(edited: first run returns 100,100 for position) And the server honours this (older) size value:
updateprop(geometry, (100, 100, 440, 270)) previous value=(100, 100, 450, 263)
The server figures out that the client already uses this value and doesn't send another resize to it. (which would create a resize loop)
_process_window_move_resize[2, 100, 100, 450, 263, 1] moving / resizing window \ GLClientWindow(2 : gtk3.GLDrawingArea(2, (440, 270), None)) (id=2) to (100, 100, 450, 263) window 2 move_resize(100, 100, 450, 263, 450) unchanged position 100x100, using resize(450, 263) resize(450, 263, 0) current size=(440, 270), fullscreen=None, maximized=False
And tells the server when it's done:
_process_configure_window([2, 100, 100, 450, 263, {}, 0, {}, False, 2, (1777, 1367), ('mod2',)]) old window geometry: (100, 100, 440, 270)
By this (convoluted) point, the position and size are "correct" on both the client and server.
scrub_x11() x11 properties=['WM_STATE', '_NET_FRAME_EXTENTS', '_NET_WM_ALLOWED_ACTIONS']
WM_NORMAL_HINTS={u'position': (100, 63), u'win_gravity': 1, u'size': (450, 263)} initial X11 position and size: requested((100, 63, 450, 263), \ {u'position': (100, 63), 'gravity': 1, u'size': (450, 263)})=(100, 63, 450, 263)
Java is clearly trying to adjust for the window frame size which is set at 27 for my client's DE.
And sure enough, by making the _NET_FRAME_EXTENTS
(#919) feature disabled using r20594 then Java maps the window at a different offset:
Window bounds: java.awt.Rectangle[x=100,y=100,width=450,height=300] Window bounds: java.awt.Rectangle[x=95,y=75,width=450,height=300] Window bounds: java.awt.Rectangle[x=95,y=75,width=440,height=270] Window bounds: java.awt.Rectangle[x=95,y=75,width=440,height=270] Window bounds: java.awt.Rectangle[x=95,y=75,width=440,height=270] Window bounds: java.awt.Rectangle[x=95,y=75,width=440,height=270]
It is probably guessing the window offsets, using something like (5,25,5,5).
And that's all I've got time for. Java is a mess, full of ugly hacks: http://hg.openjdk.java.net/jdk8/jdk8/jdk/file/687fd7c7986d/src/solaris/classes/sun/awt/X11/XWM.java and it's not the first time it gets it wrong: #725 (in particular ticket:705#comment:8).
Thanks.That explains a lot, had no idea how ugly this was. The link to the java source helped, after a quick test setting:
wm-name=NO WM env=XPRA_FRAME_EXTENTS=False
It improves the result but still moving after some time. I'll look into it further if I've time.
this ticket has been moved to: https://github.com/Xpra-org/xpra/issues/1975