Skip to content

Commit

Permalink
JBR-7972 Wayland: EXTREME lag when scrolling through any type of list…
Browse files Browse the repository at this point in the history
… in the settings when using WLToolkit

Avoid requesting the Wayland server to change the cursor when the change
is vacuous
  • Loading branch information
mkartashev authored and jbrbot committed Dec 4, 2024
1 parent cbc181a commit b794e57
Show file tree
Hide file tree
Showing 4 changed files with 110 additions and 97 deletions.
95 changes: 3 additions & 92 deletions src/java.desktop/unix/classes/sun/awt/wl/WLComponentPeer.java
Original file line number Diff line number Diff line change
Expand Up @@ -82,26 +82,6 @@ public class WLComponentPeer implements ComponentPeer {
private static final PlatformLogger focusLog = PlatformLogger.getLogger("sun.awt.wl.focus.WLComponentPeer");
private static final PlatformLogger popupLog = PlatformLogger.getLogger("sun.awt.wl.popup.WLComponentPeer");

// mapping of AWT cursor types to X cursor names
// multiple variants can be specified, that will be tried in order
// See https://freedesktop.org/wiki/Specifications/cursor-spec/
private static final String[][] CURSOR_NAMES = {
{"default", "arrow", "left_ptr", "left_arrow"}, // DEFAULT_CURSOR
{"crosshair", "cross"}, // CROSSHAIR_CURSOR
{"text", "xterm"}, // TEXT_CURSOR
{"wait", "watch", "progress"}, // WAIT_CURSOR
{"sw-resize", "bottom_left_corner"}, // SW_RESIZE_CURSOR
{"se-resize", "bottom_right_corner"}, // SE_RESIZE_CURSOR
{"nw-resize", "top_left_corner"}, // NW_RESIZE_CURSOR
{"ne-resize", "top_right_corner"}, // NE_RESIZE_CURSOR
{"n-resize", "top_side"}, // N_RESIZE_CURSOR
{"s-resize", "bottom_side"}, // S_RESIZE_CURSOR
{"w-resize", "left_side"}, // W_RESIZE_CURSOR
{"e-resize", "right_side"}, // E_RESIZE_CURSOR
{"pointer", "pointing_hand", "hand1", "hand2"}, // HAND_CURSOR
{"move"}, // MOVE_CURSOR
};

private static final int MINIMUM_WIDTH = 1;
private static final int MINIMUM_HEIGHT = 1;

Expand Down Expand Up @@ -847,17 +827,10 @@ public Font getFont() {
}

public void updateCursorImmediately() {
updateCursorImmediately(WLToolkit.getInputState());
}

private void updateCursorImmediately(WLInputState inputState) {
WLComponentPeer peer = inputState.peerForPointerEvents();
if (peer == null) return;
Cursor cursor = peer.getCursor(inputState.getPointerX(), inputState.getPointerY());
setCursor(cursor, getGraphicsDevice() != null ? getGraphicsDevice().getDisplayScale() : 1);
WLToolkit.updateCursorImmediatelyFor(this);
}

Cursor getCursor(int x, int y) {
Cursor cursorAt(int x, int y) {
Component target = this.target;
if (target instanceof Container) {
Component c = AWTAccessor.getContainerAccessor().findComponentAt((Container) target, x, y, false);
Expand All @@ -868,56 +841,6 @@ Cursor getCursor(int x, int y) {
return AWTAccessor.getComponentAccessor().getCursor(target);
}

private static void setCursor(Cursor c, int scale) {
long serial = WLToolkit.getInputState().pointerEnterSerial();
if (serial == 0) {
if (log.isLoggable(Level.WARNING)) {
log.warning("setCursor aborted due to missing event serial");
}
return; // Wayland will ignore the request anyway
}

Cursor cursor;
if (c.getType() == Cursor.CUSTOM_CURSOR && !(c instanceof WLCustomCursor)) {
cursor = Cursor.getDefaultCursor();
} else {
cursor = c;
}
performLockedGlobal(() -> {
long pData = AWTAccessor.getCursorAccessor().getPData(cursor, scale);
if (pData == 0) {
// instead of destroying and creating new cursor after changing scale could be used caching
long oldPData = AWTAccessor.getCursorAccessor().getPData(cursor);
if (oldPData != 0 && oldPData != -1) {
nativeDestroyPredefinedCursor(oldPData);
}

pData = createNativeCursor(cursor.getType(), scale);
if (pData == 0) {
pData = createNativeCursor(Cursor.DEFAULT_CURSOR, scale);
}
if (pData == 0) {
pData = -1; // mark as unavailable
}
AWTAccessor.getCursorAccessor().setPData(cursor, scale, pData);
}
nativeSetCursor(pData, scale, serial);
});
}

private static long createNativeCursor(int type, int scale) {
if (type < Cursor.DEFAULT_CURSOR || type > Cursor.MOVE_CURSOR) {
type = Cursor.DEFAULT_CURSOR;
}
for (String name : CURSOR_NAMES[type]) {
long pData = nativeGetPredefinedCursor(name, scale);
if (pData != 0) {
return pData;
}
}
return 0;
}

@Override
public Image createImage(int width, int height) {
WLGraphicsConfig graphicsConfig = (WLGraphicsConfig) target.getGraphicsConfiguration();
Expand Down Expand Up @@ -1083,9 +1006,6 @@ protected native void nativeRepositionWLPopup(long ptr,
private native void nativeSetWindowGeometry(long ptr, int x, int y, int width, int height);
private native void nativeSetMinimumSize(long ptr, int width, int height);
private native void nativeSetMaximumSize(long ptr, int width, int height);
private static native void nativeSetCursor(long pData, int scale, long pointerEnterSerial);
private static native long nativeGetPredefinedCursor(String name, int scale);
private static native long nativeDestroyPredefinedCursor(long pData);
private native void nativeShowWindowMenu(long serial, long ptr, int x, int y);
private native void nativeActivate(long serial, long ptr, long activatingSurfacePtr);

Expand Down Expand Up @@ -1128,7 +1048,7 @@ void dispatchPointerEventInContext(WLPointerEvent e, WLInputState oldInputState,
final long timestamp = newInputState.getTimestamp();

if (e.hasEnterEvent()) {
performUnlocked(() -> updateCursorImmediately(newInputState));
updateCursorImmediately();
final MouseEvent mouseEvent = new MouseEvent(getTarget(), MouseEvent.MOUSE_ENTERED,
timestamp,
newInputState.getModifiers(),
Expand Down Expand Up @@ -1721,15 +1641,6 @@ private Dimension constrainSize(Dimension bounds) {
// done using these methods. Then one can be sure that native data is not changed concurrently in any way while the
// specified task is executed.

static void performLockedGlobal(Runnable task) {
WLToolkit.awtLock();
try {
task.run();
} finally {
WLToolkit.awtUnlock();
}
}

void performLocked(Runnable task) {
WLToolkit.awtLock();
try {
Expand Down
4 changes: 2 additions & 2 deletions src/java.desktop/unix/classes/sun/awt/wl/WLDecoratedPeer.java
Original file line number Diff line number Diff line change
Expand Up @@ -144,12 +144,12 @@ final void paintClientDecorations(final Graphics g) {
}

@Override
Cursor getCursor(int x, int y) {
Cursor cursorAt(int x, int y) {
Cursor cursor = decoration.getCursor(x, y);
if (cursor != null) {
return cursor;
} else {
return super.getCursor(x, y);
return super.cursorAt(x, y);
}
}
}
102 changes: 102 additions & 0 deletions src/java.desktop/unix/classes/sun/awt/wl/WLToolkit.java
Original file line number Diff line number Diff line change
Expand Up @@ -132,11 +132,33 @@ public class WLToolkit extends UNIXToolkit implements Runnable {
private static final int MOUSE_BUTTONS_COUNT = 7;
private static final int AWT_MULTICLICK_DEFAULT_TIME_MS = 500;

// mapping of AWT cursor types to X cursor names
// multiple variants can be specified, that will be tried in order
// See https://freedesktop.org/wiki/Specifications/cursor-spec/
private static final String[][] CURSOR_NAMES = {
{"default", "arrow", "left_ptr", "left_arrow"}, // DEFAULT_CURSOR
{"crosshair", "cross"}, // CROSSHAIR_CURSOR
{"text", "xterm"}, // TEXT_CURSOR
{"wait", "watch", "progress"}, // WAIT_CURSOR
{"sw-resize", "bottom_left_corner"}, // SW_RESIZE_CURSOR
{"se-resize", "bottom_right_corner"}, // SE_RESIZE_CURSOR
{"nw-resize", "top_left_corner"}, // NW_RESIZE_CURSOR
{"ne-resize", "top_right_corner"}, // NE_RESIZE_CURSOR
{"n-resize", "top_side"}, // N_RESIZE_CURSOR
{"s-resize", "bottom_side"}, // S_RESIZE_CURSOR
{"w-resize", "left_side"}, // W_RESIZE_CURSOR
{"e-resize", "right_side"}, // E_RESIZE_CURSOR
{"pointer", "pointing_hand", "hand1", "hand2"}, // HAND_CURSOR
{"move"}, // MOVE_CURSOR
};

private static boolean initialized = false;
private static Thread toolkitThread;
private final WLClipboard clipboard;
private final WLClipboard selection;

private static Cursor currentCursor;

private static native void initIDs(long displayPtr);

static {
Expand Down Expand Up @@ -299,6 +321,10 @@ private static void dispatchPointerEvent(WLPointerEvent e) {
final WLInputState oldInputState = inputState;
final WLInputState newInputState = oldInputState.updatedFromPointerEvent(e);
inputState = newInputState;
if (e.hasLeaveEvent() || e.hasEnterEvent()) {
// We've lost the control over the cursor, assume no knowledge about it
currentCursor = null;
}
final WLComponentPeer peer = newInputState.peerForPointerEvents();
if (peer == null) {
// We don't know whom to notify of the event; may happen when
Expand Down Expand Up @@ -1052,4 +1078,80 @@ static void resetPointerInputState() {
static boolean isInitialized() {
return initialized;
}

static void performLockedGlobal(Runnable task) {
WLToolkit.awtLock();
try {
task.run();
} finally {
WLToolkit.awtUnlock();
}
}

static void updateCursorImmediatelyFor(WLComponentPeer peer) {
Cursor cursor = peer.cursorAt(inputState.getPointerX(), inputState.getPointerY());
GraphicsConfiguration gc = peer.getGraphicsConfiguration();
int scale = gc instanceof WLGraphicsConfig wlGC ? wlGC.getDisplayScale() : 1;
setCursorTo(cursor, scale);
}

static void setCursorTo(Cursor c, int scale) {
long serial = inputState.pointerEnterSerial();
if (serial == 0) {
if (log.isLoggable(PlatformLogger.Level.FINE)) {
log.fine("setCursor aborted due to missing event serial");
}
return; // Wayland will ignore the request anyway
}

Cursor cursor;
if (c.getType() == Cursor.CUSTOM_CURSOR && !(c instanceof WLCustomCursor)) {
cursor = Cursor.getDefaultCursor();
} else {
cursor = c;
}

performLockedGlobal(() -> {
// Cursors may get updated very often; prevent vacuous updates from reaching the native code so
// as not to overwhelm the Wayland server.
if (cursor == currentCursor) return;
currentCursor = cursor;

long pData = AWTAccessor.getCursorAccessor().getPData(cursor, scale);
if (pData == 0) {
// instead of destroying and creating new cursor after changing scale could be used caching
long oldPData = AWTAccessor.getCursorAccessor().getPData(cursor);
if (oldPData != 0 && oldPData != -1) {
nativeDestroyPredefinedCursor(oldPData);
}

pData = createNativeCursor(cursor.getType(), scale);
if (pData == 0) {
pData = createNativeCursor(Cursor.DEFAULT_CURSOR, scale);
}
if (pData == 0) {
pData = -1; // mark as unavailable
}
AWTAccessor.getCursorAccessor().setPData(cursor, scale, pData);
}
nativeSetCursor(pData, scale, serial);
});
}

private static long createNativeCursor(int type, int scale) {
if (type < Cursor.DEFAULT_CURSOR || type > Cursor.MOVE_CURSOR) {
type = Cursor.DEFAULT_CURSOR;
}
for (String name : CURSOR_NAMES[type]) {
long pData = nativeGetPredefinedCursor(name, scale);
if (pData != 0) {
return pData;
}
}
return 0;
}

private static native void nativeSetCursor(long pData, int scale, long pointerEnterSerial);
private static native long nativeGetPredefinedCursor(String name, int scale);
private static native long nativeDestroyPredefinedCursor(long pData);
}
6 changes: 3 additions & 3 deletions src/java.desktop/unix/native/libawt_wlawt/WLCursor.c
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ Java_java_awt_Cursor_finalizeImpl
}
}

JNIEXPORT jlong JNICALL Java_sun_awt_wl_WLComponentPeer_nativeGetPredefinedCursor
JNIEXPORT jlong JNICALL Java_sun_awt_wl_WLToolkit_nativeGetPredefinedCursor
(JNIEnv *env, jclass cls, jstring name, jint scale)
{
struct wl_cursor_theme *cursor_theme = getCursorTheme(scale);
Expand Down Expand Up @@ -91,7 +91,7 @@ JNIEXPORT jlong JNICALL Java_sun_awt_wl_WLComponentPeer_nativeGetPredefinedCurso
return ptr_to_jlong(cursor);
}

JNIEXPORT void JNICALL Java_sun_awt_wl_WLComponentPeer_nativeDestroyPredefinedCursor
JNIEXPORT void JNICALL Java_sun_awt_wl_WLToolkit_nativeDestroyPredefinedCursor
(JNIEnv *env, jclass cls, struct WLCursor *cursor)
{
free(cursor);
Expand Down Expand Up @@ -140,7 +140,7 @@ JNIEXPORT jlong JNICALL Java_sun_awt_wl_WLCustomCursor_nativeCreateCustomCursor
return ptr_to_jlong(cursor);
}

JNIEXPORT void JNICALL Java_sun_awt_wl_WLComponentPeer_nativeSetCursor
JNIEXPORT void JNICALL Java_sun_awt_wl_WLToolkit_nativeSetCursor
(JNIEnv *env, jclass cls, jlong pData, jint scale, jlong pointerEnterSerial)
{
struct wl_buffer *buffer = NULL;
Expand Down

0 comments on commit b794e57

Please sign in to comment.