Skip to content

Commit

Permalink
JBR-7504 Use accurate event serial number with the clipboard
Browse files Browse the repository at this point in the history
  • Loading branch information
mkartashev committed Oct 4, 2024
1 parent 231126c commit 3ede03b
Show file tree
Hide file tree
Showing 15 changed files with 202 additions and 144 deletions.
15 changes: 13 additions & 2 deletions src/java.desktop/unix/classes/sun/awt/wl/WLClipboard.java
Original file line number Diff line number Diff line change
Expand Up @@ -135,8 +135,19 @@ protected void clearNativeContext() {
protected void setContentsNative(Transferable contents) {
// The server requires "serial number of the event that triggered this request"
// as a proof of the right to copy data.
WLPointerEvent wlPointerEvent = WLToolkit.getInputState().eventWithSerial();
long eventSerial = wlPointerEvent == null ? 0 : wlPointerEvent.getSerial();

// It is not specified which event's serial number the Wayland server expects here,
// so the following is a speculation based on experiments.
// The worst case is that a "wrong" serial will be silently ignored, and our clipboard
// will be out of sync with the real one that Wayland maintains.
long eventSerial = isPrimary
? WLToolkit.getInputState().pointerButtonSerial()
: WLToolkit.getInputState().keySerial();
if (!isPrimary && eventSerial == 0) {
// The "regular" clipboard's content can be changed with either a mouse click
// (like on a menu item) or with the keyboard (Ctrl-C).
eventSerial = WLToolkit.getInputState().pointerButtonSerial();
}
if (log.isLoggable(PlatformLogger.Level.FINE)) {
log.fine("Clipboard: About to offer new contents using Wayland event serial " + eventSerial);
}
Expand Down
61 changes: 47 additions & 14 deletions src/java.desktop/unix/classes/sun/awt/wl/WLComponentPeer.java
Original file line number Diff line number Diff line change
Expand Up @@ -771,10 +771,16 @@ public Dimension getMinimumSize() {
return target.getSize();
}

void showWindowMenu(int x, int y) {
void showWindowMenu(long serial, int x, int y) {
// "This request must be used in response to some sort of user action like
// a button press, key press, or touch down event."
// So 'serial' must appertain to such an event.

assert serial != 0;

int xNative = javaUnitsToSurfaceUnits(x);
int yNative = javaUnitsToSurfaceUnits(y);
performLocked(() -> nativeShowWindowMenu(nativePtr, xNative, yNative));
performLocked(() -> nativeShowWindowMenu(serial, nativePtr, xNative, yNative));
}

@Override
Expand Down Expand Up @@ -852,7 +858,7 @@ public void updateCursorImmediately() {
}

private void updateCursorImmediately(WLInputState inputState) {
WLComponentPeer peer = inputState.getPeer();
WLComponentPeer peer = inputState.peerForPointerEvents();
if (peer == null) return;
Cursor cursor = peer.getCursor(inputState.getPointerX(), inputState.getPointerY());
setCursor(cursor, getGraphicsDevice() != null ? getGraphicsDevice().getDisplayScale() : 1);
Expand All @@ -870,6 +876,14 @@ Cursor getCursor(int x, int y) {
}

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();
Expand All @@ -894,7 +908,7 @@ private static void setCursor(Cursor c, int scale) {
}
AWTAccessor.getCursorAccessor().setPData(cursor, scale, pData);
}
nativeSetCursor(pData, scale);
nativeSetCursor(pData, scale, serial);
});
}

Expand Down Expand Up @@ -1019,7 +1033,16 @@ final void requestUnsetFullScreen() {
}

final void activate() {
performLocked(() -> nativeActivate(nativePtr));
// "The serial can come from an input or focus event."
long serial = WLToolkit.getInputState().keyboardEnterSerial();
long surface = WLToolkit.getInputState().surfaceForKeyboardInput();
if (serial != 0) {
performLocked(() -> nativeActivate(serial, nativePtr, surface));
} else {
if (log.isLoggable(Level.WARNING)) {
log.warning("activate() aborted due to missing keyboard enter event serial");
}
}
}

private static native void initIDs();
Expand All @@ -1042,8 +1065,8 @@ protected native void nativeRepositionWLPopup(long ptr,
protected native void nativeDisposeFrame(long ptr);

private native long getWLSurface(long ptr);
private native void nativeStartDrag(long ptr);
private native void nativeStartResize(long ptr, int edges);
private native void nativeStartDrag(long serial, long ptr);
private native void nativeStartResize(long serial, long ptr, int edges);

private native void nativeSetTitle(long ptr, String title);
private native void nativeRequestMinimized(long ptr);
Expand All @@ -1057,11 +1080,11 @@ 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);
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 ptr, int x, int y);
private native void nativeActivate(long ptr);
private native void nativeShowWindowMenu(long serial, long ptr, int x, int y);
private native void nativeActivate(long serial, long ptr, long activatingSurfacePtr);

static long getNativePtrFor(Component component) {
final ComponentAccessor acc = AWTAccessor.getComponentAccessor();
Expand Down Expand Up @@ -1465,12 +1488,22 @@ private static void convertPointerEventToMWEParameters(
}


void startDrag() {
performLocked(() -> nativeStartDrag(nativePtr));
void startDrag(long serial) {
// "This request must be used in response to some sort of user action like a button press,
// key press, or touch down event. The passed serial is used to determine the type
// of interactive move (touch, pointer, etc)."
assert serial != 0;

performLocked(() -> nativeStartDrag(serial, nativePtr));
}

void startResize(int edges) {
performLocked(() -> nativeStartResize(nativePtr, edges));
void startResize(long serial, int edges) {
// "This request must be used in response to some sort of user action like a button press,
// key press, or touch down event. The passed serial is used to determine the type
// of interactive resize (touch, pointer, etc)."
assert serial != 0;

performLocked(() -> nativeStartResize(serial, nativePtr, edges));
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -334,7 +334,7 @@ boolean processMouseEvent(MouseEvent e) {
if (isLMBPressed && peer.isInteractivelyResizable()) {
int resizeSide = getResizeEdges(point.x, point.y);
if (resizeSide != 0) {
peer.startResize(resizeSide);
peer.startResize(WLToolkit.getInputState().pointerButtonSerial(), resizeSide);
// workaround for https://gitlab.gnome.org/GNOME/mutter/-/issues/2523
WLToolkit.resetPointerInputState();
return true;
Expand All @@ -344,7 +344,7 @@ boolean processMouseEvent(MouseEvent e) {
if (isUndecorated) return false;

if (isRMBPressed && getBounds().contains(e.getX(), e.getY())) {
peer.showWindowMenu(e.getX(), e.getY());
peer.showWindowMenu(WLToolkit.getInputState().pointerButtonSerial(), e.getX(), e.getY());
return true;
}

Expand All @@ -371,7 +371,8 @@ boolean processMouseEvent(MouseEvent e) {
if (e.getID() == MouseEvent.MOUSE_PRESSED) {
pressedLocation = point;
} else if (e.getID() == MouseEvent.MOUSE_DRAGGED && pressedInDragStartArea() && isSignificantDrag(point)) {
peer.startDrag();
peer.startDrag(WLToolkit.getInputState().pointerButtonSerial());

} else if (e.getID() == MouseEvent.MOUSE_CLICKED && e.getClickCount() == 2 && pressedInDragStartArea()
&& peer.isFrameStateSupported(Frame.MAXIMIZED_BOTH)) {
toggleMaximizedState();
Expand Down
Loading

0 comments on commit 3ede03b

Please sign in to comment.