fix call xseterrorhandler while gdk error trap is up
This commit is contained in:
@@ -24,10 +24,6 @@ import java.nio.file.Path;
|
||||
import java.util.List;
|
||||
|
||||
public final class Main extends Application {
|
||||
// Mouse pointer location captured in main() before JavaFX loads GTK; used to pick the
|
||||
// startup monitor. Reading it later (after GTK) makes AWT's X11 init clash with GDK.
|
||||
private static java.awt.Point startupPointer;
|
||||
|
||||
private Compositor compositor;
|
||||
private TerminalMetrics metrics;
|
||||
private AppConfig config;
|
||||
@@ -75,10 +71,10 @@ public final class Main extends Application {
|
||||
}
|
||||
|
||||
private static Screen activeScreen() {
|
||||
java.awt.Point at = startupPointer;
|
||||
int[] at = X11Pointer.query();
|
||||
if (at != null) {
|
||||
// AWT and JavaFX share a coordinate space on the X11 virtual screen.
|
||||
List<Screen> screens = Screen.getScreensForRectangle(at.x, at.y, 1.0, 1.0);
|
||||
// libX11 and JavaFX share a coordinate space on the X11 virtual screen.
|
||||
List<Screen> screens = Screen.getScreensForRectangle(at[0], at[1], 1.0, 1.0);
|
||||
if (!screens.isEmpty()) {
|
||||
return screens.get(0);
|
||||
}
|
||||
@@ -230,19 +226,6 @@ public final class Main extends Application {
|
||||
|
||||
public static void main(String[] args) {
|
||||
System.setProperty("prism.order", System.getProperty("prism.order", "es2,sw"));
|
||||
// Initialise AWT and read the pointer here, before launch() loads GTK. Done afterwards,
|
||||
// AWT's X11 init calls XSetErrorHandler while GDK has an error trap pushed and warns.
|
||||
startupPointer = readPointerLocation();
|
||||
launch(Main.class, args);
|
||||
}
|
||||
|
||||
private static java.awt.Point readPointerLocation() {
|
||||
try {
|
||||
java.awt.PointerInfo pointer = java.awt.MouseInfo.getPointerInfo();
|
||||
return pointer != null ? pointer.getLocation() : null;
|
||||
} catch (Throwable ignored) {
|
||||
// Headless or AWT unavailable — the startup monitor falls back to the primary screen.
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
66
src/main/java/com/gregor/jprototerm/X11Pointer.java
Normal file
66
src/main/java/com/gregor/jprototerm/X11Pointer.java
Normal file
@@ -0,0 +1,66 @@
|
||||
package com.gregor.jprototerm;
|
||||
|
||||
import java.lang.foreign.Arena;
|
||||
import java.lang.foreign.FunctionDescriptor;
|
||||
import java.lang.foreign.Linker;
|
||||
import java.lang.foreign.MemorySegment;
|
||||
import java.lang.foreign.SymbolLookup;
|
||||
import java.lang.invoke.MethodHandle;
|
||||
|
||||
import static java.lang.foreign.ValueLayout.ADDRESS;
|
||||
import static java.lang.foreign.ValueLayout.JAVA_INT;
|
||||
import static java.lang.foreign.ValueLayout.JAVA_LONG;
|
||||
|
||||
/**
|
||||
* Reads the X11 pointer location directly via libX11 ({@code XQueryPointer}). Unlike AWT's
|
||||
* {@code MouseInfo}, this never calls {@code XSetErrorHandler}, so it doesn't trip GDK's
|
||||
* "XSetErrorHandler called with a GDK error trap pushed" warning when JavaFX's GTK backend is
|
||||
* already up. Returns {@code null} when not on X11 or libX11 can't be loaded.
|
||||
*/
|
||||
final class X11Pointer {
|
||||
private X11Pointer() {
|
||||
}
|
||||
|
||||
/** {@code {x, y}} of the pointer in X root-window (virtual screen) space, or {@code null}. */
|
||||
static int[] query() {
|
||||
try (Arena arena = Arena.ofConfined()) {
|
||||
Linker linker = Linker.nativeLinker();
|
||||
SymbolLookup x11 = SymbolLookup.libraryLookup("libX11.so.6", arena);
|
||||
MethodHandle openDisplay = linker.downcallHandle(x11.find("XOpenDisplay").orElseThrow(),
|
||||
FunctionDescriptor.of(ADDRESS, ADDRESS));
|
||||
MethodHandle defaultRootWindow = linker.downcallHandle(x11.find("XDefaultRootWindow").orElseThrow(),
|
||||
FunctionDescriptor.of(JAVA_LONG, ADDRESS));
|
||||
MethodHandle queryPointer = linker.downcallHandle(x11.find("XQueryPointer").orElseThrow(),
|
||||
FunctionDescriptor.of(JAVA_INT, ADDRESS, JAVA_LONG,
|
||||
ADDRESS, ADDRESS, ADDRESS, ADDRESS, ADDRESS, ADDRESS, ADDRESS));
|
||||
MethodHandle closeDisplay = linker.downcallHandle(x11.find("XCloseDisplay").orElseThrow(),
|
||||
FunctionDescriptor.of(JAVA_INT, ADDRESS));
|
||||
|
||||
MemorySegment display = (MemorySegment) openDisplay.invoke(MemorySegment.NULL);
|
||||
if (display.address() == 0) {
|
||||
return null;
|
||||
}
|
||||
try {
|
||||
long root = (long) defaultRootWindow.invoke(display);
|
||||
MemorySegment rootReturn = arena.allocate(JAVA_LONG);
|
||||
MemorySegment childReturn = arena.allocate(JAVA_LONG);
|
||||
MemorySegment rootX = arena.allocate(JAVA_INT);
|
||||
MemorySegment rootY = arena.allocate(JAVA_INT);
|
||||
MemorySegment winX = arena.allocate(JAVA_INT);
|
||||
MemorySegment winY = arena.allocate(JAVA_INT);
|
||||
MemorySegment mask = arena.allocate(JAVA_INT);
|
||||
int onSameScreen = (int) queryPointer.invoke(display, root,
|
||||
rootReturn, childReturn, rootX, rootY, winX, winY, mask);
|
||||
if (onSameScreen == 0) {
|
||||
return null;
|
||||
}
|
||||
return new int[] { rootX.get(JAVA_INT, 0), rootY.get(JAVA_INT, 0) };
|
||||
} finally {
|
||||
closeDisplay.invoke(display);
|
||||
}
|
||||
} catch (Throwable ignored) {
|
||||
// Not X11, libX11 missing, or the call failed — caller falls back to the primary screen.
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user