Skip to content

Commit

Permalink
JBR-5977 Wayland: make undecorated windows natively resizeable
Browse files Browse the repository at this point in the history
  • Loading branch information
mkartashev authored and jbrbot committed Nov 8, 2024
1 parent 47d484b commit fc735db
Show file tree
Hide file tree
Showing 2 changed files with 60 additions and 35 deletions.
36 changes: 18 additions & 18 deletions src/java.desktop/unix/classes/sun/awt/wl/WLDecoratedPeer.java
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ public abstract class WLDecoratedPeer extends WLWindowPeer {

public WLDecoratedPeer(Window target, boolean isUndecorated, boolean showMinimize, boolean showMaximize) {
super(target);
decoration = isUndecorated ? null : new WLFrameDecoration(this, showMinimize, showMaximize);
decoration = new WLFrameDecoration(this, isUndecorated, showMinimize, showMaximize);
}

private static native void initIDs();
Expand All @@ -52,7 +52,7 @@ public WLDecoratedPeer(Window target, boolean isUndecorated, boolean showMinimiz

@Override
public Insets getInsets() {
return decoration == null ? new Insets(0, 0, 0, 0) : decoration.getInsets();
return decoration.getInsets();
}

@Override
Expand All @@ -77,9 +77,11 @@ public Dimension getMinimumSize() {
final Dimension targetMinimumSize = target.isMinimumSizeSet()
? target.getMinimumSize()
: new Dimension(1, 1);
final Dimension frameMinimumSize = decoration != null
? decoration.getMinimumSize()
: new Dimension(1, 1);
final Dimension decorMinimumSize = decoration.getMinimumSize();
final Dimension frameMinimumSize
= (decorMinimumSize.getWidth() == 0 && decorMinimumSize.getHeight() == 0)
? new Dimension(1, 1)
: decorMinimumSize;
return new Rectangle(targetMinimumSize)
.union(new Rectangle(frameMinimumSize))
.getSize();
Expand All @@ -99,17 +101,16 @@ void postWindowClosing() {

@Override
void postMouseEvent(MouseEvent e) {
if (decoration == null) {
boolean processed = decoration.processMouseEvent(e);
if (!processed) {
super.postMouseEvent(e);
} else {
decoration.processMouseEvent(e);
}
}

@Override
void notifyConfigured(int newWidth, int newHeight, boolean active, boolean maximized) {
super.notifyConfigured(newWidth, newHeight, active, maximized);
if (decoration != null) decoration.setActive(active);
decoration.setActive(active);
}

@Override
Expand All @@ -126,8 +127,8 @@ public void setBounds(int x, int y, int width, int height, int op) {
}

final void notifyClientDecorationsChanged() {
if (decoration != null) {
final Rectangle bounds = decoration.getBounds();
final Rectangle bounds = decoration.getBounds();
if (!bounds.isEmpty()) {
decoration.markRepaintNeeded();
postPaintEvent(bounds.x, bounds.y, bounds.width, bounds.height);
}
Expand All @@ -142,19 +143,18 @@ void postPaintEvent() {
}

final void paintClientDecorations(final Graphics g) {
if (decoration != null && decoration.isRepaintNeeded()) {
if (decoration.isRepaintNeeded()) {
decoration.paint(g);
}
}

@Override
Cursor getCursor(int x, int y) {
if (decoration != null) {
Cursor cursor = decoration.getCursor(x, y);
if (cursor != null) {
return cursor;
}
Cursor cursor = decoration.getCursor(x, y);
if (cursor != null) {
return cursor;
} else {
return super.getCursor(x, y);
}
return super.getCursor(x, y);
}
}
59 changes: 42 additions & 17 deletions src/java.desktop/unix/classes/sun/awt/wl/WLFrameDecoration.java
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,8 @@ public class WLFrameDecoration {
};

private final WLDecoratedPeer peer;
private final boolean isUndecorated;


private final ButtonState closeButton;
private final ButtonState maximizeButton;
Expand All @@ -76,23 +78,37 @@ public class WLFrameDecoration {
private boolean pressedInside;
private Point pressedLocation;

public WLFrameDecoration(WLDecoratedPeer peer, boolean showMinimize, boolean showMaximize) {
public WLFrameDecoration(WLDecoratedPeer peer, boolean isUndecorated, boolean showMinimize, boolean showMaximize) {
this.peer = peer;
closeButton = new ButtonState(this::getCloseButtonCenter, peer::postWindowClosing);
maximizeButton = showMaximize ? new ButtonState(this::getMaximizeButtonCenter, this::toggleMaximizedState) : null;
minimizeButton = showMinimize ? new ButtonState(this::getMinimizeButtonCenter, this::minimizeWindow) : null;
this.isUndecorated = isUndecorated;

if (isUndecorated) {
closeButton = null;
maximizeButton = null;
minimizeButton = null;
} else {
closeButton = new ButtonState(this::getCloseButtonCenter, peer::postWindowClosing);
maximizeButton = showMaximize ? new ButtonState(this::getMaximizeButtonCenter, this::toggleMaximizedState) : null;
minimizeButton = showMinimize ? new ButtonState(this::getMinimizeButtonCenter, this::minimizeWindow) : null;
}
}

public Insets getInsets() {
return new Insets(HEIGHT, 0, 0, 0);
return isUndecorated
? new Insets(0, 0, 0, 0)
: new Insets(HEIGHT, 0, 0, 0);
}

public Rectangle getBounds() {
return new Rectangle(0, 0, peer.getWidth(), HEIGHT);
return isUndecorated
? new Rectangle(0, 0, 0, 0)
: new Rectangle(0, 0, peer.getWidth(), HEIGHT);
}

public Dimension getMinimumSize() {
return new Dimension(getButtonSpaceWidth(), HEIGHT);
return isUndecorated
? new Dimension(0, 0)
: new Dimension(getButtonSpaceWidth(), HEIGHT);
}

private boolean hasMinimizeButton() {
Expand Down Expand Up @@ -129,6 +145,8 @@ private int getButtonSpaceWidth() {
}

public void paint(final Graphics g) {
if (isUndecorated) return;

int width = peer.getWidth();
int height = peer.getHeight();
if (width <= 0 || height <= 0) return;
Expand Down Expand Up @@ -250,28 +268,33 @@ private boolean pressedInDragStartArea() {
pressedLocation.x < peer.getWidth() - getButtonSpaceWidth();
}

void processMouseEvent(MouseEvent e) {
boolean processMouseEvent(MouseEvent e) {
if (isUndecorated && !peer.isResizable()) return false;

final boolean isLMB = e.getButton() == MouseEvent.BUTTON1;
final boolean isRMB = e.getButton() == MouseEvent.BUTTON3;
final boolean isPressed = e.getID() == MouseEvent.MOUSE_PRESSED;
final boolean isLMBPressed = isLMB && isPressed;
final boolean isRMBPressed = isRMB && isPressed;

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

Point point = e.getPoint();
if (isLMBPressed && peer.isResizable()) {
int resizeSide = getResizeEdges(point.x, point.y);
if (resizeSide != 0) {
peer.startResize(resizeSide);
// workaround for https://gitlab.gnome.org/GNOME/mutter/-/issues/2523
WLToolkit.resetPointerInputState();
return;
return true;
}
}

if (isUndecorated) return false;

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

boolean pointerInside = e.getY() >= HEIGHT && e.getID() != MouseEvent.MOUSE_EXITED ||
pressedInside && e.getID() == MouseEvent.MOUSE_DRAGGED;
if (pointerInside && !this.pointerInside && e.getID() != MouseEvent.MOUSE_ENTERED) {
Expand All @@ -287,7 +310,7 @@ void processMouseEvent(MouseEvent e) {
if (e.getID() == MouseEvent.MOUSE_DRAGGED) {
pressedInside = pointerInside;
}
if (closeButton.processMouseEvent(e) |
if ((closeButton != null && closeButton.processMouseEvent(e)) |
(maximizeButton != null && maximizeButton.processMouseEvent(e)) |
(minimizeButton != null && minimizeButton.processMouseEvent(e))) {
peer.notifyClientDecorationsChanged();
Expand All @@ -302,6 +325,8 @@ void processMouseEvent(MouseEvent e) {
} else if (e.getID() == MouseEvent.MOUSE_MOVED && !pointerInside) {
peer.updateCursorImmediately();
}

return true;
}

private int getResizeEdges(int x, int y) {
Expand Down Expand Up @@ -338,7 +363,7 @@ private void minimizeWindow() {
private volatile boolean needRepaint = true;

boolean isRepaintNeeded() {
return needRepaint;
return !isUndecorated && needRepaint;
}

void markRepaintNeeded() {
Expand All @@ -350,7 +375,7 @@ Cursor getCursor(int x, int y) {
if (edges != 0) {
return Cursor.getPredefinedCursor(RESIZE_CURSOR_TYPES[edges]);
}
if (y < HEIGHT) {
if (!isUndecorated && y < HEIGHT) {
return Cursor.getDefaultCursor();
}
return null;
Expand Down

0 comments on commit fc735db

Please sign in to comment.