mirror of
https://github.com/JetBrains/JetBrainsRuntime.git
synced 2026-01-29 20:00:53 +01:00
Compare commits
62 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
fe178bde3e | ||
|
|
d00de81ada | ||
|
|
8435a559d8 | ||
|
|
8d2d65e21b | ||
|
|
2d553ab929 | ||
|
|
e131c41a9e | ||
|
|
786a51a73c | ||
|
|
c4134682d7 | ||
|
|
56414a4069 | ||
|
|
972a528cee | ||
|
|
97c0b33628 | ||
|
|
6f63a27fd9 | ||
|
|
936d2c86fb | ||
|
|
d4de7e69b0 | ||
|
|
c2a949b103 | ||
|
|
73619cd94d | ||
|
|
e0995bbf5f | ||
|
|
33d5d9771d | ||
|
|
0932c4e713 | ||
|
|
252156e3d7 | ||
|
|
b821ee8754 | ||
|
|
b2ef7e44f9 | ||
|
|
6a6aa5c3a4 | ||
|
|
e855cb936a | ||
|
|
1dab222bf6 | ||
|
|
52addb4101 | ||
|
|
b5a90dd0f6 | ||
|
|
4fa488c605 | ||
|
|
4974b5d5d7 | ||
|
|
8be7a5f8a7 | ||
|
|
92545f5124 | ||
|
|
7b136d77f8 | ||
|
|
b5755c715f | ||
|
|
bbdb27744a | ||
|
|
c04f7c417c | ||
|
|
1fc51ef7e8 | ||
|
|
929d8ac20a | ||
|
|
632dd39f95 | ||
|
|
9e2298e1e3 | ||
|
|
d08d3bde3c | ||
|
|
d9d7056643 | ||
|
|
48901dbed3 | ||
|
|
ced472737a | ||
|
|
6ba6f556d7 | ||
|
|
9246fbc244 | ||
|
|
290315a5ce | ||
|
|
035cf124ab | ||
|
|
f609c0bc36 | ||
|
|
decda7a749 | ||
|
|
8d2009cb50 | ||
|
|
86e36ea6fb | ||
|
|
5bfcd8ad47 | ||
|
|
bfae68d91a | ||
|
|
4c551a4146 | ||
|
|
bd026e77a8 | ||
|
|
a2979fb92c | ||
|
|
7ac6509b56 | ||
|
|
52ade26984 | ||
|
|
1d3489ff05 | ||
|
|
7875eb3b33 | ||
|
|
6eb17d80c1 | ||
|
|
d895107698 |
58
.github/workflows/main.yml
vendored
58
.github/workflows/main.yml
vendored
@@ -28,9 +28,7 @@ name: 'OpenJDK GHA Sanity Checks'
|
||||
on:
|
||||
push:
|
||||
branches-ignore:
|
||||
- master
|
||||
- pr/*
|
||||
- jdk*
|
||||
- main
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
@@ -44,6 +42,9 @@ on:
|
||||
make-arguments:
|
||||
description: 'Additional make arguments'
|
||||
required: false
|
||||
dry-run:
|
||||
description: 'Dry run: skip actual builds and tests'
|
||||
required: false
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.ref }}
|
||||
@@ -71,6 +72,7 @@ jobs:
|
||||
windows-x64: ${{ steps.include.outputs.windows-x64 }}
|
||||
windows-aarch64: ${{ steps.include.outputs.windows-aarch64 }}
|
||||
docs: ${{ steps.include.outputs.docs }}
|
||||
dry-run: ${{ steps.include.outputs.dry-run }}
|
||||
|
||||
steps:
|
||||
- name: 'Checkout the scripts'
|
||||
@@ -144,6 +146,35 @@ jobs:
|
||||
echo 'false'
|
||||
}
|
||||
|
||||
function check_dry_run() {
|
||||
if [[ $GITHUB_EVENT_NAME == workflow_dispatch ]]; then
|
||||
# Take the user-specified one.
|
||||
echo '${{ github.event.inputs.dry-run }}'
|
||||
return
|
||||
elif [[ $GITHUB_EVENT_NAME == push ]]; then
|
||||
# Cut out the real branch name
|
||||
BRANCH=${GITHUB_REF##*/}
|
||||
|
||||
# Dry run rebuilds the caches in current branch, so they can be reused
|
||||
# for any child PR branches. Because of this, we want to trigger this
|
||||
# workflow in master branch, so that actual PR branches can use the cache.
|
||||
# This workflow would trigger every time contributors sync their master
|
||||
# branches in their personal forks.
|
||||
if [[ $BRANCH == "master" ]]; then
|
||||
echo 'true'
|
||||
return
|
||||
fi
|
||||
|
||||
# ...same for stabilization branches
|
||||
if [[ $BRANCH =~ "jdk(.*)" ]]; then
|
||||
echo 'true'
|
||||
return
|
||||
fi
|
||||
fi
|
||||
|
||||
echo 'false'
|
||||
}
|
||||
|
||||
echo "linux-x64=$(check_platform linux-x64 linux x64)" >> $GITHUB_OUTPUT
|
||||
echo "linux-x64-variants=$(check_platform linux-x64-variants variants)" >> $GITHUB_OUTPUT
|
||||
echo "linux-cross-compile=$(check_platform linux-cross-compile cross-compile)" >> $GITHUB_OUTPUT
|
||||
@@ -153,6 +184,7 @@ jobs:
|
||||
echo "windows-x64=$(check_platform windows-x64 windows x64)" >> $GITHUB_OUTPUT
|
||||
echo "windows-aarch64=$(check_platform windows-aarch64 windows aarch64)" >> $GITHUB_OUTPUT
|
||||
echo "docs=$(check_platform docs)" >> $GITHUB_OUTPUT
|
||||
echo "dry-run=$(check_dry_run)" >> $GITHUB_OUTPUT
|
||||
|
||||
###
|
||||
### Build jobs
|
||||
@@ -167,6 +199,7 @@ jobs:
|
||||
gcc-major-version: '10'
|
||||
configure-arguments: ${{ github.event.inputs.configure-arguments }}
|
||||
make-arguments: ${{ github.event.inputs.make-arguments }}
|
||||
dry-run: ${{ needs.prepare.outputs.dry-run == 'true' }}
|
||||
if: needs.prepare.outputs.linux-x64 == 'true'
|
||||
|
||||
build-linux-x64-hs-nopch:
|
||||
@@ -181,6 +214,7 @@ jobs:
|
||||
extra-conf-options: '--disable-precompiled-headers'
|
||||
configure-arguments: ${{ github.event.inputs.configure-arguments }}
|
||||
make-arguments: ${{ github.event.inputs.make-arguments }}
|
||||
dry-run: ${{ needs.prepare.outputs.dry-run == 'true' }}
|
||||
if: needs.prepare.outputs.linux-x64-variants == 'true'
|
||||
|
||||
build-linux-x64-hs-zero:
|
||||
@@ -195,6 +229,7 @@ jobs:
|
||||
extra-conf-options: '--with-jvm-variants=zero --disable-precompiled-headers'
|
||||
configure-arguments: ${{ github.event.inputs.configure-arguments }}
|
||||
make-arguments: ${{ github.event.inputs.make-arguments }}
|
||||
dry-run: ${{ needs.prepare.outputs.dry-run == 'true' }}
|
||||
if: needs.prepare.outputs.linux-x64-variants == 'true'
|
||||
|
||||
build-linux-x64-hs-minimal:
|
||||
@@ -209,6 +244,7 @@ jobs:
|
||||
extra-conf-options: '--with-jvm-variants=minimal --disable-precompiled-headers'
|
||||
configure-arguments: ${{ github.event.inputs.configure-arguments }}
|
||||
make-arguments: ${{ github.event.inputs.make-arguments }}
|
||||
dry-run: ${{ needs.prepare.outputs.dry-run == 'true' }}
|
||||
if: needs.prepare.outputs.linux-x64-variants == 'true'
|
||||
|
||||
build-linux-x64-hs-optimized:
|
||||
@@ -224,6 +260,7 @@ jobs:
|
||||
extra-conf-options: '--with-debug-level=optimized --disable-precompiled-headers'
|
||||
configure-arguments: ${{ github.event.inputs.configure-arguments }}
|
||||
make-arguments: ${{ github.event.inputs.make-arguments }}
|
||||
dry-run: ${{ needs.prepare.outputs.dry-run == 'true' }}
|
||||
if: needs.prepare.outputs.linux-x64-variants == 'true'
|
||||
|
||||
build-linux-x64-static:
|
||||
@@ -239,6 +276,7 @@ jobs:
|
||||
gcc-major-version: '10'
|
||||
configure-arguments: ${{ github.event.inputs.configure-arguments }}
|
||||
make-arguments: ${{ github.event.inputs.make-arguments }}
|
||||
dry-run: ${{ needs.prepare.outputs.dry-run == 'true' }}
|
||||
static-suffix: "-static"
|
||||
if: needs.prepare.outputs.linux-x64 == 'true'
|
||||
|
||||
@@ -255,6 +293,7 @@ jobs:
|
||||
gcc-major-version: '10'
|
||||
configure-arguments: ${{ github.event.inputs.configure-arguments }}
|
||||
make-arguments: ${{ github.event.inputs.make-arguments }}
|
||||
dry-run: ${{ needs.prepare.outputs.dry-run == 'true' }}
|
||||
# Upload static libs bundles separately to avoid interference with normal linux-x64 bundle.
|
||||
# This bundle is not used by testing jobs, but downstreams use it to check that
|
||||
# dependent projects, e.g. libgraal, builds fine.
|
||||
@@ -269,6 +308,7 @@ jobs:
|
||||
gcc-major-version: '10'
|
||||
configure-arguments: ${{ github.event.inputs.configure-arguments }}
|
||||
make-arguments: ${{ github.event.inputs.make-arguments }}
|
||||
dry-run: ${{ needs.prepare.outputs.dry-run == 'true' }}
|
||||
if: needs.prepare.outputs.linux-cross-compile == 'true'
|
||||
|
||||
build-alpine-linux-x64:
|
||||
@@ -279,6 +319,7 @@ jobs:
|
||||
platform: alpine-linux-x64
|
||||
configure-arguments: ${{ github.event.inputs.configure-arguments }}
|
||||
make-arguments: ${{ github.event.inputs.make-arguments }}
|
||||
dry-run: ${{ needs.prepare.outputs.dry-run == 'true' }}
|
||||
if: needs.prepare.outputs.alpine-linux-x64 == 'true'
|
||||
|
||||
build-macos-x64:
|
||||
@@ -291,6 +332,7 @@ jobs:
|
||||
xcode-toolset-version: '14.3.1'
|
||||
configure-arguments: ${{ github.event.inputs.configure-arguments }}
|
||||
make-arguments: ${{ github.event.inputs.make-arguments }}
|
||||
dry-run: ${{ needs.prepare.outputs.dry-run == 'true' }}
|
||||
if: needs.prepare.outputs.macos-x64 == 'true'
|
||||
|
||||
build-macos-aarch64:
|
||||
@@ -303,6 +345,7 @@ jobs:
|
||||
xcode-toolset-version: '15.4'
|
||||
configure-arguments: ${{ github.event.inputs.configure-arguments }}
|
||||
make-arguments: ${{ github.event.inputs.make-arguments }}
|
||||
dry-run: ${{ needs.prepare.outputs.dry-run == 'true' }}
|
||||
if: needs.prepare.outputs.macos-aarch64 == 'true'
|
||||
|
||||
build-windows-x64:
|
||||
@@ -315,6 +358,7 @@ jobs:
|
||||
msvc-toolset-architecture: 'x86.x64'
|
||||
configure-arguments: ${{ github.event.inputs.configure-arguments }}
|
||||
make-arguments: ${{ github.event.inputs.make-arguments }}
|
||||
dry-run: ${{ needs.prepare.outputs.dry-run == 'true' }}
|
||||
if: needs.prepare.outputs.windows-x64 == 'true'
|
||||
|
||||
build-windows-aarch64:
|
||||
@@ -329,6 +373,7 @@ jobs:
|
||||
extra-conf-options: '--openjdk-target=aarch64-unknown-cygwin'
|
||||
configure-arguments: ${{ github.event.inputs.configure-arguments }}
|
||||
make-arguments: ${{ github.event.inputs.make-arguments }}
|
||||
dry-run: ${{ needs.prepare.outputs.dry-run == 'true' }}
|
||||
if: needs.prepare.outputs.windows-aarch64 == 'true'
|
||||
|
||||
build-docs:
|
||||
@@ -345,6 +390,7 @@ jobs:
|
||||
gcc-major-version: '10'
|
||||
configure-arguments: ${{ github.event.inputs.configure-arguments }}
|
||||
make-arguments: ${{ github.event.inputs.make-arguments }}
|
||||
dry-run: ${{ needs.prepare.outputs.dry-run == 'true' }}
|
||||
if: needs.prepare.outputs.docs == 'true'
|
||||
|
||||
###
|
||||
@@ -354,17 +400,20 @@ jobs:
|
||||
test-linux-x64:
|
||||
name: linux-x64
|
||||
needs:
|
||||
- prepare
|
||||
- build-linux-x64
|
||||
uses: ./.github/workflows/test.yml
|
||||
with:
|
||||
platform: linux-x64
|
||||
bootjdk-platform: linux-x64
|
||||
runs-on: ubuntu-22.04
|
||||
dry-run: ${{ needs.prepare.outputs.dry-run == 'true' }}
|
||||
debug-suffix: -debug
|
||||
|
||||
test-linux-x64-static:
|
||||
name: linux-x64-static
|
||||
needs:
|
||||
- prepare
|
||||
- build-linux-x64
|
||||
- build-linux-x64-static
|
||||
uses: ./.github/workflows/test.yml
|
||||
@@ -372,27 +421,32 @@ jobs:
|
||||
platform: linux-x64
|
||||
bootjdk-platform: linux-x64
|
||||
runs-on: ubuntu-22.04
|
||||
dry-run: ${{ needs.prepare.outputs.dry-run == 'true' }}
|
||||
static-suffix: "-static"
|
||||
|
||||
test-macos-aarch64:
|
||||
name: macos-aarch64
|
||||
needs:
|
||||
- prepare
|
||||
- build-macos-aarch64
|
||||
uses: ./.github/workflows/test.yml
|
||||
with:
|
||||
platform: macos-aarch64
|
||||
bootjdk-platform: macos-aarch64
|
||||
runs-on: macos-14
|
||||
dry-run: ${{ needs.prepare.outputs.dry-run == 'true' }}
|
||||
xcode-toolset-version: '15.4'
|
||||
debug-suffix: -debug
|
||||
|
||||
test-windows-x64:
|
||||
name: windows-x64
|
||||
needs:
|
||||
- prepare
|
||||
- build-windows-x64
|
||||
uses: ./.github/workflows/test.yml
|
||||
with:
|
||||
platform: windows-x64
|
||||
bootjdk-platform: windows-x64
|
||||
runs-on: windows-2025
|
||||
dry-run: ${{ needs.prepare.outputs.dry-run == 'true' }}
|
||||
debug-suffix: -debug
|
||||
|
||||
@@ -40,7 +40,7 @@ public class IoOverNio {
|
||||
*/
|
||||
public static final Debug DEBUG;
|
||||
public static final boolean IS_ENABLED_IN_GENERAL =
|
||||
System.getProperty("jbr.java.io.use.nio", "true").equalsIgnoreCase("true");
|
||||
System.getProperty("jbr.java.io.use.nio", "false").equalsIgnoreCase("true");
|
||||
private static final ThreadLocal<Integer> ALLOW_IN_THIS_THREAD = new ThreadLocal<>();
|
||||
|
||||
static {
|
||||
|
||||
@@ -41,8 +41,11 @@ public final class VKEnv {
|
||||
private static final class Options {
|
||||
|
||||
@SuppressWarnings("removal")
|
||||
private static final boolean vulkan = "true".equalsIgnoreCase(AccessController.doPrivileged(
|
||||
(PrivilegedAction<String>) () -> System.getProperty("sun.java2d.vulkan", "")));
|
||||
private static final String vulkanProperty = AccessController.doPrivileged(
|
||||
(PrivilegedAction<String>) () -> System.getProperty("sun.java2d.vulkan", ""));
|
||||
|
||||
private static final boolean vulkan = "true".equalsIgnoreCase(vulkanProperty);
|
||||
private static final boolean verbose = "True".equals(vulkanProperty);
|
||||
|
||||
@SuppressWarnings("removal")
|
||||
private static final boolean accelsd = vulkan && "true".equalsIgnoreCase(AccessController.doPrivileged(
|
||||
@@ -94,14 +97,23 @@ public final class VKEnv {
|
||||
}
|
||||
state = newState;
|
||||
|
||||
if (log.isLoggable(PlatformLogger.Level.FINE)) {
|
||||
if (Options.verbose || log.isLoggable(PlatformLogger.Level.FINE)) {
|
||||
String message;
|
||||
if (isVulkanEnabled()) {
|
||||
log.fine("Vulkan rendering enabled: YES" +
|
||||
"\n presentation enabled: " + (isPresentationEnabled() ? "YES" : "NO") +
|
||||
"\n accelerated surface data enabled: " + (isSurfaceDataAccelerated() ? "YES" : "NO") +
|
||||
"\n devices:" + Stream.of(devices).map(d -> (d == defaultDevice ?
|
||||
"\n *" : "\n ") + d.getName()).collect(Collectors.joining()));
|
||||
} else log.fine("Vulkan rendering enabled: NO");
|
||||
message = "Vulkan rendering enabled: YES" +
|
||||
"\n presentation enabled: " + (isPresentationEnabled() ? "YES" : "NO") +
|
||||
"\n accelerated surface data enabled: " + (isSurfaceDataAccelerated() ? "YES" : "NO") +
|
||||
"\n devices:" + Stream.of(devices).map(d -> (d == defaultDevice ?
|
||||
"\n *" : "\n ") + d.getName()).collect(Collectors.joining());
|
||||
} else {
|
||||
message = "Vulkan rendering enabled: NO";
|
||||
}
|
||||
if (Options.verbose) {
|
||||
System.err.println(message);
|
||||
}
|
||||
if (log.isLoggable(PlatformLogger.Level.FINE)) {
|
||||
log.fine(message);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -246,8 +246,7 @@ public abstract class FullFrameDecorationHelper extends FrameDecoration {
|
||||
if (e.getID() == MouseEvent.MOUSE_PRESSED) {
|
||||
pressedLocation = point;
|
||||
} else if (e.getID() == MouseEvent.MOUSE_DRAGGED && pressedInDragStartArea(point) && isSignificantDrag(point)) {
|
||||
peer.startDrag(WLToolkit.getInputState().pointerButtonSerial());
|
||||
|
||||
startDrag();
|
||||
} else if (e.getID() == MouseEvent.MOUSE_CLICKED && e.getClickCount() == 2 && pressedInDragStartArea(point)
|
||||
&& peer.isFrameStateSupported(Frame.MAXIMIZED_BOTH)) {
|
||||
toggleMaximizedState();
|
||||
@@ -258,6 +257,23 @@ public abstract class FullFrameDecorationHelper extends FrameDecoration {
|
||||
return true;
|
||||
}
|
||||
|
||||
private void startDrag() {
|
||||
pressedLocation = null;
|
||||
boolean changed = false;
|
||||
if (closeButton != null) {
|
||||
changed |= closeButton.reset();
|
||||
}
|
||||
if (maximizeButton != null) {
|
||||
changed |= maximizeButton.reset();
|
||||
}
|
||||
if (minimizeButton != null) {
|
||||
changed |= minimizeButton.reset();
|
||||
}
|
||||
if (changed) peer.notifyClientDecorationsChanged();
|
||||
|
||||
peer.startDrag(WLToolkit.getInputState().pointerButtonSerial());
|
||||
}
|
||||
|
||||
private void toggleMaximizedState() {
|
||||
peer.setExtendedState(peer.getState() == Frame.NORMAL ? Frame.MAXIMIZED_BOTH : Frame.NORMAL);
|
||||
}
|
||||
@@ -294,6 +310,13 @@ public abstract class FullFrameDecorationHelper extends FrameDecoration {
|
||||
this.action = action;
|
||||
}
|
||||
|
||||
private boolean reset() {
|
||||
boolean changed = hovered | pressed;
|
||||
hovered = false;
|
||||
pressed = false;
|
||||
return changed;
|
||||
}
|
||||
|
||||
private boolean processMouseEvent(MouseEvent e) {
|
||||
assert EventQueue.isDispatchThread();
|
||||
|
||||
|
||||
221
src/java.desktop/unix/classes/sun/awt/wl/GtkFrameDecoration.java
Normal file
221
src/java.desktop/unix/classes/sun/awt/wl/GtkFrameDecoration.java
Normal file
@@ -0,0 +1,221 @@
|
||||
/*
|
||||
* Copyright 2025 JetBrains s.r.o.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package sun.awt.wl;
|
||||
|
||||
import sun.awt.image.SunWritableRaster;
|
||||
import sun.java2d.SunGraphics2D;
|
||||
|
||||
import java.awt.Color;
|
||||
import java.awt.Dimension;
|
||||
import java.awt.Graphics;
|
||||
import java.awt.Graphics2D;
|
||||
import java.awt.Insets;
|
||||
import java.awt.Point;
|
||||
import java.awt.Rectangle;
|
||||
import java.awt.RenderingHints;
|
||||
import java.awt.Transparency;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.awt.image.ColorModel;
|
||||
import java.awt.image.DataBufferInt;
|
||||
import java.awt.image.Raster;
|
||||
import java.awt.image.WritableRaster;
|
||||
|
||||
public class GtkFrameDecoration extends FullFrameDecorationHelper {
|
||||
private static final int MIN_BUTTON_STATE_HOVERED = 1;
|
||||
private static final int MIN_BUTTON_STATE_PRESSED = 1 << 1;
|
||||
private static final int MAX_BUTTON_STATE_HOVERED = 1 << 2;
|
||||
private static final int MAX_BUTTON_STATE_PRESSED = 1 << 3;
|
||||
private static final int CLOSE_BUTTON_STATE_HOVERED = 1 << 4;
|
||||
private static final int CLOSE_BUTTON_STATE_PRESSED = 1 << 5;
|
||||
|
||||
private long nativePtr;
|
||||
private Rectangle minimizeButtonBounds; // set by the native code
|
||||
private Rectangle maximizeButtonBounds; // set by the native code
|
||||
private Rectangle closeButtonBounds; // set by the native code
|
||||
private int titleBarHeight = 37; // set by the native code
|
||||
private int titleBarMinWidth = 180; // set by the native code
|
||||
|
||||
private final int dndThreshold;
|
||||
|
||||
static {
|
||||
initIDs();
|
||||
nativeLoadGTK();
|
||||
}
|
||||
|
||||
public GtkFrameDecoration(WLDecoratedPeer peer, boolean showMinimize, boolean showMaximize) {
|
||||
super(peer, showMinimize, showMaximize);
|
||||
nativePtr = nativeCreateDecoration(showMinimize, showMaximize);
|
||||
assert nativePtr != 0;
|
||||
int t = nativeGetIntProperty(nativePtr, "gtk-dnd-drag-threshold");
|
||||
dndThreshold = t > 0 ? t : 4;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void paint(Graphics g) {
|
||||
// Determine buttons' bounds, etc.
|
||||
nativePrePaint(nativePtr, peer.getWidth());
|
||||
super.paint(g);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void paintTitleBar(Graphics2D g2d) {
|
||||
int width = peer.getWidth();
|
||||
int height = titleBarHeight;
|
||||
|
||||
double scale = ((WLGraphicsConfig) peer.getGraphicsConfiguration()).getEffectiveScale();
|
||||
g2d.setBackground(new Color(0, true));
|
||||
g2d.clearRect(0, 0, width, height);
|
||||
int nativeW = (int) Math.ceil(width * scale);
|
||||
int nativeH = (int) Math.ceil(height * scale);
|
||||
DataBufferInt dataBuffer = new DataBufferInt(nativeW * nativeH);
|
||||
nativePaintTitleBar(
|
||||
nativePtr,
|
||||
SunWritableRaster.stealData(dataBuffer, 0),
|
||||
width, height, scale, peer.getTitle(), getButtonsState());
|
||||
SunWritableRaster.markDirty(dataBuffer);
|
||||
int[] bands = {0x00ff0000, 0x0000ff00, 0x000000ff, 0xff000000};
|
||||
WritableRaster raster = Raster.createPackedRaster(dataBuffer, nativeW, nativeH, nativeW, bands, null);
|
||||
ColorModel cm = peer.getGraphicsConfiguration().getColorModel(Transparency.TRANSLUCENT);
|
||||
BufferedImage img = new BufferedImage(cm, raster, true, null);
|
||||
if (scale != 1.0 && g2d instanceof SunGraphics2D sg2d) {
|
||||
sg2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
|
||||
sg2d.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BICUBIC);
|
||||
sg2d.setRenderingHint(RenderingHints.KEY_ALPHA_INTERPOLATION, RenderingHints.VALUE_ALPHA_INTERPOLATION_QUALITY);
|
||||
}
|
||||
g2d.drawImage(img, 0, 0, width, height, 0, 0, nativeW, nativeH, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void paintBorder(Graphics2D g2d) {
|
||||
// No border in this decoration style
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dispose() {
|
||||
nativeDestroyDecoration(nativePtr);
|
||||
nativePtr = 0;
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean pressedInDragStartArea(Point p) {
|
||||
if (p.x <= 0 || p.x >= peer.getWidth() || p.y <= 0 || p.y >= titleBarHeight) return false;
|
||||
|
||||
var b1 = getMinimizeButtonBounds();
|
||||
if (b1 != null && b1.contains(p)) return false;
|
||||
|
||||
var b2 = getMaximizeButtonBounds();
|
||||
if (b2 != null && b2.contains(p)) return false;
|
||||
|
||||
var b3 = getCloseButtonBounds();
|
||||
if (b3 != null && b3.contains(p)) return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean isSignificantDragDistance(Point p1, Point p2) {
|
||||
return p1.distance(p2) > dndThreshold;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getResizeEdgeThickness() {
|
||||
return 10;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Insets getContentInsets() {
|
||||
return new Insets(titleBarHeight, 0, 0, 0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Rectangle getTitleBarBounds() {
|
||||
return new Rectangle(0, 0, peer.getWidth(), titleBarHeight);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Dimension getMinimumSize() {
|
||||
return new Dimension(titleBarMinWidth, titleBarHeight);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void notifyConfigured(boolean active, boolean maximized, boolean fullscreen) {
|
||||
nativeNotifyConfigured(nativePtr, active, maximized, fullscreen);
|
||||
super.notifyConfigured(active, maximized, fullscreen);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Rectangle getMinimizeButtonBounds() {
|
||||
if (!hasMinimizeButton()) return null;
|
||||
return minimizeButtonBounds;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Rectangle getMaximizeButtonBounds() {
|
||||
if (!hasMaximizeButton()) return null;
|
||||
return maximizeButtonBounds;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Rectangle getCloseButtonBounds() {
|
||||
return closeButtonBounds;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void notifyThemeChanged() {
|
||||
nativeSwitchTheme();
|
||||
}
|
||||
|
||||
private int getButtonsState() {
|
||||
int state = 0;
|
||||
if (closeButton.hovered) state |= CLOSE_BUTTON_STATE_HOVERED;
|
||||
if (closeButton.pressed) state |= CLOSE_BUTTON_STATE_PRESSED;
|
||||
|
||||
if (hasMinimizeButton()) {
|
||||
if (minimizeButton.hovered) state |= MIN_BUTTON_STATE_HOVERED;
|
||||
if (minimizeButton.pressed) state |= MIN_BUTTON_STATE_PRESSED;
|
||||
}
|
||||
|
||||
if (hasMaximizeButton()) {
|
||||
if (maximizeButton.hovered) state |= MAX_BUTTON_STATE_HOVERED;
|
||||
if (maximizeButton.pressed) state |= MAX_BUTTON_STATE_PRESSED;
|
||||
}
|
||||
|
||||
return state;
|
||||
}
|
||||
|
||||
private static native void initIDs();
|
||||
private static native boolean nativeLoadGTK();
|
||||
|
||||
private native long nativeCreateDecoration(boolean showMinimize, boolean showMaximize);
|
||||
private native void nativeDestroyDecoration(long nativePtr);
|
||||
private native void nativeSwitchTheme();
|
||||
private native void nativePaintTitleBar(long nativePtr, int[] buffer, int width, int height, double scale,
|
||||
String title, int buttonsState);
|
||||
private native int nativeGetIntProperty(long nativePtr, String name);
|
||||
private native void nativeNotifyConfigured(long nativePtr, boolean active, boolean maximized, boolean fullscreen);
|
||||
private native void nativePrePaint(long nativePtr, int width);
|
||||
}
|
||||
@@ -33,7 +33,6 @@ import java.awt.Rectangle;
|
||||
import java.awt.Window;
|
||||
import java.awt.event.MouseEvent;
|
||||
import java.awt.event.WindowEvent;
|
||||
import java.util.Objects;
|
||||
|
||||
public abstract class WLDecoratedPeer extends WLWindowPeer {
|
||||
private FrameDecoration decoration; // protected by stateLock
|
||||
@@ -41,12 +40,40 @@ public abstract class WLDecoratedPeer extends WLWindowPeer {
|
||||
private final boolean showMaximize;
|
||||
private final boolean showMinimize;
|
||||
|
||||
private final static String decorationPreference = System.getProperty("sun.awt.wl.WindowDecorationStyle");
|
||||
|
||||
public WLDecoratedPeer(Window target, boolean isUndecorated, boolean showMinimize, boolean showMaximize) {
|
||||
super(target);
|
||||
this.isUndecorated = isUndecorated;
|
||||
this.showMinimize = showMinimize;
|
||||
this.showMaximize = showMaximize;
|
||||
decoration = isUndecorated ? new MinimalFrameDecoration(this) : new DefaultFrameDecoration(this, showMinimize, showMaximize);
|
||||
decoration = determineDecoration(isUndecorated, showMinimize, showMaximize);
|
||||
}
|
||||
|
||||
private FrameDecoration determineDecoration(boolean isUndecorated, boolean showMinimize, boolean showMaximize) {
|
||||
FrameDecoration d;
|
||||
if (isUndecorated) {
|
||||
d = new MinimalFrameDecoration(this);
|
||||
} else if (decorationPreference != null) {
|
||||
if ("builtin".equals(decorationPreference)) {
|
||||
d = new DefaultFrameDecoration(this, showMinimize, showMaximize);
|
||||
} else if ("gtk".equals(decorationPreference) && isGTKAvailable()) {
|
||||
d = new GtkFrameDecoration(this, showMinimize, showMaximize);
|
||||
} else {
|
||||
d = new DefaultFrameDecoration(this, showMinimize, showMaximize);
|
||||
}
|
||||
} else {
|
||||
if (isGTKAvailable()) {
|
||||
d = new GtkFrameDecoration(this, showMinimize, showMaximize);
|
||||
} else {
|
||||
d = new DefaultFrameDecoration(this, showMinimize, showMaximize);
|
||||
}
|
||||
}
|
||||
return d;
|
||||
}
|
||||
|
||||
private static boolean isGTKAvailable() {
|
||||
return ((WLToolkit) WLToolkit.getDefaultToolkit()).checkGtkVersion(3, 20, 0);
|
||||
}
|
||||
|
||||
private static native void initIDs();
|
||||
@@ -70,13 +97,10 @@ public abstract class WLDecoratedPeer extends WLWindowPeer {
|
||||
return getDecoration().getContentInsets();
|
||||
}
|
||||
|
||||
public final void setDecoration(FrameDecoration newDecoration) {
|
||||
Objects.requireNonNull(newDecoration);
|
||||
public final void resetDecoration(boolean isFullscreen) {
|
||||
synchronized (getStateLock()) {
|
||||
if (decoration != newDecoration) {
|
||||
decoration.dispose();
|
||||
decoration = newDecoration;
|
||||
}
|
||||
decoration.dispose();
|
||||
decoration = determineDecoration(isFullscreen | isUndecorated, showMinimize, showMaximize);
|
||||
}
|
||||
// Since the client area of the window may have changed, need to re-validate the target
|
||||
// to let it re-layout its children.
|
||||
@@ -150,10 +174,10 @@ public abstract class WLDecoratedPeer extends WLWindowPeer {
|
||||
|
||||
if (wasFullscreen != fullscreen) {
|
||||
if (fullscreen) {
|
||||
setDecoration(new MinimalFrameDecoration(this));
|
||||
resetDecoration(true);
|
||||
} else {
|
||||
if (!isUndecorated) {
|
||||
setDecoration(new DefaultFrameDecoration(this, showMinimize, showMaximize));
|
||||
resetDecoration(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
774
src/java.desktop/unix/native/libawt_wlawt/GtkFrameDecoration.c
Normal file
774
src/java.desktop/unix/native/libawt_wlawt/GtkFrameDecoration.c
Normal file
@@ -0,0 +1,774 @@
|
||||
/*
|
||||
* Copyright (c) 2025, JetBrains s.r.o.. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
#include "sun_awt_wl_GtkFrameDecoration.h"
|
||||
#include "JNIUtilities.h"
|
||||
#include "WLToolkit.h"
|
||||
|
||||
#include <jni_util.h>
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <dlfcn.h>
|
||||
|
||||
typedef void* gpointer;
|
||||
typedef char gchar;
|
||||
typedef int gint;
|
||||
typedef unsigned int guint;
|
||||
typedef gint gboolean;
|
||||
typedef signed short gint16;
|
||||
typedef double gdouble;
|
||||
typedef void* GtkWidget;
|
||||
typedef void* GtkStyleContext;
|
||||
typedef void* GtkContainer;
|
||||
typedef void* GtkBin;
|
||||
typedef void* GtkWindow;
|
||||
typedef void* GtkHeaderBar;
|
||||
typedef void* GtkIconInfo;
|
||||
typedef void* GtkIconTheme;
|
||||
typedef void* GtkSettings;
|
||||
typedef void* GdkPixbuf;
|
||||
typedef void* GdkWindow;
|
||||
typedef void* GError;
|
||||
typedef unsigned long GType;
|
||||
typedef void (*GtkCallback)(GtkWidget *widget, gpointer data);
|
||||
typedef struct _GValue GValue;
|
||||
typedef struct _GObject GObject;
|
||||
typedef struct _GTypeInstance GTypeInstance;
|
||||
typedef struct _GMainContext GMainContext;
|
||||
|
||||
typedef enum {
|
||||
GTK_ICON_SIZE_INVALID,
|
||||
GTK_ICON_SIZE_MENU,
|
||||
GTK_ICON_SIZE_SMALL_TOOLBAR,
|
||||
GTK_ICON_SIZE_LARGE_TOOLBAR,
|
||||
GTK_ICON_SIZE_BUTTON,
|
||||
GTK_ICON_SIZE_DND,
|
||||
GTK_ICON_SIZE_DIALOG
|
||||
} GtkIconSize;
|
||||
|
||||
typedef enum {
|
||||
GTK_ICON_LOOKUP_NO_SVG = 1 << 0,
|
||||
GTK_ICON_LOOKUP_FORCE_SVG = 1 << 1,
|
||||
GTK_ICON_LOOKUP_USE_BUILTIN = 1 << 2,
|
||||
GTK_ICON_LOOKUP_GENERIC_FALLBACK = 1 << 3,
|
||||
GTK_ICON_LOOKUP_FORCE_SIZE = 1 << 4,
|
||||
GTK_ICON_LOOKUP_FORCE_REGULAR = 1 << 5,
|
||||
GTK_ICON_LOOKUP_FORCE_SYMBOLIC = 1 << 6,
|
||||
GTK_ICON_LOOKUP_DIR_LTR = 1 << 7,
|
||||
GTK_ICON_LOOKUP_DIR_RTL = 1 << 8
|
||||
} GtkIconLookupFlags;
|
||||
|
||||
typedef enum {
|
||||
GTK_STATE_FLAG_NORMAL = 0,
|
||||
GTK_STATE_FLAG_ACTIVE = 1 << 0,
|
||||
GTK_STATE_FLAG_PRELIGHT = 1 << 1,
|
||||
GTK_STATE_FLAG_SELECTED = 1 << 2,
|
||||
GTK_STATE_FLAG_INSENSITIVE = 1 << 3,
|
||||
GTK_STATE_FLAG_INCONSISTENT = 1 << 4,
|
||||
GTK_STATE_FLAG_FOCUSED = 1 << 5,
|
||||
GTK_STATE_FLAG_BACKDROP = 1 << 6
|
||||
} GtkStateFlags;
|
||||
|
||||
typedef enum {
|
||||
GTK_STYLE_CONTEXT_PRINT_NONE = 0,
|
||||
GTK_STYLE_CONTEXT_PRINT_RECURSE = 1 << 0,
|
||||
GTK_STYLE_CONTEXT_PRINT_SHOW_STYLE = 1 << 1
|
||||
} GtkStyleContextPrintFlags;
|
||||
|
||||
typedef struct {
|
||||
gint16 left;
|
||||
gint16 right;
|
||||
gint16 top;
|
||||
gint16 bottom;
|
||||
} GtkBorder;
|
||||
|
||||
typedef struct {
|
||||
int x;
|
||||
int y;
|
||||
int width;
|
||||
int height;
|
||||
} GtkAllocation;
|
||||
|
||||
#define GTK_STYLE_CLASS_TITLEBAR "titlebar"
|
||||
#define GTK_TYPE_WIDGET (p_gtk_widget_get_type())
|
||||
#define GTK_TYPE_CONTAINER (p_gtk_container_get_type())
|
||||
#define GTK_IS_CONTAINER(obj) p_g_type_check_instance_is_a((obj), GTK_TYPE_CONTAINER)
|
||||
#define GTK_IS_WIDGET(obj) p_g_type_check_instance_is_a((obj), GTK_TYPE_WIDGET)
|
||||
#define GTK_CONTAINER(obj) ((GtkContainer)(obj))
|
||||
#define GTK_BIN(obj) ((GtkBin)(obj))
|
||||
#define GTK_WINDOW(obj) ((GtkWindow)(obj))
|
||||
#define GTK_WIDGET(obj) ((GtkWidget)(obj))
|
||||
#define GTK_HEADER_BAR(obj) ((GtkHeaderBar)(obj))
|
||||
|
||||
typedef enum {
|
||||
CAIRO_FORMAT_ARGB32 = 0
|
||||
} cairo_format_t;
|
||||
|
||||
typedef struct _cairo cairo_t;
|
||||
typedef struct _cairo_surface cairo_surface_t;
|
||||
|
||||
typedef char* (*gtk_style_context_to_string_t)(GtkStyleContext*, GtkStyleContextPrintFlags);
|
||||
typedef gboolean (*gtk_icon_size_lookup_t)(GtkIconSize, gint*, gint*);
|
||||
typedef GdkPixbuf* (*gtk_icon_info_load_symbolic_for_context_t)(GtkIconInfo*, GtkStyleContext*, gboolean*, GError**);
|
||||
typedef GtkIconInfo* (*gtk_icon_theme_lookup_icon_for_scale_t)(GtkIconTheme*, const gchar*, gint, gint, GtkIconLookupFlags);
|
||||
typedef GtkIconTheme* (*gtk_icon_theme_get_default_t)(void);
|
||||
typedef GtkSettings* (*gtk_widget_get_settings_t)(GtkWidget*);
|
||||
typedef GtkStateFlags (*gtk_style_context_get_state_t)(GtkStyleContext *context);
|
||||
typedef GtkStyleContext* (*gtk_widget_get_style_context_t)(GtkWidget*);
|
||||
typedef GtkWidget* (*gtk_bin_get_child_t)(GtkBin*);
|
||||
typedef GtkWidget* (*gtk_header_bar_new_t)(void);
|
||||
typedef GtkWidget* (*gtk_offscreen_window_new_t)(void);
|
||||
typedef GType (*gtk_container_get_type_t)(void);
|
||||
typedef GType (*gtk_widget_get_type_t)(void);
|
||||
typedef void (*gtk_container_forall_t)(GtkContainer*, GtkCallback, gpointer);
|
||||
typedef void (*gtk_header_bar_set_show_close_button_t)(GtkHeaderBar*, gboolean);
|
||||
typedef void (*gtk_header_bar_set_title_t)(GtkHeaderBar*, const gchar*);
|
||||
typedef void (*gtk_render_background_t)(GtkStyleContext*, cairo_t*, gdouble, gdouble, gdouble, gdouble);
|
||||
typedef void (*gtk_render_frame_t)(GtkStyleContext*, cairo_t*, gdouble, gdouble, gdouble, gdouble);
|
||||
typedef void (*gtk_render_icon_surface_t)(GtkStyleContext*, cairo_t*, cairo_surface_t*, gdouble, gdouble);
|
||||
typedef void (*gtk_style_context_add_class_t)(GtkStyleContext*, const gchar*);
|
||||
typedef void (*gtk_style_context_get_border_t)(GtkStyleContext*, GtkStateFlags, GtkBorder*);
|
||||
typedef void (*gtk_style_context_get_padding_t)(GtkStyleContext*, GtkStateFlags, GtkBorder*);
|
||||
typedef void (*gtk_style_context_get_t)(GtkStyleContext*, GtkStateFlags, const gchar*, ...);
|
||||
typedef void (*gtk_style_context_remove_class_t)(GtkStyleContext*, const gchar*);
|
||||
typedef void (*gtk_style_context_restore_t)(GtkStyleContext*);
|
||||
typedef void (*gtk_style_context_save_t)(GtkStyleContext*);
|
||||
typedef void (*gtk_style_context_set_state_t)(GtkStyleContext*, GtkStateFlags);
|
||||
typedef void (*gtk_widget_destroy_t)(GtkWidget*);
|
||||
typedef void (*gtk_widget_draw_t)(GtkWidget*, cairo_t*);
|
||||
typedef void (*gtk_widget_get_allocation_t)(GtkWidget*, GtkAllocation*);
|
||||
typedef void (*gtk_widget_get_clip_t)(GtkWidget*, GtkAllocation*);
|
||||
typedef void (*gtk_widget_get_preferred_height_t)(GtkWidget*, gint*, gint*);
|
||||
typedef void (*gtk_widget_get_preferred_width_t)(GtkWidget*, gint*, gint*);
|
||||
typedef void (*gtk_widget_set_state_flags_t)(GtkWidget*, GtkStateFlags, gboolean);
|
||||
typedef void (*gtk_widget_show_all_t)(GtkWidget*);
|
||||
typedef void (*gtk_widget_size_allocate_t)(GtkWidget*, GtkAllocation*);
|
||||
typedef void (*gtk_widget_unset_state_flags_t)(GtkWidget*, GtkStateFlags);
|
||||
typedef void (*gtk_window_set_resizable_t)(GtkWindow*, gboolean);
|
||||
typedef void (*gtk_window_set_titlebar_t)(GtkWindow*, GtkWidget*);
|
||||
|
||||
typedef cairo_surface_t* (*gdk_cairo_surface_create_from_pixbuf_t)(const GdkPixbuf*, int, GdkWindow*);
|
||||
typedef void (*gdk_threads_enter_t)(void);
|
||||
typedef void (*gdk_threads_leave_t)(void);
|
||||
|
||||
typedef cairo_surface_t* (*cairo_image_surface_create_for_data_t)(unsigned char*, cairo_format_t, int, int, int);
|
||||
typedef cairo_surface_t* (*cairo_surface_create_for_rectangle_t)(cairo_surface_t*, double, double, double, double);
|
||||
typedef cairo_t* (*cairo_create_t)(cairo_surface_t*);
|
||||
typedef int (*cairo_format_stride_for_width_t)(cairo_format_t, int);
|
||||
typedef void (*cairo_destroy_t)(cairo_t*);
|
||||
typedef void (*cairo_paint_t)(cairo_t*);
|
||||
typedef void (*cairo_surface_destroy_t)(cairo_surface_t*);
|
||||
typedef void (*cairo_surface_flush_t)(cairo_surface_t *);
|
||||
typedef void (*cairo_surface_set_device_scale_t)(cairo_surface_t *, double, double);
|
||||
|
||||
typedef void (*g_object_unref_t)(gpointer);
|
||||
typedef void (*g_object_get_t)(gpointer, const gchar*, ...);
|
||||
typedef void (*g_object_set_t)(gpointer, const gchar*, ...);
|
||||
typedef void (*g_object_get_property_t)(GObject*, const gchar*, GValue*);
|
||||
typedef gboolean (*g_type_check_instance_is_a_t)(void**, GType);
|
||||
typedef gboolean (*g_main_context_iteration_t)(GMainContext *context, gboolean);
|
||||
|
||||
typedef struct GtkFrameDecorationDescr {
|
||||
GtkWidget *window;
|
||||
GtkWidget *titlebar;
|
||||
jboolean show_minimize;
|
||||
jboolean show_maximize;
|
||||
jboolean is_active;
|
||||
jboolean is_maximized;
|
||||
} GtkFrameDecorationDescr;
|
||||
|
||||
struct WidgetCallbackData {
|
||||
const char *name;
|
||||
GtkWidget *widget;
|
||||
};
|
||||
|
||||
static jfieldID CloseButtonBoundsFID;
|
||||
static jfieldID MinButtonBoundsFID;
|
||||
static jfieldID MaxButtonBoundsFID;
|
||||
static jfieldID TitleBarHeightFID;
|
||||
static jfieldID TitleBarMinWidthFID;
|
||||
|
||||
static gtk_bin_get_child_t p_gtk_bin_get_child;
|
||||
static gtk_container_forall_t p_gtk_container_forall;
|
||||
static gtk_container_get_type_t p_gtk_container_get_type;
|
||||
static gtk_header_bar_new_t p_gtk_header_bar_new;
|
||||
static gtk_header_bar_set_show_close_button_t p_gtk_header_bar_set_show_close_button;
|
||||
static gtk_header_bar_set_title_t p_gtk_header_bar_set_title;
|
||||
static gtk_icon_info_load_symbolic_for_context_t p_gtk_icon_info_load_symbolic_for_context;
|
||||
static gtk_icon_size_lookup_t p_gtk_icon_size_lookup;
|
||||
static gtk_icon_theme_get_default_t p_gtk_icon_theme_get_default;
|
||||
static gtk_icon_theme_lookup_icon_for_scale_t p_gtk_icon_theme_lookup_icon_for_scale;
|
||||
static gtk_offscreen_window_new_t p_gtk_offscreen_window_new;
|
||||
static gtk_render_background_t p_gtk_render_background;
|
||||
static gtk_render_frame_t p_gtk_render_frame;
|
||||
static gtk_render_icon_surface_t p_gtk_render_icon_surface;
|
||||
static gtk_style_context_add_class_t p_gtk_style_context_add_class;
|
||||
static gtk_style_context_get_border_t p_gtk_style_context_get_border;
|
||||
static gtk_style_context_get_padding_t p_gtk_style_context_get_padding;
|
||||
static gtk_style_context_get_state_t p_gtk_style_context_get_state;
|
||||
static gtk_style_context_get_t p_gtk_style_context_get;
|
||||
static gtk_style_context_remove_class_t p_gtk_style_context_remove_class;
|
||||
static gtk_style_context_restore_t p_gtk_style_context_restore;
|
||||
static gtk_style_context_save_t p_gtk_style_context_save;
|
||||
static gtk_style_context_set_state_t p_gtk_style_context_set_state;
|
||||
static gtk_style_context_to_string_t p_gtk_style_context_to_string;
|
||||
static gtk_widget_destroy_t p_gtk_widget_destroy;
|
||||
static gtk_widget_draw_t p_gtk_widget_draw;
|
||||
static gtk_widget_get_allocation_t p_gtk_widget_get_allocation;
|
||||
static gtk_widget_get_clip_t p_gtk_widget_get_clip;
|
||||
static gtk_widget_get_preferred_height_t p_gtk_widget_get_preferred_height;
|
||||
static gtk_widget_get_preferred_width_t p_gtk_widget_get_preferred_width;
|
||||
static gtk_widget_get_settings_t p_gtk_widget_get_settings;
|
||||
static gtk_widget_get_style_context_t p_gtk_widget_get_style_context;
|
||||
static gtk_widget_get_type_t p_gtk_widget_get_type;
|
||||
static gtk_widget_set_state_flags_t p_gtk_widget_set_state_flags;
|
||||
static gtk_widget_show_all_t p_gtk_widget_show_all;
|
||||
static gtk_widget_size_allocate_t p_gtk_widget_size_allocate;
|
||||
static gtk_widget_unset_state_flags_t p_gtk_widget_unset_state_flags;
|
||||
static gtk_window_set_resizable_t p_gtk_window_set_resizable;
|
||||
static gtk_window_set_titlebar_t p_gtk_window_set_titlebar;
|
||||
|
||||
static gdk_cairo_surface_create_from_pixbuf_t p_gdk_cairo_surface_create_from_pixbuf;
|
||||
static gdk_threads_enter_t p_gdk_threads_enter;
|
||||
static gdk_threads_leave_t p_gdk_threads_leave;
|
||||
|
||||
static cairo_create_t p_cairo_create;
|
||||
static cairo_destroy_t p_cairo_destroy;
|
||||
static cairo_format_stride_for_width_t p_cairo_format_stride_for_width;
|
||||
static cairo_image_surface_create_for_data_t p_cairo_image_surface_create_for_data;
|
||||
static cairo_paint_t p_cairo_paint;
|
||||
static cairo_surface_create_for_rectangle_t p_cairo_surface_create_for_rectangle;
|
||||
static cairo_surface_destroy_t p_cairo_surface_destroy;
|
||||
static cairo_surface_flush_t p_cairo_surface_flush;
|
||||
static cairo_surface_set_device_scale_t p_cairo_surface_set_device_scale;
|
||||
|
||||
static g_object_unref_t p_g_object_unref;
|
||||
static g_object_get_t p_g_object_get;
|
||||
static g_object_set_t p_g_object_set;
|
||||
static g_object_get_property_t p_g_object_get_property;
|
||||
static g_type_check_instance_is_a_t p_g_type_check_instance_is_a;
|
||||
static g_main_context_iteration_t p_g_main_context_iteration;
|
||||
|
||||
static void* gtk_handle;
|
||||
static void* gdk_handle;
|
||||
|
||||
static void* find_func(JNIEnv* env, void* lib_handle, const char* name) {
|
||||
void* f = dlsym(lib_handle, name);
|
||||
if (!f) {
|
||||
int len = strlen(name) + 128;
|
||||
char *msg = malloc(len);
|
||||
if (msg) {
|
||||
snprintf(msg, len, "Can't find function '%s'", name);
|
||||
JNU_ThrowByName(env, "java/lang/UnsatisfiedLinkError", msg);
|
||||
free(msg);
|
||||
} else {
|
||||
JNU_ThrowByName(env, "java/lang/UnsatisfiedLinkError", "Can't find some function; also ran out of memory.");
|
||||
}
|
||||
}
|
||||
return f;
|
||||
}
|
||||
|
||||
static jboolean load_gtk(JNIEnv *env) {
|
||||
gtk_handle = dlopen(VERSIONED_JNI_LIB_NAME("gtk-3", "0"), RTLD_LAZY | RTLD_LOCAL);
|
||||
if (!gtk_handle) {
|
||||
gtk_handle = dlopen(JNI_LIB_NAME("gtk-3"), RTLD_LAZY | RTLD_LOCAL);
|
||||
}
|
||||
|
||||
if (!gtk_handle) {
|
||||
return JNI_FALSE;
|
||||
}
|
||||
|
||||
gdk_handle = dlopen(VERSIONED_JNI_LIB_NAME("gdk-3", "0"), RTLD_LAZY | RTLD_LOCAL);
|
||||
if (!gdk_handle) {
|
||||
gdk_handle = dlopen(JNI_LIB_NAME("gdk-3"), RTLD_LAZY | RTLD_LOCAL);
|
||||
}
|
||||
|
||||
if (!gdk_handle) {
|
||||
dlclose(gtk_handle);
|
||||
return JNI_FALSE;
|
||||
}
|
||||
|
||||
p_gtk_bin_get_child = find_func(env, gtk_handle, "gtk_bin_get_child");
|
||||
p_gtk_container_forall = find_func(env, gtk_handle, "gtk_container_forall");
|
||||
p_gtk_container_get_type = find_func(env, gtk_handle, "gtk_container_get_type");
|
||||
p_gtk_header_bar_new = find_func(env, gtk_handle, "gtk_header_bar_new");
|
||||
p_gtk_header_bar_set_show_close_button = find_func(env, gtk_handle, "gtk_header_bar_set_show_close_button");
|
||||
p_gtk_header_bar_set_title = find_func(env, gtk_handle, "gtk_header_bar_set_title");
|
||||
p_gtk_icon_info_load_symbolic_for_context = find_func(env, gtk_handle, "gtk_icon_info_load_symbolic_for_context");
|
||||
p_gtk_icon_size_lookup = find_func(env, gtk_handle, "gtk_icon_size_lookup");
|
||||
p_gtk_icon_theme_get_default = find_func(env, gtk_handle, "gtk_icon_theme_get_default");
|
||||
p_gtk_icon_theme_lookup_icon_for_scale = find_func(env, gtk_handle, "gtk_icon_theme_lookup_icon_for_scale");
|
||||
p_gtk_offscreen_window_new = find_func(env, gtk_handle, "gtk_offscreen_window_new");
|
||||
p_gtk_widget_destroy = find_func(env, gtk_handle, "gtk_widget_destroy");
|
||||
p_gtk_render_background = find_func(env, gtk_handle, "gtk_render_background");
|
||||
p_gtk_render_frame = find_func(env, gtk_handle, "gtk_render_frame");
|
||||
p_gtk_render_icon_surface = find_func(env, gtk_handle, "gtk_render_icon_surface");
|
||||
p_gtk_style_context_add_class = find_func(env, gtk_handle, "gtk_style_context_add_class");
|
||||
p_gtk_style_context_get_border = find_func(env, gtk_handle, "gtk_style_context_get_border");
|
||||
p_gtk_style_context_get = find_func(env, gtk_handle, "gtk_style_context_get");
|
||||
p_gtk_style_context_get_padding = find_func(env, gtk_handle, "gtk_style_context_get_padding");
|
||||
p_gtk_style_context_get_state = find_func(env, gtk_handle, "gtk_style_context_get_state");
|
||||
p_gtk_style_context_remove_class = find_func(env, gtk_handle, "gtk_style_context_remove_class");
|
||||
p_gtk_style_context_restore = find_func(env, gtk_handle, "gtk_style_context_restore");
|
||||
p_gtk_style_context_save = find_func(env, gtk_handle, "gtk_style_context_save");
|
||||
p_gtk_style_context_set_state = find_func(env, gtk_handle, "gtk_style_context_set_state");
|
||||
p_gtk_style_context_to_string = find_func(env, gtk_handle, "gtk_style_context_to_string");
|
||||
p_gtk_widget_draw = find_func(env, gtk_handle, "gtk_widget_draw");
|
||||
p_gtk_widget_get_allocation = find_func(env, gtk_handle, "gtk_widget_get_allocation");
|
||||
p_gtk_widget_get_clip = find_func(env, gtk_handle, "gtk_widget_get_clip");
|
||||
p_gtk_widget_get_preferred_height = find_func(env, gtk_handle, "gtk_widget_get_preferred_height");
|
||||
p_gtk_widget_get_preferred_width = find_func(env, gtk_handle, "gtk_widget_get_preferred_width");
|
||||
p_gtk_widget_get_settings = find_func(env, gtk_handle, "gtk_widget_get_settings");
|
||||
p_gtk_widget_get_style_context = find_func(env, gtk_handle, "gtk_widget_get_style_context");
|
||||
p_gtk_widget_get_type = find_func(env, gtk_handle, "gtk_widget_get_type");
|
||||
p_gtk_widget_set_state_flags = find_func(env, gtk_handle, "gtk_widget_set_state_flags");
|
||||
p_gtk_widget_show_all = find_func(env, gtk_handle, "gtk_widget_show_all");
|
||||
p_gtk_widget_size_allocate = find_func(env, gtk_handle, "gtk_widget_size_allocate");
|
||||
p_gtk_widget_unset_state_flags = find_func(env, gtk_handle, "gtk_widget_unset_state_flags");
|
||||
p_gtk_window_set_resizable = find_func(env, gtk_handle, "gtk_window_set_resizable");
|
||||
p_gtk_window_set_titlebar = find_func(env, gtk_handle, "gtk_window_set_titlebar");
|
||||
|
||||
p_gdk_cairo_surface_create_from_pixbuf = find_func(env, gdk_handle, "gdk_cairo_surface_create_from_pixbuf");
|
||||
p_gdk_threads_enter = find_func(env, gdk_handle, "gdk_threads_enter");
|
||||
p_gdk_threads_leave = find_func(env, gdk_handle, "gdk_threads_leave");
|
||||
|
||||
p_cairo_surface_create_for_rectangle = find_func(env, gtk_handle, "cairo_surface_create_for_rectangle");
|
||||
p_cairo_create = find_func(env, gtk_handle, "cairo_create");
|
||||
p_cairo_destroy = find_func(env, gtk_handle, "cairo_destroy");
|
||||
p_cairo_surface_destroy = find_func(env, gtk_handle, "cairo_surface_destroy");
|
||||
p_cairo_paint = find_func(env, gtk_handle, "cairo_paint");
|
||||
p_cairo_image_surface_create_for_data = find_func(env, gtk_handle, "cairo_image_surface_create_for_data");
|
||||
p_cairo_surface_set_device_scale = find_func(env, gtk_handle, "cairo_surface_set_device_scale");
|
||||
p_cairo_format_stride_for_width = find_func(env, gtk_handle, "cairo_format_stride_for_width");
|
||||
p_cairo_surface_flush = find_func(env, gtk_handle, "cairo_surface_flush");
|
||||
|
||||
p_g_object_unref = find_func(env, gtk_handle, "g_object_unref");
|
||||
p_g_object_get = find_func(env, gtk_handle, "g_object_get");
|
||||
p_g_object_set = find_func(env, gtk_handle, "g_object_set");
|
||||
p_g_object_get_property = find_func(env, gtk_handle, "g_object_get_property");
|
||||
p_g_type_check_instance_is_a = find_func(env, gtk_handle, "g_type_check_instance_is_a");
|
||||
p_g_main_context_iteration = find_func(env, gtk_handle, "g_main_context_iteration");
|
||||
|
||||
// NB: An error had been thrown in case some function was missing
|
||||
return JNI_TRUE;
|
||||
}
|
||||
|
||||
static void widget_by_name_cb(GtkWidget *widget, void *payload) {
|
||||
struct WidgetCallbackData *data = payload;
|
||||
if (GTK_IS_WIDGET(widget)) {
|
||||
char *style_ctx = p_gtk_style_context_to_string(
|
||||
p_gtk_widget_get_style_context(widget),
|
||||
GTK_STYLE_CONTEXT_PRINT_SHOW_STYLE);
|
||||
if (strstr(style_ctx, data->name)) {
|
||||
data->widget = widget;
|
||||
free(style_ctx);
|
||||
return;
|
||||
}
|
||||
free(style_ctx);
|
||||
}
|
||||
|
||||
if (GTK_IS_CONTAINER(widget)) {
|
||||
p_gtk_container_forall(GTK_CONTAINER(widget), &widget_by_name_cb, data);
|
||||
}
|
||||
}
|
||||
|
||||
static GtkWidget* widget_by_name(GtkWidget *widget, const char *name) {
|
||||
struct WidgetCallbackData data = {.name = name, .widget = NULL};
|
||||
widget_by_name_cb(widget, &data);
|
||||
return data.widget;
|
||||
}
|
||||
|
||||
static void draw_titlebar_background(GtkFrameDecorationDescr* decor, cairo_t *cr) {
|
||||
GtkAllocation allocation;
|
||||
p_gtk_widget_get_allocation(GTK_WIDGET(decor->titlebar), &allocation);
|
||||
GtkStyleContext* style = p_gtk_widget_get_style_context(decor->titlebar);
|
||||
p_gtk_render_background(style, cr, allocation.x, allocation.y, allocation.width, allocation.height);
|
||||
}
|
||||
|
||||
static void draw_titlebar_title(GtkFrameDecorationDescr* decor, cairo_surface_t * surface) {
|
||||
GtkWidget *label = widget_by_name(decor->titlebar, "label.title:");
|
||||
GtkAllocation allocation;
|
||||
p_gtk_widget_get_allocation(label, &allocation);
|
||||
cairo_surface_t *label_surface = p_cairo_surface_create_for_rectangle(
|
||||
surface, allocation.x, allocation.y, allocation.width, allocation.height);
|
||||
cairo_t *cr = p_cairo_create(label_surface);
|
||||
p_gtk_widget_draw(label, cr);
|
||||
p_cairo_destroy(cr);
|
||||
p_cairo_surface_destroy(label_surface);
|
||||
}
|
||||
|
||||
static void draw_titlebar_button(GtkFrameDecorationDescr* decor, cairo_surface_t * surface, cairo_t *cr,
|
||||
double scale,
|
||||
jboolean hovered, jboolean pressed,
|
||||
const char *name, const char *icon_name) {
|
||||
GtkWidget *button = widget_by_name(decor->titlebar, name);
|
||||
if (!button)
|
||||
return;
|
||||
|
||||
GtkStateFlags style_state = GTK_STATE_FLAG_NORMAL;
|
||||
if (!decor->is_active) {
|
||||
style_state |= GTK_STATE_FLAG_BACKDROP;
|
||||
} else {
|
||||
style_state |= GTK_STATE_FLAG_FOCUSED;
|
||||
}
|
||||
if (hovered) {
|
||||
style_state |= GTK_STATE_FLAG_PRELIGHT;
|
||||
}
|
||||
if (pressed) {
|
||||
style_state |= GTK_STATE_FLAG_ACTIVE;
|
||||
}
|
||||
|
||||
GtkAllocation allocation;
|
||||
p_gtk_widget_get_clip(button, &allocation);
|
||||
|
||||
GtkStyleContext* button_style = p_gtk_widget_get_style_context(button);
|
||||
p_gtk_style_context_save(button_style);
|
||||
p_gtk_style_context_set_state(button_style, style_state);
|
||||
p_gtk_render_background(button_style, cr,
|
||||
allocation.x, allocation.y, allocation.width, allocation.height);
|
||||
p_gtk_render_frame(button_style, cr,
|
||||
allocation.x, allocation.y, allocation.width, allocation.height);
|
||||
p_gtk_style_context_restore(button_style);
|
||||
|
||||
int icon_width;
|
||||
int icon_height;
|
||||
if (!p_gtk_icon_size_lookup(GTK_ICON_SIZE_MENU, &icon_width, &icon_height)) {
|
||||
icon_width = 16;
|
||||
icon_height = 16;
|
||||
}
|
||||
GtkIconInfo* icon_info = p_gtk_icon_theme_lookup_icon_for_scale(
|
||||
p_gtk_icon_theme_get_default(), icon_name, icon_width, (int) scale, 0);
|
||||
p_gtk_style_context_save(button_style);
|
||||
p_gtk_style_context_set_state(button_style, style_state);
|
||||
GdkPixbuf* icon_pixbuf = p_gtk_icon_info_load_symbolic_for_context(icon_info, button_style, NULL, NULL);
|
||||
cairo_surface_t* icon_surface = p_gdk_cairo_surface_create_from_pixbuf(icon_pixbuf, (int) scale, NULL);
|
||||
p_gtk_style_context_restore(button_style);
|
||||
|
||||
int width = 0;
|
||||
int height = 0;
|
||||
p_gtk_style_context_get(button_style, p_gtk_style_context_get_state(button_style),
|
||||
"min-width", &width, "min-height", &height, NULL);
|
||||
|
||||
if (width < icon_width)
|
||||
width = icon_width;
|
||||
if (height < icon_height)
|
||||
height = icon_height;
|
||||
|
||||
int left = 0;
|
||||
int top = 0;
|
||||
int right = 0;
|
||||
int bottom = 0;
|
||||
GtkBorder border;
|
||||
GtkBorder padding;
|
||||
|
||||
p_gtk_style_context_get_border(button_style, p_gtk_style_context_get_state(button_style), &border);
|
||||
left += border.left;
|
||||
right += border.right;
|
||||
top += border.top;
|
||||
bottom += border.bottom;
|
||||
|
||||
p_gtk_style_context_get_padding(button_style, p_gtk_style_context_get_state(button_style), &padding);
|
||||
left += padding.left;
|
||||
right += padding.right;
|
||||
top += padding.top;
|
||||
bottom += padding.bottom;
|
||||
|
||||
width += left + right;
|
||||
height += top + bottom;
|
||||
|
||||
int offset_x = (width - icon_width + 0.5) / 2;
|
||||
int offset_y = (height - icon_height + 0.5) / 2;
|
||||
GtkWidget *icon_widget = p_gtk_bin_get_child(GTK_BIN(button));
|
||||
p_gtk_render_icon_surface(p_gtk_widget_get_style_context(icon_widget),
|
||||
cr, icon_surface, allocation.x + offset_x, allocation.y + offset_y);
|
||||
p_cairo_paint(cr);
|
||||
p_cairo_surface_destroy(icon_surface);
|
||||
p_g_object_unref(icon_pixbuf);
|
||||
}
|
||||
|
||||
static void draw_titlebar_buttons(GtkFrameDecorationDescr* decor, cairo_surface_t * surface, cairo_t *cr,
|
||||
double scale, int buttonsState) {
|
||||
if (decor->show_minimize) {
|
||||
jboolean hovered = buttonsState & sun_awt_wl_GtkFrameDecoration_MIN_BUTTON_STATE_HOVERED;
|
||||
jboolean pressed = buttonsState & sun_awt_wl_GtkFrameDecoration_MIN_BUTTON_STATE_PRESSED;
|
||||
draw_titlebar_button(decor, surface, cr, scale, hovered, pressed,
|
||||
".minimize", "window-minimize-symbolic");
|
||||
}
|
||||
|
||||
if (decor->show_maximize) {
|
||||
jboolean hovered = buttonsState & sun_awt_wl_GtkFrameDecoration_MAX_BUTTON_STATE_HOVERED;
|
||||
jboolean pressed = buttonsState & sun_awt_wl_GtkFrameDecoration_MAX_BUTTON_STATE_PRESSED;
|
||||
draw_titlebar_button(decor, surface, cr, scale, hovered, pressed,
|
||||
".maximize",
|
||||
decor->is_maximized ? "window-restore-symbolic" : "window-maximize-symbolic");
|
||||
}
|
||||
|
||||
jboolean hovered = buttonsState & sun_awt_wl_GtkFrameDecoration_CLOSE_BUTTON_STATE_HOVERED;
|
||||
jboolean pressed = buttonsState & sun_awt_wl_GtkFrameDecoration_CLOSE_BUTTON_STATE_PRESSED;
|
||||
draw_titlebar_button(decor, surface, cr, scale, hovered, pressed,
|
||||
".close", "window-close-symbolic");
|
||||
}
|
||||
|
||||
static void draw_title_bar(GtkFrameDecorationDescr* decor, cairo_surface_t * surface, cairo_t *cr,
|
||||
int width, int height, double scale, const char *title, int buttonsState) {
|
||||
GtkStyleContext *style = p_gtk_widget_get_style_context(decor->window);
|
||||
|
||||
if (!decor->is_active) {
|
||||
p_gtk_widget_set_state_flags(decor->window, GTK_STATE_FLAG_BACKDROP, true);
|
||||
} else {
|
||||
p_gtk_widget_unset_state_flags(decor->window, GTK_STATE_FLAG_BACKDROP);
|
||||
}
|
||||
|
||||
if (decor->is_maximized) {
|
||||
p_gtk_style_context_add_class(style, "maximized");
|
||||
} else {
|
||||
p_gtk_style_context_remove_class(style, "maximized");
|
||||
}
|
||||
|
||||
p_gtk_widget_show_all(decor->window);
|
||||
|
||||
p_gtk_header_bar_set_title(GTK_HEADER_BAR(decor->titlebar), title);
|
||||
GtkAllocation allocation = {0, 0, width, height};
|
||||
p_gtk_widget_size_allocate(decor->titlebar, &allocation);
|
||||
|
||||
draw_titlebar_background(decor, cr);
|
||||
draw_titlebar_title(decor, surface);
|
||||
draw_titlebar_buttons(decor, surface, cr, scale, buttonsState);
|
||||
}
|
||||
|
||||
JNIEXPORT void JNICALL Java_sun_awt_wl_GtkFrameDecoration_initIDs(JNIEnv *env, jclass clazz) {
|
||||
CHECK_NULL_THROW_IE(env,
|
||||
CloseButtonBoundsFID = (*env)->GetFieldID(env, clazz, "closeButtonBounds", "Ljava/awt/Rectangle;"),
|
||||
"Failed to find field closeButtonBounds");
|
||||
CHECK_NULL_THROW_IE(env,
|
||||
MinButtonBoundsFID = (*env)->GetFieldID(env, clazz, "minimizeButtonBounds", "Ljava/awt/Rectangle;"),
|
||||
"Failed to find field minimizeButtonBounds");
|
||||
CHECK_NULL_THROW_IE(env,
|
||||
MaxButtonBoundsFID = (*env)->GetFieldID(env, clazz, "maximizeButtonBounds", "Ljava/awt/Rectangle;"),
|
||||
"Failed to find field maximizeButtonBounds");
|
||||
CHECK_NULL_THROW_IE(env,
|
||||
TitleBarHeightFID = (*env)->GetFieldID(env, clazz, "titleBarHeight", "I"),
|
||||
"Failed to find field titleBarHeightBounds");
|
||||
CHECK_NULL_THROW_IE(env,
|
||||
TitleBarMinWidthFID = (*env)->GetFieldID(env, clazz, "titleBarMinWidth", "I"),
|
||||
"Failed to find field titleBarMinWidth");
|
||||
}
|
||||
|
||||
JNIEXPORT jboolean JNICALL Java_sun_awt_wl_GtkFrameDecoration_nativeLoadGTK(JNIEnv *env, jclass clazz) {
|
||||
return load_gtk(env);
|
||||
}
|
||||
|
||||
JNIEXPORT jlong JNICALL Java_sun_awt_wl_GtkFrameDecoration_nativeCreateDecoration
|
||||
(JNIEnv *env, jobject obj, jboolean show_minimize, jboolean show_maximize) {
|
||||
GtkFrameDecorationDescr *d = calloc(1, sizeof(GtkFrameDecorationDescr));
|
||||
CHECK_NULL_THROW_OOME_RETURN(env, d, "Failed to allocate GtkFrameDeocration", 0);
|
||||
|
||||
p_gdk_threads_enter();
|
||||
|
||||
d->show_minimize = show_minimize;
|
||||
d->show_maximize = show_maximize;
|
||||
d->window = p_gtk_offscreen_window_new();
|
||||
d->titlebar = p_gtk_header_bar_new();
|
||||
p_g_object_set(d->titlebar,
|
||||
"title", "Default Title",
|
||||
"has-subtitle", false,
|
||||
"show-close-button", true,
|
||||
NULL);
|
||||
GtkStyleContext *context_hdr = p_gtk_widget_get_style_context(d->titlebar);
|
||||
p_gtk_style_context_add_class(context_hdr, GTK_STYLE_CLASS_TITLEBAR);
|
||||
p_gtk_style_context_add_class(context_hdr, "default-decoration");
|
||||
p_gtk_window_set_titlebar(GTK_WINDOW(d->window), d->titlebar);
|
||||
p_gtk_header_bar_set_show_close_button(GTK_HEADER_BAR(d->titlebar), true);
|
||||
p_gtk_window_set_resizable(GTK_WINDOW(d->window), true);
|
||||
|
||||
p_gdk_threads_leave();
|
||||
|
||||
return ptr_to_jlong(d);
|
||||
}
|
||||
|
||||
JNIEXPORT void JNICALL Java_sun_awt_wl_GtkFrameDecoration_nativeDestroyDecoration
|
||||
(JNIEnv *env, jobject obj, jlong ptr) {
|
||||
assert (ptr != 0);
|
||||
GtkFrameDecorationDescr* decor = jlong_to_ptr(ptr);
|
||||
|
||||
p_gdk_threads_enter();
|
||||
|
||||
p_gtk_widget_destroy(decor->titlebar);
|
||||
p_gtk_widget_destroy(decor->window);
|
||||
|
||||
p_gdk_threads_leave();
|
||||
|
||||
free(decor);
|
||||
}
|
||||
|
||||
JNIEXPORT void JNICALL Java_sun_awt_wl_GtkFrameDecoration_nativePaintTitleBar
|
||||
(JNIEnv *env, jobject obj, jlong ptr, jintArray dest,
|
||||
jint width, jint height, jdouble scale, jstring title, jint buttonsState) {
|
||||
GtkFrameDecorationDescr* decor = jlong_to_ptr(ptr);
|
||||
|
||||
jint pixel_width = ceil(width * scale);
|
||||
jint pixel_height = ceil(height * scale);
|
||||
|
||||
unsigned char *buffer = (*env)->GetPrimitiveArrayCritical(env, dest, 0);
|
||||
if (!buffer) {
|
||||
JNU_ThrowOutOfMemoryError(env, "Could not get image buffer");
|
||||
return;
|
||||
}
|
||||
|
||||
p_gdk_threads_enter();
|
||||
|
||||
cairo_surface_t *surface = p_cairo_image_surface_create_for_data(
|
||||
buffer, CAIRO_FORMAT_ARGB32,
|
||||
pixel_width, pixel_height,
|
||||
p_cairo_format_stride_for_width(CAIRO_FORMAT_ARGB32, pixel_width));
|
||||
|
||||
p_cairo_surface_set_device_scale(surface, scale, scale);
|
||||
|
||||
cairo_t *cr = p_cairo_create(surface);
|
||||
|
||||
jboolean is_copy = JNI_FALSE;
|
||||
const char *title_c_str = "";
|
||||
if (title) {
|
||||
title_c_str = JNU_GetStringPlatformChars(env, title, &is_copy);
|
||||
if (!title_c_str)
|
||||
return;
|
||||
}
|
||||
draw_title_bar(decor, surface, cr, width, height, scale, title_c_str, buttonsState);
|
||||
|
||||
if (is_copy) {
|
||||
JNU_ReleaseStringPlatformChars(env, title, title_c_str);
|
||||
}
|
||||
|
||||
// Make sure pixels have been flush into the underlying buffer
|
||||
p_cairo_surface_flush(surface);
|
||||
|
||||
p_gdk_threads_leave();
|
||||
|
||||
(*env)->ReleasePrimitiveArrayCritical(env, dest, buffer, 0);
|
||||
p_cairo_destroy(cr);
|
||||
p_cairo_surface_destroy(surface);
|
||||
}
|
||||
|
||||
JNIEXPORT void JNICALL Java_sun_awt_wl_GtkFrameDecoration_nativePrePaint(JNIEnv *env, jobject obj,
|
||||
jlong ptr, jint width) {
|
||||
assert (ptr != 0);
|
||||
GtkFrameDecorationDescr* decor = jlong_to_ptr(ptr);
|
||||
|
||||
p_gdk_threads_enter();
|
||||
|
||||
if (decor->is_active) {
|
||||
p_gtk_widget_set_state_flags(decor->window, GTK_STATE_FLAG_BACKDROP, true);
|
||||
} else {
|
||||
p_gtk_widget_unset_state_flags(decor->window, GTK_STATE_FLAG_BACKDROP);
|
||||
}
|
||||
|
||||
GtkStyleContext *style = p_gtk_widget_get_style_context(decor->window);
|
||||
if (decor->is_maximized) {
|
||||
p_gtk_style_context_add_class(style, "maximized");
|
||||
} else {
|
||||
p_gtk_style_context_remove_class(style, "maximized");
|
||||
}
|
||||
|
||||
p_gtk_header_bar_set_title(GTK_HEADER_BAR(decor->titlebar), "Title");
|
||||
p_gtk_widget_show_all(decor->window);
|
||||
|
||||
jint pref_height;
|
||||
p_gtk_widget_get_preferred_height(decor->titlebar, NULL, &pref_height);
|
||||
jint min_width;
|
||||
p_gtk_widget_get_preferred_width(decor->titlebar, &min_width, NULL);
|
||||
|
||||
(*env)->SetIntField(env, obj, TitleBarHeightFID, pref_height);
|
||||
(*env)->SetIntField(env, obj, TitleBarMinWidthFID, min_width);
|
||||
|
||||
GtkAllocation ha = {0, 0, width, pref_height};
|
||||
p_gtk_widget_size_allocate(decor->titlebar, &ha);
|
||||
|
||||
GtkWidget *button = widget_by_name(decor->titlebar, ".close");
|
||||
GtkAllocation ba;
|
||||
if (button) {
|
||||
p_gtk_widget_get_clip(button, &ba);
|
||||
jobject recObj = JNU_NewObjectByName(env, "java/awt/Rectangle", "(IIII)V",
|
||||
ba.x, ba.y, ba.width, ba.height);
|
||||
(*env)->SetObjectField(env, obj, CloseButtonBoundsFID, recObj);
|
||||
}
|
||||
|
||||
button = widget_by_name(decor->titlebar, ".minimize");
|
||||
if (button) {
|
||||
p_gtk_widget_get_clip(button, &ba);
|
||||
jobject recObj = JNU_NewObjectByName(env, "java/awt/Rectangle", "(IIII)V",
|
||||
ba.x, ba.y, ba.width, ba.height);
|
||||
(*env)->SetObjectField(env, obj, MinButtonBoundsFID, recObj);
|
||||
}
|
||||
|
||||
button = widget_by_name(decor->titlebar, ".maximize");
|
||||
if (button) {
|
||||
p_gtk_widget_get_clip(button, &ba);
|
||||
jobject recObj = JNU_NewObjectByName(env, "java/awt/Rectangle", "(IIII)V",
|
||||
ba.x, ba.y, ba.width, ba.height);
|
||||
(*env)->SetObjectField(env, obj, MaxButtonBoundsFID, recObj);
|
||||
}
|
||||
|
||||
p_gdk_threads_leave();
|
||||
}
|
||||
|
||||
JNIEXPORT void JNICALL Java_sun_awt_wl_GtkFrameDecoration_nativeSwitchTheme(JNIEnv *env, jobject obj) {
|
||||
while ((*p_g_main_context_iteration)(NULL, false));
|
||||
}
|
||||
|
||||
JNIEXPORT jint JNICALL Java_sun_awt_wl_GtkFrameDecoration_nativeGetIntProperty
|
||||
(JNIEnv *env, jobject obj, jlong ptr, jstring name) {
|
||||
assert (ptr != 0);
|
||||
GtkFrameDecorationDescr* decor = jlong_to_ptr(ptr);
|
||||
|
||||
jboolean is_copy = JNI_FALSE;
|
||||
const char *name_c_str = JNU_GetStringPlatformChars(env, name, &is_copy);
|
||||
if (!name_c_str)
|
||||
return 0;
|
||||
|
||||
jint result;
|
||||
p_gdk_threads_enter();
|
||||
|
||||
p_g_object_get(p_gtk_widget_get_settings(decor->window), name_c_str, &result, NULL);
|
||||
|
||||
p_gdk_threads_leave();
|
||||
if (is_copy) {
|
||||
JNU_ReleaseStringPlatformChars(env, name, name_c_str);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
JNIEXPORT void JNICALL Java_sun_awt_wl_GtkFrameDecoration_nativeNotifyConfigured
|
||||
(JNIEnv *env, jobject obj, jlong ptr, jboolean active, jboolean maximized, jboolean fullscreen) {
|
||||
assert (ptr != 0);
|
||||
GtkFrameDecorationDescr* decor = jlong_to_ptr(ptr);
|
||||
|
||||
decor->is_active = active;
|
||||
decor->is_maximized = maximized;
|
||||
}
|
||||
|
||||
@@ -2,6 +2,8 @@
|
||||
|
||||
# :hotspot_runtime
|
||||
|
||||
containers/cgroup/TestContainerized.java JBR-9076 linux-all
|
||||
|
||||
runtime/8176717/TestInheritFD.java JBR-6974 linux-all
|
||||
runtime/ErrorHandling/CreateCoredumpOnCrash.java JBR-7917 linux-all
|
||||
runtime/Thread/ThreadCountLimit.java#id0 JBR-7974 linux-all
|
||||
|
||||
@@ -170,6 +170,8 @@ runtime/jni/daemonDestroy/TestDaemonDestroy.java JBR-6261 windows-all
|
||||
runtime/jni/nativeStack/TestNativeStack.java JBR-8521 windows-aarch64
|
||||
runtime/jni/terminatedThread/TestTerminatedThread.java 8317789 aix-ppc64
|
||||
runtime/cds/CheckDefaultArchiveFile.java JBR-4227 generic-all
|
||||
runtime/cds/SharedBaseAddress.java#id2 JBR-9078 windows-aarch64
|
||||
runtime/cds/SharedBaseAddress.java#id3 JBR-9078 windows-aarch64
|
||||
runtime/handshake/HandshakeSuspendExitTest.java 8318631 generic-all
|
||||
runtime/modules/ClassLoaderNoUnnamedModuleTest.java JBR-8516 windows-aarch64
|
||||
runtime/Monitor/SyncOnValueBasedClassTest.java 8340995,JBR-8517 linux-s390x,windows-aarch64
|
||||
@@ -222,7 +224,6 @@ runtime/cds/appcds/dynamicArchive/CDSStreamTestDriver.java initial_run generic-a
|
||||
runtime/ReservedStack/ReservedStackTest.java initial_run windows-aarch64
|
||||
runtime/cds/appcds/methodHandles/MethodHandlesPermuteArgumentsTest.java initial_run generic-all
|
||||
runtime/cds/appcds/methodHandles/MethodHandlesAsCollectorTest.java initial_run generic-all
|
||||
runtime/cds/SharedBaseAddress.java initial_run generic-all
|
||||
runtime/cds/TestCDSVMCrash.java JBR-6616 windows-aarch64
|
||||
runtime/cds/TestDefaultArchiveLoading.java#coops_nocoh JBR-6616 windows-aarch64
|
||||
runtime/cds/TestDefaultArchiveLoading.java#nocoops_nocoh JBR-6616 windows-aarch64
|
||||
|
||||
@@ -125,5 +125,6 @@ javax/swing/UI/UnninstallUIMemoryLeaks/UnninstallUIMemoryLeaks.java JBR-5952,834
|
||||
|
||||
jb/build/ResolveSymbolsTest/ResolveSymbolsRealEnv.java JBR-8544 linux-all
|
||||
jb/java/awt/Window/UndecoratedDialogInTransientsChain.java JBR-8710 windows-aarch64
|
||||
jb/javax/swing/JDialog/JDialog1054.java JBR-5004 macosx-aarch64
|
||||
|
||||
sun/awt/dnd/8024061/bug8024061.java JBR-9033 windows-all
|
||||
@@ -21,6 +21,7 @@ java/awt/font/TextLayout/HitTest.java JBR-8764 linux-all
|
||||
java/awt/font/TextLayout/TestGetPixelBounds.java JBR-8765 linux-all
|
||||
java/awt/font/TextLayout/VisibleAdvance.java JBR-8766 linux-all
|
||||
java/awt/FontMetrics/ExtremeFontSizeTest.java JBR-7823 linux-all
|
||||
java/awt/Graphics2D/DrawString/IgnoredWhitespaceTest.java JBR-9086 linux-all
|
||||
java/awt/Graphics2D/DrawString/RotTransText.java JBR-8767 linux-all
|
||||
java/awt/Graphics/XORPaint.java#id2 JBR-7373 linux-x64
|
||||
java/awt/image/DrawImage/SimpleManagedImage.java JBR-8769 linux-all
|
||||
|
||||
@@ -794,6 +794,7 @@ java/beans/XMLEncoder/Test6570354.java 8015593 macosx-all
|
||||
# jdk_foreign
|
||||
|
||||
java/foreign/critical/TestCriticalUpcall.java JBR-8711 windows-aarch64
|
||||
java/foreign/TestBufferStackStress.java JBR-8930 windows-aarch64
|
||||
java/foreign/TestMismatch.java 8249684 macosx-all
|
||||
|
||||
############################################################################
|
||||
@@ -1384,6 +1385,13 @@ java/awt/List/HandlingKeyEventIfMousePressedTest.java 6848358 macosx-all,windows
|
||||
|
||||
############################################################################
|
||||
|
||||
# jdk_since_checks
|
||||
|
||||
tools/sincechecker/modules/java.base/JavaBaseCheckSince.java 8358627 generic-all
|
||||
tools/sincechecker/modules/jdk.management.jfr/JdkManagementJfrCheckSince.java 8354921 generic-all
|
||||
|
||||
############################################################################
|
||||
|
||||
# various Windows are created spontaneously during test execution
|
||||
|
||||
javax/swing/JList/4618767/JListSelectedElementTest.java JBR-4955 windows-all
|
||||
@@ -1554,7 +1562,7 @@ javax/swing/LookAndFeel/8145547/DemandGTK3.sh JBR-5510,JBR-6908 linux-5.18.2-arc
|
||||
jb/java/awt/Focus/BrokenTraversalAWT.java JBR-5799 windows-all
|
||||
jb/java/awt/Focus/ComplexFocusSequence.java JBR-6728 linux-all,windows-x64
|
||||
jb/java/awt/Focus/ContextMenuAfterPopup.java JBR-5799 windows-all
|
||||
jb/java/awt/Focus/FileDialogClosing.java JBR-8309 macosx-x64
|
||||
jb/java/awt/Focus/FileDialogClosing.java JBR-5799,JBR-8309 windows-all,macosx-x64
|
||||
jb/java/awt/Focus/FocusTraversalOrderTest.java JBR-6060 generic-all
|
||||
jb/java/awt/Focus/PopupIncomingFocusTest.java JBR-5799 windows-all
|
||||
jb/java/awt/Focus/TitleBarClickTest.java JBR-6394 linux-5.18.2-arch1-1
|
||||
|
||||
@@ -74,7 +74,6 @@ javax/swing/plaf/basic/BasicGraphicsUtils/8132119/bug8132119.java JBR-8357 linux
|
||||
|
||||
jb/java/awt/event/MouseEvent/ReleaseAndClickModifiers.java JBR-6589 windows-all
|
||||
jb/java/awt/Focus/FileDialogClosing.java JBR-5799,JBR-8309 windows-all,macosx-x64
|
||||
jb/java/awt/Focus/ModalDialogFromMenuTest.java JBR-5799 windows-all
|
||||
jb/java/awt/Focus/ModalDialogOverSiblingTest.java JBR-5716 windows-all
|
||||
jb/java/awt/Focus/PopupFromMenuTest.java JBR-5799 windows-all
|
||||
jb/java/awt/Focus/PopupIncomingFocusTest.java JBR-2651 generic-all
|
||||
@@ -86,6 +85,7 @@ jb/java/awt/Window/UndecoratedDialogInTransientsChain.java
|
||||
jdk/editpad/EditPadTest.java JBR-5712 windows-all
|
||||
|
||||
sanity/client/SwingSet/src/ColorChooserDemoTest.java JBR-8354,JBR-8933 linux-all,windows-aarch64,windows-10.0
|
||||
sanity/client/SwingSet/src/EditorPaneDemoTest.java JBR-5510,JBR-6285 linux-5.18.2-arch1-1,linux-all
|
||||
sanity/client/SwingSet/src/InternalFrameDemoTest.java JBR-6685 linux-all
|
||||
sanity/client/SwingSet/src/ToolTipDemoTest.java 8293001,JBR-6293 linux-all,windows-all
|
||||
sun/java2d/GdiRendering/ClipShapeRendering.java JBR-5204 linux-all,macosx-all,windows-all
|
||||
|
||||
Reference in New Issue
Block a user