xpra icon
Bug tracker and wiki

Opened 5 years ago

Closed 5 years ago

Last modified 15 months ago

#718 closed defect (fixed)

focus change requests in java applications does not work

Reported by: Antoine Martin Owned by: Antoine Martin
Priority: major Milestone: 0.15
Component: core Version: trunk
Keywords: Cc:

Description (last modified by Antoine Martin)

As per the (ugly) example application attached to this ticket, it is impossible to request a raise window in Java using Window.toFront.

Usage:

javac ToolbarFrame1.java
java ToolbarFrame1

Then click raise on one of the windows (only one of the two works... because of lazy coding)

Attachments (2)

ToolbarFrame1.java (1.2 KB) - added by Antoine Martin 5 years ago.
example Java raise application
RaiseTest.java (2.3 KB) - added by Antoine Martin 5 years ago.
updated test code, which does raise the window even when it is minimized

Download all attachments as: .zip

Change History (18)

Changed 5 years ago by Antoine Martin

Attachment: ToolbarFrame1.java added

example Java raise application

comment:1 Changed 5 years ago by Antoine Martin

Description: modified (diff)
Owner: changed from Antoine Martin to Antoine Martin
Status: newassigned

comment:2 Changed 5 years ago by Antoine Martin

Description: modified (diff)

The fix looks quite simple:

--- xpra/x11/gtk_x11/window.py	(revision 7956)
+++ xpra/x11/gtk_x11/window.py	(working copy)
@@ -624,7 +624,10 @@
     def do_xpra_focus_in_event(self, event):
         grablog("focus_in_event(%s) mode=%s, detail=%s",
             event, GRAB_CONSTANTS.get(event.mode), DETAIL_CONSTANTS.get(event.detail, event.detail))
