Xpra-org / xpra

Persistent remote applications for X11; screen sharing for X11, MacOS and MSWindows.
https://xpra.org/
GNU General Public License v2.0
1.96k stars 169 forks source link

Java applications running with JDK6 or older can produce windows 1 pixel high / wide #705

Closed totaam closed 9 years ago

totaam commented 10 years ago

Attached is a very simple test case.

export JAVA_HOME=/opt/jdk1.6
$JAVA_HOME/bin/javac Main.java 
$JAVA_HOME/bin/java Main 

Click on the button and the dialog window appears correctly, close it and try again and it gets mapped as a 1 pixel high window..

I have tested many versions of Java, including the IBM SDK, opensdk, Sun's SDK, etc.. This only affects Java 6 and earlier. (which is the version supported in centos 5 and some centos 6 installations..)

r7959 added CreateNotify support for X11 event logging since the window seemed to be configured wrong by the time we get notified.

So the problem occurs very early on, when we read the window's initial dimensions. It looks like Java is caching something (in one of its numerous hidden event windows?) which causes the new dialog window to inherit the wrong size. During a reparent maybe? This obviously does not happen with other window managers, so we must be doing something wrong.

This ticket was originally recorded as a JOGL bug - but as can be seen in the example code, that was wrong, JOGL has nothing to do with it.

totaam commented 10 years ago

I have also tried:

So... that leaves tracing the X11 calls done by twm and comparing with xpra's. Oh joy.

totaam commented 10 years ago

2014-10-28 20:50:01: totaam uploaded file test-Xnest-twm.xtrace (81.9 KiB)

xtrace of the test application running under twm via Xnest

totaam commented 10 years ago

Interesting: by killing (kill -9) the xpra server at various points and doing the other steps from a shadow copy with no window manager running, I have narrowed down the problem to the mapping of the initial 2 windows:

I also found a ticket which looks very similar: JOSM starts as few pixel width window. - but the resolution does not apply here.

totaam commented 10 years ago

2014-10-31 10:28:40: totaam uploaded file test-xpra.xtrace (189.9 KiB)

same xtrace but with xpra

totaam commented 9 years ago

Comparing the two xtraces, edited from the moment of the button release that creates the new dialog window:

twm does:


Comparing the two xtraces, edited from the moment of the button release that creates the new dialog window:

twm does:

000:<:0365: 56: Request(1): CreateWindow depth=0x18 window=0x00600029 parent=0x00000025 \
    x=0 y=0 width=200 height=71 border-width=0 class=InputOutput(0x0001) \
    visual=0x00000020 value-list={border-pixel=0x00000000 bit-gravity=NorthWest(0x01) \
    backing-store=NotUseful(0x00) override-redirect=false(0x00) \
    event-mask=ButtonPress,ButtonRelease,EnterWindow,LeaveWindow,PointerMotion,ButtonMotion,Exposure,VisibilityChange,StructureNotify,PropertyChange,OwnerGrabButton \
    colormap=0x00000021}
000:<:0366: 28: Request(18): ChangeProperty mode=Replace(0x00) window=0x00600029 property=0x27("WM_NAME") type=0x1f("STRING") data=' '
(..)
000:>:0370:44: GetWindowAttributes: (..) map-is-installed=true(0x01) map-state=Unmapped(0x00) override-redirect=false(0x00)
000:>:0371:32: Reply to GetGeometry: depth=0x18 root=0x00000025 x=0 y=0 width=200 height=71 border-width=0
(..)
000:<:0383: 48: Request(1): CreateWindow depth=0x18 window=0x0060002f parent=0x00000025 \
    x=0 y=0 width=16 height=16 border-width=0 class=InputOutput(0x0001) visual=0x00000020 \
    value-list={background-pixmap=0x0060002b border-pixel=0x00000020 event-mask=PropertyChange,OwnerGrabButton colormap=0x00000021}
000:<:0384: 48: Request(18): ChangeProperty mode=Replace(0x00) window=0x0060002f property=0x27("WM_NAME") type=0x1f("STRING") \
    data='sun-awt-X11-XIconWindow'
(..)
000:<:0389: 60: Request(18): ChangeProperty mode=Replace(0x00) window=0x00600029 property=0x23("WM_HINTS") type=0x23("WM_HINTS") \
    data=0x0000006c,0x00000000,0x00000000,0x0060002b,0x0060002f,0x00000000,0x00000000,0x0060002d,0x00600006;