-        self.may_emit_grab(event)
+        if event.mode==NotifyNormal and event.detail==NotifyNonlinearVirtual:
+            self.emit("raised", event)
+        else:
+            self.may_emit_grab(event)
 
     def do_xpra_focus_out_event(self, event):
         grablog("focus_out_event(%s) mode=%s, detail=%s",

But this is similar to grabs (#139 - see also #556) so maybe there are corner cases, and maybe this can cause regressions with clients that deal with focus client side? Will need testing with some of the test apps (and maybe write new ones for it).

So I am not applying it just yet.

comment:3 Changed 5 years ago by Antoine Martin

Worth mentioning: jdk7 known issues:. Quoting here since there is no internal link:

Area: API: AWT

Synopsis: This issue is specific to Window.toFront() and Window.toBack() behavior on X11 systems (Linux, Solaris). AWT always performs all necessary actions required to bring a window to the top or the bottom in the stacking order, according to the specifications of the windowing systems (e.g. the ICCCM and/or the EWMH for X11 systems). Whether the actions take effect or not depends on the window manager currently running in the system. Some windowing systems enforce additional constraints on when a window may be brought to the top in the window stacking order. In most cases, the purpose for such additional constraints is to enhance usability or security of these windowing environments. In other cases, these may simply be bugs in the windowing systems. This means that invoking the Window.toFront() or Window.toBack() methods may not always produce the expected results.
While this issue is, to some extent, reflected in the specification of the toFront() method, we've received several user complaints on this particular behavior while developing JDK7. All of these CRs have been closed as "Not a Defect" because AWT can't short-circuit the additional constraints, or work around any bugs in third-party software. If the problem is encountered with a Java application, in most cases it makes sense to check if native applications behave the same way, and file a bug against the windowing system accordingly.

Last edited 5 years ago by Antoine Martin (previous) (diff)

comment:4 Changed 5 years ago by Antoine Martin

The first difficulty is in finding some test code that does raise another window, even when minimized. Sounds simple, but it isn't in Java. See How to bring a window to the front?
When the window is minimized using the client window manager rather than programmatically (as apposed to How do I minimize and restore frames and JFrames?), the only thing that does restore it is to hide it then show it again, otherwise Java just doesn't change its state... (see RaiseTest.java)

Also it seems there are a few Java bugs in this area:

Now, we do fail this test. Adding the patch from comment:2 does improve things, but not it isn't very reliable and we don't handle the window when minimized, because we don't actually minimize it server side...

comment:5 Changed 5 years ago by Antoine Martin

I am moving the lack of support for setting the minimized state of windows to #726. This should resolve the raising of minimized windows (assuming this ticket is also fixed).

Running the example above under xtrace, I see that the request to raise the window is done using a XConfigureRequestEvent with stack-mode=Above:

000:<:04c9: 16: Request(12): ConfigureWindow window=0x00800007 values={stack-mode=Above(0x00)}

So we should be able to select for those events on the window.. except I can't seem to receive them!?
The window in the request data is the "client window" as found in our window model, that's the application's own window.
According to the docs ConfigureRequest Events: To receive ConfigureRequest events, set the SubstructureRedirectMask bit in the event-mask attribute of the window. ConfigureRequest events are generated when a ConfigureWindow protocol request is issued on a child window by another client. For example, suppose a client application calls XLowerWindow() to lower a window. If you had selected SubstructureRedirectMask on the parent window and if the override-redirect attribute of the window is set to False, the X server reports a ConfigureRequest event to you and does not lower the specified window.

We do already select those events using X11Window.substructureRedirect, this is how we already intercept client applications that resize themselves, but I am not seeing the stack-raise event in the X11 filter! Why!?

Last edited 15 months ago by Antoine Martin (previous) (diff)

comment:6 Changed 5 years ago by Antoine Martin

Improved the test examples in r8050 + r8051.

Running the GTK resize test and xtracing it with:

xtrace ./tests/xpra/test_apps/test_window_resize.py |& \
    egrep -vi "render|keyboard|cliprect|copyarea|changegc|pixmap|polyfill|motionnotify|expose|polysegment"

I see the configure request, but still not in the xpra event loop. At least it is consistent.

comment:7 Changed 5 years ago by Antoine Martin

Running the raise test example, I can see that Java fails to see our window as iconified.

There is a difference between what a normal desktop environment does and what we do when minimizing a window:

  • the normal window state is: Map State: IsViewable
  • my DE sets it to: Map State: IsUnMapped
  • xpra: Map State: IsUnviewable

In all cases:

  • the window state goes from window state: Normal to window state: Iconic
  • _NET_WM_STATE goes from empty to _NET_WM_STATE_HIDDEN

comment:8 Changed 5 years ago by Antoine Martin

See #726 for the fix to WM_STATE. Now going back to the actual toFront to try to find a cleaner solution for detecting the "window raise" event.

The relevant code for toFront() in the Java source looks like this one in solaris/classes/sun/awt/X11/XBaseWindow.java using XRaiseWindow:

public void toFront() {
    XToolkit.awtLock();
    try {
        XlibWrapper.XRaiseWindow(XToolkit.getDisplay(), getWindow());
    } finally {
        XToolkit.awtUnlock();
    }
}

This should allow us to write a simple example to test with.

comment:9 Changed 5 years ago by Antoine Martin

The improvements done as part of #765 (in particular r8319) now allow Java to see the window as iconified.
The updated example code correctly unminimizes the window before trying to raise it. But the raising part is still problematic..

Changed 5 years ago by Antoine Martin

Attachment: RaiseTest.java added

updated test code, which does raise the window even when it is minimized

comment:10 Changed 5 years ago by Antoine Martin

Owner: changed from Antoine Martin to alas
Status: assignednew

Having read again (with difficulty) Normal Focus Events and Focus Events While Grabbed, I believe the change from comment:2 may well be correct in the end so I've applied it in r8351. (it could be backported - but not need to rush it)

afarr: just re-assigning to you so you know about this, in case we hit focus related issues somewhere else - this could be the cause. Feel free to just close it as an ACK.
To run the example test code, just run:

javac RaiseTest.java
java RaiseTest
Last edited 5 years ago by Antoine Martin (previous) (diff)

comment:11 Changed 5 years ago by Antoine Martin

I've not seen any adverse effects so far, so backported to v0.14.x in r8384.

comment:12 Changed 5 years ago by Antoine Martin

Spoke too soon: r8286 (+backport in r8287) needed to prevent minimize + restore loops when minimizing a window which does not have focus.

comment:13 Changed 5 years ago by alas

Err... think I'm doing something wrong trying to launch.

Running: $ java ToolbarFrame1.java I get Error: Could not find or load main class ToolbarFrame1.java.

(Google says something about javac, but that's giving me a command not found error... I know I'm missing something.)

comment:14 Changed 5 years ago by Antoine Martin

Please see comment:10, you need to run javac before you can run java on the class file that gets generated.

javac, but that's giving me a command not found error..


Which package provides javac depends on what distro you are testing with.

comment:15 Changed 5 years ago by alas

Owner: changed from alas to Antoine Martin

Ok... run and now vaguely familiar with it. Handing back to you to close (assuming you don't have more bits to handle).

comment:16 Changed 5 years ago by Antoine Martin

Resolution: fixed
Status: newclosed

Done! Closing.

Note: See TracTickets for help on using tickets.