000:<:038a: 96: Request(18): ChangeProperty mode=Replace(0x00) window=0x00600029 property=0x28("WM_NORMAL_HINTS") type=0x29("WM_SIZE_HINTS") \
    data=0x0000020d,0x00000000,0x00000000,0x000000c8,0x00000047,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000001;
(..)
000:<:038b: 52: Request(1): CreateWindow depth=0x18 window=0x00600030 parent=0x00600029 \
    x=0 y=-29 width=200 height=100 border-width=0 class=InputOutput(0x0001) \
    visual=0x00000020 value-list={border-pixel=0x00000000 bit-gravity=NorthWest(0x01) \
    backing-store=NotUseful(0x00) \
    event-mask=KeyPress,KeyRelease,ButtonPress,ButtonRelease,EnterWindow,LeaveWindow,PointerMotion,ButtonMotion,Exposure,FocusChange,PropertyChange,OwnerGrabButton colormap=0x00000021}
000:<:038c: 40: Request(18): ChangeProperty mode=Replace(0x00) window=0x00600030 property=0x27("WM_NAME") type=0x1f("STRING") \
    data='Content window'
(..)
000:<:0392:  8: Request(8): MapWindow window=0x00600030
000:<:0393: 36: Request(1): CreateWindow depth=0x00 window=0x00600032 parent=0x00600029 \
    x=-1 y=-1 width=1 height=1 border-width=0 class=InputOnly(0x0002) visual=CopyFromParent(0x00000000) \
    value-list={event-mask=KeyPress,KeyRelease,SubstructureNotify,FocusChange,PropertyChange,OwnerGrabButton}
000:<:0394: 36: Request(18): ChangeProperty mode=Replace(0x00) window=0x00600032 property=0x27("WM_NAME") type=0x1f("STRING") \
    data='FocusProxy'
(..)
000:<:039a: 48: Request(1): CreateWindow depth=0x18 window=0x00600033 parent=0x00600030 \
    x=0 y=0 width=1 height=1 border-width=0 class=InputOutput(0x0001) visual=0x00000020 \
    value-list={border-pixel=0x00000000 backing-store=NotUseful(0x00) event-mask=KeyPress,KeyRelease,ButtonPress,ButtonRelease,EnterWindow,LeaveWindow,PointerMotion,ButtonMotion,Exposure,StructureNotify,FocusChange,PropertyChange,OwnerGrabButton \
    colormap=0x00000021}
000:<:039b: 48: Request(18): ChangeProperty mode=Replace(0x00) window=0x00600033 property=0x27("WM_NAME") type=0x1f("STRING") \
    data='sun-awt-X11-XButtonPeer'
(..)
000:<:03a2: 28: Request(12): ConfigureWindow window=0x00600033 values={x=0 y=0 width=1 height=1}
000:<:03a3:  8: Request(8): MapWindow window=0x00600033
000:<:03a4:  8: Request(15): QueryTree window=0x00600030
000:>:03a4: Event MapNotify(19) event=0x00600033 window=0x00600033 override-redirect=false(0x00)
000:<:03a6: 28: Request(12): ConfigureWindow window=0x00600033 values={x=0 y=29 width=200 height=71}
000:>:03a8: Event ConfigureNotify(22) event=0x00600033 window=0x00600033 above-sibling=None(0x00000000) \
    x=0 y=29 width=200 height=71 border-width=0 override-redirect=false(0x00)
(..)
000:<:03b6: 16: Request(12): ConfigureWindow window=0x00600029 values={stack-mode=Above(0x00)}
000:<:03b7:  8: Request(8): MapWindow window=0x00600029
(..)
000:>:03b7: Event ReparentNotify(21) event=0x00600029 window=0x00600029 parent=0x004000a5 x=0 y=29 override-redirect=false(0x00)
000:>:03b7: Event (generated) ConfigureNotify(22) event=0x00600029 window=0x00600029 above-sibling=0x004000a5 x=2 y=31 width=200 height=71 border-width=0 override-redirect=false(0x00)
000:>:03b7: Event MapNotify(19) event=0x00600029 window=0x00600029 override-redirect=false(0x00)
(..)
000:>:03b8: Event PropertyNotify(28) window=0x00600029 atom=0xf5("WM_STATE") time=0x07aa0198 state=NewValue(0x00)
(..)
000:>:03b9:44: Reply to GetWindowAttributes: (..) map-is-installed=true(0x01) map-state=Viewable(0x02) override-redirect=false(0x00) (..)
000:>:03ba:32: Reply to GetGeometry: depth=0x18 root=0x00000025 x=0 y=0 width=200 height=100 border-width=2

Which can be translated as (verbs are as seen from the application context):

totaam commented 9 years ago

with xpra it does this:

Some of the configure requests aren't honoured, and some of those don't make much sense!

000:<:02b1: 20: Request(12): ConfigureWindow window=0x00800019 values={width=0 height=0}
000:<:02b2: 20: Request(12): ConfigureWindow window=0x00800019 values={x=0 y=0}
000:<:02b3: 28: Request(12): ConfigureWindow window=0x0080001b values={x=-4 y=-28 width=2370 height=1530
(..)
000:<:02b5: 28: Request(12): ConfigureWindow window=0x0080001b values={x=-4 y=-28 width=2560 height=1600}
(..)
000:<:02b8: 28: Request(12): ConfigureWindow window=0x0080001e values={x=4 y=28 width=190 height=70}
000:>:02b9: Event ConfigureNotify(22) event=0x0080001e window=0x0080001e above-sibling=None(0x00000000) \
    x=4 y=28 width=190 height=70 000:>:02ba: Event (generated) ClientMessage(33) format=0x20 window=0x00800019 type=0xea("WM_PROTOCOLS") \
    data=0xeb,0x00,0x00,0x00,0xac,0x7e,0x62,0x05,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00;

Need to investigate:

totaam commented 9 years ago

Attacking this from different angles:

Since there are a few tricks in the Java source code based on the window manager name, I added r8025 which allows us to easily set it (_NET_WM_NAME on the ewmh window). Alternatively, wmname could be used for testing. I've tried a few of them (LG3D, Sawfish, Compiz) and this did not help.

I've also tried setting: AWT_TOOLKIT=MToolkit - no change (wasn't really expecting it to work since we are a reparenting window manager), it did cause crashes with some of the window manager names. (in catgets called from GetAllProtocolsMgr - whatever this is, probably because it is not expecting us to reparent) Useful information on this subject can be found here: [http://awesome.naquadah.org/wiki/Problems_with_Java]

This looks like it could be related: [http://bugs.java.com/bugdatabase/view_bug.do?bug_id=6632124] and [http://bugs.java.com/bugdatabase/view_bug.do?bug_id=6429775], but we do set _NET_FRAME_EXTENTS as early as we can already. Also found a good reference for focus events: Java 6 Focus Spec.


totaam commented 9 years ago

2014-11-01 16:04:44: totaam uploaded file jdk-vs-openjdk.log (162.0 KiB)

diff between broken and working debug log

totaam commented 9 years ago

Found this in the Java patch nomotif-6706121.patch - worth a read: '' Unfortunately the concept of "insets" borrowed to AWT from Win32 is absolutely, unbelievably foreign to X11. Few WMs provide the size of frame decor (i.e. insets) in a property they set on the client window, so we check if we can get away with just peeking at it. [Future versions of wm-spec might add a standardized hint for this].''

-Otherwise we do some special casing. Actually the fallback code ("default" case) seems to cover most of the existing WMs (modulo Reparent/Configure order perhaps?).*

-Fallback code tries to account for the two most common cases:*

This code is absolutely horrible, no wonder they refactored it in JDK 7! See also JDK bug 4304985: Frame opening fails to restore location

I think what is happening is that the code checks for the parent size, finds it is the same as the window (because we don't have any window decorations on the server!) and assumes that the real window frame has to be the grand parent... which is the root window, and it is huge which causes the crazy large inset calculations.

Setting the window manager as Sawfish seems to fix this problem! (makes Java assume single-reparenting behaviour)

Run xpra as of r8033 (will backport the important bits):

XPRA_NET_WM_NAME=Sawfish xpra start ...

Keeping this ticket open as we may want to find a cleaner solution, one that does not involve lying about our window manager name!

totaam commented 9 years ago

2014-11-02 08:20:42: totaam uploaded file Main.java (2.1 KiB)

updated test class which also dumps information about the graphics context

totaam commented 9 years ago

Backport in 8061. Closing.

totaam commented 9 years ago

r8065 makes it easier to verify that the workaround is in place, ie:

$ XPRA_NET_WM_NAME=Sawfish xpra start
$ xpra info | grep window-manager-name
window-manager-name=Sawfish

We query it at runtime to catch changes made externally using tools like wmname.

totaam commented 9 years ago

Improvements in r8329 + r8330, backported in 8333.