mirror of
https://github.com/JetBrains/JetBrainsRuntime.git
synced 2026-01-28 19:30:52 +01:00
Compare commits
1 Commits
jbr21.1168
...
batrdmi/tr
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
44f519d8c4 |
@@ -152,7 +152,7 @@ $ sudo wget -qO /etc/apt/sources.list.d/lunarg-vulkan-noble.list https://package
|
||||
$ sudo apt update
|
||||
$ sudo apt-get -y install openjdk-21-jdk file zip unzip autoconf make build-essential libx11-dev libxext-dev libxrender-dev \
|
||||
libxtst-dev libxt-dev libxrandr-dev libcups2-dev libfontconfig1-dev libasound2-dev libspeechd-dev libwayland-dev \
|
||||
libxkbcommon-x11-0 libdbus-1-dev vulkan-sdk vulkan-utility-libraries-dev
|
||||
libxkbcommon-x11-0 vulkan-sdk vulkan-utility-libraries-dev
|
||||
```
|
||||
|
||||
Then run the following:
|
||||
|
||||
@@ -109,12 +109,6 @@ else
|
||||
WITH_BUNDLED_FREETYPE=""
|
||||
fi
|
||||
|
||||
if [ "$bundle_type" == "lb" ]; then
|
||||
WITH_VULKAN=""
|
||||
else
|
||||
WITH_VULKAN="--with-vulkan"
|
||||
fi
|
||||
|
||||
REPRODUCIBLE_BUILD_OPTS="--with-source-date=$SOURCE_DATE_EPOCH
|
||||
--with-hotspot-build-time=$BUILD_TIME
|
||||
--with-copyright-year=$COPYRIGHT_YEAR
|
||||
|
||||
@@ -35,7 +35,7 @@ function do_configure {
|
||||
--with-version-opt=b"$build_number" \
|
||||
--with-boot-jdk="$BOOT_JDK" \
|
||||
--enable-cds=yes \
|
||||
$WITH_VULKAN \
|
||||
--with-vulkan \
|
||||
$DISABLE_WARNINGS_AS_ERRORS \
|
||||
$STATIC_CONF_ARGS \
|
||||
$REPRODUCIBLE_BUILD_OPTS \
|
||||
@@ -113,11 +113,6 @@ case "$bundle_type" in
|
||||
jbr_name_postfix="_${bundle_type}"
|
||||
do_maketest=1
|
||||
;;
|
||||
"lb")
|
||||
do_reset_changes=1
|
||||
jbr_name_postfix="_${bundle_type}"
|
||||
do_maketest=1
|
||||
;;
|
||||
"nomod" | "")
|
||||
bundle_type=""
|
||||
;;
|
||||
|
||||
@@ -32,6 +32,13 @@ function do_configure {
|
||||
--build=x86_64-unknown-linux-gnu \
|
||||
--openjdk-target=x86_64-unknown-linux-gnu"
|
||||
fi
|
||||
|
||||
if [ -n "${JCEF_BUILD_LEGACY:-}" ]; then
|
||||
WITH_VULKAN=""
|
||||
else
|
||||
WITH_VULKAN="--with-vulkan"
|
||||
fi
|
||||
|
||||
sh configure \
|
||||
$WITH_DEBUG_LEVEL \
|
||||
--with-vendor-name="$VENDOR_NAME" \
|
||||
@@ -95,7 +102,9 @@ function create_image_bundle {
|
||||
|
||||
# jmod does not preserve file permissions (JDK-8173610)
|
||||
[ -f "$IMAGES_DIR"/"$__root_dir"/lib/jcef_helper ] && chmod a+x "$IMAGES_DIR"/"$__root_dir"/lib/jcef_helper
|
||||
[ -f "$IMAGES_DIR"/"$__root_dir"/lib/cef_server ] && chmod a+x "$IMAGES_DIR"/"$__root_dir"/lib/cef_server
|
||||
if [ ! -n "${JCEF_BUILD_LEGACY:-}" ]; then
|
||||
[ -f "$IMAGES_DIR"/"$__root_dir"/lib/cef_server ] && chmod a+x "$IMAGES_DIR"/"$__root_dir"/lib/cef_server
|
||||
fi
|
||||
|
||||
echo Creating "$JBR".tar.gz ...
|
||||
|
||||
@@ -121,11 +130,6 @@ case "$bundle_type" in
|
||||
jbr_name_postfix="_${bundle_type}"
|
||||
do_maketest=1
|
||||
;;
|
||||
"lb")
|
||||
do_reset_changes=1
|
||||
jbr_name_postfix="_${bundle_type}"
|
||||
do_maketest=1
|
||||
;;
|
||||
"nomod" | "")
|
||||
bundle_type=""
|
||||
;;
|
||||
@@ -154,7 +158,7 @@ JBRSDK_BUNDLE=jbrsdk
|
||||
echo Fixing permissions
|
||||
chmod -R a+r $JSDK
|
||||
|
||||
if [ "$bundle_type" == "jcef" ] || [ "$bundle_type" == "lb" ]; then
|
||||
if [ "$bundle_type" == "jcef" ]; then
|
||||
git apply -p0 < jb/project/tools/patches/add_jcef_module.patch || do_exit $?
|
||||
update_jsdk_mods $JSDK $JCEF_PATH/jmods $JSDK/jmods $JSDK_MODS_DIR || do_exit $?
|
||||
cp $JCEF_PATH/jmods/* $JSDK_MODS_DIR # $JSDK/jmods is not changed
|
||||
@@ -167,7 +171,7 @@ create_image_bundle "jbr${jbr_name_postfix}" "jbr" $JSDK_MODS_DIR "$modules" ||
|
||||
|
||||
# create sdk image bundle
|
||||
modules=$(cat $JSDK/release | grep MODULES | sed s/MODULES=//g | sed s/' '/','/g | sed s/\"//g | sed s/\\n//g) || do_exit $?
|
||||
if [ "$bundle_type" == "jcef" ] || [ "$bundle_type" == "lb" ] || [ "$bundle_type" == "$JBRSDK_BUNDLE" ]; then
|
||||
if [ "$bundle_type" == "jcef" ]|| [ "$bundle_type" == "$JBRSDK_BUNDLE" ]; then
|
||||
modules=${modules},$(get_mods_list "$JCEF_PATH"/jmods)
|
||||
fi
|
||||
create_image_bundle "$JBRSDK_BUNDLE${jbr_name_postfix}" $JBRSDK_BUNDLE $JSDK_MODS_DIR "$modules" || do_exit $?
|
||||
|
||||
@@ -93,7 +93,7 @@ WITH_DEBUG_LEVEL="--with-debug-level=release"
|
||||
RELEASE_NAME=linux-x86-server-release
|
||||
|
||||
case "$bundle_type" in
|
||||
"jcef" | "lb")
|
||||
"jcef")
|
||||
echo "not implemented" && do_exit 1
|
||||
;;
|
||||
"nomod" | "")
|
||||
@@ -120,7 +120,7 @@ JBRSDK_BUNDLE=jbrsdk
|
||||
echo Fixing permissions
|
||||
chmod -R a+r $JSDK
|
||||
|
||||
if [ "$bundle_type" == "jcef" ] || [ "$bundle_type" == "fd" ] || [ "$bundle_type" == "lb" ]; then
|
||||
if [ "$bundle_type" == "jcef" ] || [ "$bundle_type" == "fd" ]; then
|
||||
jbr_name_postfix="_${bundle_type}"
|
||||
else
|
||||
jbr_name_postfix=""
|
||||
|
||||
@@ -40,13 +40,13 @@ else ifeq ($(call isBuildOsEnv, windows.wsl1 windows.wsl2), true)
|
||||
else
|
||||
M2_REPO := $(HOME)/.m2/repository
|
||||
endif
|
||||
M2_ARTIFACT := $(M2_REPO)/org/jetbrains/runtime/jbr-api/SNAPSHOT
|
||||
M2_ARTIFACT := $(M2_REPO)/com/jetbrains/jbr-api/SNAPSHOT
|
||||
M2_POM_CONTENT := \
|
||||
<?xml version="1.0" encoding="UTF-8"?> \
|
||||
<project xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd" \
|
||||
xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> \
|
||||
<modelVersion>4.0.0</modelVersion> \
|
||||
<groupId>org.jetbrains.runtime</groupId> \
|
||||
<groupId>com.jetbrains</groupId> \
|
||||
<artifactId>jbr-api</artifactId> \
|
||||
<version>SNAPSHOT</version> \
|
||||
</project> \
|
||||
@@ -65,8 +65,7 @@ jbr-api:
|
||||
$(MKDIR) -p $(M2_ARTIFACT); \
|
||||
$(ECHO) "$(M2_POM_CONTENT)" > $(M2_ARTIFACT)/$(ARTIFACT_NAME).pom; \
|
||||
$(CP) "$(JBR_API_DIR)/out/$(ARTIFACT_NAME).jar" "$(M2_ARTIFACT)"; \
|
||||
$(ECHO) "Installed into local Maven repository as org.jetbrains.runtime:jbr-api:SNAPSHOT"; \
|
||||
cd "$(M2_ARTIFACT)" && sha256sum --binary "$(ARTIFACT_NAME).jar"; \
|
||||
$(ECHO) "Installed into local Maven repository as com.jetbrains:jbr-api:SNAPSHOT"; \
|
||||
else \
|
||||
$(ECHO) "No Maven repository found at $(M2_REPO) - skipping local installation"; \
|
||||
fi
|
||||
|
||||
@@ -89,7 +89,7 @@ AC_DEFUN_ONCE([LIB_SETUP_VULKAN],
|
||||
if (test "x${with_vulkan_shader_compiler}" = x || test "x${with_vulkan_shader_compiler}" = xglslc); then
|
||||
UTIL_LOOKUP_PROGS(GLSLC, glslc)
|
||||
SHADER_COMPILER="$GLSLC"
|
||||
VULKAN_SHADER_COMPILER="glslc --target-env=vulkan1.2 -mfmt=num"
|
||||
VULKAN_SHADER_COMPILER="glslc --target-env=vulkan1.2 -mfmt=num -o"
|
||||
fi
|
||||
|
||||
# Check glslangValidator
|
||||
@@ -97,8 +97,7 @@ AC_DEFUN_ONCE([LIB_SETUP_VULKAN],
|
||||
test "x$SHADER_COMPILER" = x; then
|
||||
UTIL_LOOKUP_PROGS(GLSLANG, glslangValidator)
|
||||
SHADER_COMPILER="$GLSLANG"
|
||||
# Newer glslangValidator could use -P\"\#extension GL_GOOGLE_include_directive: require\"
|
||||
VULKAN_SHADER_COMPILER="glslangValidator --target-env vulkan1.2 -x"
|
||||
VULKAN_SHADER_COMPILER="glslangValidator --target-env vulkan1.2 -x -o"
|
||||
fi
|
||||
|
||||
if test "x$SHADER_COMPILER" = x; then
|
||||
|
||||
@@ -241,7 +241,7 @@ endif
|
||||
# Compile Vulkan shaders
|
||||
define compile-spirv
|
||||
$(call MakeTargetDir)
|
||||
$(VULKAN_SHADER_COMPILER) -D$(call uppercase,$(patsubst .%,STAGE_%,$(suffix $<))) -o '$(call DecodeSpace, $@)' '$(call DecodeSpace, $<)'
|
||||
$(VULKAN_SHADER_COMPILER) '$(call DecodeSpace, $@)' '$(call DecodeSpace, $<)'
|
||||
endef
|
||||
spirv-name = $(strip $1).h
|
||||
|
||||
|
||||
@@ -41,8 +41,7 @@ public abstract class CGraphicsConfig extends GraphicsConfiguration
|
||||
|
||||
private final CGraphicsDevice device;
|
||||
private ColorModel colorModel;
|
||||
private final SurfaceManager.ProxyCache surfaceDataProxyCache =
|
||||
new SurfaceManager.ProxyCache();
|
||||
private final SurfaceManager.ProxyCache surfaceDataProxyCache = new SurfaceManager.ProxyCache();
|
||||
|
||||
protected CGraphicsConfig(CGraphicsDevice device) {
|
||||
this.device = device;
|
||||
|
||||
@@ -42,7 +42,9 @@ import java.util.ListIterator;
|
||||
import java.util.Map;
|
||||
|
||||
import sun.java2d.MacOSFlags;
|
||||
import sun.java2d.MacosxSurfaceManagerFactory;
|
||||
import sun.java2d.SunGraphicsEnvironment;
|
||||
import sun.java2d.SurfaceManagerFactory;
|
||||
import sun.java2d.metal.MTLGraphicsConfig;
|
||||
import sun.util.logging.PlatformLogger;
|
||||
|
||||
@@ -110,6 +112,9 @@ public final class CGraphicsEnvironment extends SunGraphicsEnvironment {
|
||||
metalPipelineEnabled = true;
|
||||
}
|
||||
}
|
||||
|
||||
// Install the correct surface manager factory.
|
||||
SurfaceManagerFactory.setInstance(new MacosxSurfaceManagerFactory());
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -0,0 +1,75 @@
|
||||
/*
|
||||
* Copyright (c) 2011, 2022, Oracle and/or its affiliates. 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.
|
||||
*/
|
||||
|
||||
package sun.java2d;
|
||||
|
||||
import java.awt.GraphicsConfiguration;
|
||||
import java.awt.Image;
|
||||
|
||||
import sun.awt.CGraphicsEnvironment;
|
||||
import sun.awt.image.SunVolatileImage;
|
||||
import sun.awt.image.SurfaceManager;
|
||||
import sun.awt.image.TextureWrapperSurfaceManager;
|
||||
import sun.awt.image.VolatileSurfaceManager;
|
||||
import sun.java2d.metal.MTLGraphicsConfig;
|
||||
import sun.java2d.metal.MTLSurfaceData;
|
||||
import sun.java2d.metal.MTLVolatileSurfaceManager;
|
||||
import sun.java2d.opengl.CGLVolatileSurfaceManager;
|
||||
|
||||
/**
|
||||
* This is a factory class with static methods for creating a
|
||||
* platform-specific instance of a particular SurfaceManager. Each platform
|
||||
* (Windows, Unix, etc.) has its own specialized SurfaceManagerFactory.
|
||||
*/
|
||||
public class MacosxSurfaceManagerFactory extends SurfaceManagerFactory {
|
||||
|
||||
/**
|
||||
* Creates a new instance of a VolatileSurfaceManager given any
|
||||
* arbitrary SunVolatileImage. An optional context Object can be supplied
|
||||
* as a way for the caller to pass pipeline-specific context data to
|
||||
* the VolatileSurfaceManager (such as a backbuffer handle, for example).
|
||||
*
|
||||
* For Mac OS X, this method returns either an CGL/MTL-specific
|
||||
* VolatileSurfaceManager based on the GraphicsConfiguration
|
||||
* under which the SunVolatileImage was created.
|
||||
*/
|
||||
public VolatileSurfaceManager createVolatileManager(SunVolatileImage vImg,
|
||||
Object context)
|
||||
{
|
||||
return CGraphicsEnvironment.usingMetalPipeline() ? new MTLVolatileSurfaceManager(vImg, context) :
|
||||
new CGLVolatileSurfaceManager(vImg, context);
|
||||
}
|
||||
|
||||
@Override
|
||||
public SurfaceManager createTextureWrapperSurfaceManager(GraphicsConfiguration gc, Image image, long texture) {
|
||||
SurfaceData sd;
|
||||
if (gc instanceof MTLGraphicsConfig) {
|
||||
sd = MTLSurfaceData.createData((MTLGraphicsConfig) gc, image, texture);
|
||||
} else {
|
||||
throw new UnsupportedOperationException("Unsupported GraphicsConfiguration");
|
||||
}
|
||||
return new TextureWrapperSurfaceManager(sd);
|
||||
}
|
||||
}
|
||||
@@ -30,9 +30,6 @@ import sun.awt.CGraphicsDevice;
|
||||
import sun.awt.CGraphicsEnvironment;
|
||||
import sun.awt.image.OffScreenImage;
|
||||
import sun.awt.image.SunVolatileImage;
|
||||
import sun.awt.image.SurfaceManager;
|
||||
import sun.awt.image.TextureWrapperSurfaceManager;
|
||||
import sun.awt.image.VolatileSurfaceManager;
|
||||
import sun.java2d.Disposer;
|
||||
import sun.java2d.DisposerRecord;
|
||||
import sun.java2d.Surface;
|
||||
@@ -49,7 +46,6 @@ import java.awt.BufferCapabilities;
|
||||
import java.awt.Component;
|
||||
import java.awt.Graphics;
|
||||
import java.awt.Graphics2D;
|
||||
import java.awt.GraphicsConfiguration;
|
||||
import java.awt.Image;
|
||||
import java.awt.ImageCapabilities;
|
||||
import java.awt.Rectangle;
|
||||
@@ -71,7 +67,7 @@ import static sun.java2d.pipe.hw.ContextCapabilities.*;
|
||||
import static sun.java2d.metal.MTLContext.MTLContextCaps.CAPS_EXT_BIOP_SHADER;
|
||||
|
||||
public final class MTLGraphicsConfig extends CGraphicsConfig
|
||||
implements AccelGraphicsConfig, SurfaceManager.Factory, SurfaceManager.TextureWrapperFactory
|
||||
implements AccelGraphicsConfig
|
||||
{
|
||||
private static boolean mtlAvailable;
|
||||
private static ImageCapabilities imageCaps = new MTLImageCaps();
|
||||
@@ -384,17 +380,4 @@ public final class MTLGraphicsConfig extends CGraphicsConfig
|
||||
return Math.max(maxTextureSize / getDevice().getScaleFactor(),
|
||||
getBounds().height);
|
||||
}
|
||||
|
||||
@Override
|
||||
public VolatileSurfaceManager createVolatileManager(SunVolatileImage image,
|
||||
Object context) {
|
||||
return new MTLVolatileSurfaceManager(image, context);
|
||||
}
|
||||
|
||||
@Override
|
||||
public SurfaceManager createTextureWrapperSurfaceManager(
|
||||
GraphicsConfiguration gc, Image image, long texture) {
|
||||
SurfaceData sd = MTLSurfaceData.createData(this, image, texture);
|
||||
return new TextureWrapperSurfaceManager(sd);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -47,8 +47,6 @@ import sun.awt.CGraphicsConfig;
|
||||
import sun.awt.CGraphicsDevice;
|
||||
import sun.awt.image.OffScreenImage;
|
||||
import sun.awt.image.SunVolatileImage;
|
||||
import sun.awt.image.SurfaceManager;
|
||||
import sun.awt.image.VolatileSurfaceManager;
|
||||
import sun.java2d.Disposer;
|
||||
import sun.java2d.DisposerRecord;
|
||||
import sun.java2d.Surface;
|
||||
@@ -416,10 +414,4 @@ public final class CGLGraphicsConfig extends CGraphicsConfig
|
||||
return Math.max(maxTextureSize / getDevice().getScaleFactor(),
|
||||
getBounds().height);
|
||||
}
|
||||
|
||||
@Override
|
||||
public VolatileSurfaceManager createVolatileManager(SunVolatileImage image,
|
||||
Object context) {
|
||||
return new CGLVolatileSurfaceManager(image, context);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -75,19 +75,6 @@ BOOL isColorMatchingEnabled() {
|
||||
return (BOOL)colorMatchingEnabled;
|
||||
}
|
||||
|
||||
BOOL isWindowAnimationEnabled() {
|
||||
static int windowAnimationEnabled = -1;
|
||||
if (windowAnimationEnabled == -1) {
|
||||
JNIEnv *env = [ThreadUtilities getJNIEnvUncached];
|
||||
if (env == NULL) return NO;
|
||||
NSString* windowAnimationEnabledProp = [PropertiesUtilities javaSystemPropertyForKey:@"apple.awt.window.animation"
|
||||
withEnv:env];
|
||||
windowAnimationEnabled = [@"true" isCaseInsensitiveLike:windowAnimationEnabledProp] ? YES : NO;
|
||||
J2dRlsTraceLn1(J2D_TRACE_INFO, "AWTWindow_windowAnimationEnabled: %d", windowAnimationEnabled);
|
||||
}
|
||||
return (BOOL)windowAnimationEnabled;
|
||||
}
|
||||
|
||||
@interface NSTitlebarAccessoryViewController (Private)
|
||||
- (void)_setHidden:(BOOL)h animated:(BOOL)a;
|
||||
@end
|
||||
@@ -618,10 +605,6 @@ AWT_ASSERT_APPKIT_THREAD;
|
||||
if (self.nsWindow == nil) return nil; // no hope either
|
||||
[self.nsWindow release]; // the property retains the object already
|
||||
|
||||
if (!isWindowAnimationEnabled()
|
||||
&& (self.nsWindow.animationBehavior != NSWindowAnimationBehaviorNone)) {
|
||||
self.nsWindow.animationBehavior = NSWindowAnimationBehaviorNone;
|
||||
}
|
||||
if (isColorMatchingEnabled()) {
|
||||
// Supported by both OpenGL & Metal pipelines
|
||||
// Tell the system we have an sRGB backing store
|
||||
@@ -3027,6 +3010,8 @@ JNIEXPORT void JNICALL Java_sun_lwawt_macosx_CPlatformWindow_nativeSetRoundedCor
|
||||
|
||||
NSWindow *w = (NSWindow *)jlong_to_ptr(windowPtr);
|
||||
[ThreadUtilities performOnMainThreadWaiting:NO block:^(){
|
||||
w.hasShadow = YES;
|
||||
w.contentView.wantsLayer = YES;
|
||||
w.contentView.layer.cornerRadius = radius;
|
||||
w.contentView.layer.masksToBounds = YES;
|
||||
w.contentView.layer.opaque = NO;
|
||||
@@ -3041,11 +3026,11 @@ JNIEXPORT void JNICALL Java_sun_lwawt_macosx_CPlatformWindow_nativeSetRoundedCor
|
||||
w.contentView.layer.borderWidth = borderWidth;
|
||||
w.contentView.layer.borderColor = color.CGColor;
|
||||
}
|
||||
w.contentView.wantsLayer = YES;
|
||||
|
||||
w.backgroundColor = NSColor.clearColor;
|
||||
w.opaque = NO;
|
||||
w.hasShadow = YES;
|
||||
// remove corner radius animation
|
||||
[w.contentView.layer removeAllAnimations];
|
||||
[w invalidateShadow];
|
||||
}];
|
||||
|
||||
|
||||
@@ -129,7 +129,6 @@ BOOL MTLLayer_isExtraRedrawEnabled() {
|
||||
[NSNull null], @"anchorPoint",
|
||||
[NSNull null], @"bounds",
|
||||
[NSNull null], @"contents",
|
||||
[NSNull null], @"cornerRadius",
|
||||
[NSNull null], @"contentsScale",
|
||||
[NSNull null], @"onOrderIn",
|
||||
[NSNull null], @"onOrderOut",
|
||||
|
||||
@@ -63,7 +63,6 @@ AWT_ASSERT_APPKIT_THREAD;
|
||||
[NSNull null], @"anchorPoint",
|
||||
[NSNull null], @"bounds",
|
||||
[NSNull null], @"contents",
|
||||
[NSNull null], @"cornerRadius",
|
||||
[NSNull null], @"contentsScale",
|
||||
[NSNull null], @"onOrderIn",
|
||||
[NSNull null], @"onOrderOut",
|
||||
|
||||
@@ -1,68 +0,0 @@
|
||||
/*
|
||||
* 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 com.jetbrains.desktop;
|
||||
|
||||
import com.jetbrains.exported.JBRApi;
|
||||
import sun.java2d.vulkan.VKEnv;
|
||||
import sun.java2d.vulkan.VKGPU;
|
||||
|
||||
@JBRApi.Service
|
||||
@JBRApi.Provides("Vulkan")
|
||||
public class Vulkan {
|
||||
|
||||
Vulkan() {
|
||||
if (!VKEnv.isVulkanEnabled()) throw new JBRApi.ServiceNotAvailableException("Vulkan is not enabled");
|
||||
}
|
||||
|
||||
boolean isPresentationEnabled() {
|
||||
return VKEnv.isPresentationEnabled();
|
||||
}
|
||||
|
||||
Device[] getDevices() {
|
||||
return VKEnv.getDevices().map(Device::new).toArray(Device[]::new);
|
||||
}
|
||||
|
||||
@JBRApi.Provides("Vulkan.Device")
|
||||
static class Device {
|
||||
private final VKGPU device;
|
||||
|
||||
Device(VKGPU device) {
|
||||
this.device = device;
|
||||
}
|
||||
|
||||
String getName() {
|
||||
return device.getName();
|
||||
}
|
||||
|
||||
String getTypeString() {
|
||||
return device.getType().toString();
|
||||
}
|
||||
|
||||
int getCapabilities() {
|
||||
return device.getCaps();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -27,6 +27,7 @@ package com.jetbrains.desktop.image;
|
||||
|
||||
import sun.awt.image.SurfaceManager;
|
||||
import sun.java2d.SurfaceData;
|
||||
import sun.java2d.SurfaceManagerFactory;
|
||||
|
||||
import java.awt.AlphaComposite;
|
||||
import java.awt.GraphicsConfiguration;
|
||||
@@ -70,10 +71,7 @@ public class TextureWrapperImage extends Image {
|
||||
public TextureWrapperImage(GraphicsConfiguration gc, long texture)
|
||||
throws UnsupportedOperationException, IllegalArgumentException {
|
||||
this.gc = gc;
|
||||
SurfaceManager surfaceManager;
|
||||
if (gc instanceof SurfaceManager.TextureWrapperFactory factory) {
|
||||
surfaceManager = factory.createTextureWrapperSurfaceManager(gc, this, texture);
|
||||
} else throw new UnsupportedOperationException();
|
||||
SurfaceManager surfaceManager = SurfaceManagerFactory.getInstance().createTextureWrapperSurfaceManager(gc, this, texture);
|
||||
sd = surfaceManager.getPrimarySurfaceData();
|
||||
SurfaceManager.setManager(this, surfaceManager);
|
||||
}
|
||||
|
||||
@@ -4547,11 +4547,6 @@ public class Window extends Container implements Accessible {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addWindowListener(Window w, WindowListener listener) {
|
||||
w.addWindowListener(listener);
|
||||
}
|
||||
|
||||
private static void dumpCounter(final String counterName, final double valPerSecond) {
|
||||
if (USE_COUNTERS) {
|
||||
doLog(String.format("%s per second: %.2f", counterName, valPerSecond),
|
||||
|
||||
@@ -689,27 +689,6 @@ public class BasicTreeUI extends TreeUI
|
||||
return bounds;
|
||||
}
|
||||
|
||||
/**
|
||||
* A potentially faster version of {@link #getPathBounds(JTree, TreePath)}
|
||||
* which calculates only {@code y} and {@code height}
|
||||
* of the bounding {@code Rectangle}
|
||||
*/
|
||||
private Rectangle getVerticalPathBounds(TreePath path) {
|
||||
if (tree == null || treeState == null) {
|
||||
return null;
|
||||
}
|
||||
int rowHeight = treeState.getRowHeight();
|
||||
if (rowHeight <= 0) {
|
||||
return getPathBounds(tree, path);
|
||||
}
|
||||
int row = treeState.getRowForPath(path);
|
||||
if (row < 0) {
|
||||
return null;
|
||||
}
|
||||
return new Rectangle(0, tree.getInsets().top + row * rowHeight,
|
||||
0, rowHeight);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the path for passed in row. If row is not visible
|
||||
* null is returned.
|
||||
@@ -4340,9 +4319,10 @@ public class BasicTreeUI extends TreeUI
|
||||
updateSize();
|
||||
}
|
||||
else if (treeState.isExpanded(parentPath)) {
|
||||
boolean isShowing = tree.isShowing();
|
||||
TreePath minPath = null;
|
||||
Rectangle minBounds = null;
|
||||
if (tree.isShowing()) {
|
||||
if (isShowing) {
|
||||
// Changed nodes are visible
|
||||
// Find the minimum index, we only need paint from there
|
||||
// down.
|
||||
@@ -4353,27 +4333,28 @@ public class BasicTreeUI extends TreeUI
|
||||
Object minChild = treeModel.getChild(
|
||||
parentPath.getLastPathComponent(), minIndex);
|
||||
minPath = parentPath.pathByAddingChild(minChild);
|
||||
minBounds = getVerticalPathBounds(minPath);
|
||||
minBounds = getPathBounds(tree, minPath);
|
||||
}
|
||||
|
||||
// Forward to the treestate
|
||||
treeState.treeNodesChanged(e);
|
||||
|
||||
// Mark preferred size as bogus.
|
||||
updateSize0();
|
||||
|
||||
if (minBounds != null) {
|
||||
if (isShowing) {
|
||||
// And repaint
|
||||
Rectangle newMinBounds = getVerticalPathBounds(minPath);
|
||||
if (newMinBounds != null) {
|
||||
if (indices.length == 1 &&
|
||||
newMinBounds.height == minBounds.height) {
|
||||
tree.repaint(0, minBounds.y, tree.getWidth(),
|
||||
minBounds.height);
|
||||
} else {
|
||||
tree.repaint(0, minBounds.y, tree.getWidth(),
|
||||
tree.getHeight() - minBounds.y);
|
||||
}
|
||||
Rectangle newMinBounds = getPathBounds(tree, minPath);
|
||||
if (minBounds == null || newMinBounds == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (indices.length == 1 &&
|
||||
newMinBounds.height == minBounds.height) {
|
||||
tree.repaint(0, minBounds.y, tree.getWidth(),
|
||||
minBounds.height);
|
||||
} else {
|
||||
tree.repaint(0, minBounds.y, tree.getWidth(),
|
||||
tree.getHeight() - minBounds.y);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -37,7 +37,6 @@ import java.awt.event.InputEvent;
|
||||
import java.awt.event.InvocationEvent;
|
||||
import java.awt.event.KeyEvent;
|
||||
import java.awt.event.MouseEvent;
|
||||
import java.awt.event.WindowListener;
|
||||
import java.awt.geom.Point2D;
|
||||
import java.awt.image.BufferStrategy;
|
||||
import java.awt.peer.ComponentPeer;
|
||||
@@ -358,8 +357,6 @@ public final class AWTAccessor {
|
||||
double getCounterPerSecond(Window w, String counterName);
|
||||
|
||||
void dumpStats(Window w, boolean reset, StringBuilder sb);
|
||||
|
||||
void addWindowListener(Window w, WindowListener listener);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -50,7 +50,6 @@ import java.awt.KeyboardFocusManager;
|
||||
import java.awt.Label;
|
||||
import java.awt.MenuComponent;
|
||||
import java.awt.Panel;
|
||||
import java.awt.Point;
|
||||
import java.awt.RenderingHints;
|
||||
import java.awt.ScrollPane;
|
||||
import java.awt.Scrollbar;
|
||||
@@ -92,7 +91,6 @@ import java.util.concurrent.atomic.AtomicBoolean;
|
||||
import java.util.concurrent.locks.Condition;
|
||||
import java.util.concurrent.locks.ReentrantLock;
|
||||
|
||||
import com.jetbrains.exported.JBRApi;
|
||||
import sun.awt.im.InputContext;
|
||||
import sun.awt.image.ByteArrayImageSource;
|
||||
import sun.awt.image.FileImageSource;
|
||||
@@ -2148,23 +2146,6 @@ public abstract class SunToolkit extends Toolkit
|
||||
return AWTAccessor.getAWTEventAccessor().isSystemGenerated(e);
|
||||
}
|
||||
|
||||
@JBRApi.Service
|
||||
@JBRApi.Provides("RelativePointerMovement")
|
||||
public interface RelativePointerMovementInfoProvider {
|
||||
private static RelativePointerMovementInfoProvider create() {
|
||||
var tk = Toolkit.getDefaultToolkit();
|
||||
if (tk instanceof ComponentFactory cf) {
|
||||
var mouseInfoPeer = cf.getMouseInfoPeer();
|
||||
if (mouseInfoPeer instanceof RelativePointerMovementInfoProvider p){
|
||||
return p;
|
||||
}
|
||||
}
|
||||
|
||||
throw new JBRApi.ServiceNotAvailableException("Service not supported for toolkit " + tk.getClass().getName());
|
||||
}
|
||||
|
||||
Point getAccumulatedMouseDeltaAndReset();
|
||||
}
|
||||
} // class SunToolkit
|
||||
|
||||
|
||||
|
||||
@@ -37,6 +37,7 @@ import java.awt.image.BufferedImage;
|
||||
import java.awt.image.ImageObserver;
|
||||
import java.awt.image.VolatileImage;
|
||||
import sun.java2d.SunGraphics2D;
|
||||
import sun.java2d.SurfaceManagerFactory;
|
||||
import sun.java2d.DestSurfaceProvider;
|
||||
import sun.java2d.Surface;
|
||||
import sun.java2d.pipe.Region;
|
||||
@@ -157,19 +158,29 @@ public class SunVolatileImage extends VolatileImage
|
||||
return forcedAccelSurfaceType;
|
||||
}
|
||||
|
||||
private VolatileSurfaceManager createSurfaceManager(
|
||||
Object context, ImageCapabilities caps) {
|
||||
// GraphicsConfig may provide some specific surface manager
|
||||
// implementation.
|
||||
// In case it doesn't, or we were specifically requested to use
|
||||
// an unaccelerated surface, fall back to the buffered image
|
||||
// surface manager.
|
||||
if ((caps == null || caps.isAccelerated()) &&
|
||||
graphicsConfig instanceof SurfaceManager.Factory factory) {
|
||||
return factory.createVolatileManager(this, context);
|
||||
} else {
|
||||
protected VolatileSurfaceManager createSurfaceManager(Object context,
|
||||
ImageCapabilities caps)
|
||||
{
|
||||
/**
|
||||
* Platform-specific SurfaceManagerFactories will return a
|
||||
* manager suited to acceleration on each platform. But if
|
||||
* the user is asking for a VolatileImage from a BufferedImageGC,
|
||||
* then we need to return the appropriate unaccelerated manager.
|
||||
* Note: this could change in the future; if some platform would
|
||||
* like to accelerate BIGC volatile images, then this special-casing
|
||||
* of the BIGC graphicsConfig should live in platform-specific
|
||||
* code instead.
|
||||
* We do the same for a Printer Device, and if user requested an
|
||||
* unaccelerated VolatileImage by passing the capabilities object.
|
||||
*/
|
||||
if (graphicsConfig instanceof BufferedImageGraphicsConfig ||
|
||||
graphicsConfig instanceof sun.print.PrinterGraphicsConfig ||
|
||||
(caps != null && !caps.isAccelerated()))
|
||||
{
|
||||
return new BufImgVolatileSurfaceManager(this, context);
|
||||
}
|
||||
SurfaceManagerFactory smf = SurfaceManagerFactory.getInstance();
|
||||
return smf.createVolatileManager(this, context);
|
||||
}
|
||||
|
||||
private Color getForeground() {
|
||||
|
||||
@@ -184,31 +184,6 @@ public abstract class SurfaceManager {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* See TextureWrapperImage.
|
||||
*/
|
||||
public interface TextureWrapperFactory {
|
||||
SurfaceManager createTextureWrapperSurfaceManager(
|
||||
GraphicsConfiguration gc, Image image, long texture);
|
||||
}
|
||||
|
||||
/**
|
||||
* An interface for GraphicsConfiguration objects to implement if
|
||||
* they create their own VolatileSurfaceManager implementations.
|
||||
*/
|
||||
public interface Factory {
|
||||
|
||||
/**
|
||||
* Creates a new instance of a VolatileSurfaceManager given a
|
||||
* compatible SunVolatileImage.
|
||||
* An optional context Object can be supplied as a way for the caller
|
||||
* to pass pipeline-specific context data to the VolatileSurfaceManager
|
||||
* (such as a backbuffer handle, for example).
|
||||
*/
|
||||
VolatileSurfaceManager createVolatileManager(SunVolatileImage image,
|
||||
Object context);
|
||||
}
|
||||
|
||||
/**
|
||||
* An interface for GraphicsConfiguration objects to implement if
|
||||
* their surfaces accelerate images using SurfaceDataProxy objects.
|
||||
@@ -227,8 +202,7 @@ public abstract class SurfaceManager {
|
||||
}
|
||||
|
||||
public static class ProxyCache {
|
||||
private final Map<SurfaceManager, SurfaceDataProxy> map =
|
||||
Collections.synchronizedMap(new WeakHashMap<>());
|
||||
private final Map<SurfaceManager, SurfaceDataProxy> map = Collections.synchronizedMap(new WeakHashMap<>());
|
||||
|
||||
/**
|
||||
* Return a cached SurfaceDataProxy object for a given SurfaceManager.
|
||||
@@ -279,8 +253,7 @@ public abstract class SurfaceManager {
|
||||
|
||||
void flush(boolean deaccelerate) {
|
||||
synchronized (weakCache) {
|
||||
Iterator<WeakReference<SurfaceDataProxy>> i =
|
||||
weakCache.values().iterator();
|
||||
Iterator<WeakReference<SurfaceDataProxy>> i = weakCache.values().iterator();
|
||||
while (i.hasNext()) {
|
||||
SurfaceDataProxy sdp = i.next().get();
|
||||
if (sdp == null || sdp.flush(deaccelerate)) {
|
||||
|
||||
@@ -0,0 +1,97 @@
|
||||
/*
|
||||
* Copyright (c) 2003, 2008, Oracle and/or its affiliates. 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.
|
||||
*/
|
||||
|
||||
package sun.java2d;
|
||||
|
||||
import sun.awt.image.SunVolatileImage;
|
||||
import sun.awt.image.SurfaceManager;
|
||||
import sun.awt.image.VolatileSurfaceManager;
|
||||
|
||||
import java.awt.GraphicsConfiguration;
|
||||
import java.awt.Image;
|
||||
|
||||
/**
|
||||
* This factory creates platform specific VolatileSurfaceManager
|
||||
* implementations.
|
||||
*
|
||||
* There are two platform specific SurfaceManagerFactories in OpenJDK,
|
||||
* UnixSurfaceManagerFactory and WindowsSurfaceManagerFactory.
|
||||
* The actually used SurfaceManagerFactory is set by the respective platform
|
||||
* GraphicsEnvironment implementations in the static initializer.
|
||||
*/
|
||||
public abstract class SurfaceManagerFactory {
|
||||
|
||||
/**
|
||||
* The single shared instance.
|
||||
*/
|
||||
private static SurfaceManagerFactory instance;
|
||||
|
||||
/**
|
||||
* Returns the surface manager factory instance. This returns a factory
|
||||
* that has been set by {@link #setInstance(SurfaceManagerFactory)}.
|
||||
*
|
||||
* @return the surface manager factory
|
||||
*/
|
||||
public static synchronized SurfaceManagerFactory getInstance() {
|
||||
|
||||
if (instance == null) {
|
||||
throw new IllegalStateException("No SurfaceManagerFactory set.");
|
||||
}
|
||||
return instance;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the surface manager factory. This may only be called once, and it
|
||||
* may not be set back to {@code null} when the factory is already
|
||||
* instantiated.
|
||||
*
|
||||
* @param factory the factory to set
|
||||
*/
|
||||
public static synchronized void setInstance(SurfaceManagerFactory factory) {
|
||||
|
||||
if (factory == null) {
|
||||
// We don't want to allow setting this to null at any time.
|
||||
throw new IllegalArgumentException("factory must be non-null");
|
||||
}
|
||||
|
||||
if (instance != null) {
|
||||
// We don't want to re-set the instance at any time.
|
||||
throw new IllegalStateException("The surface manager factory is already initialized");
|
||||
}
|
||||
|
||||
instance = factory;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new instance of a VolatileSurfaceManager given any
|
||||
* arbitrary SunVolatileImage. An optional context Object can be supplied
|
||||
* as a way for the caller to pass pipeline-specific context data to
|
||||
* the VolatileSurfaceManager (such as a backbuffer handle, for example).
|
||||
*/
|
||||
public abstract VolatileSurfaceManager
|
||||
createVolatileManager(SunVolatileImage image, Object context);
|
||||
|
||||
public abstract SurfaceManager createTextureWrapperSurfaceManager(GraphicsConfiguration gc, Image image, long texture);
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2007, 2025, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2007, 2021, Oracle and/or its affiliates. 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
|
||||
@@ -144,9 +144,7 @@ final class Curve {
|
||||
// finds points where the first and second derivative are
|
||||
// perpendicular. This happens when g(t) = f'(t)*f''(t) == 0 (where
|
||||
// * is a dot product). Unfortunately, we have to solve a cubic.
|
||||
private int perpendiculardfddf(final double[] pts, final int off,
|
||||
final double A, final double B)
|
||||
{
|
||||
private int perpendiculardfddf(final double[] pts, final int off) {
|
||||
assert pts.length >= off + 4;
|
||||
|
||||
// these are the coefficients of some multiple of g(t) (not g(t),
|
||||
@@ -157,7 +155,7 @@ final class Curve {
|
||||
final double c = 2.0d * (dax * cx + day * cy) + dbx * dbx + dby * dby;
|
||||
final double d = dbx * cx + dby * cy;
|
||||
|
||||
return Helpers.cubicRootsInAB(a, b, c, d, pts, off, A, B);
|
||||
return Helpers.cubicRootsInAB(a, b, c, d, pts, off, 0.0d, 1.0d);
|
||||
}
|
||||
|
||||
// Tries to find the roots of the function ROC(t)-w in [0, 1). It uses
|
||||
@@ -173,43 +171,35 @@ final class Curve {
|
||||
// at most 4 sub-intervals of (0,1). ROC has asymptotes at inflection
|
||||
// points, so roc-w can have at least 6 roots. This shouldn't be a
|
||||
// problem for what we're trying to do (draw a nice looking curve).
|
||||
int rootsOfROCMinusW(final double[] roots, final int off, final double w2,
|
||||
final double A, final double B)
|
||||
{
|
||||
int rootsOfROCMinusW(final double[] roots, final int off, final double w2, final double err) {
|
||||
// no OOB exception, because by now off<=6, and roots.length >= 10
|
||||
assert off <= 6 && roots.length >= 10;
|
||||
|
||||
int ret = off;
|
||||
final int end = off + perpendiculardfddf(roots, off, A, B);
|
||||
Helpers.isort(roots, off, end);
|
||||
final int end = off + perpendiculardfddf(roots, off);
|
||||
roots[end] = 1.0d; // always check interval end points
|
||||
|
||||
double t0 = 0.0d;
|
||||
double ft0 = eliminateInf(ROCsq(t0) - w2);
|
||||
double t1, ft1;
|
||||
double t0 = 0.0d, ft0 = ROCsq(t0) - w2;
|
||||
|
||||
for (int i = off; i <= end; i++) {
|
||||
t1 = roots[i];
|
||||
ft1 = eliminateInf(ROCsq(t1) - w2);
|
||||
double t1 = roots[i], ft1 = ROCsq(t1) - w2;
|
||||
if (ft0 == 0.0d) {
|
||||
roots[ret++] = t0;
|
||||
} else if (ft1 * ft0 < 0.0d) { // have opposite signs
|
||||
// (ROC(t)^2 == w^2) == (ROC(t) == w) is true because
|
||||
// ROC(t) >= 0 for all t.
|
||||
roots[ret++] = falsePositionROCsqMinusX(t0, t1, ft0, ft1, w2, A); // A = err
|
||||
roots[ret++] = falsePositionROCsqMinusX(t0, t1, w2, err);
|
||||
}
|
||||
t0 = t1;
|
||||
ft0 = ft1;
|
||||
}
|
||||
|
||||
return ret - off;
|
||||
}
|
||||
|
||||
private final static double MAX_ROC_SQ = 1e20;
|
||||
|
||||
private static double eliminateInf(final double x2) {
|
||||
// limit the value of x to avoid numerical problems (smaller step):
|
||||
// must handle NaN and +Infinity:
|
||||
return (x2 <= MAX_ROC_SQ) ? x2 : MAX_ROC_SQ;
|
||||
private static double eliminateInf(final double x) {
|
||||
return (x == Double.POSITIVE_INFINITY ? Double.MAX_VALUE :
|
||||
(x == Double.NEGATIVE_INFINITY ? Double.MIN_VALUE : x));
|
||||
}
|
||||
|
||||
// A slight modification of the false position algorithm on wikipedia.
|
||||
@@ -220,18 +210,17 @@ final class Curve {
|
||||
// and turn out. Same goes for the newton's method
|
||||
// algorithm in Helpers.java
|
||||
private double falsePositionROCsqMinusX(final double t0, final double t1,
|
||||
final double ft0, final double ft1,
|
||||
final double w2, final double err)
|
||||
{
|
||||
final int iterLimit = 100;
|
||||
int side = 0;
|
||||
double s = t0, fs = eliminateInf(ft0);
|
||||
double t = t1, ft = eliminateInf(ft1);
|
||||
double t = t1, ft = eliminateInf(ROCsq(t) - w2);
|
||||
double s = t0, fs = eliminateInf(ROCsq(s) - w2);
|
||||
double r = s, fr;
|
||||
|
||||
for (int i = 0; i < iterLimit && Math.abs(t - s) > err; i++) {
|
||||
for (int i = 0; i < iterLimit && Math.abs(t - s) > err * Math.abs(t + s); i++) {
|
||||
r = (fs * t - ft * s) / (fs - ft);
|
||||
fr = eliminateInf(ROCsq(r) - w2);
|
||||
fr = ROCsq(r) - w2;
|
||||
if (sameSign(fr, ft)) {
|
||||
ft = fr; t = r;
|
||||
if (side < 0) {
|
||||
@@ -252,7 +241,7 @@ final class Curve {
|
||||
break;
|
||||
}
|
||||
}
|
||||
return (Math.abs(ft) <= Math.abs(fs)) ? t : s;
|
||||
return r;
|
||||
}
|
||||
|
||||
private static boolean sameSign(final double x, final double y) {
|
||||
@@ -267,9 +256,9 @@ final class Curve {
|
||||
final double dy = t * (t * day + dby) + cy;
|
||||
final double ddx = 2.0d * dax * t + dbx;
|
||||
final double ddy = 2.0d * day * t + dby;
|
||||
final double dx2dy2 = dx * dx + dy * dy; // positive
|
||||
final double dxddyddxdy = dx * ddy - dy * ddx;
|
||||
// may return +Infinity if dxddyddxdy = 0 or NaN if 0/0:
|
||||
return (dx2dy2 * dx2dy2 * dx2dy2) / (dxddyddxdy * dxddyddxdy); // both positive
|
||||
final double dx2dy2 = dx * dx + dy * dy;
|
||||
final double ddx2ddy2 = ddx * ddx + ddy * ddy;
|
||||
final double ddxdxddydy = ddx * dx + ddy * dy;
|
||||
return dx2dy2 * ((dx2dy2 * dx2dy2) / (dx2dy2 * ddx2ddy2 - ddxdxddydy * ddxdxddydy));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2007, 2025, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2007, 2023, Oracle and/or its affiliates. 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
|
||||
@@ -566,7 +566,7 @@ public final class DMarlinRenderingEngine extends RenderingEngine
|
||||
}
|
||||
|
||||
private static boolean nearZero(final double num) {
|
||||
return Math.abs(num) < 2.0d * Helpers.ulp(num);
|
||||
return Math.abs(num) < 2.0d * Math.ulp(num);
|
||||
}
|
||||
|
||||
abstract static class NormalizingPathIterator implements PathIterator {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2007, 2025, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2007, 2022, Oracle and/or its affiliates. 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
|
||||
@@ -31,19 +31,12 @@ import sun.java2d.marlin.stats.StatLong;
|
||||
|
||||
final class Helpers implements MarlinConst {
|
||||
|
||||
private final static double T_ERR = 1e-4;
|
||||
private final static double T_A = T_ERR;
|
||||
private final static double T_B = 1.0 - T_ERR;
|
||||
|
||||
private static final double EPS = 1e-9d;
|
||||
|
||||
private Helpers() {
|
||||
throw new Error("This is a non instantiable class");
|
||||
}
|
||||
|
||||
/** use lower precision like former Pisces and Marlin (float-precision) */
|
||||
static double ulp(final double value) { return Math.ulp((float)value); }
|
||||
|
||||
static boolean within(final double x, final double y) {
|
||||
return within(x, y, EPS);
|
||||
}
|
||||
@@ -329,10 +322,10 @@ final class Helpers implements MarlinConst {
|
||||
|
||||
// now we must subdivide at points where one of the offset curves will have
|
||||
// a cusp. This happens at ts where the radius of curvature is equal to w.
|
||||
ret += c.rootsOfROCMinusW(ts, ret, w2, T_A, T_B);
|
||||
ret += c.rootsOfROCMinusW(ts, ret, w2, 0.0001d);
|
||||
|
||||
ret = filterOutNotInAB(ts, 0, ret, T_A, T_B);
|
||||
isort(ts, 0, ret);
|
||||
ret = filterOutNotInAB(ts, 0, ret, 0.0001d, 0.9999d);
|
||||
isort(ts, ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -361,7 +354,7 @@ final class Helpers implements MarlinConst {
|
||||
if ((outCodeOR & OUTCODE_BOTTOM) != 0) {
|
||||
ret += curve.yPoints(ts, ret, clipRect[1]);
|
||||
}
|
||||
isort(ts, 0, ret);
|
||||
isort(ts, ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -381,11 +374,11 @@ final class Helpers implements MarlinConst {
|
||||
}
|
||||
}
|
||||
|
||||
static void isort(final double[] a, final int off, final int len) {
|
||||
for (int i = off + 1, j; i < len; i++) {
|
||||
static void isort(final double[] a, final int len) {
|
||||
for (int i = 1, j; i < len; i++) {
|
||||
final double ai = a[i];
|
||||
j = i - 1;
|
||||
for (; j >= off && a[j] > ai; j--) {
|
||||
for (; j >= 0 && a[j] > ai; j--) {
|
||||
a[j + 1] = a[j];
|
||||
}
|
||||
a[j + 1] = ai;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2007, 2025, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2007, 2023, Oracle and/or its affiliates. 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
|
||||
@@ -886,8 +886,8 @@ final class Stroker implements StartFlagPathConsumer2D, MarlinConst {
|
||||
|
||||
// if p1 == p2 && p3 == p4: draw line from p1->p4, unless p1 == p4,
|
||||
// in which case ignore if p1 == p2
|
||||
final boolean p1eqp2 = Helpers.withinD(dx1, dy1, 6.0d * Helpers.ulp(y2));
|
||||
final boolean p3eqp4 = Helpers.withinD(dx4, dy4, 6.0d * Helpers.ulp(y4));
|
||||
final boolean p1eqp2 = Helpers.withinD(dx1, dy1, 6.0d * Math.ulp(y2));
|
||||
final boolean p3eqp4 = Helpers.withinD(dx4, dy4, 6.0d * Math.ulp(y4));
|
||||
|
||||
if (p1eqp2 && p3eqp4) {
|
||||
return getLineOffsets(x1, y1, x4, y4, leftOff, rightOff);
|
||||
@@ -905,7 +905,7 @@ final class Stroker implements StartFlagPathConsumer2D, MarlinConst {
|
||||
final double l1sq = dx1 * dx1 + dy1 * dy1;
|
||||
final double l4sq = dx4 * dx4 + dy4 * dy4;
|
||||
|
||||
if (Helpers.within(dotsq, l1sq * l4sq, 4.0d * Helpers.ulp(dotsq))) {
|
||||
if (Helpers.within(dotsq, l1sq * l4sq, 4.0d * Math.ulp(dotsq))) {
|
||||
return getLineOffsets(x1, y1, x4, y4, leftOff, rightOff);
|
||||
}
|
||||
|
||||
@@ -1078,8 +1078,8 @@ final class Stroker implements StartFlagPathConsumer2D, MarlinConst {
|
||||
// equal if they're very close to each other.
|
||||
|
||||
// if p1 == p2 or p2 == p3: draw line from p1->p3
|
||||
final boolean p1eqp2 = Helpers.withinD(dx12, dy12, 6.0d * Helpers.ulp(y2));
|
||||
final boolean p2eqp3 = Helpers.withinD(dx23, dy23, 6.0d * Helpers.ulp(y3));
|
||||
final boolean p1eqp2 = Helpers.withinD(dx12, dy12, 6.0d * Math.ulp(y2));
|
||||
final boolean p2eqp3 = Helpers.withinD(dx23, dy23, 6.0d * Math.ulp(y3));
|
||||
|
||||
if (p1eqp2 || p2eqp3) {
|
||||
return getLineOffsets(x1, y1, x3, y3, leftOff, rightOff);
|
||||
@@ -1091,7 +1091,7 @@ final class Stroker implements StartFlagPathConsumer2D, MarlinConst {
|
||||
final double l1sq = dx12 * dx12 + dy12 * dy12;
|
||||
final double l3sq = dx23 * dx23 + dy23 * dy23;
|
||||
|
||||
if (Helpers.within(dotsq, l1sq * l3sq, 4.0d * Helpers.ulp(dotsq))) {
|
||||
if (Helpers.within(dotsq, l1sq * l3sq, 4.0d * Math.ulp(dotsq))) {
|
||||
return getLineOffsets(x1, y1, x3, y3, leftOff, rightOff);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2015, 2025, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2015, 2023, Oracle and/or its affiliates. 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
|
||||
@@ -27,7 +27,7 @@ package sun.java2d.marlin;
|
||||
|
||||
public final class Version {
|
||||
|
||||
private static final String VERSION = "marlin-0.9.4.9-Unsafe-OpenJDK";
|
||||
private static final String VERSION = "marlin-0.9.4.7-Unsafe-OpenJDK";
|
||||
|
||||
public static String getVersion() {
|
||||
return VERSION;
|
||||
|
||||
@@ -31,20 +31,18 @@ package sun.java2d.marlin.stats;
|
||||
public class StatLong {
|
||||
|
||||
public final String name;
|
||||
public long count = 0L;
|
||||
public long sum = 0L;
|
||||
public long min = Integer.MAX_VALUE;
|
||||
public long max = Integer.MIN_VALUE;
|
||||
public long count, sum, min, max;
|
||||
|
||||
public StatLong(final String name) {
|
||||
this.name = name;
|
||||
reset();
|
||||
}
|
||||
|
||||
public void reset() {
|
||||
count = 0L;
|
||||
sum = 0L;
|
||||
min = Integer.MAX_VALUE;
|
||||
max = Integer.MIN_VALUE;
|
||||
min = Long.MAX_VALUE;
|
||||
max = Long.MIN_VALUE;
|
||||
}
|
||||
|
||||
public void add(final int val) {
|
||||
@@ -78,7 +76,7 @@ public class StatLong {
|
||||
sb.append(name).append('[').append(count);
|
||||
sb.append("] sum: ").append(sum).append(" avg: ");
|
||||
sb.append(trimTo3Digits(((double) sum) / count));
|
||||
sb.append(" [").append(min).append(" | ").append(max).append("]");
|
||||
sb.append(" [").append(min).append(" - ").append(max).append("]");
|
||||
return sb;
|
||||
}
|
||||
|
||||
@@ -89,7 +87,7 @@ public class StatLong {
|
||||
* @return double value with only 3 decimal digits
|
||||
*/
|
||||
public static double trimTo3Digits(final double value) {
|
||||
return ((long) (1e3d * value)) / 1e3d;
|
||||
return Double.isFinite(value) ? ((long) (1e3d * value)) / 1e3d : Double.NaN;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -35,7 +35,7 @@ import sun.java2d.pipe.hw.AccelGraphicsConfig;
|
||||
* methods directly from OGLSurfaceData.
|
||||
*/
|
||||
interface OGLGraphicsConfig extends
|
||||
AccelGraphicsConfig, SurfaceManager.ProxiedGraphicsConfig, SurfaceManager.Factory
|
||||
AccelGraphicsConfig, SurfaceManager.ProxiedGraphicsConfig
|
||||
{
|
||||
OGLContext getContext();
|
||||
long getNativeConfigInfo();
|
||||
|
||||
@@ -48,7 +48,7 @@ public final class VKEnv {
|
||||
|
||||
@SuppressWarnings("removal")
|
||||
private static final boolean accelsd = vulkan && "true".equalsIgnoreCase(AccessController.doPrivileged(
|
||||
(PrivilegedAction<String>) () -> System.getProperty("sun.java2d.vulkan.accelsd", "true")));
|
||||
(PrivilegedAction<String>) () -> System.getProperty("sun.java2d.vulkan.accelsd", "")));
|
||||
|
||||
@SuppressWarnings("removal")
|
||||
private static final int deviceNumber = !vulkan ? 0 : AccessController.doPrivileged(
|
||||
|
||||
@@ -33,6 +33,7 @@ import sun.awt.image.SunVolatileImage;
|
||||
import sun.awt.image.SurfaceManager;
|
||||
import sun.awt.image.VolatileSurfaceManager;
|
||||
import sun.java2d.Surface;
|
||||
import sun.java2d.SurfaceManagerFactory;
|
||||
import sun.java2d.pipe.BufferedContext;
|
||||
import sun.java2d.pipe.hw.AccelGraphicsConfig;
|
||||
import sun.java2d.pipe.hw.AccelTypedVolatileImage;
|
||||
@@ -53,9 +54,8 @@ import static sun.java2d.pipe.hw.AccelSurface.TEXTURE;
|
||||
* for most of the methods, including base methods of GraphicsConfiguration class.
|
||||
*/
|
||||
public interface VKGraphicsConfig extends AccelGraphicsConfig,
|
||||
SurfaceManager.ProxiedGraphicsConfig, SurfaceManager.Factory {
|
||||
SurfaceManager.ProxiedGraphicsConfig {
|
||||
|
||||
@Override
|
||||
default VolatileSurfaceManager createVolatileManager(SunVolatileImage image,
|
||||
Object context) {
|
||||
return new VKVolatileSurfaceManager(image, context);
|
||||
|
||||
@@ -36,7 +36,6 @@ import sun.java2d.loops.CompositeType;
|
||||
import sun.java2d.loops.GraphicsPrimitive;
|
||||
import sun.java2d.loops.SurfaceType;
|
||||
import static sun.java2d.pipe.BufferedOpCodes.CONFIGURE_SURFACE;
|
||||
import static sun.java2d.pipe.BufferedOpCodes.DISPOSE_SURFACE;
|
||||
import sun.java2d.pipe.BufferedContext;
|
||||
import sun.java2d.pipe.ParallelogramPipe;
|
||||
import sun.java2d.pipe.PixelToParallelogramConverter;
|
||||
@@ -44,6 +43,7 @@ import sun.java2d.pipe.RenderBuffer;
|
||||
import sun.java2d.pipe.TextPipe;
|
||||
import sun.java2d.pipe.hw.AccelSurface;
|
||||
import java.awt.GraphicsConfiguration;
|
||||
import java.awt.GraphicsEnvironment;
|
||||
import java.awt.Rectangle;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.awt.image.Raster;
|
||||
@@ -137,28 +137,6 @@ public abstract class VKSurfaceData extends SurfaceData
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Disposes the native resources associated with the given VKSurfaceData
|
||||
* (referenced by the pData parameter). This method is invoked from
|
||||
* the native Dispose() method from the Disposer thread when the
|
||||
* Java-level VKSurfaceData object is about to go away.
|
||||
*/
|
||||
static void dispose(long pData) {
|
||||
VKRenderQueue rq = VKRenderQueue.getInstance();
|
||||
rq.lock();
|
||||
try {
|
||||
RenderBuffer buf = rq.getBuffer();
|
||||
rq.ensureCapacityAndAlignment(12, 4);
|
||||
buf.putInt(DISPOSE_SURFACE);
|
||||
buf.putLong(pData);
|
||||
|
||||
// this call is expected to complete synchronously, so flush now
|
||||
rq.flushNow();
|
||||
} finally {
|
||||
rq.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
public BufferedImage getSnapshot(int x, int y, int width, int height) {
|
||||
BufferedImage image = getFormat().createCompatibleImage(width, height, getTransparency());
|
||||
SurfaceData sd = SurfaceData.getPrimarySurfaceData(image);
|
||||
|
||||
20
src/java.desktop/share/glsl/vulkan/alpha_type.glsl
Normal file
20
src/java.desktop/share/glsl/vulkan/alpha_type.glsl
Normal file
@@ -0,0 +1,20 @@
|
||||
|
||||
#define ALPHA_TYPE_PRE_MULTIPLIED 0U
|
||||
#define ALPHA_TYPE_STRAIGHT 1U
|
||||
|
||||
vec4 convertAlpha(vec4 color, uint inType, uint outType) {
|
||||
if (inType == ALPHA_TYPE_STRAIGHT && outType == ALPHA_TYPE_PRE_MULTIPLIED) {
|
||||
return vec4(color.rgb * color.a, color.a);
|
||||
} else if (inType == ALPHA_TYPE_PRE_MULTIPLIED && outType == ALPHA_TYPE_STRAIGHT && color.a > 0.0) {
|
||||
return vec4(color.rgb / color.a, color.a);
|
||||
} else return color;
|
||||
}
|
||||
|
||||
#ifdef ALPHA_TYPE_SPEC_INDEX
|
||||
layout (constant_id = ALPHA_TYPE_SPEC_INDEX ) const uint const_InAlphaType = ALPHA_TYPE_PRE_MULTIPLIED;
|
||||
layout (constant_id = ALPHA_TYPE_SPEC_INDEX+1) const uint const_OutAlphaType = ALPHA_TYPE_PRE_MULTIPLIED;
|
||||
|
||||
vec4 convertAlpha(vec4 color) {
|
||||
return convertAlpha(color, const_InAlphaType, const_OutAlphaType);
|
||||
}
|
||||
#endif
|
||||
@@ -1,7 +1,7 @@
|
||||
#version 450
|
||||
#extension GL_GOOGLE_include_directive: require
|
||||
#include "common.glsl"
|
||||
DEFAULT_PUSH_CONSTANTS();
|
||||
#define ALPHA_TYPE_SPEC_INDEX 0
|
||||
#include "alpha_type.glsl"
|
||||
|
||||
layout(set = 0, binding = 0) uniform texture2D u_Texture;
|
||||
layout(set = 1, binding = 0) uniform sampler u_Sampler;
|
||||
@@ -9,5 +9,5 @@ layout(location = 0) in vec2 in_TexCoord;
|
||||
layout(location = 0) out vec4 out_Color;
|
||||
|
||||
void main() {
|
||||
out_Color = APPLY_COMPOSITE(convertAlpha(texture(sampler2D(u_Texture, u_Sampler), in_TexCoord)));
|
||||
out_Color = convertAlpha(texture(sampler2D(u_Texture, u_Sampler), in_TexCoord));
|
||||
}
|
||||
|
||||
@@ -1,12 +1,14 @@
|
||||
#version 450
|
||||
#extension GL_GOOGLE_include_directive: require
|
||||
#include "common.glsl"
|
||||
|
||||
layout(push_constant) uniform PushConstants {
|
||||
mat2x3 transform;
|
||||
} push;
|
||||
|
||||
layout(location = 0) in vec2 in_Position;
|
||||
layout(location = 1) in vec2 in_TexCoord;
|
||||
layout(location = 0) out vec2 out_TexCoord;
|
||||
|
||||
void main() {
|
||||
gl_Position = transformToDeviceSpace(in_Position);
|
||||
gl_Position = vec4(vec3(in_Position, 1.0)*push.transform, 0.0, 1.0);
|
||||
out_TexCoord = in_TexCoord;
|
||||
}
|
||||
@@ -1,9 +1,11 @@
|
||||
#version 450
|
||||
#extension GL_GOOGLE_include_directive: require
|
||||
#include "common.glsl"
|
||||
|
||||
layout(push_constant) uniform PushConstants {
|
||||
mat2x3 transform;
|
||||
} push;
|
||||
|
||||
layout(location = 0) in ivec2 in_Position;
|
||||
|
||||
void main() {
|
||||
gl_Position = transformToDeviceSpace(in_Position);
|
||||
gl_Position = vec4(vec3(in_Position, 1)*push.transform, 0.0, 1.0);
|
||||
}
|
||||
@@ -1,12 +1,14 @@
|
||||
#version 450
|
||||
#extension GL_GOOGLE_include_directive: require
|
||||
#include "common.glsl"
|
||||
|
||||
layout(push_constant) uniform PushConstants {
|
||||
mat2x3 transform;
|
||||
} push;
|
||||
|
||||
layout(location = 0) in vec2 in_Position;
|
||||
layout(location = 1) in uint in_Color;
|
||||
layout(location = 1) in vec4 in_Color;
|
||||
layout(location = 0) out flat vec4 out_Color;
|
||||
|
||||
void main() {
|
||||
gl_Position = transformToDeviceSpace(in_Position);
|
||||
out_Color = convertAlpha(decodeColor(in_Color)); // No need to APPLY_COMPOSITE - it was already done on the host.
|
||||
gl_Position = vec4(vec3(in_Position, 1)*push.transform, 0.0, 1.0);
|
||||
out_Color = in_Color;
|
||||
}
|
||||
@@ -1,103 +0,0 @@
|
||||
|
||||
// Shader specialization.
|
||||
#define SHADER_MOD_XOR 1U // Xor composite mode
|
||||
#define SHADER_MOD_MASK 2U // MASK_FILL / MASK_BLIT
|
||||
|
||||
layout (constant_id = 0) const uint const_InAlphaType = 0;
|
||||
layout (constant_id = 1) const uint const_OutAlphaType = 0;
|
||||
layout (constant_id = 2) const uint const_ShaderVariant = 0;
|
||||
layout (constant_id = 3) const uint const_ShaderModifier = 0;
|
||||
|
||||
// Host structs.
|
||||
struct VKTransform {
|
||||
float m00, m01, m02;
|
||||
float m10, m11, m12;
|
||||
};
|
||||
struct VKCompositeConstants {
|
||||
uint xorColor;
|
||||
float extraAlpha;
|
||||
};
|
||||
|
||||
// Vertex shader transformation support.
|
||||
#ifdef STAGE_VERT
|
||||
layout(push_constant) uniform PushConstants { VKTransform transform; } push;
|
||||
|
||||
vec4 transformToDeviceSpace(vec2 v) {
|
||||
return vec4(vec3(v, 1.0) * mat2x3(push.transform.m00, push.transform.m01, push.transform.m02, push.transform.m10, push.transform.m11, push.transform.m12), 0.0, 1.0);
|
||||
}
|
||||
#endif
|
||||
|
||||
// Fragment shader push constant support.
|
||||
#ifdef STAGE_FRAG
|
||||
#define PUSH_CONSTANTS_IMPL(STATEMENT) \
|
||||
layout(push_constant) uniform PushConstants { VKTransform _; VKCompositeConstants push_composite; STATEMENT }
|
||||
#define DEFAULT_PUSH_CONSTANTS() PUSH_CONSTANTS_IMPL(STAGE_FRAG)
|
||||
#define PUSH_CONSTANTS(TYPE) PUSH_CONSTANTS_IMPL(TYPE push;)
|
||||
#endif
|
||||
|
||||
// Color conversion support.
|
||||
#define ALPHA_TYPE_PRE_MULTIPLIED 0U
|
||||
#define ALPHA_TYPE_STRAIGHT 1U
|
||||
|
||||
vec4 convertAlpha(vec4 color, uint inType, uint outType) {
|
||||
if (inType == ALPHA_TYPE_STRAIGHT && outType == ALPHA_TYPE_PRE_MULTIPLIED) {
|
||||
return vec4(color.rgb * color.a, color.a);
|
||||
} else if (inType == ALPHA_TYPE_PRE_MULTIPLIED && outType == ALPHA_TYPE_STRAIGHT && color.a > 0.0) {
|
||||
return vec4(color.rgb / color.a, color.a);
|
||||
} else return color;
|
||||
}
|
||||
|
||||
vec4 convertAlpha(vec4 color) {
|
||||
return convertAlpha(color, const_InAlphaType, const_OutAlphaType);
|
||||
}
|
||||
|
||||
// When applying alpha to a color, straight alpha only multiplies alpha,
|
||||
// and pre-multiplied multiplies the whole color. Use this for convenience.
|
||||
vec4 alphaMask(float alpha, uint alphaType) {
|
||||
return alphaType == ALPHA_TYPE_PRE_MULTIPLIED ? vec4(alpha) : vec4(1.0, 1.0, 1.0, alpha);
|
||||
}
|
||||
|
||||
// Decode color from uint-packed ARGB components.
|
||||
vec4 decodeColor(uint srgb) {
|
||||
return vec4((uvec4(srgb) >> uvec4(16, 8, 0, 24)) & 0xFFU) / 255.0;
|
||||
}
|
||||
|
||||
#ifdef STAGE_FRAG
|
||||
// Before outputting the color, some post-processing is needed:
|
||||
// - For alpha composite, apply extra alpha.
|
||||
// - For XOR composite, apply xor.
|
||||
vec4 applyComposite(vec4 color, VKCompositeConstants composite) {
|
||||
if ((const_ShaderModifier & SHADER_MOD_XOR) != 0) {
|
||||
uvec4 xor = uvec4(composite.xorColor) >> uvec4(16, 8, 0, 24);
|
||||
xor = (uvec4(color * 255.0) ^ xor) & 0xFFU;
|
||||
return vec4(xor) / 255.0;
|
||||
} else return color * alphaMask(composite.extraAlpha, const_OutAlphaType);
|
||||
}
|
||||
#define APPLY_COMPOSITE(COLOR) applyComposite(COLOR, push_composite)
|
||||
|
||||
// MASK_FILL / MASK_BLIT support.
|
||||
int calculateMaskIndex(vec2 localCoord, ivec4 originOffsetAndScanline) {
|
||||
ivec2 maskPos = ivec2(localCoord - vec2(originOffsetAndScanline.xy));
|
||||
int offset = originOffsetAndScanline.z;
|
||||
int scanline = originOffsetAndScanline.w;
|
||||
return offset + scanline * maskPos.y + min(scanline, maskPos.x);
|
||||
}
|
||||
vec4 applyMaskOp(vec4 color, float mask) {
|
||||
if ((const_ShaderModifier & SHADER_MOD_XOR) != 0) return color * float(mask > 0.0);
|
||||
else return color * alphaMask(mask, const_OutAlphaType);
|
||||
}
|
||||
#define APPLY_MASK(COLOR) applyMaskOp(COLOR, imageLoad(u_Mask, calculateMaskIndex(gl_FragCoord.xy, in_OriginOffsetAndScanline)).r)
|
||||
|
||||
// Generic shader support.
|
||||
#define GENERIC_INOUT() \
|
||||
layout(location = 0) out vec4 out_Color; \
|
||||
layout(location = 0) in vec2 in_Position; \
|
||||
layout(location = 1) in flat uint in_Data; \
|
||||
layout(location = 2) in flat ivec4 in_OriginOffsetAndScanline; \
|
||||
layout(origin_upper_left) in vec4 gl_FragCoord; \
|
||||
layout(set = 0, binding = 0, r8) uniform readonly restrict imageBuffer u_Mask
|
||||
|
||||
// Generic color output - handles composite and mask automatically.
|
||||
#define OUTPUT(COLOR) out_Color = COLOR; out_Color = APPLY_COMPOSITE(out_Color); \
|
||||
if ((const_ShaderModifier & SHADER_MOD_MASK) != 0) out_Color = APPLY_MASK(out_Color)
|
||||
#endif
|
||||
@@ -1,21 +0,0 @@
|
||||
#version 450
|
||||
#extension GL_GOOGLE_include_directive: require
|
||||
#include "common.glsl"
|
||||
|
||||
#define SHADER_VARIANT_GRADIENT_CLAMP 0
|
||||
#define SHADER_VARIANT_GRADIENT_CYCLE 1
|
||||
|
||||
struct VKGradientPaintConstants {
|
||||
vec4 c0, c1;
|
||||
vec3 p;
|
||||
};
|
||||
PUSH_CONSTANTS(VKGradientPaintConstants);
|
||||
GENERIC_INOUT();
|
||||
|
||||
void main() {
|
||||
float t = dot(vec3(in_Position, 1.0), push.p);
|
||||
t = const_ShaderVariant == SHADER_VARIANT_GRADIENT_CYCLE ?
|
||||
abs(mod(t + 1.0, 2.0) - 1.0) : // Cycle
|
||||
clamp(t, 0.0, 1.0); // Clamp
|
||||
OUTPUT(convertAlpha(mix(push.c0, push.c1, t)));
|
||||
}
|
||||
@@ -1,21 +0,0 @@
|
||||
#version 450
|
||||
#extension GL_GOOGLE_include_directive: require
|
||||
#include "common.glsl"
|
||||
|
||||
layout(location = 0) in ivec4 in_PositionOffsetAndScanline;
|
||||
layout(location = 1) in uint in_Data;
|
||||
|
||||
layout(location = 0) out vec2 out_Position;
|
||||
layout(location = 1) out uint out_Data;
|
||||
|
||||
// This starts with "Origin" and not "Position" intentionally.
|
||||
// When drawing, vertices are ordered in a such way, that provoking vertex is always the top-left one.
|
||||
// This gives us an easy way to calculate offset within the rectangle without additional inputs.
|
||||
layout(location = 2) out flat ivec4 out_OriginOffsetAndScanline;
|
||||
|
||||
void main() {
|
||||
out_Position = in_PositionOffsetAndScanline.xy;
|
||||
out_Data = in_Data;
|
||||
out_OriginOffsetAndScanline = in_PositionOffsetAndScanline;
|
||||
gl_Position = transformToDeviceSpace(in_PositionOffsetAndScanline.xy);
|
||||
}
|
||||
@@ -1,6 +1,4 @@
|
||||
#version 450
|
||||
#extension GL_GOOGLE_include_directive: require
|
||||
#include "common.glsl"
|
||||
|
||||
layout(set = 0, binding = 0, r8) uniform readonly restrict imageBuffer u_Mask;
|
||||
|
||||
@@ -12,5 +10,9 @@ layout(location = 1) in flat vec4 in_Color;
|
||||
layout(location = 0) out vec4 out_Color;
|
||||
|
||||
void main() {
|
||||
out_Color = APPLY_MASK(in_Color);
|
||||
ivec2 maskPos = ivec2(gl_FragCoord.xy - vec2(in_OriginOffsetAndScanline.xy));
|
||||
int offset = in_OriginOffsetAndScanline.z;
|
||||
int scanline = in_OriginOffsetAndScanline.w;
|
||||
int maskIndex = offset + scanline * maskPos.y + min(scanline, maskPos.x);
|
||||
out_Color = in_Color * imageLoad(u_Mask, maskIndex).r;
|
||||
}
|
||||
|
||||
@@ -1,9 +1,11 @@
|
||||
#version 450
|
||||
#extension GL_GOOGLE_include_directive: require
|
||||
#include "common.glsl"
|
||||
|
||||
layout(push_constant) uniform PushConstants {
|
||||
mat2x3 transform;
|
||||
} push;
|
||||
|
||||
layout(location = 0) in ivec4 in_PositionOffsetAndScanline;
|
||||
layout(location = 1) in uint in_Color;
|
||||
layout(location = 1) in vec4 in_Color;
|
||||
|
||||
// This starts with "Origin" and not "Position" intentionally.
|
||||
// When drawing, vertices are ordered in a such way, that provoking vertex is always the top-left one.
|
||||
@@ -12,7 +14,7 @@ layout(location = 0) out flat ivec4 out_OriginOffsetAndScanline;
|
||||
layout(location = 1) out flat vec4 out_Color;
|
||||
|
||||
void main() {
|
||||
gl_Position = transformToDeviceSpace(in_PositionOffsetAndScanline.xy);
|
||||
gl_Position = vec4(vec3(in_PositionOffsetAndScanline.xy, 1)*push.transform, 0.0, 1.0);
|
||||
out_OriginOffsetAndScanline = in_PositionOffsetAndScanline;
|
||||
out_Color = convertAlpha(decodeColor(in_Color));
|
||||
out_Color = in_Color;
|
||||
}
|
||||
@@ -1,15 +0,0 @@
|
||||
#version 450
|
||||
#extension GL_GOOGLE_include_directive: require
|
||||
#include "common.glsl"
|
||||
|
||||
layout(location = 0) in vec2 in_Position;
|
||||
layout(location = 1) in uint in_Data;
|
||||
layout(location = 0) out vec2 out_Position;
|
||||
layout(location = 1) out uint out_Data;
|
||||
layout(location = 2) out flat ivec4 _; // Unused output
|
||||
|
||||
void main() {
|
||||
out_Position = in_Position;
|
||||
out_Data = in_Data;
|
||||
gl_Position = transformToDeviceSpace(in_Position);
|
||||
}
|
||||
@@ -114,7 +114,7 @@ void VKBlitLoops_IsoBlit(VKSDOps* srcOps, jint filter,
|
||||
VK_COMPONENT_SWIZZLE_ONE);
|
||||
VKPackedSwizzle swizzle = srcOpaque ? OPAQUE_SWIZZLE : 0;
|
||||
|
||||
if (!VKRenderer_Validate(SHADER_BLIT, NO_SHADER_VARIANT, VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP, alphaType)) return;
|
||||
if (!VKRenderer_Validate(SHADER_BLIT, VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP, alphaType)) return;
|
||||
VKRenderer_DrawImage(srcOps->image, srcOps->image->format, swizzle, filter, SAMPLER_WRAP_BORDER,
|
||||
(float)sx1, (float)sy1, (float)sx2, (float)sy2, (float)dx1, (float)dy1, (float)dx2, (float)dy2);
|
||||
VKRenderer_AddSurfaceDependency(srcOps, context->surface);
|
||||
@@ -170,12 +170,11 @@ void VKBlitLoops_Blit(JNIEnv *env,
|
||||
|
||||
// Need to validate render pass early, as image may not yet be configured.
|
||||
AlphaType alphaType = getSrcAlphaType(srctype);
|
||||
if (!VKRenderer_Validate(SHADER_BLIT, NO_SHADER_VARIANT, VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP, alphaType)) return;
|
||||
if (!VKRenderer_Validate(SHADER_BLIT, VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP, alphaType)) return;
|
||||
|
||||
VKDevice* device = context->surface->device;
|
||||
BlitSrcType type = decodeSrcType(device, srctype);
|
||||
VKTexturePoolHandle* imageHandle =
|
||||
VKTexturePool_GetTexture(VKRenderer_GetTexturePool(device->renderer), sw, sh, type.format);
|
||||
VKTexturePoolHandle* imageHandle = VKTexturePool_GetTexture(device->texturePool, sw, sh, type.format);
|
||||
VKImage* image = VKTexturePoolHandle_GetTexture(imageHandle);
|
||||
|
||||
VkDeviceSize dataSize = sh * sw * srcInfo.pixelStride;
|
||||
|
||||
@@ -56,7 +56,7 @@ VKComposites VKComposites_Create() {
|
||||
.colorWriteMask = VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT |
|
||||
VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT },
|
||||
{ .logicOpEnable = VK_TRUE,
|
||||
.logicOp = VK_LOGIC_OP_XOR }, ALPHA_TYPE_STRAIGHT });
|
||||
.logicOp = VK_LOGIC_OP_XOR }, ALPHA_TYPE_PRE_MULTIPLIED });
|
||||
|
||||
// NAME | SRC_COLOR | DST_COLOR | SRC_ALPHA | DST_ALPHA ||
|
||||
ALPHA_BLEND( CLEAR , ZERO , ZERO , ZERO , ZERO );
|
||||
@@ -138,6 +138,7 @@ void VKComposites_AddState(VKComposites* composites, VKCompositeMode mode, VKCom
|
||||
state.blendState.sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO;
|
||||
state.blendState.pNext = NULL;
|
||||
state.blendState.attachmentCount = 1;
|
||||
state.outAlphaType = ALPHA_TYPE_PRE_MULTIPLIED;
|
||||
MAP_AT(composites->map, (VKCompositeDescriptor) { mode, VK_FALSE }) = state;
|
||||
|
||||
// Using pre-multiplied alpha is necessary for correct blending,
|
||||
|
||||
@@ -272,6 +272,7 @@ void VKDevice_CheckAndAdd(VKEnv* vk, VkPhysicalDevice physicalDevice) {
|
||||
void VKDevice_Reset(VKDevice* device) {
|
||||
if (device == NULL) return;
|
||||
VKRenderer_Destroy(device->renderer);
|
||||
VKTexturePool_Dispose(device->texturePool);
|
||||
VKAllocator_Destroy(device->allocator);
|
||||
ARRAY_FREE(device->enabledExtensions);
|
||||
ARRAY_FREE(device->enabledLayers);
|
||||
@@ -391,4 +392,11 @@ Java_sun_java2d_vulkan_VKGPU_init(JNIEnv *env, jclass jClass, jlong jDevice) {
|
||||
JNU_ThrowByName(env, "java/lang/RuntimeException", "Vulkan: Cannot create renderer");
|
||||
return;
|
||||
}
|
||||
|
||||
device->texturePool = VKTexturePool_InitWithDevice(device);
|
||||
if (!device->texturePool) {
|
||||
VKDevice_Reset(device);
|
||||
JNU_ThrowByName(env, "java/lang/RuntimeException", "Vulkan: Cannot create texture pool");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -59,6 +59,7 @@ struct VKDevice {
|
||||
|
||||
VKAllocator* allocator;
|
||||
VKRenderer* renderer;
|
||||
VKTexturePool* texturePool;
|
||||
|
||||
DEVICE_FUNCTION_TABLE(DECL_PFN)
|
||||
SWAPCHAIN_DEVICE_FUNCTION_TABLE(DECL_PFN)
|
||||
|
||||
@@ -49,7 +49,6 @@ static size_t pipelineDescriptorHash(const void* ptr) {
|
||||
hash(&h, d->inAlphaType);
|
||||
hash(&h, d->composite);
|
||||
hash(&h, d->shader);
|
||||
hash(&h, d->shaderVariant);
|
||||
hash(&h, d->topology);
|
||||
return (size_t) h;
|
||||
}
|
||||
@@ -60,7 +59,6 @@ static bool pipelineDescriptorEquals(const void* ap, const void* bp) {
|
||||
a->inAlphaType == b->inAlphaType &&
|
||||
a->composite == b->composite &&
|
||||
a->shader == b->shader &&
|
||||
a->shaderVariant == b->shaderVariant &&
|
||||
a->topology == b->topology;
|
||||
}
|
||||
|
||||
@@ -146,20 +144,12 @@ static VKPipelineInfo VKPipelines_CreatePipelines(VKRenderPassContext* renderPas
|
||||
VkPipelineShaderStageCreateInfo createInfos[2]; // vert + frag
|
||||
} ShaderStages;
|
||||
ShaderStages stages[count];
|
||||
typedef struct {
|
||||
uint32_t inAlphaType, outAlphaType, shaderVariant, shaderModifier;
|
||||
} SpecializationData;
|
||||
const VkSpecializationMapEntry SPECIALIZATION_ENTRIES[] = {
|
||||
{ 0, 0, 4 },
|
||||
{ 1, 4, 4 },
|
||||
{ 2, 8, 4 },
|
||||
{ 3, 12, 4 }
|
||||
};
|
||||
typedef struct {
|
||||
VkSpecializationInfo info;
|
||||
SpecializationData data;
|
||||
VkSpecializationMapEntry entries[2];
|
||||
uint64_t data[1];
|
||||
} Specialization;
|
||||
Specialization specializations[count];
|
||||
Specialization specializations[count][2];
|
||||
VkPipelineInputAssemblyStateCreateInfo inputAssemblyStates[count];
|
||||
VkPipelineDepthStencilStateCreateInfo depthStencilStates[count];
|
||||
VkPipelineDynamicStateCreateInfo dynamicStates[count];
|
||||
@@ -173,19 +163,14 @@ static VKPipelineInfo VKPipelines_CreatePipelines(VKRenderPassContext* renderPas
|
||||
// - pStages (but stageCount is set to 2)
|
||||
// - pVertexInputState
|
||||
// - createInfo.layout
|
||||
specializations[i] = (Specialization) {
|
||||
.info = {
|
||||
.mapEntryCount = SARRAY_COUNT_OF(SPECIALIZATION_ENTRIES),
|
||||
.pMapEntries = SPECIALIZATION_ENTRIES,
|
||||
.dataSize = sizeof(SpecializationData),
|
||||
.pData = &specializations[i].data
|
||||
},
|
||||
.data = {
|
||||
descriptors[i].inAlphaType, pipelineInfos[i].outAlphaType, (uint32_t) descriptors[i].shaderVariant,
|
||||
(descriptors[i].composite == LOGIC_COMPOSITE_XOR ? 1 : 0) |
|
||||
(descriptors[i].shader & SHADER_MASK ? 2 : 0)
|
||||
}
|
||||
};
|
||||
for (uint32_t j = 0; j < SARRAY_COUNT_OF(specializations[i]); j++) {
|
||||
specializations[i][j].info = (VkSpecializationInfo) {
|
||||
.mapEntryCount = 0,
|
||||
.pMapEntries = specializations[i][j].entries,
|
||||
.dataSize = 0,
|
||||
.pData = specializations[i][j].data
|
||||
};
|
||||
}
|
||||
inputAssemblyStates[i] = (VkPipelineInputAssemblyStateCreateInfo) {
|
||||
.sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO,
|
||||
.topology = descriptors[i].topology
|
||||
@@ -249,38 +234,37 @@ static VKPipelineInfo VKPipelines_CreatePipelines(VKRenderPassContext* renderPas
|
||||
}
|
||||
|
||||
// Setup input states.
|
||||
MAKE_INPUT_STATE(PRIMITIVE, VKVertex, VK_FORMAT_R32G32_SFLOAT, VK_FORMAT_R32_UINT);
|
||||
MAKE_INPUT_STATE(MASK_FILL, VKMaskFillVertex, VK_FORMAT_R32G32B32A32_SINT, VK_FORMAT_R32_UINT);
|
||||
MAKE_INPUT_STATE(COLOR, VKColorVertex, VK_FORMAT_R32G32_SFLOAT, VK_FORMAT_R32G32B32A32_SFLOAT);
|
||||
MAKE_INPUT_STATE(MASK_FILL_COLOR, VKMaskFillColorVertex, VK_FORMAT_R32G32B32A32_SINT, VK_FORMAT_R32G32B32A32_SFLOAT);
|
||||
MAKE_INPUT_STATE(BLIT, VKTxVertex, VK_FORMAT_R32G32_SFLOAT, VK_FORMAT_R32G32_SFLOAT);
|
||||
MAKE_INPUT_STATE(CLIP, VKIntVertex, VK_FORMAT_R32G32_SINT);
|
||||
|
||||
for (uint32_t i = 0; i < count; i++) {
|
||||
// Setup shader-specific pipeline parameters.
|
||||
switch ((int) descriptors[i].shader) {
|
||||
switch (descriptors[i].shader) {
|
||||
case SHADER_COLOR:
|
||||
createInfos[i].pVertexInputState = &INPUT_STATE_PRIMITIVE;
|
||||
createInfos[i].layout = pipelineContext->commonPipelineLayout;
|
||||
createInfos[i].pVertexInputState = &INPUT_STATE_COLOR;
|
||||
createInfos[i].layout = pipelineContext->colorPipelineLayout;
|
||||
stages[i] = (ShaderStages) {{ shaders->color_vert, shaders->color_frag }};
|
||||
break;
|
||||
case SHADER_COLOR | SHADER_MASK:
|
||||
createInfos[i].pVertexInputState = &INPUT_STATE_MASK_FILL;
|
||||
case SHADER_MASK_FILL_COLOR:
|
||||
createInfos[i].pVertexInputState = &INPUT_STATE_MASK_FILL_COLOR;
|
||||
createInfos[i].layout = pipelineContext->maskFillPipelineLayout;
|
||||
stages[i] = (ShaderStages) {{ shaders->mask_fill_color_vert, shaders->mask_fill_color_frag }};
|
||||
break;
|
||||
case SHADER_GRADIENT:
|
||||
createInfos[i].pVertexInputState = &INPUT_STATE_PRIMITIVE;
|
||||
createInfos[i].layout = pipelineContext->maskFillPipelineLayout;
|
||||
stages[i] = (ShaderStages) {{ shaders->primitive_vert, shaders->gradient_frag }};
|
||||
break;
|
||||
case SHADER_GRADIENT | SHADER_MASK:
|
||||
createInfos[i].pVertexInputState = &INPUT_STATE_MASK_FILL;
|
||||
createInfos[i].layout = pipelineContext->maskFillPipelineLayout;
|
||||
stages[i] = (ShaderStages) {{ shaders->mask_fill_vert, shaders->gradient_frag }};
|
||||
break;
|
||||
case SHADER_BLIT:
|
||||
createInfos[i].pVertexInputState = &INPUT_STATE_BLIT;
|
||||
createInfos[i].layout = pipelineContext->texturePipelineLayout;
|
||||
stages[i] = (ShaderStages) {{ shaders->blit_vert, shaders->blit_frag }};
|
||||
// Alpha conversion specialization.
|
||||
uint32_t* spec = (uint32_t*) specializations[i][1].data;
|
||||
spec[0] = descriptors[i].inAlphaType;
|
||||
spec[1] = pipelineInfos[i].outAlphaType;
|
||||
specializations[i][1].info.dataSize = 8;
|
||||
specializations[i][1].entries[0] = (VkSpecializationMapEntry) { 0, 0, 4 };
|
||||
specializations[i][1].entries[1] = (VkSpecializationMapEntry) { 1, 4, 4 };
|
||||
specializations[i][1].info.mapEntryCount = 2;
|
||||
stages[i].createInfos[1].pSpecializationInfo = &specializations[i][1].info;
|
||||
break;
|
||||
case SHADER_CLIP:
|
||||
createInfos[i].pVertexInputState = &INPUT_STATE_CLIP;
|
||||
@@ -306,9 +290,6 @@ static VKPipelineInfo VKPipelines_CreatePipelines(VKRenderPassContext* renderPas
|
||||
default:
|
||||
VK_FATAL_ERROR("Cannot create pipeline, unknown shader requested!");
|
||||
}
|
||||
for (uint32_t j = 0; j < createInfos[i].stageCount; j++) {
|
||||
stages[i].createInfos[j].pSpecializationInfo = &specializations[i].info;
|
||||
}
|
||||
assert(createInfos[i].pDynamicState->dynamicStateCount <= MAX_DYNAMIC_STATES);
|
||||
J2dRlsTraceLn5(J2D_TRACE_INFO, "VKPipelines_CreatePipelines: stencilMode=%d, dstOpaque=%d, composite=%d, shader=%d, topology=%d",
|
||||
descriptors[i].stencilMode, descriptors[i].dstOpaque, descriptors[i].composite, descriptors[i].shader, descriptors[i].topology);
|
||||
@@ -322,7 +303,6 @@ static VKPipelineInfo VKPipelines_CreatePipelines(VKRenderPassContext* renderPas
|
||||
J2dRlsTraceLn1(J2D_TRACE_INFO, "VKPipelines_CreatePipelines: created %d pipelines", count);
|
||||
for (uint32_t i = 0; i < count; i++) {
|
||||
pipelineInfos[i].pipeline = pipelines[i];
|
||||
pipelineInfos[i].layout = createInfos[i].layout;
|
||||
MAP_AT(renderPassContext->pipelines, descriptors[i]) = pipelineInfos[i];
|
||||
}
|
||||
return pipelineInfos[0];
|
||||
@@ -423,49 +403,21 @@ static VkResult VKPipelines_InitPipelineLayouts(VKDevice* device, VKPipelineCont
|
||||
assert(device != NULL && pipelines != NULL);
|
||||
VkResult result;
|
||||
|
||||
// We want all our pipelines to have the same push constant ranges to ensure a common state is compatible between pipelines.
|
||||
VkPushConstantRange pushConstantRanges[] = {{
|
||||
// We want all our pipelines to have same push constant range to ensure common state is compatible between pipelines.
|
||||
VkPushConstantRange pushConstantRange = {
|
||||
.stageFlags = VK_SHADER_STAGE_VERTEX_BIT,
|
||||
.offset = 0,
|
||||
.size = sizeof(VKTransform)
|
||||
}, {
|
||||
.stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT,
|
||||
.offset = PUSH_CONSTANTS_OFFSET,
|
||||
.size = PUSH_CONSTANTS_SIZE
|
||||
}};
|
||||
|
||||
// Common pipeline.
|
||||
};
|
||||
VkPipelineLayoutCreateInfo createInfo = {
|
||||
.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO,
|
||||
.setLayoutCount = 0,
|
||||
.pushConstantRangeCount = SARRAY_COUNT_OF(pushConstantRanges),
|
||||
.pPushConstantRanges = pushConstantRanges
|
||||
.pushConstantRangeCount = 1,
|
||||
.pPushConstantRanges = &pushConstantRange
|
||||
};
|
||||
result = device->vkCreatePipelineLayout(device->handle, &createInfo, NULL, &pipelines->commonPipelineLayout);
|
||||
result = device->vkCreatePipelineLayout(device->handle, &createInfo, NULL, &pipelines->colorPipelineLayout);
|
||||
VK_IF_ERROR(result) return result;
|
||||
|
||||
// Mask fill pipeline.
|
||||
VkDescriptorSetLayoutBinding maskBufferLayoutBinding = {
|
||||
.binding = 0,
|
||||
.descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER,
|
||||
.descriptorCount = 1,
|
||||
.stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT,
|
||||
.pImmutableSamplers = NULL
|
||||
};
|
||||
VkDescriptorSetLayoutCreateInfo descriptorSetLayoutCreateInfo = {
|
||||
.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO,
|
||||
.bindingCount = 1,
|
||||
.pBindings = &maskBufferLayoutBinding
|
||||
};
|
||||
result = device->vkCreateDescriptorSetLayout(device->handle, &descriptorSetLayoutCreateInfo, NULL, &pipelines->maskFillDescriptorSetLayout);
|
||||
VK_IF_ERROR(result) return result;
|
||||
|
||||
createInfo.setLayoutCount = 1;
|
||||
createInfo.pSetLayouts = &pipelines->maskFillDescriptorSetLayout;
|
||||
result = device->vkCreatePipelineLayout(device->handle, &createInfo, NULL, &pipelines->maskFillPipelineLayout);
|
||||
VK_IF_ERROR(result) return result;
|
||||
|
||||
// Texture pipeline.
|
||||
VkDescriptorSetLayoutBinding textureLayoutBinding = {
|
||||
.binding = 0,
|
||||
.descriptorType = VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE,
|
||||
@@ -485,11 +437,31 @@ static VkResult VKPipelines_InitPipelineLayouts(VKDevice* device, VKPipelineCont
|
||||
pipelines->textureDescriptorSetLayout,
|
||||
pipelines->samplers.descriptorSetLayout
|
||||
};
|
||||
createInfo.setLayoutCount = SARRAY_COUNT_OF(textureDescriptorSetLayouts);
|
||||
createInfo.setLayoutCount = 2;
|
||||
createInfo.pSetLayouts = textureDescriptorSetLayouts;
|
||||
result = device->vkCreatePipelineLayout(device->handle, &createInfo, NULL, &pipelines->texturePipelineLayout);
|
||||
VK_IF_ERROR(result) return result;
|
||||
|
||||
VkDescriptorSetLayoutBinding maskBufferLayoutBinding = {
|
||||
.binding = 0,
|
||||
.descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER,
|
||||
.descriptorCount = 1,
|
||||
.stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT,
|
||||
.pImmutableSamplers = NULL
|
||||
};
|
||||
VkDescriptorSetLayoutCreateInfo descriptorSetLayoutCreateInfo = {
|
||||
.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO,
|
||||
.bindingCount = 1,
|
||||
.pBindings = &maskBufferLayoutBinding
|
||||
};
|
||||
result = device->vkCreateDescriptorSetLayout(device->handle, &descriptorSetLayoutCreateInfo, NULL, &pipelines->maskFillDescriptorSetLayout);
|
||||
VK_IF_ERROR(result) return result;
|
||||
|
||||
createInfo.setLayoutCount = 1;
|
||||
createInfo.pSetLayouts = &pipelines->maskFillDescriptorSetLayout;
|
||||
result = device->vkCreatePipelineLayout(device->handle, &createInfo, NULL, &pipelines->maskFillPipelineLayout);
|
||||
VK_IF_ERROR(result) return result;
|
||||
|
||||
return VK_SUCCESS;
|
||||
}
|
||||
|
||||
@@ -532,7 +504,7 @@ void VKPipelines_DestroyContext(VKPipelineContext* pipelineContext) {
|
||||
|
||||
VKPipelines_DestroyShaders(device, pipelineContext->shaders);
|
||||
|
||||
device->vkDestroyPipelineLayout(device->handle, pipelineContext->commonPipelineLayout, NULL);
|
||||
device->vkDestroyPipelineLayout(device->handle, pipelineContext->colorPipelineLayout, NULL);
|
||||
device->vkDestroyPipelineLayout(device->handle, pipelineContext->texturePipelineLayout, NULL);
|
||||
device->vkDestroyDescriptorSetLayout(device->handle, pipelineContext->textureDescriptorSetLayout, NULL);
|
||||
device->vkDestroyPipelineLayout(device->handle, pipelineContext->maskFillPipelineLayout, NULL);
|
||||
|
||||
@@ -36,26 +36,13 @@
|
||||
* Shader programs.
|
||||
*/
|
||||
typedef enum {
|
||||
// Base shaders.
|
||||
SHADER_COLOR,
|
||||
SHADER_GRADIENT,
|
||||
SHADER_MASK_FILL_COLOR,
|
||||
SHADER_BLIT,
|
||||
SHADER_CLIP,
|
||||
NO_SHADER = 0x7FFFFFFF,
|
||||
// Mask modifier bit (MASK_FILL & MASK_BLIT).
|
||||
SHADER_MASK = ~NO_SHADER
|
||||
NO_SHADER = 0x7FFFFFFF
|
||||
} VKShader;
|
||||
|
||||
/**
|
||||
* Shader variant.
|
||||
* It is used to specialize shader behavior, and its meaning varies with each particular shader.
|
||||
*/
|
||||
typedef enum {
|
||||
SHADER_VARIANT_GRADIENT_CLAMP = 0,
|
||||
SHADER_VARIANT_GRADIENT_CYCLE = 1,
|
||||
NO_SHADER_VARIANT = 0x7FFFFFFF
|
||||
} VKShaderVariant;
|
||||
|
||||
typedef enum {
|
||||
STENCIL_MODE_NONE = 0, // No stencil attachment.
|
||||
STENCIL_MODE_OFF = 1, // Has stencil attachment, stencil test disabled.
|
||||
@@ -72,14 +59,12 @@ typedef struct {
|
||||
AlphaType inAlphaType : 1;
|
||||
VKCompositeMode composite;
|
||||
VKShader shader;
|
||||
VKShaderVariant shaderVariant;
|
||||
VkPrimitiveTopology topology;
|
||||
} VKPipelineDescriptor;
|
||||
|
||||
typedef struct {
|
||||
VkPipeline pipeline;
|
||||
VkPipelineLayout layout;
|
||||
AlphaType outAlphaType;
|
||||
VkPipeline pipeline;
|
||||
AlphaType outAlphaType;
|
||||
} VKPipelineInfo;
|
||||
|
||||
/**
|
||||
@@ -87,7 +72,7 @@ typedef struct {
|
||||
*/
|
||||
struct VKPipelineContext {
|
||||
VKDevice* device;
|
||||
VkPipelineLayout commonPipelineLayout;
|
||||
VkPipelineLayout colorPipelineLayout;
|
||||
VkDescriptorSetLayout textureDescriptorSetLayout;
|
||||
VkPipelineLayout texturePipelineLayout;
|
||||
VkDescriptorSetLayout maskFillDescriptorSetLayout;
|
||||
@@ -108,42 +93,14 @@ struct VKRenderPassContext {
|
||||
MAP(VKPipelineDescriptor, VKPipelineInfo) pipelines;
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
unsigned int xorColor;
|
||||
float extraAlpha;
|
||||
} VKCompositeConstants;
|
||||
|
||||
typedef struct {
|
||||
RGBA c0, c1;
|
||||
float p0, p1, p3;
|
||||
} VKGradientPaintConstants;
|
||||
|
||||
typedef union {
|
||||
// The minimum guaranteed size of push constants is 128 bytes.
|
||||
alignas(32) // The maximum alignment for built-in glsl types is 32 bytes (dvec4).
|
||||
char data[(128 - sizeof(VKTransform) - sizeof(VKCompositeConstants)) / 32 * 32];
|
||||
VKGradientPaintConstants gradientPaint;
|
||||
} VKShaderConstants;
|
||||
#define MAX_SHADER_CONSTANTS_SIZE 96 // We expect 96 bytes
|
||||
typedef char VKShaderConstantsCheckOffset[sizeof(VKShaderConstants) == MAX_SHADER_CONSTANTS_SIZE ? 1 : -1]; // Verify.
|
||||
|
||||
typedef struct {
|
||||
VKTransform transform;
|
||||
VKCompositeConstants composite;
|
||||
VKShaderConstants shader;
|
||||
} VKPushConstants;
|
||||
typedef char VKPushConstantsCheckSize[sizeof(VKPushConstants) <= 128 ? 1 : -1]; // We should not exceed 128 bytes.
|
||||
static const uint32_t PUSH_CONSTANTS_OFFSET = (uintptr_t) &((VKPushConstants*) NULL)->composite;
|
||||
static const uint32_t PUSH_CONSTANTS_SIZE = sizeof(VKPushConstants) - PUSH_CONSTANTS_OFFSET;
|
||||
|
||||
typedef struct {
|
||||
int x, y;
|
||||
} VKIntVertex;
|
||||
|
||||
typedef struct {
|
||||
float x, y;
|
||||
unsigned int data;
|
||||
} VKVertex;
|
||||
RGBA color;
|
||||
} VKColorVertex;
|
||||
|
||||
typedef struct {
|
||||
float px, py;
|
||||
@@ -152,8 +109,8 @@ typedef struct {
|
||||
|
||||
typedef struct {
|
||||
int x, y, maskOffset, maskScanline;
|
||||
unsigned int data;
|
||||
} VKMaskFillVertex;
|
||||
RGBA color;
|
||||
} VKMaskFillColorVertex;
|
||||
|
||||
VKPipelineContext* VKPipelines_CreateContext(VKDevice* device);
|
||||
void VKPipelines_DestroyContext(VKPipelineContext* pipelines);
|
||||
|
||||
@@ -93,21 +93,6 @@
|
||||
#define OFFSET_XFORM sun_java2d_vulkan_VKBlitLoops_OFFSET_XFORM
|
||||
#define OFFSET_ISOBLIT sun_java2d_vulkan_VKBlitLoops_OFFSET_ISOBLIT
|
||||
|
||||
static void applyXor() {
|
||||
if (VKRenderer_GetContext()->shader == SHADER_COLOR) {
|
||||
VKRenderer_GetContext()->vertexData ^= VKRenderer_GetContext()->constants.composite.xorColor;
|
||||
}
|
||||
}
|
||||
|
||||
static void setComposite(VKCompositeMode comp, unsigned int xorColor, float extraAlpha) {
|
||||
VKRenderer_GetContext()->composite = comp;
|
||||
if (VKRenderer_GetContext()->constants.composite.xorColor != xorColor ||
|
||||
VKRenderer_GetContext()->constants.composite.extraAlpha != extraAlpha) {
|
||||
VKRenderer_GetContext()->constants.composite = (VKCompositeConstants) { xorColor, extraAlpha };
|
||||
VKRenderer_GetContext()->constantsModCount++;
|
||||
}
|
||||
}
|
||||
|
||||
JNIEXPORT void JNICALL Java_sun_java2d_vulkan_VKRenderQueue_flushBuffer
|
||||
(JNIEnv *env, jobject oglrq, jlong buf, jint limit)
|
||||
{
|
||||
@@ -496,26 +481,30 @@ JNIEXPORT void JNICALL Java_sun_java2d_vulkan_VKRenderQueue_flushBuffer
|
||||
jint flags = NEXT_INT(b);
|
||||
J2dRlsTraceLn3(J2D_TRACE_VERBOSE,
|
||||
"VKRenderQueue_flushBuffer: SET_ALPHA_COMPOSITE(%d, %f, %d)", rule, extraAlpha, flags);
|
||||
applyXor();
|
||||
setComposite((VKCompositeMode) rule, 0, extraAlpha);
|
||||
VKRenderer_GetContext()->renderColor = VKRenderer_GetContext()->color;
|
||||
VKRenderer_GetContext()->composite = (VKCompositeMode) rule;
|
||||
VKRenderer_GetContext()->extraAlpha = extraAlpha;
|
||||
}
|
||||
break;
|
||||
case sun_java2d_pipe_BufferedOpCodes_SET_XOR_COMPOSITE:
|
||||
{
|
||||
jint xorPixel = NEXT_INT(b);
|
||||
J2dRlsTraceLn1(J2D_TRACE_VERBOSE,
|
||||
"VKRenderQueue_flushBuffer: SET_XOR_COMPOSITE(0x%08x)", xorPixel);
|
||||
applyXor();
|
||||
setComposite(LOGIC_COMPOSITE_XOR, xorPixel, -1.0f);
|
||||
applyXor();
|
||||
J2dRlsTraceLn(J2D_TRACE_VERBOSE,
|
||||
"VKRenderQueue_flushBuffer: SET_XOR_COMPOSITE");
|
||||
VKRenderer_GetContext()->renderColor = VKUtil_DecodeJavaColor(xorPixel, ALPHA_TYPE_STRAIGHT);
|
||||
// TODO Fix XOR mode!
|
||||
// VKRenderer_GetContext()->renderColor.a = 0.0f; // Alpha is left unchanged in XOR mode.
|
||||
VKRenderer_GetContext()->composite = LOGIC_COMPOSITE_XOR;
|
||||
VKRenderer_GetContext()->extraAlpha = 1.0f;
|
||||
}
|
||||
break;
|
||||
case sun_java2d_pipe_BufferedOpCodes_RESET_COMPOSITE:
|
||||
{
|
||||
J2dRlsTraceLn(J2D_TRACE_VERBOSE,
|
||||
"VKRenderQueue_flushBuffer: RESET_COMPOSITE");
|
||||
applyXor();
|
||||
setComposite(ALPHA_COMPOSITE_SRC, 0, 1.0f);
|
||||
VKRenderer_GetContext()->renderColor = VKRenderer_GetContext()->color;
|
||||
VKRenderer_GetContext()->composite = ALPHA_COMPOSITE_SRC;
|
||||
VKRenderer_GetContext()->extraAlpha = 1.0f;
|
||||
}
|
||||
break;
|
||||
case sun_java2d_pipe_BufferedOpCodes_SET_TRANSFORM:
|
||||
@@ -538,8 +527,8 @@ JNIEXPORT void JNICALL Java_sun_java2d_vulkan_VKRenderQueue_flushBuffer
|
||||
};
|
||||
|
||||
VKRenderingContext* context = VKRenderer_GetContext();
|
||||
if (VK_IS_NEQ_TRANSFORM(&context->constants.transform, &transform)) {
|
||||
context->constants.transform = transform;
|
||||
if (VK_IS_NEQ_TRANSFORM(&context->transform, &transform)) {
|
||||
context->transform = transform;
|
||||
context->transformModCount++;
|
||||
}
|
||||
}
|
||||
@@ -549,8 +538,8 @@ JNIEXPORT void JNICALL Java_sun_java2d_vulkan_VKRenderQueue_flushBuffer
|
||||
J2dRlsTraceLn(J2D_TRACE_VERBOSE,
|
||||
"VKRenderQueue_flushBuffer: RESET_TRANSFORM");
|
||||
VKRenderingContext* context = VKRenderer_GetContext();
|
||||
if (VK_IS_NEQ_TRANSFORM(&context->constants.transform, &VK_ID_TRANSFORM)) {
|
||||
context->constants.transform = VK_ID_TRANSFORM;
|
||||
if (VK_IS_NEQ_TRANSFORM(&context->transform, &VK_ID_TRANSFORM)) {
|
||||
context->transform = VK_ID_TRANSFORM;
|
||||
context->transformModCount++;
|
||||
}
|
||||
}
|
||||
@@ -584,10 +573,9 @@ JNIEXPORT void JNICALL Java_sun_java2d_vulkan_VKRenderQueue_flushBuffer
|
||||
break;
|
||||
case sun_java2d_pipe_BufferedOpCodes_DISPOSE_SURFACE:
|
||||
{
|
||||
VKSDOps* surface = NEXT_VK_SURFACE(b);
|
||||
jlong pData = NEXT_LONG(b);
|
||||
J2dRlsTraceLn(J2D_TRACE_VERBOSE,
|
||||
"VKRenderQueue_flushBuffer: DISPOSE_SURFACE");
|
||||
VKSD_ResetSurface(surface);
|
||||
}
|
||||
break;
|
||||
case sun_java2d_pipe_BufferedOpCodes_DISPOSE_CONFIG:
|
||||
@@ -660,34 +648,31 @@ JNIEXPORT void JNICALL Java_sun_java2d_vulkan_VKRenderQueue_flushBuffer
|
||||
break;
|
||||
case sun_java2d_pipe_BufferedOpCodes_SET_COLOR:
|
||||
{
|
||||
VKRenderer_GetContext()->inAlphaType = ALPHA_TYPE_STRAIGHT;
|
||||
VKRenderer_GetContext()->shader = SHADER_COLOR;
|
||||
VKRenderer_GetContext()->shaderVariant = NO_SHADER_VARIANT;
|
||||
VKRenderer_GetContext()->vertexData = NEXT_INT(b);
|
||||
applyXor();
|
||||
J2dRlsTraceLn1(J2D_TRACE_VERBOSE, "VKRenderQueue_flushBuffer: SET_COLOR(0x%08x)", VKRenderer_GetContext()->vertexData);
|
||||
jint javaColor = NEXT_INT(b);
|
||||
VKRenderer_GetContext()->color = VKUtil_DecodeJavaColor(javaColor, ALPHA_TYPE_STRAIGHT);
|
||||
if (COMPOSITE_GROUP(VKRenderer_GetContext()->composite) == ALPHA_COMPOSITE_GROUP) {
|
||||
VKRenderer_GetContext()->renderColor = VKRenderer_GetContext()->color;
|
||||
}
|
||||
J2dRlsTraceLn1(J2D_TRACE_VERBOSE, "VKRenderQueue_flushBuffer: SET_COLOR(0x%08x)", javaColor);
|
||||
J2dTraceLn4(J2D_TRACE_VERBOSE, // Print color values with straight alpha for convenience.
|
||||
" srgb={%.3f, %.3f, %.3f, %.3f}",
|
||||
VKUtil_GetRGBA(VKRenderer_GetContext()->color, ALPHA_TYPE_STRAIGHT).r,
|
||||
VKUtil_GetRGBA(VKRenderer_GetContext()->color, ALPHA_TYPE_STRAIGHT).g,
|
||||
VKUtil_GetRGBA(VKRenderer_GetContext()->color, ALPHA_TYPE_STRAIGHT).b,
|
||||
VKUtil_GetRGBA(VKRenderer_GetContext()->color, ALPHA_TYPE_STRAIGHT).a);
|
||||
}
|
||||
break;
|
||||
case sun_java2d_pipe_BufferedOpCodes_SET_GRADIENT_PAINT:
|
||||
{
|
||||
jboolean useMask = NEXT_BOOLEAN(b); // Unused.
|
||||
jboolean cyclic = NEXT_BOOLEAN(b);
|
||||
jdouble p0 = NEXT_DOUBLE(b);
|
||||
jdouble p1 = NEXT_DOUBLE(b);
|
||||
jdouble p3 = NEXT_DOUBLE(b);
|
||||
jint pixel1 = NEXT_INT(b);
|
||||
jint pixel2 = NEXT_INT(b);
|
||||
jboolean useMask= NEXT_BOOLEAN(b);
|
||||
jboolean cyclic = NEXT_BOOLEAN(b);
|
||||
jdouble p0 = NEXT_DOUBLE(b);
|
||||
jdouble p1 = NEXT_DOUBLE(b);
|
||||
jdouble p3 = NEXT_DOUBLE(b);
|
||||
jint pixel1 = NEXT_INT(b);
|
||||
jint pixel2 = NEXT_INT(b);
|
||||
J2dRlsTraceLn(J2D_TRACE_VERBOSE,
|
||||
"VKRenderQueue_flushBuffer: SET_GRADIENT_PAINT");
|
||||
VKRenderer_GetContext()->inAlphaType = ALPHA_TYPE_PRE_MULTIPLIED;
|
||||
VKRenderer_GetContext()->shader = SHADER_GRADIENT;
|
||||
VKRenderer_GetContext()->shaderVariant = cyclic ? SHADER_VARIANT_GRADIENT_CYCLE : SHADER_VARIANT_GRADIENT_CLAMP;
|
||||
VKRenderer_GetContext()->constants.shader.gradientPaint = (VKGradientPaintConstants) {
|
||||
VKUtil_GetRGBA(VKUtil_DecodeJavaColor(pixel1, ALPHA_TYPE_PRE_MULTIPLIED), ALPHA_TYPE_PRE_MULTIPLIED),
|
||||
VKUtil_GetRGBA(VKUtil_DecodeJavaColor(pixel2, ALPHA_TYPE_PRE_MULTIPLIED), ALPHA_TYPE_PRE_MULTIPLIED),
|
||||
p0*2.0, p1*2.0, p3*2.0-0.5
|
||||
};
|
||||
VKRenderer_GetContext()->constantsModCount++;
|
||||
}
|
||||
break;
|
||||
case sun_java2d_pipe_BufferedOpCodes_SET_LINEAR_GRADIENT_PAINT:
|
||||
|
||||
@@ -94,7 +94,6 @@ typedef struct {
|
||||
struct VKRenderer {
|
||||
VKDevice* device;
|
||||
VKPipelineContext* pipelineContext;
|
||||
VKTexturePool* texturePool;
|
||||
|
||||
POOL(VkCommandBuffer, commandBufferPool);
|
||||
POOL(VkCommandBuffer, secondaryCommandBufferPool);
|
||||
@@ -164,7 +163,6 @@ struct VKRenderPass {
|
||||
BufferWritingState maskFillBufferWriting;
|
||||
|
||||
VKPipelineDescriptor state;
|
||||
uint64_t constantsModCount; // Just a tag to detect when constants were changed.
|
||||
uint64_t transformModCount; // Just a tag to detect when transform was changed.
|
||||
uint64_t clipModCount; // Just a tag to detect when clip was changed.
|
||||
VkBool32 pendingFlush : 1;
|
||||
@@ -177,17 +175,12 @@ struct VKRenderPass {
|
||||
// which is only called from queue flusher thread, no need for synchronization.
|
||||
static VKRenderingContext context = {
|
||||
.surface = NULL,
|
||||
.composite = ALPHA_COMPOSITE_SRC_OVER,
|
||||
.inAlphaType = ALPHA_TYPE_UNKNOWN,
|
||||
.shader = NO_SHADER,
|
||||
.shaderVariant = NO_SHADER_VARIANT,
|
||||
.vertexData = 0,
|
||||
.constantsModCount = 1,
|
||||
.transform = VK_ID_TRANSFORM,
|
||||
.transformModCount = 1,
|
||||
.constants = {
|
||||
.transform = VK_ID_TRANSFORM,
|
||||
.composite = { 0, 1.0f }
|
||||
},
|
||||
.color = {},
|
||||
.renderColor = {},
|
||||
.composite = ALPHA_COMPOSITE_SRC_OVER,
|
||||
.extraAlpha = 1.0f,
|
||||
.clipModCount = 1,
|
||||
.clipRect = NO_CLIP,
|
||||
.clipSpanVertices = NULL
|
||||
@@ -200,9 +193,6 @@ VKRenderingContext *VKRenderer_GetContext() {
|
||||
return &context;
|
||||
}
|
||||
|
||||
VKTexturePool *VKRenderer_GetTexturePool(VKRenderer* renderer) {
|
||||
return renderer->texturePool;
|
||||
}
|
||||
/**
|
||||
* Helper function for POOL_TAKE macro.
|
||||
*/
|
||||
@@ -227,7 +217,7 @@ static VkBool32 VKRenderer_CheckPoolDrain(void* pool, void* entry) {
|
||||
return VK_FALSE;
|
||||
}
|
||||
|
||||
#define VERTEX_BUFFER_SIZE (128 * 1024) // 128KiB - enough to draw 1820 quads (6 verts) with VKVertex.
|
||||
#define VERTEX_BUFFER_SIZE (128 * 1024) // 128KiB - enough to draw 910 quads (6 verts) with VKColorVertex.
|
||||
#define VERTEX_BUFFER_PAGE_SIZE (1 * 1024 * 1024) // 1MiB - fits 8 buffers.
|
||||
static void VKRenderer_FindVertexBufferMemoryType(VKMemoryRequirements* requirements) {
|
||||
VKAllocator_FindMemoryType(requirements, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_CACHED_BIT,
|
||||
@@ -378,12 +368,6 @@ VKRenderer* VKRenderer_Create(VKDevice* device) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
renderer->texturePool = VKTexturePool_InitWithDevice(device);
|
||||
if (!renderer->texturePool) {
|
||||
VKRenderer_Destroy(renderer);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Create command pool
|
||||
// TODO we currently have single command pool with VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT
|
||||
// we may need to consider having multiple pools to avoid resetting buffers one-by-one
|
||||
@@ -454,9 +438,6 @@ void VKRenderer_Destroy(VKRenderer* renderer) {
|
||||
device->vkDestroyDescriptorPool(device->handle, renderer->descriptorPools[i], NULL);
|
||||
}
|
||||
ARRAY_FREE(renderer->descriptorPools);
|
||||
|
||||
VKTexturePool_Dispose(renderer->texturePool);
|
||||
|
||||
for (uint32_t i = 0; i < ARRAY_SIZE(renderer->imageDescriptorPools); i++) {
|
||||
device->vkDestroyDescriptorPool(device->handle, renderer->imageDescriptorPools[i], NULL);
|
||||
}
|
||||
@@ -603,47 +584,33 @@ inline void VKRenderer_FlushDraw(VKSDOps* surface) {
|
||||
static void VKRenderer_ResetDrawing(VKSDOps* surface) {
|
||||
assert(surface != NULL && surface->renderPass != NULL);
|
||||
VKRenderer* renderer = surface->device->renderer;
|
||||
VKRenderPass* renderPass = surface->renderPass;
|
||||
renderPass->state.composite = NO_COMPOSITE;
|
||||
renderPass->state.shader = NO_SHADER;
|
||||
renderPass->constantsModCount = 0;
|
||||
renderPass->transformModCount = 0;
|
||||
renderPass->firstVertex = 0;
|
||||
renderPass->vertexCount = 0;
|
||||
renderPass->vertexBufferWriting = (BufferWritingState) { NULL, 0, VK_FALSE };
|
||||
renderPass->maskFillBufferWriting = (BufferWritingState) { NULL, 0, VK_FALSE };
|
||||
if (ARRAY_SIZE(renderPass->flushRanges) > 0) {
|
||||
surface->renderPass->state.composite = NO_COMPOSITE;
|
||||
surface->renderPass->state.shader = NO_SHADER;
|
||||
surface->renderPass->transformModCount = 0;
|
||||
surface->renderPass->firstVertex = 0;
|
||||
surface->renderPass->vertexCount = 0;
|
||||
surface->renderPass->vertexBufferWriting = (BufferWritingState) {NULL, 0, VK_FALSE};
|
||||
surface->renderPass->maskFillBufferWriting = (BufferWritingState) {NULL, 0, VK_FALSE};
|
||||
if (ARRAY_SIZE(surface->renderPass->flushRanges) > 0) {
|
||||
VK_IF_ERROR(surface->device->vkFlushMappedMemoryRanges(surface->device->handle,
|
||||
ARRAY_SIZE(renderPass->flushRanges), renderPass->flushRanges)) {}
|
||||
ARRAY_RESIZE(renderPass->flushRanges, 0);
|
||||
ARRAY_SIZE(surface->renderPass->flushRanges), surface->renderPass->flushRanges)) {}
|
||||
ARRAY_RESIZE(surface->renderPass->flushRanges, 0);
|
||||
}
|
||||
size_t vertexBufferCount = ARRAY_SIZE(renderPass->vertexBuffers);
|
||||
size_t maskFillBufferCount = ARRAY_SIZE(renderPass->maskFillBuffers);
|
||||
size_t cleanupQueueCount = ARRAY_SIZE(renderPass->cleanupQueue);
|
||||
size_t vertexBufferCount = ARRAY_SIZE(surface->renderPass->vertexBuffers);
|
||||
size_t maskFillBufferCount = ARRAY_SIZE(surface->renderPass->maskFillBuffers);
|
||||
size_t cleanupQueueCount = ARRAY_SIZE(surface->renderPass->cleanupQueue);
|
||||
for (uint32_t i = 0; i < vertexBufferCount; i++) {
|
||||
POOL_RETURN(renderer, vertexBufferPool, renderPass->vertexBuffers[i]);
|
||||
POOL_RETURN(surface->device->renderer, vertexBufferPool, surface->renderPass->vertexBuffers[i]);
|
||||
}
|
||||
for (uint32_t i = 0; i < maskFillBufferCount; i++) {
|
||||
POOL_RETURN(renderer, maskFillBufferPool, renderPass->maskFillBuffers[i]);
|
||||
POOL_RETURN(surface->device->renderer, maskFillBufferPool, surface->renderPass->maskFillBuffers[i]);
|
||||
}
|
||||
for (uint32_t i = 0; i < cleanupQueueCount; i++) {
|
||||
POOL_RETURN(renderer, cleanupQueue, renderPass->cleanupQueue[i]);
|
||||
POOL_RETURN(surface->device->renderer, cleanupQueue, surface->renderPass->cleanupQueue[i]);
|
||||
}
|
||||
ARRAY_RESIZE(renderPass->vertexBuffers, 0);
|
||||
ARRAY_RESIZE(renderPass->maskFillBuffers, 0);
|
||||
ARRAY_RESIZE(renderPass->cleanupQueue, 0);
|
||||
|
||||
// Update dependencies on used surfaces.
|
||||
for (uint32_t i = 0, surfaces = (uint32_t) ARRAY_SIZE(renderPass->usedSurfaces); i < surfaces; i++) {
|
||||
VKSDOps* usedSurface = renderPass->usedSurfaces[i];
|
||||
uint32_t newSize = 0, oldSize = (uint32_t) ARRAY_SIZE(usedSurface->dependentSurfaces);
|
||||
for (uint32_t j = 0; j < oldSize; j++) {
|
||||
VKSDOps* s = usedSurface->dependentSurfaces[j];
|
||||
if (s != surface) usedSurface->dependentSurfaces[newSize++] = s;
|
||||
}
|
||||
if (newSize != oldSize) ARRAY_RESIZE(usedSurface->dependentSurfaces, newSize);
|
||||
}
|
||||
ARRAY_RESIZE(renderPass->usedSurfaces, 0);
|
||||
ARRAY_RESIZE(surface->renderPass->vertexBuffers, 0);
|
||||
ARRAY_RESIZE(surface->renderPass->maskFillBuffers, 0);
|
||||
ARRAY_RESIZE(surface->renderPass->cleanupQueue, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -731,7 +698,6 @@ static VkBool32 VKRenderer_InitRenderPass(VKSDOps* surface) {
|
||||
.composite = NO_COMPOSITE,
|
||||
.shader = NO_SHADER
|
||||
},
|
||||
.constantsModCount = 0,
|
||||
.transformModCount = 0,
|
||||
.clipModCount = 0,
|
||||
.pendingFlush = VK_FALSE,
|
||||
@@ -898,11 +864,19 @@ VkBool32 VKRenderer_FlushRenderPass(VKSDOps* surface) {
|
||||
VKRenderer* renderer = device->renderer;
|
||||
VkCommandBuffer cb = VKRenderer_Record(renderer);
|
||||
|
||||
// Update timestamps on used surfaces.
|
||||
// Update dependencies on used surfaces.
|
||||
surface->lastTimestamp = renderer->writeTimestamp;
|
||||
for (uint32_t i = 0, surfaces = (uint32_t) ARRAY_SIZE(surface->renderPass->usedSurfaces); i < surfaces; i++) {
|
||||
surface->renderPass->usedSurfaces[i]->lastTimestamp = renderer->writeTimestamp;
|
||||
VKSDOps* usedSurface = surface->renderPass->usedSurfaces[i];
|
||||
usedSurface->lastTimestamp = renderer->writeTimestamp;
|
||||
uint32_t newSize = 0, oldSize = (uint32_t) ARRAY_SIZE(usedSurface->dependentSurfaces);
|
||||
for (uint32_t j = 0; j < oldSize; j++) {
|
||||
VKSDOps* s = usedSurface->dependentSurfaces[j];
|
||||
if (s != surface) usedSurface->dependentSurfaces[newSize++] = s;
|
||||
}
|
||||
if (newSize != oldSize) ARRAY_RESIZE(usedSurface->dependentSurfaces, newSize);
|
||||
}
|
||||
ARRAY_RESIZE(surface->renderPass->usedSurfaces, 0);
|
||||
|
||||
// Insert barriers to prepare surface for rendering.
|
||||
VkImageMemoryBarrier barriers[2];
|
||||
@@ -1135,7 +1109,7 @@ static uint32_t VKRenderer_AllocateVertices(uint32_t primitives, uint32_t vertic
|
||||
* This function can invalidate drawing state, always call it before VK_DRAW.
|
||||
*/
|
||||
static BufferWritingState VKRenderer_AllocateMaskFillBytes(uint32_t size) {
|
||||
// assert(size > 0); // size can be 0 when binding the buffer without allocating any data.
|
||||
assert(size > 0);
|
||||
assert(size <= MASK_FILL_BUFFER_SIZE);
|
||||
VKSDOps* surface = VKRenderer_GetContext()->surface;
|
||||
BufferWritingState state = VKRenderer_AllocateBufferData(
|
||||
@@ -1171,35 +1145,16 @@ static void VKRenderer_ValidateTransform() {
|
||||
0.0f, 2.0f / (float) surface->image->extent.height, -1.0f
|
||||
};
|
||||
// Combine it with user transform.
|
||||
VKUtil_ConcatenateTransform(&transform, &context->constants.transform);
|
||||
VKUtil_ConcatenateTransform(&transform, &context->transform);
|
||||
// Push the transform into shader.
|
||||
surface->device->vkCmdPushConstants(
|
||||
renderPass->commandBuffer,
|
||||
surface->device->renderer->pipelineContext->commonPipelineLayout,
|
||||
surface->device->renderer->pipelineContext->colorPipelineLayout, // TODO what if our pipeline layout differs?
|
||||
VK_SHADER_STAGE_VERTEX_BIT, 0, sizeof(VKTransform), &transform
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
static void VKRenderer_ValidateConstants() {
|
||||
VKRenderingContext* context = VKRenderer_GetContext();
|
||||
assert(context->surface != NULL);
|
||||
VKSDOps* surface = context->surface;
|
||||
VKRenderPass* renderPass = surface->renderPass;
|
||||
// Update constants, ignoring clip and color shaders.
|
||||
if (renderPass->constantsModCount != context->constantsModCount &&
|
||||
renderPass->state.shader != SHADER_CLIP && renderPass->state.shader != SHADER_COLOR) {
|
||||
J2dTraceLn(J2D_TRACE_VERBOSE, "VKRenderer_ValidateConstants: updating constants");
|
||||
VKRenderer_FlushDraw(surface);
|
||||
renderPass->constantsModCount = context->constantsModCount;
|
||||
surface->device->vkCmdPushConstants(
|
||||
renderPass->commandBuffer,
|
||||
surface->device->renderer->pipelineContext->commonPipelineLayout,
|
||||
VK_SHADER_STAGE_FRAGMENT_BIT, PUSH_CONSTANTS_OFFSET, PUSH_CONSTANTS_SIZE, &context->constants.composite
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Setup stencil attachment according to the context clip state.
|
||||
* If there is a clip shape, attachment is cleared with "fail" value and then
|
||||
@@ -1236,7 +1191,6 @@ static void VKRenderer_SetupStencil() {
|
||||
.inAlphaType = ALPHA_TYPE_UNKNOWN,
|
||||
.composite = NO_COMPOSITE,
|
||||
.shader = SHADER_CLIP,
|
||||
.shaderVariant = NO_SHADER_VARIANT,
|
||||
.topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST
|
||||
}).pipeline);
|
||||
// Reset vertex buffer binding.
|
||||
@@ -1280,7 +1234,7 @@ void VKRenderer_RecordBarriers(VKRenderer* renderer,
|
||||
/**
|
||||
* Setup pipeline for drawing. Returns FALSE if surface is not yet ready for drawing.
|
||||
*/
|
||||
VkBool32 VKRenderer_Validate(VKShader shader, VKShaderVariant shaderVariant, VkPrimitiveTopology topology, AlphaType inAlphaType) {
|
||||
VkBool32 VKRenderer_Validate(VKShader shader, VkPrimitiveTopology topology, AlphaType inAlphaType) {
|
||||
assert(context.surface != NULL);
|
||||
VKSDOps* surface = context.surface;
|
||||
|
||||
@@ -1322,18 +1276,10 @@ VkBool32 VKRenderer_Validate(VKShader shader, VKShaderVariant shaderVariant, VkP
|
||||
J2dTraceLn(J2D_TRACE_VERBOSE, "VKRenderer_Validate: updating clip");
|
||||
surface->device->vkCmdSetScissor(renderPass->commandBuffer, 0, 1, &context.clipRect);
|
||||
if (clipChanged) {
|
||||
VKStencilMode stencilMode = STENCIL_MODE_NONE;
|
||||
if (ARRAY_SIZE(context.clipSpanVertices) > 0) {
|
||||
VKRenderer_SetupStencil();
|
||||
stencilMode = STENCIL_MODE_ON;
|
||||
} else if (surface->stencil != NULL) {
|
||||
stencilMode = STENCIL_MODE_OFF;
|
||||
}
|
||||
// Reset the pipeline when changing stencil mode.
|
||||
if (renderPass->state.stencilMode != stencilMode) {
|
||||
renderPass->state.shader = NO_SHADER;
|
||||
}
|
||||
renderPass->state.stencilMode = stencilMode;
|
||||
renderPass->state.stencilMode = STENCIL_MODE_ON;
|
||||
} else renderPass->state.stencilMode = surface->stencil != NULL ? STENCIL_MODE_OFF : STENCIL_MODE_NONE;
|
||||
}
|
||||
}
|
||||
// Validate current composite.
|
||||
@@ -1349,7 +1295,6 @@ VkBool32 VKRenderer_Validate(VKShader shader, VKShaderVariant shaderVariant, VkP
|
||||
|
||||
// Validate current pipeline.
|
||||
if (renderPass->state.shader != shader ||
|
||||
renderPass->state.shaderVariant != shaderVariant ||
|
||||
renderPass->state.topology != topology ||
|
||||
renderPass->state.inAlphaType != inAlphaType) {
|
||||
J2dTraceLn2(J2D_TRACE_VERBOSE, "VKRenderer_Validate: updating pipeline, old=%d, new=%d",
|
||||
@@ -1357,7 +1302,6 @@ VkBool32 VKRenderer_Validate(VKShader shader, VKShaderVariant shaderVariant, VkP
|
||||
VKRenderer_FlushDraw(surface);
|
||||
VkCommandBuffer cb = renderPass->commandBuffer;
|
||||
renderPass->state.shader = shader;
|
||||
renderPass->state.shaderVariant = shaderVariant;
|
||||
renderPass->state.topology = topology;
|
||||
renderPass->state.inAlphaType = inAlphaType;
|
||||
VKPipelineInfo pipelineInfo = VKPipelines_GetPipelineInfo(renderPass->context, renderPass->state);
|
||||
@@ -1365,26 +1309,10 @@ VkBool32 VKRenderer_Validate(VKShader shader, VKShaderVariant shaderVariant, VkP
|
||||
surface->device->vkCmdBindPipeline(cb, VK_PIPELINE_BIND_POINT_GRAPHICS, pipelineInfo.pipeline);
|
||||
renderPass->vertexBufferWriting.bound = VK_FALSE;
|
||||
renderPass->maskFillBufferWriting.bound = VK_FALSE;
|
||||
|
||||
// If pipeline uses mask fill layout, but the shader is not actually a MASK one, that must be a generic-layout pipeline.
|
||||
// In that case, we need to bind a mask buffer, even if we won't ever use it.
|
||||
// We could use VK_DESCRIPTOR_BINDING_PARTIALLY_BOUND_BIT or nullDescriptor, but those require
|
||||
// optional features or extensions, so don't bother for now...
|
||||
// TODO this is ugly, do something with it.
|
||||
if (pipelineInfo.layout == surface->device->renderer->pipelineContext->maskFillPipelineLayout && !(shader & SHADER_MASK)) {
|
||||
VKRenderer_AllocateMaskFillBytes(0);
|
||||
}
|
||||
}
|
||||
|
||||
VKRenderer_ValidateConstants();
|
||||
return VK_TRUE;
|
||||
}
|
||||
|
||||
static VkBool32 VKRenderer_ValidatePaint(VKShader shaderModifier, VkBool32 fill) {
|
||||
return VKRenderer_Validate(context.shader | shaderModifier, context.shaderVariant,
|
||||
fill ? VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST : VK_PRIMITIVE_TOPOLOGY_LINE_LIST, context.inAlphaType);
|
||||
}
|
||||
|
||||
// Drawing operations.
|
||||
|
||||
void VKRenderer_RenderRect(VkBool32 fill, jint x, jint y, jint w, jint h) {
|
||||
@@ -1395,9 +1323,12 @@ void VKRenderer_RenderRect(VkBool32 fill, jint x, jint y, jint w, jint h) {
|
||||
void VKRenderer_RenderParallelogram(VkBool32 fill,
|
||||
jfloat x11, jfloat y11,
|
||||
jfloat dx21, jfloat dy21,
|
||||
jfloat dx12, jfloat dy12) {
|
||||
if (!VKRenderer_ValidatePaint(0, fill)) return; // Not ready.
|
||||
|
||||
jfloat dx12, jfloat dy12)
|
||||
{
|
||||
if (!VKRenderer_Validate(SHADER_COLOR,
|
||||
fill ? VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST
|
||||
: VK_PRIMITIVE_TOPOLOGY_LINE_LIST, ALPHA_TYPE_UNKNOWN)) return; // Not ready.
|
||||
RGBA c = VKRenderer_GetRGBA(context.surface, context.renderColor);
|
||||
/* dx21
|
||||
* (p1)---------(p2) | (p1)------
|
||||
* |\ \ | | \ dy21
|
||||
@@ -1408,12 +1339,12 @@ void VKRenderer_RenderParallelogram(VkBool32 fill,
|
||||
* dy21 \ |
|
||||
* -----(p3)
|
||||
*/
|
||||
VKVertex p1 = {x11, y11, context.vertexData};
|
||||
VKVertex p2 = {x11 + dx21, y11 + dy21, context.vertexData};
|
||||
VKVertex p3 = {x11 + dx21 + dx12, y11 + dy21 + dy12, context.vertexData};
|
||||
VKVertex p4 = {x11 + dx12, y11 + dy12, context.vertexData};
|
||||
VKColorVertex p1 = {x11, y11, c};
|
||||
VKColorVertex p2 = {x11 + dx21, y11 + dy21, c};
|
||||
VKColorVertex p3 = {x11 + dx21 + dx12, y11 + dy21 + dy12, c};
|
||||
VKColorVertex p4 = {x11 + dx12, y11 + dy12, c};
|
||||
|
||||
VKVertex* vs;
|
||||
VKColorVertex* vs;
|
||||
VK_DRAW(vs, 1, fill ? 6 : 8);
|
||||
uint32_t i = 0;
|
||||
vs[i++] = p1;
|
||||
@@ -1430,18 +1361,19 @@ void VKRenderer_RenderParallelogram(VkBool32 fill,
|
||||
|
||||
void VKRenderer_FillSpans(jint spanCount, jint *spans) {
|
||||
if (spanCount == 0) return;
|
||||
if (!VKRenderer_ValidatePaint(0, VK_TRUE)) return; // Not ready.
|
||||
if (!VKRenderer_Validate(SHADER_COLOR, VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST, ALPHA_TYPE_UNKNOWN)) return; // Not ready.
|
||||
RGBA c = VKRenderer_GetRGBA(context.surface, context.renderColor);
|
||||
|
||||
jfloat x1 = (float)*(spans++);
|
||||
jfloat y1 = (float)*(spans++);
|
||||
jfloat x2 = (float)*(spans++);
|
||||
jfloat y2 = (float)*(spans++);
|
||||
VKVertex p1 = {x1, y1, context.vertexData};
|
||||
VKVertex p2 = {x2, y1, context.vertexData};
|
||||
VKVertex p3 = {x2, y2, context.vertexData};
|
||||
VKVertex p4 = {x1, y2, context.vertexData};
|
||||
VKColorVertex p1 = {x1, y1, c};
|
||||
VKColorVertex p2 = {x2, y1, c};
|
||||
VKColorVertex p3 = {x2, y2, c};
|
||||
VKColorVertex p4 = {x1, y2, c};
|
||||
|
||||
VKVertex* vs;
|
||||
VKColorVertex* vs;
|
||||
VK_DRAW(vs, 1, 6);
|
||||
vs[0] = p1; vs[1] = p2; vs[2] = p3; vs[3] = p3; vs[4] = p4; vs[5] = p1;
|
||||
|
||||
@@ -1458,8 +1390,8 @@ void VKRenderer_FillSpans(jint spanCount, jint *spans) {
|
||||
|
||||
void VKRenderer_MaskFill(jint x, jint y, jint w, jint h,
|
||||
jint maskoff, jint maskscan, jint masklen, uint8_t *mask) {
|
||||
if (!VKRenderer_ValidatePaint(SHADER_MASK, VK_TRUE)) return; // Not ready.
|
||||
|
||||
if (!VKRenderer_Validate(SHADER_MASK_FILL_COLOR,
|
||||
VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST, ALPHA_TYPE_UNKNOWN)) return; // Not ready.
|
||||
// maskoff is the offset from the beginning of mask,
|
||||
// it's the same as x and y offset within a tile (maskoff % maskscan, maskoff / maskscan).
|
||||
// maskscan is the number of bytes in a row/
|
||||
@@ -1477,13 +1409,14 @@ void VKRenderer_MaskFill(jint x, jint y, jint w, jint h,
|
||||
*((char *)maskState.data) = (char)0xFF;
|
||||
}
|
||||
|
||||
VKMaskFillVertex* vs;
|
||||
VKMaskFillColorVertex* vs;
|
||||
VK_DRAW(vs, 1, 6);
|
||||
RGBA c = VKRenderer_GetRGBA(context.surface, context.renderColor);
|
||||
int offset = (int) maskState.offset;
|
||||
VKMaskFillVertex p1 = {x, y, offset, maskscan, context.vertexData};
|
||||
VKMaskFillVertex p2 = {x + w, y, offset, maskscan, context.vertexData};
|
||||
VKMaskFillVertex p3 = {x + w, y + h, offset, maskscan, context.vertexData};
|
||||
VKMaskFillVertex p4 = {x, y + h, offset, maskscan, context.vertexData};
|
||||
VKMaskFillColorVertex p1 = {x, y, offset, maskscan, c};
|
||||
VKMaskFillColorVertex p2 = {x + w, y, offset, maskscan, c};
|
||||
VKMaskFillColorVertex p3 = {x + w, y + h, offset, maskscan, c};
|
||||
VKMaskFillColorVertex p4 = {x, y + h, offset, maskscan, c};
|
||||
// Always keep p1 as provoking vertex for correct origin calculation in vertex shader.
|
||||
vs[0] = p1; vs[1] = p3; vs[2] = p2;
|
||||
vs[3] = p1; vs[4] = p3; vs[5] = p4;
|
||||
|
||||
@@ -29,22 +29,27 @@
|
||||
|
||||
#include "VKTypes.h"
|
||||
#include "VKPipelines.h"
|
||||
#include "VKTexturePool.h"
|
||||
|
||||
#define NO_CLIP ((VkRect2D) {{0, 0}, {0x7FFFFFFFU, 0x7FFFFFFFU}})
|
||||
|
||||
struct VKRenderingContext {
|
||||
VKSDOps* surface;
|
||||
|
||||
VKCompositeMode composite;
|
||||
AlphaType inAlphaType;
|
||||
VKShader shader;
|
||||
VKShaderVariant shaderVariant;
|
||||
unsigned int vertexData;
|
||||
VKPushConstants constants;
|
||||
uint64_t constantsModCount;
|
||||
VKTransform transform;
|
||||
uint64_t transformModCount;
|
||||
|
||||
// We keep this color separately from renderColor,
|
||||
// because we need consistent state when switching between XOR and alpha
|
||||
// composite modes. This variable holds last value set by SET_COLOR, while
|
||||
// renderColor holds color, currently used for drawing, which may have
|
||||
// also been provided by SET_XOR_COMPOSITE.
|
||||
Color color;
|
||||
Color renderColor;
|
||||
VKCompositeMode composite;
|
||||
|
||||
// Extra alpha is not used when painting with plain color,
|
||||
// in this case color.a already includes it.
|
||||
float extraAlpha;
|
||||
uint64_t clipModCount; // Used to track changes to the clip.
|
||||
VkRect2D clipRect;
|
||||
ARRAY(VKIntVertex) clipSpanVertices;
|
||||
@@ -57,7 +62,7 @@ VKRenderer* VKRenderer_Create(VKDevice* device);
|
||||
/**
|
||||
* Setup pipeline for drawing. Returns FALSE if the surface is not yet ready for drawing.
|
||||
*/
|
||||
VkBool32 VKRenderer_Validate(VKShader shader, VKShaderVariant shaderVariant, VkPrimitiveTopology topology, AlphaType inAlphaType);
|
||||
VkBool32 VKRenderer_Validate(VKShader shader, VkPrimitiveTopology topology, AlphaType inAlphaType);
|
||||
|
||||
/**
|
||||
* Record commands into the primary command buffer (outside of a render pass).
|
||||
@@ -142,6 +147,5 @@ void VKRenderer_DrawImage(VKImage* image, VkFormat format,
|
||||
float dx1, float dy1, float dx2, float dy2);
|
||||
|
||||
VKRenderingContext* VKRenderer_GetContext();
|
||||
VKTexturePool* VKRenderer_GetTexturePool(VKRenderer* );
|
||||
|
||||
#endif //VKRenderer_h_Included
|
||||
|
||||
@@ -292,7 +292,15 @@ VkBool32 VKSD_ConfigureWindowSurface(VKWinSDOps* vkwinsdo) {
|
||||
}
|
||||
|
||||
static void VKSD_OnDispose(JNIEnv* env, SurfaceDataOps* ops) {
|
||||
JNU_CallStaticMethodByName(env, NULL, "sun/java2d/vulkan/VKSurfaceData", "dispose", "(J)V", ptr_to_jlong(ops));
|
||||
// We are being called from the disposer thread, RQ might be working in parallel.
|
||||
// VKRenderQueue.lock/unlock is equivalent to AWT_LOCK/AWT_UNLOCK,
|
||||
// but those are only available in the toolkit-specific part of AWT, so we call RQ there.
|
||||
jobject rq = JNU_CallStaticMethodByName(env, NULL,
|
||||
"sun/java2d/vulkan/VKRenderQueue", "getInstance", "()Lsun/java2d/vulkan/VKRenderQueue;").l;
|
||||
JNU_CallMethodByName(env, NULL, rq, "lock", "()V");
|
||||
VKSD_ResetSurface((VKSDOps*) ops);
|
||||
JNU_CallMethodByName(env, NULL, rq, "unlock", "()V");
|
||||
(*env)->DeleteLocalRef(env, rq);
|
||||
}
|
||||
|
||||
JNIEXPORT VKSDOps* VKSD_CreateSurface(JNIEnv* env, jobject vksd, jint type, jint format, jint backgroundRGB,
|
||||
|
||||
@@ -62,7 +62,7 @@ typedef uint16_t VKPackedSwizzle;
|
||||
*/
|
||||
typedef struct {
|
||||
float m00, m01, m02;
|
||||
float m10, m11, m12;
|
||||
float m10 __attribute__((aligned(16))), m11, m12;
|
||||
} VKTransform;
|
||||
|
||||
VK_DEFINE_NON_DISPATCHABLE_HANDLE(VKMemory);
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2005, 2025, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2005, 2013, Oracle and/or its affiliates. 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
|
||||
@@ -48,7 +48,7 @@
|
||||
// restore the area overwritten by the graphic with
|
||||
// what was there prior to rendering the graphic.
|
||||
|
||||
static const char szNetscape20ext[] = "NETSCAPE2.0";
|
||||
static const char szNetscape20ext[11] = "NETSCAPE2.0";
|
||||
|
||||
#define NSEXT_LOOP 0x01 // Loop Count field code
|
||||
|
||||
@@ -181,7 +181,7 @@ SplashDecodeGif(Splash * splash, GifFileType * gif)
|
||||
}
|
||||
case APPLICATION_EXT_FUNC_CODE:
|
||||
{
|
||||
if (size == strlen(szNetscape20ext)
|
||||
if (size == sizeof(szNetscape20ext)
|
||||
&& memcmp(pExtension, szNetscape20ext, size) == 0) {
|
||||
int iSubCode;
|
||||
|
||||
|
||||
@@ -47,7 +47,6 @@ import java.awt.image.WritableRaster;
|
||||
import sun.awt.image.OffScreenImage;
|
||||
import sun.awt.image.SunVolatileImage;
|
||||
import sun.awt.image.SurfaceManager;
|
||||
import sun.awt.image.VolatileSurfaceManager;
|
||||
import sun.java2d.Disposer;
|
||||
import sun.java2d.DisposerRecord;
|
||||
import sun.java2d.SurfaceData;
|
||||
@@ -56,7 +55,6 @@ import sun.java2d.loops.RenderLoops;
|
||||
import sun.java2d.loops.SurfaceType;
|
||||
import sun.java2d.pipe.Region;
|
||||
import sun.java2d.x11.X11SurfaceData;
|
||||
import sun.java2d.x11.X11VolatileSurfaceManager;
|
||||
|
||||
/**
|
||||
* This is an implementation of a GraphicsConfiguration object for a
|
||||
@@ -66,7 +64,7 @@ import sun.java2d.x11.X11VolatileSurfaceManager;
|
||||
* @see GraphicsDevice
|
||||
*/
|
||||
public class X11GraphicsConfig extends GraphicsConfiguration
|
||||
implements SurfaceManager.ProxiedGraphicsConfig, SurfaceManager.Factory
|
||||
implements SurfaceManager.ProxiedGraphicsConfig
|
||||
{
|
||||
private final X11GraphicsDevice device;
|
||||
protected int visual;
|
||||
@@ -502,10 +500,4 @@ public class X11GraphicsConfig extends GraphicsConfiguration
|
||||
}
|
||||
|
||||
private native boolean isTranslucencyCapable(long x11ConfigData);
|
||||
|
||||
@Override
|
||||
public VolatileSurfaceManager createVolatileManager(SunVolatileImage image,
|
||||
Object context) {
|
||||
return new X11VolatileSurfaceManager(image, context);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -67,8 +67,7 @@ public final class X11GraphicsDevice extends GraphicsDevice
|
||||
* therefore methods, which is using this id should be ready to it.
|
||||
*/
|
||||
private volatile int screen;
|
||||
Map<SurfaceType, SurfaceManager.ProxyCache> x11ProxyCacheMap =
|
||||
Collections.synchronizedMap(new HashMap<>());
|
||||
Map<SurfaceType, SurfaceManager.ProxyCache> x11ProxyCacheMap = Collections.synchronizedMap(new HashMap<>());
|
||||
|
||||
private static AWTPermission fullScreenExclusivePermission;
|
||||
private static Boolean xrandrExtSupported;
|
||||
@@ -119,8 +118,7 @@ public final class X11GraphicsDevice extends GraphicsDevice
|
||||
}
|
||||
|
||||
public SurfaceManager.ProxyCache getProxyCacheFor(SurfaceType st) {
|
||||
return x11ProxyCacheMap.computeIfAbsent(st,
|
||||
unused -> new SurfaceManager.ProxyCache());
|
||||
return x11ProxyCacheMap.computeIfAbsent(st, unused -> new SurfaceManager.ProxyCache());
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -42,6 +42,8 @@ import java.util.Map;
|
||||
|
||||
import sun.awt.X11.XToolkit;
|
||||
import sun.java2d.SunGraphicsEnvironment;
|
||||
import sun.java2d.SurfaceManagerFactory;
|
||||
import sun.java2d.UnixSurfaceManagerFactory;
|
||||
import sun.java2d.xr.XRSurfaceData;
|
||||
|
||||
/**
|
||||
@@ -134,6 +136,10 @@ public final class X11GraphicsEnvironment extends SunGraphicsEnvironment impleme
|
||||
return null;
|
||||
}
|
||||
});
|
||||
|
||||
// Install the correct surface manager factory.
|
||||
SurfaceManagerFactory.setInstance(new UnixSurfaceManagerFactory());
|
||||
|
||||
}
|
||||
|
||||
private static boolean isVMWare() {
|
||||
|
||||
@@ -114,8 +114,6 @@ public class DefaultFrameDecoration extends FullFrameDecorationHelper {
|
||||
|
||||
@Override
|
||||
protected Rectangle getMaximizeButtonBounds() {
|
||||
if (!hasMaximizeButton()) return null;
|
||||
|
||||
int x = peer.getWidth() - BUTTON_SIZE * 2 - BUTTONS_RIGHT_PADDING
|
||||
- BUTTONS_PADDING - BORDER_SIZE;
|
||||
int y = (int) Math.floor((HEIGHT - BUTTON_SIZE + 1f) / 2);
|
||||
@@ -124,8 +122,6 @@ public class DefaultFrameDecoration extends FullFrameDecorationHelper {
|
||||
|
||||
@Override
|
||||
protected Rectangle getMinimizeButtonBounds() {
|
||||
if (!hasMinimizeButton()) return null;
|
||||
|
||||
int x = peer.getWidth() - BUTTON_SIZE * 3 - BUTTONS_RIGHT_PADDING
|
||||
- BUTTONS_PADDING * 2 - BORDER_SIZE;
|
||||
int y = (int) Math.floor((HEIGHT - BUTTON_SIZE + 1f) / 2);
|
||||
|
||||
@@ -268,7 +268,7 @@ public class WLComponentPeer implements ComponentPeer, WLSurfaceSizeListener {
|
||||
return false;
|
||||
}
|
||||
|
||||
public static Window getToplevelFor(Component component) {
|
||||
private static Window getToplevelFor(Component component) {
|
||||
Container container = component instanceof Container c ? c : component.getParent();
|
||||
for (Container p = container; p != null; p = p.getParent()) {
|
||||
if (p instanceof Window window && !isWlPopup(window)) {
|
||||
@@ -285,7 +285,7 @@ public class WLComponentPeer implements ComponentPeer, WLSurfaceSizeListener {
|
||||
: c.getParent();
|
||||
}
|
||||
|
||||
public static Point getRelativeLocation(Component c, Window toplevel) {
|
||||
static Point getRelativeLocation(Component c, Window toplevel) {
|
||||
Objects.requireNonNull(c);
|
||||
|
||||
if (toplevel == null) {
|
||||
@@ -1590,7 +1590,7 @@ public class WLComponentPeer implements ComponentPeer, WLSurfaceSizeListener {
|
||||
* Converts a value in the Java coordinate system into the Wayland
|
||||
* surface-local coordinate system.
|
||||
*/
|
||||
public final int javaUnitsToSurfaceUnits(int value) {
|
||||
int javaUnitsToSurfaceUnits(int value) {
|
||||
if (!WLGraphicsEnvironment.isDebugScaleEnabled()) {
|
||||
return value;
|
||||
} else {
|
||||
@@ -1600,7 +1600,7 @@ public class WLComponentPeer implements ComponentPeer, WLSurfaceSizeListener {
|
||||
}
|
||||
}
|
||||
|
||||
public final int javaUnitsToSurfaceSize(int value) {
|
||||
int javaUnitsToSurfaceSize(int value) {
|
||||
if (!WLGraphicsEnvironment.isDebugScaleEnabled()) {
|
||||
return value;
|
||||
} else {
|
||||
|
||||
@@ -47,7 +47,7 @@ public class WLDataSource {
|
||||
|
||||
private static native void setDnDActionsImpl(long nativePtr, int actions);
|
||||
|
||||
private static native void setDnDIconImpl(long nativePtr, int scale, int width, int height, int offsetX, int offsetY, int[] pixels);
|
||||
private static native void setDnDIconImpl(long nativePtr, int width, int height, int offsetX, int offsetY, int[] pixels);
|
||||
|
||||
WLDataSource(WLDataDevice dataDevice, int protocol, Transferable data) {
|
||||
var wlDataTransferer = (WLDataTransferer) WLDataTransferer.getInstance();
|
||||
@@ -96,7 +96,7 @@ public class WLDataSource {
|
||||
setDnDActionsImpl(nativePtr, actions);
|
||||
}
|
||||
|
||||
public void setDnDIcon(Image image, int scale, int offsetX, int offsetY) {
|
||||
public void setDnDIcon(Image image, int offsetX, int offsetY) {
|
||||
if (nativePtr == 0) {
|
||||
throw new IllegalStateException("Native pointer is null");
|
||||
}
|
||||
@@ -118,7 +118,7 @@ public class WLDataSource {
|
||||
bufferedImage.getRGB(0, 0, width, height, pixels, 0, width);
|
||||
}
|
||||
|
||||
setDnDIconImpl(nativePtr, scale, width, height, offsetX, offsetY, pixels);
|
||||
setDnDIconImpl(nativePtr, width, height, offsetX, offsetY, pixels);
|
||||
}
|
||||
|
||||
public synchronized void destroy() {
|
||||
|
||||
@@ -92,33 +92,21 @@ public class WLDragSourceContextPeer extends SunDragSourceContextPeer {
|
||||
this.dataDevice = dataDevice;
|
||||
}
|
||||
|
||||
private WLComponentPeer getPeer() {
|
||||
private long getComponentWlSurfacePtr() {
|
||||
var comp = getComponent();
|
||||
while (comp != null) {
|
||||
var peer = AWTAccessor.getComponentAccessor().getPeer(comp);
|
||||
if (peer instanceof WLComponentPeer wlPeer) {
|
||||
return wlPeer;
|
||||
return wlPeer.getSurface().getWlSurfacePtr();
|
||||
}
|
||||
comp = comp.getParent();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private WLMainSurface getSurface() {
|
||||
WLComponentPeer peer = getPeer();
|
||||
if (peer != null) {
|
||||
return peer.getSurface();
|
||||
}
|
||||
return null;
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void startDrag(Transferable trans, long[] formats, Map<Long, DataFlavor> formatMap) {
|
||||
var mainSurface = getSurface();
|
||||
if (mainSurface == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
// formats and formatMap are unused, because WLDataSource already references the same DataTransferer singleton
|
||||
var source = new WLDragSource(trans);
|
||||
|
||||
@@ -130,14 +118,13 @@ public class WLDragSourceContextPeer extends SunDragSourceContextPeer {
|
||||
var dragImage = getDragImage();
|
||||
if (dragImage != null) {
|
||||
var dragImageOffset = getDragImageOffset();
|
||||
source.setDnDIcon(dragImage,
|
||||
mainSurface.getGraphicsDevice().getDisplayScale(),
|
||||
dragImageOffset.x, dragImageOffset.y);
|
||||
source.setDnDIcon(dragImage, dragImageOffset.x, dragImageOffset.y);
|
||||
}
|
||||
|
||||
long eventSerial = WLToolkit.getInputState().pointerButtonSerial();
|
||||
|
||||
dataDevice.startDrag(source, mainSurface.getWlSurfacePtr(), eventSerial);
|
||||
var wlSurface = getComponentWlSurfacePtr();
|
||||
dataDevice.startDrag(source, wlSurface, eventSerial);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -26,7 +26,6 @@
|
||||
package sun.awt.wl;
|
||||
|
||||
import java.awt.*;
|
||||
import java.awt.event.WindowAdapter;
|
||||
import java.awt.event.WindowEvent;
|
||||
import java.awt.peer.FramePeer;
|
||||
import sun.awt.AWTAccessor;
|
||||
@@ -43,12 +42,6 @@ public class WLFramePeer extends WLDecoratedPeer implements FramePeer {
|
||||
super(target, target.isUndecorated(),
|
||||
Toolkit.getDefaultToolkit().isFrameStateSupported(Frame.ICONIFIED),
|
||||
Toolkit.getDefaultToolkit().isFrameStateSupported(Frame.MAXIMIZED_BOTH));
|
||||
AWTAccessor.getWindowAccessor().addWindowListener(target, new WindowAdapter() {
|
||||
@Override
|
||||
public void windowClosing(WindowEvent e) {
|
||||
getFrame().removeNotify();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -38,9 +38,35 @@ import sun.java2d.wl.WLSurfaceSizeListener;
|
||||
|
||||
public abstract class WLGraphicsConfig extends GraphicsConfiguration {
|
||||
private final WLGraphicsDevice device;
|
||||
private final int x;
|
||||
private final int y;
|
||||
private final int xLogical; // logical (scaled) horizontal location; optional, could be zero
|
||||
private final int yLogical; // logical (scaled) vertical location; optional, could be zero
|
||||
private final int width;
|
||||
private final int height;
|
||||
private final int widthLogical; // logical (scaled) width; optional, could be zero
|
||||
private final int heightLogical;// logical (scaled) height; optional, could be zero
|
||||
private final int displayScale; // as reported by Wayland
|
||||
private final double effectiveScale; // as enforced by Java
|
||||
|
||||
protected WLGraphicsConfig(WLGraphicsDevice device) {
|
||||
protected WLGraphicsConfig(WLGraphicsDevice device, int x, int y, int xLogical, int yLogical,
|
||||
int width, int height, int widthLogical, int heightLogical,
|
||||
int displayScale) {
|
||||
this.device = device;
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
this.xLogical = xLogical;
|
||||
this.yLogical = yLogical;
|
||||
this.width = width;
|
||||
this.height = height;
|
||||
this.widthLogical = widthLogical;
|
||||
this.heightLogical = heightLogical;
|
||||
this.displayScale = displayScale;
|
||||
this.effectiveScale = WLGraphicsEnvironment.effectiveScaleFrom(displayScale);
|
||||
}
|
||||
|
||||
boolean differsFrom(int width, int height, int scale) {
|
||||
return width != this.width || height != this.height || scale != this.displayScale;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -58,7 +84,7 @@ public abstract class WLGraphicsConfig extends GraphicsConfiguration {
|
||||
|
||||
@Override
|
||||
public AffineTransform getDefaultTransform() {
|
||||
double scale = device.getEffectiveScale();
|
||||
double scale = effectiveScale;
|
||||
return AffineTransform.getScaleInstance(scale, scale);
|
||||
}
|
||||
|
||||
@@ -71,18 +97,20 @@ public abstract class WLGraphicsConfig extends GraphicsConfiguration {
|
||||
|
||||
@Override
|
||||
public Rectangle getBounds() {
|
||||
return device.getBounds();
|
||||
return (widthLogical > 0 && heightLogical > 0)
|
||||
? new Rectangle(xLogical, yLogical, widthLogical, heightLogical)
|
||||
: new Rectangle(x, y, width, height);
|
||||
}
|
||||
|
||||
public Rectangle getRealBounds() {
|
||||
return device.getRealBounds();
|
||||
return new Rectangle(x, y, width, height);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the preferred Wayland buffer scale for this display configuration.
|
||||
*/
|
||||
public int getDisplayScale() {
|
||||
return device.getDisplayScale();
|
||||
return displayScale;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -90,7 +118,7 @@ public abstract class WLGraphicsConfig extends GraphicsConfiguration {
|
||||
* if overridden with the sun.java2d.uiScale system property.
|
||||
*/
|
||||
public double getEffectiveScale() {
|
||||
return device.getEffectiveScale();
|
||||
return effectiveScale;
|
||||
}
|
||||
|
||||
public abstract SurfaceType getSurfaceType();
|
||||
@@ -99,7 +127,6 @@ public abstract class WLGraphicsConfig extends GraphicsConfiguration {
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
Rectangle bounds = getBounds();
|
||||
return String.format("%dx%d@(%d, %d) %dx scale", bounds.width, bounds.height, bounds.x, bounds.y, getDisplayScale());
|
||||
return String.format("%dx%d@(%d, %d) %dx scale", width, height, x, y, displayScale);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -39,21 +39,15 @@ import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* Corresponds to a Wayland output and is identified by its wlID.
|
||||
* Owns all graphics configurations associated with this device.
|
||||
* Encapsulates all the other properties of the output, such as its size
|
||||
* and location in a multi-monitor configuration.
|
||||
* Whenever any of these properties change, they are updated and
|
||||
* the GraphicsConfiguration objects get re-created to let referents know of the change.
|
||||
* Corresponds to Wayland's output and is identified by its wlID and x, y coordinates
|
||||
* in the multi-monitor setup. Whenever those change, this device is re-created.
|
||||
*/
|
||||
public class WLGraphicsDevice extends GraphicsDevice {
|
||||
private static final double MM_IN_INCH = 25.4;
|
||||
|
||||
/**
|
||||
* ID of the corresponding wl_output object received from Wayland.
|
||||
* Only changes when the device gets invalidated.
|
||||
*/
|
||||
private volatile int wlID;
|
||||
private volatile int wlID; // only changes when the device gets invalidated
|
||||
|
||||
/**
|
||||
* Some human-readable name of the device that came from Wayland.
|
||||
@@ -64,142 +58,75 @@ public class WLGraphicsDevice extends GraphicsDevice {
|
||||
/**
|
||||
* The horizontal location of this device in the multi-monitor configuration.
|
||||
*/
|
||||
private volatile int x;
|
||||
private volatile int x; // only changes when the device gets invalidated
|
||||
|
||||
/**
|
||||
* The vertical location of this device in the multi-monitor configuration.
|
||||
*/
|
||||
private volatile int y;
|
||||
private volatile int y; // only changes when the device gets invalidated
|
||||
|
||||
/**
|
||||
* Pixel width, mostly for accounting and reporting.
|
||||
*/
|
||||
private volatile int width;
|
||||
private volatile int xLogical; // logical (scaled) horizontal location; optional, could be zero
|
||||
private volatile int yLogical; // logical (scaled) vertical location; optional, could be zero
|
||||
|
||||
/**
|
||||
* Pixel height, mostly for accounting and reporting.
|
||||
*/
|
||||
private volatile int height;
|
||||
private final int widthMm;
|
||||
private final int heightMm;
|
||||
|
||||
/**
|
||||
* Logical (scaled) width in Java units.
|
||||
*/
|
||||
private volatile int widthLogical;
|
||||
// Configs are always the same in size and scale
|
||||
private volatile GraphicsConfiguration[] configs = null;
|
||||
|
||||
/**
|
||||
* Logical (scaled) height in Java units.
|
||||
*/
|
||||
private volatile int heightLogical;
|
||||
// The default config is an object from the configs array
|
||||
private volatile WLGraphicsConfig defaultConfig = null;
|
||||
|
||||
/**
|
||||
* Width in millimeters.
|
||||
*/
|
||||
private volatile int widthMm;
|
||||
|
||||
/**
|
||||
* Height in millimeters.
|
||||
*/
|
||||
private volatile int heightMm;
|
||||
|
||||
/**
|
||||
* The device's scale factor as reported by Wayland.
|
||||
* Since it is an integer, it's usually higher than the real fraction scale.
|
||||
*/
|
||||
private volatile int displayScale;
|
||||
|
||||
/**
|
||||
* The effective scale factor as determined by Java.
|
||||
*/
|
||||
private volatile double effectiveScale;
|
||||
|
||||
private volatile GraphicsConfiguration[] configs;
|
||||
private volatile WLGraphicsConfig defaultConfig; // A reference to the configs array
|
||||
|
||||
/**
|
||||
* Top-level window peers that consider this device as their primary one
|
||||
* and get their graphics configuration from it
|
||||
*/
|
||||
// Top-level window peers that consider this device as their primary one
|
||||
// and get their graphics configuration from it
|
||||
private final Set<WLComponentPeer> toplevels = new HashSet<>(); // guarded by 'this'
|
||||
|
||||
private WLGraphicsDevice(int id,
|
||||
String name,
|
||||
int x, int y,
|
||||
int width, int height,
|
||||
int widthLogical, int heightLogical,
|
||||
int widthMm, int heightMm,
|
||||
int displayScale) {
|
||||
assert width > 0 && height > 0;
|
||||
assert widthLogical > 0 && heightLogical > 0;
|
||||
assert widthMm > 0 && heightMm > 0;
|
||||
assert displayScale > 0;
|
||||
|
||||
private WLGraphicsDevice(int id, int x, int y, int xLogical, int yLogical, int widthMm, int heightMm) {
|
||||
this.wlID = id;
|
||||
this.name = name;
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
this.width = width;
|
||||
this.height = height;
|
||||
this.widthLogical = widthLogical;
|
||||
this.heightLogical = heightLogical;
|
||||
this.xLogical = xLogical;
|
||||
this.yLogical = yLogical;
|
||||
this.widthMm = widthMm;
|
||||
this.heightMm = heightMm;
|
||||
this.displayScale = displayScale;
|
||||
this.effectiveScale = WLGraphicsEnvironment.effectiveScaleFrom(displayScale);
|
||||
|
||||
makeGC();
|
||||
}
|
||||
|
||||
private void makeGC() {
|
||||
GraphicsConfiguration[] newConfigs;
|
||||
WLGraphicsConfig newDefaultConfig;
|
||||
if (VKEnv.isPresentationEnabled()) {
|
||||
newConfigs = VKEnv.getDevices().flatMap(d -> d.getPresentableGraphicsConfigs().map(
|
||||
gc -> WLVKGraphicsConfig.getConfig(gc, this)))
|
||||
.toArray(WLGraphicsConfig[]::new);
|
||||
newDefaultConfig = (WLGraphicsConfig) newConfigs[0];
|
||||
} else {
|
||||
// TODO: Actually, Wayland may support a lot more shared memory buffer configurations, need to
|
||||
// subscribe to the wl_shm:format event and get the list from there.
|
||||
newDefaultConfig = WLSMGraphicsConfig.getConfig(this, true);
|
||||
newConfigs = new GraphicsConfiguration[2];
|
||||
newConfigs[0] = newDefaultConfig;
|
||||
newConfigs[1] = WLSMGraphicsConfig.getConfig(this, false);
|
||||
int getID() {
|
||||
return wlID;
|
||||
}
|
||||
|
||||
void updateConfiguration(String name, int width, int height, int widthLogical, int heightLogical, int scale) {
|
||||
this.name = name;
|
||||
|
||||
WLGraphicsConfig config = defaultConfig;
|
||||
// Note that all configs are of equal size and scale
|
||||
if (config == null || config.differsFrom(width, height, scale)) {
|
||||
GraphicsConfiguration[] newConfigs;
|
||||
WLGraphicsConfig newDefaultConfig;
|
||||
// It is necessary to create a new object whenever config changes as its
|
||||
// identity is used to detect changes in scale, among other things.
|
||||
if (VKEnv.isPresentationEnabled()) {
|
||||
newConfigs = VKEnv.getDevices().flatMap(d -> d.getPresentableGraphicsConfigs().map(
|
||||
gc -> WLVKGraphicsConfig.getConfig(
|
||||
gc, this, x, y, xLogical, yLogical, width, height, widthLogical, heightLogical, scale)))
|
||||
.toArray(WLGraphicsConfig[]::new);
|
||||
newDefaultConfig = (WLGraphicsConfig) newConfigs[0];
|
||||
} else {
|
||||
// TODO: Actually, Wayland may support a lot more shared memory buffer configurations, need to
|
||||
// subscribe to the wl_shm:format event and get the list from there.
|
||||
newDefaultConfig = WLSMGraphicsConfig.getConfig(this, x, y, xLogical, yLogical, width, height, widthLogical, heightLogical, scale, true);
|
||||
newConfigs = new GraphicsConfiguration[2];
|
||||
newConfigs[0] = newDefaultConfig;
|
||||
newConfigs[1] = WLSMGraphicsConfig.getConfig(this, x, y, xLogical, yLogical, width, height, widthLogical, heightLogical, scale, false);
|
||||
}
|
||||
|
||||
configs = newConfigs;
|
||||
defaultConfig = newDefaultConfig;
|
||||
}
|
||||
|
||||
configs = newConfigs;
|
||||
defaultConfig = newDefaultConfig;
|
||||
}
|
||||
|
||||
void updateConfiguration(String name,
|
||||
int x, int y,
|
||||
int width, int height,
|
||||
int widthLogical, int heightLogical,
|
||||
int widthMm, int heightMm,
|
||||
int scale) {
|
||||
assert width > 0 && height > 0;
|
||||
assert widthLogical > 0 && heightLogical > 0;
|
||||
assert widthMm > 0 && heightMm > 0;
|
||||
assert scale > 0;
|
||||
|
||||
this.name = name;
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
this.width = width;
|
||||
this.height = height;
|
||||
this.widthLogical = widthLogical;
|
||||
this.heightLogical = heightLogical;
|
||||
this.widthMm = widthMm;
|
||||
this.heightMm = heightMm;
|
||||
this.displayScale = scale;
|
||||
this.effectiveScale = WLGraphicsEnvironment.effectiveScaleFrom(scale);
|
||||
|
||||
// It is necessary to create new config objects whenever this device changes
|
||||
// as GraphicsConfiguration identity is used to detect changes in scale, among other things.
|
||||
makeGC();
|
||||
|
||||
// It is important that by the time displayChanged() events are delivered,
|
||||
// all the peers on this device had their graphics configuration updated
|
||||
// to refer to the new ones with, perhaps, a different scale or resolution.
|
||||
// to refer to the new ones with, perhaps, different scale or resolution.
|
||||
// This affects various BufferStrategy that use volatile images as their buffers.
|
||||
notifyToplevels();
|
||||
}
|
||||
@@ -209,36 +136,47 @@ public class WLGraphicsDevice extends GraphicsDevice {
|
||||
synchronized (this) {
|
||||
toplevelsCopy.addAll(toplevels);
|
||||
}
|
||||
toplevelsCopy.forEach(WLComponentPeer::checkIfOnNewScreen);
|
||||
int wlOutputID = this.wlID;
|
||||
// NB: each of those peers will likely receive another such notification
|
||||
// from Wayland when it gets the wl_surface::enter event, but the second one
|
||||
// will effectively be a no-op.
|
||||
toplevelsCopy.forEach((peer) -> peer.notifyEnteredOutput(wlOutputID));
|
||||
}
|
||||
|
||||
/**
|
||||
* Changes all aspects of this device, including its identity to be that of the given
|
||||
* Changes all aspects of this device including its identity to be that of the given
|
||||
* device. Only used for devices that are no longer physically present, but references
|
||||
* to which may still exist in the program.
|
||||
*/
|
||||
void invalidate(WLGraphicsDevice similarDevice) {
|
||||
// Note: It is expected that all the surface this device used to host have already received
|
||||
// the 'leave' event and updated their device/graphics configurations accordingly.
|
||||
this.wlID = similarDevice.wlID;
|
||||
updateConfiguration(similarDevice.name,
|
||||
similarDevice.x,
|
||||
similarDevice.y,
|
||||
similarDevice.width,
|
||||
similarDevice.height,
|
||||
similarDevice.widthLogical,
|
||||
similarDevice.heightLogical,
|
||||
similarDevice.widthMm,
|
||||
similarDevice.heightMm,
|
||||
similarDevice.displayScale);
|
||||
this.x = similarDevice.x;
|
||||
this.y = similarDevice.y;
|
||||
this.xLogical = similarDevice.xLogical;
|
||||
this.yLogical = similarDevice.yLogical;
|
||||
|
||||
int newScale = similarDevice.getDisplayScale();
|
||||
Rectangle newBounds = similarDevice.defaultConfig.getBounds();
|
||||
Rectangle newRealBounds = similarDevice.defaultConfig.getRealBounds();
|
||||
updateConfiguration(similarDevice.name, newRealBounds.width, newRealBounds.height, newBounds.width, newBounds.height, newScale);
|
||||
}
|
||||
|
||||
public static WLGraphicsDevice createWithConfiguration(int id, String name,
|
||||
int x, int y,
|
||||
int x, int y, int xLogical, int yLogical,
|
||||
int width, int height, int widthLogical, int heightLogical,
|
||||
int widthMm, int heightMm,
|
||||
int scale) {
|
||||
return new WLGraphicsDevice(id, name, x, y, width, height, widthLogical, heightLogical, widthMm, heightMm, scale);
|
||||
WLGraphicsDevice device = new WLGraphicsDevice(id, x, y, xLogical, yLogical, widthMm, heightMm);
|
||||
device.updateConfiguration(name, width, height, widthLogical, heightLogical, scale);
|
||||
return device;
|
||||
}
|
||||
|
||||
/**
|
||||
* Compares the identity of this device with the given attributes
|
||||
* and returns true iff the attributes identify the same device.
|
||||
*/
|
||||
boolean isSameDeviceAs(int wlID, int x, int y, int xLogical, int yLogical) {
|
||||
return this.wlID == wlID && this.x == x && this.y == y && this.xLogical == xLogical && this.yLogical == yLogical;
|
||||
}
|
||||
|
||||
boolean hasSameNameAs(WLGraphicsDevice otherDevice) {
|
||||
@@ -269,8 +207,8 @@ public class WLGraphicsDevice extends GraphicsDevice {
|
||||
public GraphicsConfiguration[] getConfigurations() {
|
||||
// From wayland.xml, wl_output.mode event:
|
||||
// "Non-current modes are deprecated. A compositor can decide to only
|
||||
// advertise the current mode and never send other modes. Clients
|
||||
// should not rely on non-current modes."
|
||||
// advertise the current mode and never send other modes. Clients
|
||||
// should not rely on non-current modes."
|
||||
// So there's always the same set of configs.
|
||||
return configs.clone();
|
||||
}
|
||||
@@ -280,24 +218,8 @@ public class WLGraphicsDevice extends GraphicsDevice {
|
||||
return defaultConfig;
|
||||
}
|
||||
|
||||
int getID() {
|
||||
return wlID;
|
||||
}
|
||||
|
||||
Rectangle getBounds() {
|
||||
return new Rectangle(x, y, widthLogical, heightLogical);
|
||||
}
|
||||
|
||||
Rectangle getRealBounds() {
|
||||
return new Rectangle(x, y, width, height);
|
||||
}
|
||||
|
||||
int getDisplayScale() {
|
||||
return displayScale;
|
||||
}
|
||||
|
||||
double getEffectiveScale() {
|
||||
return effectiveScale;
|
||||
return defaultConfig.getDisplayScale();
|
||||
}
|
||||
|
||||
int getResolution() {
|
||||
@@ -305,6 +227,13 @@ public class WLGraphicsDevice extends GraphicsDevice {
|
||||
return getResolutionX(defaultConfig);
|
||||
}
|
||||
|
||||
double getPhysicalResolution() {
|
||||
Rectangle bounds = defaultConfig.getRealBounds();
|
||||
double daigInPixels = Math.sqrt(bounds.width * bounds.width + bounds.height * bounds.height);
|
||||
double diagInMm = Math.sqrt(widthMm * widthMm + heightMm * heightMm);
|
||||
return daigInPixels * MM_IN_INCH / diagInMm;
|
||||
}
|
||||
|
||||
double getPhysicalScale() {
|
||||
Rectangle bounds = defaultConfig.getRealBounds();
|
||||
double daigInPixels = Math.sqrt(bounds.width * bounds.width + bounds.height * bounds.height);
|
||||
@@ -338,7 +267,7 @@ public class WLGraphicsDevice extends GraphicsDevice {
|
||||
|
||||
boolean fsSupported = isFullScreenSupported();
|
||||
if (fsSupported && old != null) {
|
||||
// enter windowed mode and restore the original display mode
|
||||
// enter windowed mode and restore original display mode
|
||||
exitFullScreenExclusive(old);
|
||||
}
|
||||
|
||||
@@ -382,8 +311,9 @@ public class WLGraphicsDevice extends GraphicsDevice {
|
||||
@Override
|
||||
public String toString() {
|
||||
var config = defaultConfig;
|
||||
return String.format("WLGraphicsDevice: '%s' id=%d at (%d, %d) with %s",
|
||||
name, wlID, x, y, config != null ? config : "<no configs>");
|
||||
return String.format("WLGraphicsDevice: '%s' id=%d at (%d, %d) ((%d, %d) logical) with %s",
|
||||
name, wlID, x, y, xLogical, yLogical,
|
||||
config != null ? config : "<no configs>");
|
||||
}
|
||||
|
||||
public Insets getInsets() {
|
||||
|
||||
@@ -26,7 +26,6 @@
|
||||
|
||||
package sun.awt.wl;
|
||||
|
||||
import java.awt.AWTError;
|
||||
import java.awt.Dimension;
|
||||
import java.awt.GraphicsConfiguration;
|
||||
import java.awt.GraphicsDevice;
|
||||
@@ -37,6 +36,8 @@ import java.util.Optional;
|
||||
|
||||
import sun.awt.HiDPIInfoProvider;
|
||||
import sun.java2d.SunGraphicsEnvironment;
|
||||
import sun.java2d.SurfaceManagerFactory;
|
||||
import sun.java2d.UnixSurfaceManagerFactory;
|
||||
import sun.util.logging.PlatformLogger;
|
||||
import sun.util.logging.PlatformLogger.Level;
|
||||
|
||||
@@ -55,10 +56,9 @@ public class WLGraphicsEnvironment extends SunGraphicsEnvironment implements HiD
|
||||
private static final boolean debugScaleEnabled;
|
||||
private final Dimension totalDisplayBounds = new Dimension();
|
||||
|
||||
private final List<WLGraphicsDevice> devices = new ArrayList<>(5);
|
||||
|
||||
static {
|
||||
System.loadLibrary("awt");
|
||||
SurfaceManagerFactory.setInstance(new UnixSurfaceManagerFactory());
|
||||
|
||||
debugScaleEnabled = SunGraphicsEnvironment.isUIScaleEnabled() && SunGraphicsEnvironment.getDebugScale() >= 1;
|
||||
|
||||
@@ -92,30 +92,15 @@ public class WLGraphicsEnvironment extends SunGraphicsEnvironment implements HiD
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public GraphicsDevice getDefaultScreenDevice() {
|
||||
synchronized (devices) {
|
||||
if (devices.isEmpty()) {
|
||||
throw new AWTError("no screen devices");
|
||||
}
|
||||
return devices.getFirst();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized GraphicsDevice[] getScreenDevices() {
|
||||
synchronized (devices) {
|
||||
return devices.toArray(new GraphicsDevice[0]);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isDisplayLocal() {
|
||||
return true;
|
||||
}
|
||||
|
||||
private final List<WLGraphicsDevice> devices = new ArrayList<>(5);
|
||||
|
||||
private void notifyOutputConfigured(String name, String make, String model, int wlID,
|
||||
int x, int y,
|
||||
int x, int y, int xLogical, int yLogical,
|
||||
int width, int height,
|
||||
int widthLogical, int heightLogical,
|
||||
int widthMm, int heightMm,
|
||||
@@ -123,33 +108,44 @@ public class WLGraphicsEnvironment extends SunGraphicsEnvironment implements HiD
|
||||
// Called from native code whenever a new output appears or an existing one changes its properties
|
||||
// NB: initially called during WLToolkit.initIDs() on the main thread; later on EDT.
|
||||
if (log.isLoggable(Level.FINE)) {
|
||||
log.fine(String.format("Output configured id=%d at (%d, %d) %dx%d (%dx%d logical) %dx scale",
|
||||
wlID, x, y, width, height, widthLogical, heightLogical, scale));
|
||||
log.fine(String.format("Output configured id=%d at (%d, %d) (%d, %d logical) %dx%d (%dx%d logical) %dx scale",
|
||||
wlID, x, y, xLogical, yLogical, width, height, widthLogical, heightLogical, scale));
|
||||
}
|
||||
|
||||
// Logical size comes from an optional protocol, so take the data from the main one, if absent
|
||||
if (widthLogical == 0) widthLogical = width;
|
||||
if (heightLogical == 0) heightLogical = height;
|
||||
String humanID = deviceNameFrom(name, make, model);
|
||||
|
||||
WLGraphicsDevice gd = deviceWithID(wlID);
|
||||
if (gd != null) {
|
||||
// Some properties of an existing device have changed; update the existing device and
|
||||
// let all the windows it hosts know about the change.
|
||||
gd.updateConfiguration(humanID, x, y, width, height, widthLogical, heightLogical, widthMm, heightMm, scale);
|
||||
} else {
|
||||
WLGraphicsDevice newGD = WLGraphicsDevice.createWithConfiguration(wlID, humanID,
|
||||
x, y, width, height, widthLogical, heightLogical,
|
||||
widthMm, heightMm, scale);
|
||||
synchronized (devices) {
|
||||
devices.add(newGD);
|
||||
String humanID =
|
||||
(name != null ? name + " " : "")
|
||||
+ (make != null ? make + " " : "")
|
||||
+ (model != null ? model : "");
|
||||
synchronized (devices) {
|
||||
boolean newOutput = true;
|
||||
for (int i = 0; i < devices.size(); i++) {
|
||||
final WLGraphicsDevice gd = devices.get(i);
|
||||
if (gd.getID() == wlID) {
|
||||
newOutput = false;
|
||||
if (gd.isSameDeviceAs(wlID, x, y, xLogical, yLogical)) {
|
||||
// These coordinates and the size are not scaled.
|
||||
gd.updateConfiguration(humanID, width, height, widthLogical, heightLogical, scale);
|
||||
} else {
|
||||
final WLGraphicsDevice updatedDevice = WLGraphicsDevice.createWithConfiguration(wlID, humanID,
|
||||
x, y, xLogical, yLogical, width, height, widthLogical, heightLogical,
|
||||
widthMm, heightMm, scale);
|
||||
devices.set(i, updatedDevice);
|
||||
gd.invalidate(updatedDevice);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (newOutput) {
|
||||
final WLGraphicsDevice gd = WLGraphicsDevice.createWithConfiguration(wlID, humanID,
|
||||
x, y, xLogical, yLogical, width, height, widthLogical, heightLogical,
|
||||
widthMm, heightMm, scale);
|
||||
devices.add(gd);
|
||||
}
|
||||
if (LogDisplay.ENABLED) {
|
||||
double effectiveScale = effectiveScaleFrom(scale);
|
||||
LogDisplay log = newOutput ? LogDisplay.ADDED : LogDisplay.CHANGED;
|
||||
log.log(wlID, (int) (width / effectiveScale) + "x" + (int) (height / effectiveScale), effectiveScale);
|
||||
}
|
||||
}
|
||||
|
||||
if (LogDisplay.ENABLED) {
|
||||
double effectiveScale = effectiveScaleFrom(scale);
|
||||
LogDisplay log = (gd == null) ? LogDisplay.ADDED : LogDisplay.CHANGED;
|
||||
log.log(wlID, (int) (width / effectiveScale) + "x" + (int) (height / effectiveScale), effectiveScale);
|
||||
}
|
||||
|
||||
updateTotalDisplayBounds();
|
||||
@@ -160,12 +156,6 @@ public class WLGraphicsEnvironment extends SunGraphicsEnvironment implements HiD
|
||||
}
|
||||
}
|
||||
|
||||
private static String deviceNameFrom(String name, String make, String model) {
|
||||
return (name != null ? name + " " : "")
|
||||
+ (make != null ? make + " " : "")
|
||||
+ (model != null ? model : "");
|
||||
}
|
||||
|
||||
private WLGraphicsDevice getSimilarDevice(WLGraphicsDevice modelDevice) {
|
||||
WLGraphicsDevice similarDevice = devices.isEmpty() ? null : devices.getFirst();
|
||||
for (WLGraphicsDevice device : devices) {
|
||||
@@ -189,33 +179,47 @@ public class WLGraphicsEnvironment extends SunGraphicsEnvironment implements HiD
|
||||
log.fine(String.format("Output destroyed id=%d", wlID));
|
||||
}
|
||||
// NB: id may *not* be that of any output; if so, just ignore this event.
|
||||
WLGraphicsDevice gd = deviceWithID(wlID);
|
||||
if (gd != null) {
|
||||
if (LogDisplay.ENABLED) {
|
||||
WLGraphicsConfig config = (WLGraphicsConfig) gd.getDefaultConfiguration();
|
||||
Rectangle bounds = config.getBounds();
|
||||
LogDisplay.REMOVED.log(wlID, bounds.width + "x" + bounds.height, config.getEffectiveScale());
|
||||
synchronized (devices) {
|
||||
final Optional<WLGraphicsDevice> deviceOptional = devices.stream()
|
||||
.filter(device -> device.getID() == wlID)
|
||||
.findFirst();
|
||||
if (deviceOptional.isPresent()) {
|
||||
final WLGraphicsDevice destroyedDevice = deviceOptional.get();
|
||||
if (LogDisplay.ENABLED) {
|
||||
WLGraphicsConfig config = (WLGraphicsConfig) destroyedDevice.getDefaultConfiguration();
|
||||
Rectangle bounds = config.getBounds();
|
||||
LogDisplay.REMOVED.log(wlID, bounds.width + "x" + bounds.height, config.getEffectiveScale());
|
||||
}
|
||||
devices.remove(destroyedDevice);
|
||||
final WLGraphicsDevice similarDevice = getSimilarDevice(destroyedDevice);
|
||||
if (similarDevice != null) destroyedDevice.invalidate(similarDevice);
|
||||
}
|
||||
synchronized (devices) {
|
||||
devices.remove(gd);
|
||||
}
|
||||
final WLGraphicsDevice similarDevice = getSimilarDevice(gd);
|
||||
if (similarDevice != null) gd.invalidate(similarDevice);
|
||||
}
|
||||
|
||||
updateTotalDisplayBounds();
|
||||
displayChanged();
|
||||
}
|
||||
|
||||
WLGraphicsDevice deviceWithID(int wlOutputID) {
|
||||
WLGraphicsDevice notifySurfaceEnteredOutput(WLComponentPeer wlComponentPeer, int wlOutputID) {
|
||||
synchronized (devices) {
|
||||
for (WLGraphicsDevice gd : devices) {
|
||||
if (gd.getID() == wlOutputID) {
|
||||
return gd;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
WLGraphicsDevice notifySurfaceLeftOutput(WLComponentPeer wlComponentPeer, int wlOutputID) {
|
||||
synchronized (devices) {
|
||||
for (WLGraphicsDevice gd : devices) {
|
||||
if (gd.getID() == wlOutputID) {
|
||||
return gd;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public Dimension getTotalDisplayBounds() {
|
||||
@@ -225,14 +229,16 @@ public class WLGraphicsEnvironment extends SunGraphicsEnvironment implements HiD
|
||||
}
|
||||
|
||||
private void updateTotalDisplayBounds() {
|
||||
Rectangle virtualBounds = new Rectangle();
|
||||
synchronized (devices) {
|
||||
for (var gd : devices) {
|
||||
virtualBounds = virtualBounds.union(gd.getBounds());
|
||||
Rectangle virtualBounds = new Rectangle();
|
||||
for (GraphicsDevice gd : devices) {
|
||||
for (GraphicsConfiguration gc : gd.getConfigurations()) {
|
||||
virtualBounds = virtualBounds.union(gc.getBounds());
|
||||
}
|
||||
}
|
||||
synchronized (totalDisplayBounds) {
|
||||
totalDisplayBounds.setSize(virtualBounds.getSize());
|
||||
}
|
||||
}
|
||||
synchronized (totalDisplayBounds) {
|
||||
totalDisplayBounds.setSize(virtualBounds.getSize());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -67,7 +67,7 @@ public class WLMainSurface extends WLSurface {
|
||||
// Called from native code whenever the corresponding wl_surface enters an output (monitor)
|
||||
synchronized (devices) {
|
||||
final WLGraphicsEnvironment ge = (WLGraphicsEnvironment)WLGraphicsEnvironment.getLocalGraphicsEnvironment();
|
||||
final WLGraphicsDevice gd = ge.deviceWithID(wlOutputID);
|
||||
final WLGraphicsDevice gd = ge.notifySurfaceEnteredOutput(peer, wlOutputID);
|
||||
if (gd != null) {
|
||||
devices.add(gd);
|
||||
}
|
||||
@@ -81,7 +81,7 @@ public class WLMainSurface extends WLSurface {
|
||||
// Called from native code whenever the corresponding wl_surface leaves an output (monitor)
|
||||
synchronized (devices) {
|
||||
final WLGraphicsEnvironment ge = (WLGraphicsEnvironment)WLGraphicsEnvironment.getLocalGraphicsEnvironment();
|
||||
final WLGraphicsDevice gd = ge.deviceWithID(wlOutputID);
|
||||
final WLGraphicsDevice gd = ge.notifySurfaceLeftOutput(peer, wlOutputID);
|
||||
if (gd != null) {
|
||||
devices.remove(gd);
|
||||
}
|
||||
|
||||
@@ -24,16 +24,11 @@
|
||||
*/
|
||||
package sun.awt.wl;
|
||||
|
||||
import sun.awt.SunToolkit;
|
||||
|
||||
import java.awt.Point;
|
||||
import java.awt.Window;
|
||||
import java.awt.peer.MouseInfoPeer;
|
||||
|
||||
public class WLMouseInfoPeer implements MouseInfoPeer, SunToolkit.RelativePointerMovementInfoProvider {
|
||||
private final Object mouseDeltaLock = new Object();
|
||||
private double mouseDeltaX = 0.0;
|
||||
private double mouseDeltaY = 0.0;
|
||||
public class WLMouseInfoPeer implements MouseInfoPeer {
|
||||
|
||||
@Override
|
||||
public int fillPointWithCoords(Point point) {
|
||||
@@ -60,23 +55,4 @@ public class WLMouseInfoPeer implements MouseInfoPeer, SunToolkit.RelativePointe
|
||||
return HOLDER.instance;
|
||||
}
|
||||
|
||||
void accumulatePointerDelta(double dx, double dy) {
|
||||
synchronized (mouseDeltaLock) {
|
||||
mouseDeltaX += dx;
|
||||
mouseDeltaY += dy;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Point getAccumulatedMouseDeltaAndReset() {
|
||||
var p = new Point();
|
||||
synchronized (mouseDeltaLock) {
|
||||
int idx = (int) mouseDeltaX;
|
||||
int idy = (int) mouseDeltaY;
|
||||
p.setLocation(idx, idy);
|
||||
mouseDeltaX = mouseDeltaX - idx;
|
||||
mouseDeltaY = mouseDeltaY - idy;
|
||||
}
|
||||
return p;
|
||||
}
|
||||
}
|
||||
@@ -53,16 +53,36 @@ public class WLSMGraphicsConfig extends WLGraphicsConfig {
|
||||
private final ColorModel colorModel;
|
||||
private final SurfaceType surfaceType;
|
||||
|
||||
private WLSMGraphicsConfig(WLGraphicsDevice device, boolean translucencyCapable) {
|
||||
super(device);
|
||||
private WLSMGraphicsConfig(WLGraphicsDevice device,
|
||||
int x,
|
||||
int y,
|
||||
int xLogical,
|
||||
int yLogical,
|
||||
int width,
|
||||
int height,
|
||||
int widthLogical,
|
||||
int heightLogical,
|
||||
int scale,
|
||||
boolean translucencyCapable) {
|
||||
super(device, x, y, xLogical, yLogical, width, height, widthLogical, heightLogical, scale);
|
||||
this.translucencyCapable = translucencyCapable;
|
||||
this.colorModel = colorModelFor(translucencyCapable ? Transparency.TRANSLUCENT : Transparency.OPAQUE);
|
||||
// Note: GNOME Shell definitely expects alpha values to be pre-multiplied
|
||||
this.surfaceType = translucencyCapable ? SurfaceType.IntArgbPre : SurfaceType.IntRgb;
|
||||
}
|
||||
|
||||
public static WLSMGraphicsConfig getConfig(WLGraphicsDevice device, boolean translucencyCapable) {
|
||||
var newConfig = new WLSMGraphicsConfig(device, translucencyCapable);
|
||||
public static WLSMGraphicsConfig getConfig(WLGraphicsDevice device,
|
||||
int x,
|
||||
int y,
|
||||
int xLogical,
|
||||
int yLogical,
|
||||
int width,
|
||||
int height,
|
||||
int widthLogical,
|
||||
int heightLogical,
|
||||
int scale,
|
||||
boolean translucencyCapable) {
|
||||
var newConfig = new WLSMGraphicsConfig(device, x, y, xLogical, yLogical, width, height, widthLogical, heightLogical, scale, translucencyCapable);
|
||||
if (log.isLoggable(PlatformLogger.Level.FINE)) {
|
||||
log.fine("New shared memory config " + newConfig);
|
||||
}
|
||||
|
||||
@@ -36,7 +36,6 @@ import sun.awt.PeerEvent;
|
||||
import sun.awt.SunToolkit;
|
||||
import sun.awt.UNIXToolkit;
|
||||
import sun.awt.datatransfer.DataTransferer;
|
||||
import sun.awt.wl.im.WLInputMethodMetaDescriptor;
|
||||
import sun.java2d.vulkan.VKEnv;
|
||||
import sun.java2d.vulkan.VKRenderQueue;
|
||||
import sun.util.logging.PlatformLogger;
|
||||
@@ -300,10 +299,6 @@ public class WLToolkit extends UNIXToolkit implements Runnable {
|
||||
private static WLInputState inputState = WLInputState.initialState();
|
||||
private static WLKeyboard keyboard;
|
||||
|
||||
private static void dispatchRelativePointerEvent(double dx, double dy) {
|
||||
WLMouseInfoPeer.getInstance().accumulatePointerDelta(dx, dy);
|
||||
}
|
||||
|
||||
private static void dispatchPointerEvent(WLPointerEvent e) {
|
||||
// Invoked from the native code
|
||||
assert EventQueue.isDispatchThread();
|
||||
@@ -448,6 +443,7 @@ public class WLToolkit extends UNIXToolkit implements Runnable {
|
||||
final WLInputState newInputState = inputState.updatedFromKeyboardLeaveEvent(serial, surfacePtr);
|
||||
final WLWindowPeer peer = peerFromSurface(surfacePtr);
|
||||
if (peer != null && peer.getTarget() instanceof Window window) {
|
||||
((WLToolkit) Toolkit.getDefaultToolkit()).ungrab(window);
|
||||
final WindowEvent winLostFocusEvent = new WindowEvent(window, WindowEvent.WINDOW_LOST_FOCUS);
|
||||
WLKeyboardFocusManagerPeer.getInstance().setCurrentFocusedWindow(null);
|
||||
WLKeyboardFocusManagerPeer.getInstance().setCurrentFocusOwner(null);
|
||||
@@ -782,27 +778,13 @@ public class WLToolkit extends UNIXToolkit implements Runnable {
|
||||
return 16777216; // 24 bits per pixel, 8 bits per channel
|
||||
}
|
||||
|
||||
/**
|
||||
* {@link java.awt.event.InputMethodEvent#getText()} can contain attributes which provide AWT/Swing with additional useful information
|
||||
* (e.g. a language of the text).
|
||||
*
|
||||
* One kind of the possible attributes is {@link InputMethodHighlight}. It informs AWT/Swing that some parts of
|
||||
* the text are in different states of the text composing process, hence they should look differently from the others.
|
||||
* However, it doesn't tell how exactly they should look; this choice is left to Toolkit's implementations,
|
||||
* or more precisely implementations of this method.
|
||||
*
|
||||
* @param highlight a state of a part of InputMethodEvent's text
|
||||
*
|
||||
* @return a collection of {@link TextAttribute}s (with their corresponding values as documented) informing how exactly
|
||||
* such text should look or {@code null} if a mapping can't be provided.
|
||||
*
|
||||
* @see Toolkit#mapInputMethodHighlight(InputMethodHighlight)
|
||||
*/
|
||||
@Override
|
||||
public Map<TextAttribute, ?> mapInputMethodHighlight(InputMethodHighlight highlight) {
|
||||
return WLInputMethodMetaDescriptor.mapInputMethodHighlight(highlight);
|
||||
public Map<TextAttribute, ?> mapInputMethodHighlight( InputMethodHighlight highlight) {
|
||||
if (log.isLoggable(PlatformLogger.Level.FINE)) {
|
||||
log.fine("Not implemented: WLToolkit.mapInputMethodHighlight()");
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean getLockingKeyState(int key) {
|
||||
return switch (key) {
|
||||
@@ -873,7 +855,10 @@ public class WLToolkit extends UNIXToolkit implements Runnable {
|
||||
*/
|
||||
@Override
|
||||
public InputMethodDescriptor getInputMethodAdapterDescriptor() {
|
||||
return WLInputMethodMetaDescriptor.getInstanceIfAvailableOnPlatform();
|
||||
if (log.isLoggable(PlatformLogger.Level.FINE)) {
|
||||
log.fine("Not implemented: WLToolkit.getInputMethodAdapterDescriptor()");
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -882,6 +867,9 @@ public class WLToolkit extends UNIXToolkit implements Runnable {
|
||||
*/
|
||||
@Override
|
||||
public boolean enableInputMethodsForTextComponent() {
|
||||
if (log.isLoggable(PlatformLogger.Level.FINE)) {
|
||||
log.fine("Not implemented: WLToolkit.enableInputMethodsForTextComponent()");
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -996,10 +984,9 @@ public class WLToolkit extends UNIXToolkit implements Runnable {
|
||||
|
||||
var peer = AWTAccessor.getComponentAccessor().getPeer(w);
|
||||
if (peer instanceof WLWindowPeer windowPeer) {
|
||||
windowPeer.ungrab(false);
|
||||
windowPeer.ungrab();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns if the java.awt.Desktop class is supported on the current
|
||||
* desktop.
|
||||
|
||||
@@ -33,7 +33,6 @@ import sun.java2d.wl.WLSMSurfaceData;
|
||||
|
||||
import javax.swing.JRootPane;
|
||||
import javax.swing.RootPaneContainer;
|
||||
import java.awt.AWTEvent;
|
||||
import java.awt.AlphaComposite;
|
||||
import java.awt.Color;
|
||||
import java.awt.Component;
|
||||
@@ -101,7 +100,7 @@ public class WLWindowPeer extends WLComponentPeer implements WindowPeer, Surface
|
||||
|
||||
@Override
|
||||
protected void wlSetVisible(boolean v) {
|
||||
if (!v) ungrab(true);
|
||||
if (!v) ungrab();
|
||||
|
||||
if (v && targetIsWlPopup() && shouldBeFocusedOnShowing()) {
|
||||
requestWindowFocus();
|
||||
@@ -205,7 +204,7 @@ public class WLWindowPeer extends WLComponentPeer implements WindowPeer, Surface
|
||||
|
||||
@Override
|
||||
public void dispose() {
|
||||
ungrab(true);
|
||||
ungrab();
|
||||
resetCornerMasks();
|
||||
super.dispose();
|
||||
}
|
||||
@@ -247,17 +246,15 @@ public class WLWindowPeer extends WLComponentPeer implements WindowPeer, Surface
|
||||
|
||||
public void grab() {
|
||||
if (grabbingWindow != null && !isGrabbing()) {
|
||||
grabbingWindow.ungrab(false);
|
||||
grabbingWindow.ungrab();
|
||||
}
|
||||
grabbingWindow = this;
|
||||
}
|
||||
|
||||
public void ungrab(boolean externalUngrab) {
|
||||
public void ungrab() {
|
||||
if (isGrabbing()) {
|
||||
grabbingWindow = null;
|
||||
if (externalUngrab) {
|
||||
WLToolkit.postEvent(new UngrabEvent(getTarget()));
|
||||
}
|
||||
WLToolkit.postEvent(new UngrabEvent(getTarget()));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -265,13 +262,6 @@ public class WLWindowPeer extends WLComponentPeer implements WindowPeer, Surface
|
||||
return this == grabbingWindow;
|
||||
}
|
||||
|
||||
@Override
|
||||
void handleJavaWindowFocusEvent(AWTEvent e) {
|
||||
if (e.getID() == WindowEvent.WINDOW_LOST_FOCUS) {
|
||||
ungrab(true);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public BufferedImage getClientAreaSnapshot(int x, int y, int width, int height) {
|
||||
// Move the coordinate system to the client area
|
||||
|
||||
@@ -1,220 +0,0 @@
|
||||
/*
|
||||
* 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.im;
|
||||
|
||||
import sun.awt.wl.im.text_input_unstable_v3.WLInputMethodDescriptorZwpTextInputV3;
|
||||
import sun.security.action.GetPropertyAction;
|
||||
import sun.util.logging.PlatformLogger;
|
||||
|
||||
import java.awt.AWTException;
|
||||
import java.awt.Image;
|
||||
import java.awt.font.TextAttribute;
|
||||
import java.awt.im.InputMethodHighlight;
|
||||
import java.awt.im.spi.InputMethod;
|
||||
import java.awt.im.spi.InputMethodDescriptor;
|
||||
import java.security.AccessController;
|
||||
import java.util.Arrays;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
|
||||
|
||||
/**
|
||||
* Since Wayland compositors may support multiple IM protocols,
|
||||
* this class is responsible for choosing one specific among them,
|
||||
* and the corresponding "real" implementation of {@code InputMethodDescriptor} from a subpackage.
|
||||
*/
|
||||
public final class WLInputMethodMetaDescriptor implements InputMethodDescriptor {
|
||||
// NB: the class loading routine has to be as fast and not demanding on resources as possible.
|
||||
// Also, it has to succeed in any practically possible situation.
|
||||
// E.g. if the Wayland compositor doesn't support any known IM protocol,
|
||||
// it mustn't prevent this class from being loaded successfully.
|
||||
// Ideally, nothing additional should happen at the loading time.
|
||||
//
|
||||
// This class is directly used by WLToolkit to find and instantiate an InputMethod implementation.
|
||||
|
||||
// See java.text.MessageFormat for the formatting syntax
|
||||
private static final PlatformLogger log = PlatformLogger.getLogger("sun.awt.wl.im.WLInputMethodMetaDescriptor");
|
||||
|
||||
|
||||
/** @see sun.awt.wl.WLToolkit#mapInputMethodHighlight(InputMethodHighlight) */
|
||||
public static Map<TextAttribute, ?> mapInputMethodHighlight(final InputMethodHighlight highlight) {
|
||||
// NB: The implementation is supposed to produce results exactly equal to XToolkit's implementation
|
||||
// for better visual consistency.
|
||||
|
||||
if (highlight == null)
|
||||
return null;
|
||||
|
||||
switch (highlight.getState()) {
|
||||
case InputMethodHighlight.RAW_TEXT -> {
|
||||
if (highlight.isSelected())
|
||||
return imHighlightMapSelectedRawText;
|
||||
else
|
||||
return imHighlightMapUnselectedRawText;
|
||||
}
|
||||
|
||||
case InputMethodHighlight.CONVERTED_TEXT -> {
|
||||
if (highlight.isSelected())
|
||||
return imHighlightMapSelectedConvertedText;
|
||||
else
|
||||
return imHighlightMapUnselectedConvertedText;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
public static WLInputMethodMetaDescriptor getInstanceIfAvailableOnPlatform() {
|
||||
final WLInputMethodMetaDescriptor result;
|
||||
|
||||
if (!ENABLE_NATIVE_IM_SUPPORT) {
|
||||
result = null;
|
||||
} else {
|
||||
// For now there's only 1 possible implementation of IM,
|
||||
// but if/when there are more, this method will have to choose one of them.
|
||||
// It'll be good if the preferable engine can be chosen via a system property.
|
||||
|
||||
final InputMethodDescriptor realImDescriptor = WLInputMethodDescriptorZwpTextInputV3.getInstanceIfAvailableOnPlatform();
|
||||
if (realImDescriptor != null) {
|
||||
result = new WLInputMethodMetaDescriptor(realImDescriptor);
|
||||
} else {
|
||||
result = null;
|
||||
}
|
||||
}
|
||||
|
||||
if (log.isLoggable(PlatformLogger.Level.FINE)) {
|
||||
log.fine("getInstanceIfAvailableOnPlatform(): result={0}, ENABLE_NATIVE_IM_SUPPORT={1}.", result, ENABLE_NATIVE_IM_SUPPORT);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/* java.awt.im.spi.InputMethodDescriptor methods section */
|
||||
|
||||
@Override
|
||||
public Locale[] getAvailableLocales() throws AWTException {
|
||||
final Locale[] result = realImDescriptor.getAvailableLocales();
|
||||
|
||||
if (log.isLoggable(PlatformLogger.Level.FINE)) {
|
||||
log.fine("getAvailableLocales(): result={0}, this={1}.", Arrays.toString(result), this);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasDynamicLocaleList() {
|
||||
final boolean result = realImDescriptor.hasDynamicLocaleList();
|
||||
|
||||
if (log.isLoggable(PlatformLogger.Level.FINE)) {
|
||||
log.fine("hasDynamicLocaleList(): result={0}, this={1}.", result, this);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getInputMethodDisplayName(Locale inputLocale, Locale displayLanguage) {
|
||||
return realImDescriptor.getInputMethodDisplayName(inputLocale, displayLanguage);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Image getInputMethodIcon(Locale inputLocale) {
|
||||
return realImDescriptor.getInputMethodIcon(inputLocale);
|
||||
}
|
||||
|
||||
@Override
|
||||
public InputMethod createInputMethod() throws Exception {
|
||||
final InputMethod result = realImDescriptor.createInputMethod();
|
||||
|
||||
if (log.isLoggable(PlatformLogger.Level.FINE)) {
|
||||
log.fine("createInputMethod(): result={0}, this={1}.", result, this);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
/* java.lang.Object methods section */
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return String.format("WLInputMethodMetaDescriptor@%d[realImDescriptor=%s]", System.identityHashCode(this), realImDescriptor);
|
||||
}
|
||||
|
||||
|
||||
/* Implementation details section */
|
||||
|
||||
/**
|
||||
* The values are copied from XToolkit's implementation for better visual consistency with AWT on X11.
|
||||
*
|
||||
* @see #mapInputMethodHighlight(InputMethodHighlight)
|
||||
* @see sun.awt.X11InputMethodBase
|
||||
*/
|
||||
private final static Map<TextAttribute, ?> imHighlightMapUnselectedRawText = Map.of(
|
||||
TextAttribute.WEIGHT, TextAttribute.WEIGHT_BOLD
|
||||
);
|
||||
private final static Map<TextAttribute, ?> imHighlightMapUnselectedConvertedText = Map.of(
|
||||
TextAttribute.INPUT_METHOD_UNDERLINE, TextAttribute.UNDERLINE_LOW_ONE_PIXEL
|
||||
);
|
||||
private final static Map<TextAttribute, ?> imHighlightMapSelectedRawText = Map.of(
|
||||
TextAttribute.SWAP_COLORS, TextAttribute.SWAP_COLORS_ON
|
||||
);
|
||||
private final static Map<TextAttribute, ?> imHighlightMapSelectedConvertedText = Map.of(
|
||||
TextAttribute.SWAP_COLORS, TextAttribute.SWAP_COLORS_ON
|
||||
);
|
||||
|
||||
/**
|
||||
* This flag allows disabling ALL integrations with native IMs. The idea is to allow users to disable
|
||||
* unnecessary for them functionality if they face any problems because of it.
|
||||
* Therefore, if it's {@code false}, the Toolkit code shouldn't use (directly or indirectly)
|
||||
* any of Wayland's input methods-related APIs (e.g. the "text-input" protocol).
|
||||
*/
|
||||
private final static boolean ENABLE_NATIVE_IM_SUPPORT;
|
||||
|
||||
static {
|
||||
boolean enableNativeImSupportInitializer = true;
|
||||
try {
|
||||
@SuppressWarnings("removal") // still needed for JBR21
|
||||
final boolean enableNativeImSupportPropertyValue = Boolean.parseBoolean(
|
||||
AccessController.doPrivileged(new GetPropertyAction("sun.awt.wl.im.enabled", "true"))
|
||||
);
|
||||
enableNativeImSupportInitializer = enableNativeImSupportPropertyValue;
|
||||
} catch (Exception err) {
|
||||
log.severe("Failed to read the value of the system property \"sun.awt.wl.im.enabled\". Assuming the default value(=true).", err);
|
||||
}
|
||||
|
||||
ENABLE_NATIVE_IM_SUPPORT = enableNativeImSupportInitializer;
|
||||
}
|
||||
|
||||
|
||||
private final InputMethodDescriptor realImDescriptor;
|
||||
|
||||
private WLInputMethodMetaDescriptor(InputMethodDescriptor realImDescriptor) {
|
||||
this.realImDescriptor = Objects.requireNonNull(realImDescriptor, "realImDescriptor");
|
||||
}
|
||||
}
|
||||
@@ -1,40 +0,0 @@
|
||||
/*
|
||||
* 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.im.text_input_unstable_v3;
|
||||
|
||||
|
||||
/** Reason for the change of surrounding text or cursor position */
|
||||
enum ChangeCause {
|
||||
/** input method caused the change */
|
||||
INPUT_METHOD(0),
|
||||
/** something else than the input method caused the change */
|
||||
OTHER (1);
|
||||
|
||||
public final int intValue;
|
||||
ChangeCause(int intValue) {
|
||||
this.intValue = intValue;
|
||||
}
|
||||
}
|
||||
@@ -1,371 +0,0 @@
|
||||
/*
|
||||
* 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.im.text_input_unstable_v3;
|
||||
|
||||
import sun.util.logging.PlatformLogger;
|
||||
|
||||
import javax.swing.event.CaretEvent;
|
||||
import javax.swing.event.CaretListener;
|
||||
import javax.swing.text.JTextComponent;
|
||||
import java.awt.AWTEvent;
|
||||
import java.awt.Component;
|
||||
import java.awt.EventQueue;
|
||||
import java.awt.Rectangle;
|
||||
import java.awt.TextComponent;
|
||||
import java.awt.event.ComponentEvent;
|
||||
import java.awt.event.ComponentListener;
|
||||
import java.awt.event.KeyEvent;
|
||||
import java.awt.event.MouseEvent;
|
||||
import java.awt.event.TextEvent;
|
||||
import java.awt.event.TextListener;
|
||||
import java.lang.ref.WeakReference;
|
||||
import java.util.Objects;
|
||||
|
||||
|
||||
/**
|
||||
* This class is intended to track all the cases when a new {@code zwp_text_input_v3::set_cursor_rectangle} request
|
||||
* may have to be issued. Here are the examples of such cases:
|
||||
* <ul>
|
||||
* <li>The caret position has changed ;
|
||||
* <li>The component has been moved/resized ;
|
||||
* <li>The component's window has been moved/resized ;
|
||||
* <li>The component's text has been changed ;
|
||||
* </ul>
|
||||
*/
|
||||
class ClientComponentCaretPositionTracker implements ComponentListener, CaretListener, TextListener
|
||||
{
|
||||
// See java.text.MessageFormat for the formatting syntax
|
||||
private static final PlatformLogger log = PlatformLogger.getLogger("sun.awt.wl.im.text_input_unstable_v3.ClientComponentCaretPositionTracker");
|
||||
|
||||
|
||||
public ClientComponentCaretPositionTracker(WLInputMethodZwpTextInputV3 im) {
|
||||
this.im = new WeakReference<>(Objects.requireNonNull(im, "im"));
|
||||
}
|
||||
|
||||
|
||||
public void startTracking(final Component component) {
|
||||
assert(EventQueue.isDispatchThread());
|
||||
|
||||
if (log.isLoggable(PlatformLogger.Level.FINER)) {
|
||||
log.finer(
|
||||
String.format("startTracking(component=%s): im=%s, this=%s.", component, getOwnerIm(), this),
|
||||
new Throwable("Stacktrace")
|
||||
);
|
||||
}
|
||||
|
||||
stopTrackingCurrentComponent();
|
||||
|
||||
if (component == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
trackedComponent = new WeakReference<>(component);
|
||||
|
||||
lastKnownClientWindowBounds = null;
|
||||
|
||||
try {
|
||||
// Moving and changing the size causes a possible change of caret position
|
||||
component.addComponentListener(this);
|
||||
|
||||
if (component instanceof JTextComponent jtc) {
|
||||
jtc.addCaretListener(this);
|
||||
isCaretListenerInstalled = true;
|
||||
} else if (component instanceof TextComponent tc) {
|
||||
tc.addTextListener(this);
|
||||
isTextListenerInstalled = true;
|
||||
}
|
||||
|
||||
if (log.isLoggable(PlatformLogger.Level.FINEST)) {
|
||||
log.finest("startTracking(...): updated this={0}.", this);
|
||||
}
|
||||
} catch (Exception err) {
|
||||
stopTrackingCurrentComponent();
|
||||
throw err;
|
||||
}
|
||||
}
|
||||
|
||||
public void stopTrackingCurrentComponent() {
|
||||
assert(EventQueue.isDispatchThread());
|
||||
|
||||
if (log.isLoggable(PlatformLogger.Level.FINER)) {
|
||||
log.finer(String.format("stopTrackingCurrentComponent(): this=%s.", this), new Throwable("Stacktrace"));
|
||||
}
|
||||
|
||||
final Component trackedComponentStrong = getTrackedComponentIfTracking();
|
||||
if (trackedComponentStrong == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (isTextListenerInstalled) {
|
||||
isTextListenerInstalled = false;
|
||||
try {
|
||||
((TextComponent)trackedComponentStrong).removeTextListener(this);
|
||||
} catch (Exception err) {
|
||||
if (log.isLoggable(PlatformLogger.Level.WARNING)) {
|
||||
log.warning(String.format("stopTrackingCurrentComponent(): exception occurred while removing the text listener from %s.", trackedComponentStrong), err);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (isCaretListenerInstalled) {
|
||||
isCaretListenerInstalled = false;
|
||||
try {
|
||||
((JTextComponent)trackedComponentStrong).removeCaretListener(this);
|
||||
} catch (Exception err) {
|
||||
if (log.isLoggable(PlatformLogger.Level.WARNING)) {
|
||||
log.warning(String.format("stopTrackingCurrentComponent(): exception occurred while removing the caret listener from %s.", trackedComponentStrong), err);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
trackedComponentStrong.removeComponentListener(this);
|
||||
} catch (Exception err) {
|
||||
if (log.isLoggable(PlatformLogger.Level.WARNING)) {
|
||||
log.warning(String.format("stopTrackingCurrentComponent(): exception occurred while removing the component listener from %s.", trackedComponentStrong), err);
|
||||
}
|
||||
}
|
||||
|
||||
lastKnownClientWindowBounds = null;
|
||||
|
||||
updatesAreDeferred = false;
|
||||
|
||||
if (trackedComponent != null) {
|
||||
trackedComponent.clear();
|
||||
trackedComponent = null;
|
||||
}
|
||||
}
|
||||
|
||||
public Component getTrackedComponentIfTracking() {
|
||||
assert(EventQueue.isDispatchThread());
|
||||
|
||||
final Component trackedComponentStrong;
|
||||
if (trackedComponent == null) {
|
||||
trackedComponentStrong = null;
|
||||
} else {
|
||||
trackedComponentStrong = trackedComponent.get();
|
||||
}
|
||||
|
||||
if (trackedComponentStrong == null) {
|
||||
isTextListenerInstalled = false;
|
||||
isCaretListenerInstalled = false;
|
||||
|
||||
lastKnownClientWindowBounds = null;
|
||||
|
||||
updatesAreDeferred = false;
|
||||
|
||||
if (trackedComponent != null) {
|
||||
trackedComponent.clear();
|
||||
trackedComponent = null;
|
||||
}
|
||||
}
|
||||
|
||||
return trackedComponentStrong;
|
||||
}
|
||||
|
||||
|
||||
public void deferUpdates() {
|
||||
assert(EventQueue.isDispatchThread());
|
||||
|
||||
if (log.isLoggable(PlatformLogger.Level.FINER)) {
|
||||
log.finer(String.format("deferUpdates(): this=%s.", this), new Throwable("Stacktrace"));
|
||||
}
|
||||
|
||||
updatesAreDeferred = true;
|
||||
}
|
||||
|
||||
public void resumeUpdates(final boolean discardDeferredUpdates) {
|
||||
assert(EventQueue.isDispatchThread());
|
||||
|
||||
if (log.isLoggable(PlatformLogger.Level.FINER)) {
|
||||
log.finer(String.format("resumeUpdates(%b): this=%s.", discardDeferredUpdates, this), new Throwable("Stacktrace"));
|
||||
}
|
||||
|
||||
if (getTrackedComponentIfTracking() == null) return;
|
||||
|
||||
updatesAreDeferred = false;
|
||||
hasDeferredUpdates = hasDeferredUpdates && !discardDeferredUpdates;
|
||||
|
||||
if (hasDeferredUpdates) {
|
||||
updateNotify();
|
||||
}
|
||||
}
|
||||
|
||||
public boolean areUpdatesDeferred() {
|
||||
assert(EventQueue.isDispatchThread());
|
||||
|
||||
return updatesAreDeferred;
|
||||
}
|
||||
|
||||
|
||||
/* Listening callbacks */
|
||||
|
||||
/** This method is intended to be called from the owning IM's {@link java.awt.im.spi.InputMethod#dispatchEvent(AWTEvent)}. */
|
||||
public void onIMDispatchEvent(AWTEvent event) {
|
||||
assert(EventQueue.isDispatchThread());
|
||||
|
||||
if (log.isLoggable(PlatformLogger.Level.FINER)) {
|
||||
log.finer("onIMDispatchEvent(event={0}): this={1}.", event, this);
|
||||
}
|
||||
|
||||
final int eventId = event.getID();
|
||||
|
||||
if (eventId >= MouseEvent.MOUSE_FIRST && eventId <= MouseEvent.MOUSE_LAST) {
|
||||
// MouseEvent or MouseWheelEvent
|
||||
if (!isCaretListenerInstalled || eventId == MouseEvent.MOUSE_WHEEL) {
|
||||
// We expect no mouse events except MouseWheelEvent can change the physical position of the caret
|
||||
// without changing its logical position inside the document. The logical position is handled by caretUpdate.
|
||||
|
||||
// The event hasn't been handled by the component yet, so the caret position couldn't have been changed yet.
|
||||
// Hence, we have to postpone the updating request.
|
||||
EventQueue.invokeLater(this::updateNotify);
|
||||
}
|
||||
}
|
||||
|
||||
if (eventId >= KeyEvent.KEY_FIRST && eventId <= KeyEvent.KEY_LAST) {
|
||||
if ( !isCaretListenerInstalled && (!isTextListenerInstalled || eventId != KeyEvent.KEY_TYPED) ) {
|
||||
EventQueue.invokeLater(this::updateNotify);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** This method is intended to be called from the owning IM's {@link java.awt.im.spi.InputMethod#notifyClientWindowChange(Rectangle)}. */
|
||||
public void onIMNotifyClientWindowChange(Rectangle location) {
|
||||
assert(EventQueue.isDispatchThread());
|
||||
|
||||
if (log.isLoggable(PlatformLogger.Level.FINER)) {
|
||||
log.finer("onIMNotifyClientWindowChange(location={0}): this={1}.", location, this);
|
||||
}
|
||||
|
||||
if (location != null) {
|
||||
// null means the window has become iconified or invisible, so no need to try to update the caret position.
|
||||
|
||||
lastKnownClientWindowBounds = location;
|
||||
|
||||
updateNotify();
|
||||
}
|
||||
}
|
||||
|
||||
// ComponentListener
|
||||
|
||||
@Override
|
||||
public void componentHidden(ComponentEvent e) {}
|
||||
|
||||
@Override
|
||||
public void componentMoved(ComponentEvent e) {
|
||||
updateNotify();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void componentResized(ComponentEvent e) {
|
||||
updateNotify();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void componentShown(ComponentEvent e) {
|
||||
updateNotify();
|
||||
}
|
||||
|
||||
// CaretListener
|
||||
|
||||
@Override
|
||||
public void caretUpdate(CaretEvent e) {
|
||||
updateNotify();
|
||||
}
|
||||
|
||||
// TextListener
|
||||
|
||||
@Override
|
||||
public void textValueChanged(TextEvent e) {
|
||||
updateNotify();
|
||||
}
|
||||
|
||||
|
||||
/* java.lang.Object methods section */
|
||||
@Override
|
||||
public String toString() {
|
||||
final StringBuilder sb = new StringBuilder(1024);
|
||||
sb.append("ClientComponentCaretPositionTracker@").append(System.identityHashCode(this));
|
||||
sb.append('{');
|
||||
sb.append("isCaretListenerInstalled=").append(isCaretListenerInstalled);
|
||||
sb.append(", isTextListenerInstalled=").append(isTextListenerInstalled);
|
||||
sb.append(", lastKnownClientWindowBounds=").append(lastKnownClientWindowBounds);
|
||||
sb.append(", updatesAreDeferred=").append(updatesAreDeferred);
|
||||
sb.append(", hasDeferredUpdates=").append(hasDeferredUpdates);
|
||||
sb.append(", trackedComponent=").append(trackedComponent == null ? "null" : trackedComponent.get());
|
||||
sb.append('}');
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
|
||||
/* Implementation details */
|
||||
|
||||
private final WeakReference<WLInputMethodZwpTextInputV3> im;
|
||||
private WeakReference<Component> trackedComponent = null;
|
||||
private boolean isCaretListenerInstalled = false;
|
||||
private boolean isTextListenerInstalled = false;
|
||||
private Rectangle lastKnownClientWindowBounds = null;
|
||||
private boolean updatesAreDeferred = false;
|
||||
private boolean hasDeferredUpdates = false;
|
||||
|
||||
|
||||
private WLInputMethodZwpTextInputV3 getOwnerIm() {
|
||||
assert(EventQueue.isDispatchThread());
|
||||
|
||||
final WLInputMethodZwpTextInputV3 thisImStrong;
|
||||
if (this.im == null) {
|
||||
thisImStrong = null;
|
||||
} else {
|
||||
thisImStrong = this.im.get();
|
||||
}
|
||||
|
||||
if (thisImStrong == null) {
|
||||
stopTrackingCurrentComponent();
|
||||
}
|
||||
|
||||
return thisImStrong;
|
||||
}
|
||||
|
||||
private void updateNotify() {
|
||||
if (log.isLoggable(PlatformLogger.Level.FINEST)) {
|
||||
log.finest(String.format("updateNotify(): this=%s.", this), new Throwable("Stacktrace"));
|
||||
}
|
||||
|
||||
if (getTrackedComponentIfTracking() == null) return;
|
||||
|
||||
if (updatesAreDeferred) {
|
||||
hasDeferredUpdates = true;
|
||||
return;
|
||||
}
|
||||
hasDeferredUpdates = false;
|
||||
|
||||
final var imToNotify = getOwnerIm();
|
||||
if (imToNotify != null) {
|
||||
imToNotify.wlUpdateCursorRectangle(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,58 +0,0 @@
|
||||
/*
|
||||
* 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.im.text_input_unstable_v3;
|
||||
|
||||
|
||||
/** Content hint is a bitmask to allow to modify the behavior of the text input */
|
||||
enum ContentHint {
|
||||
/** no special behavior */
|
||||
NONE (0x0),
|
||||
/** suggest word completions */
|
||||
COMPLETION (0x1),
|
||||
/** suggest word corrections */
|
||||
SPELLCHECK (0x2),
|
||||
/** switch to uppercase letters at the start of a sentence */
|
||||
AUTO_CAPITALIZATION(0x4),
|
||||
/** prefer lowercase letters */
|
||||
LOWERCASE (0x8),
|
||||
/** prefer uppercase letters */
|
||||
UPPERCASE (0x10),
|
||||
/** prefer casing for titles and headings (can be language dependent) */
|
||||
TITLECASE (0x20),
|
||||
/** characters should be hidden */
|
||||
HIDDEN_TEXT (0x40),
|
||||
/** typed text should not be stored */
|
||||
SENSITIVE_DATA (0x80),
|
||||
/** just Latin characters should be entered */
|
||||
LATIN (0x100),
|
||||
/** the text input is multiline */
|
||||
MULTILINE (0x200);
|
||||
|
||||
public final int intMask;
|
||||
ContentHint(int intMask) {
|
||||
this.intMask = intMask;
|
||||
}
|
||||
}
|
||||
@@ -1,67 +0,0 @@
|
||||
/*
|
||||
* 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.im.text_input_unstable_v3;
|
||||
|
||||
|
||||
/**
|
||||
* The content purpose allows to specify the primary purpose of a text input.
|
||||
* This allows an input method to show special purpose input panels with extra characters or to disallow some characters.
|
||||
*/
|
||||
enum ContentPurpose {
|
||||
/** default input, allowing all characters */
|
||||
NORMAL (0),
|
||||
/** allow only alphabetic characters */
|
||||
ALPHA (1),
|
||||
/** allow only digits */
|
||||
DIGITS (2),
|
||||
/** input a number (including decimal separator and sign) */
|
||||
NUMBER (3),
|
||||
/** input a phone number */
|
||||
PHONE (4),
|
||||
/** input an URL */
|
||||
URL (5),
|
||||
/** input an email address */
|
||||
EMAIL (6),
|
||||
/** input a name of a person */
|
||||
NAME (7),
|
||||
/** input a password (combine with sensitive_data hint) */
|
||||
PASSWORD(8),
|
||||
/** input is a numeric password (combine with sensitive_data hint) */
|
||||
PIN (9),
|
||||
/** input a date */
|
||||
DATE (10),
|
||||
/** input a time */
|
||||
TIME (11),
|
||||
/** input a date and time */
|
||||
DATETIME(12),
|
||||
/** input for a terminal */
|
||||
TERMINAL(13);
|
||||
|
||||
public final int intValue;
|
||||
ContentPurpose(int intValue) {
|
||||
this.intValue = intValue;
|
||||
}
|
||||
}
|
||||
@@ -1,131 +0,0 @@
|
||||
/*
|
||||
* 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.im.text_input_unstable_v3;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Objects;
|
||||
|
||||
|
||||
/**
|
||||
* This class accumulates changes received as
|
||||
* {@code zwp_text_input_v3::preedit_string}, {@code zwp_text_input_v3::commit_string} events until
|
||||
* a {@code zwp_text_input_v3::done} event is received.
|
||||
*/
|
||||
final class IncomingChanges
|
||||
{
|
||||
public IncomingChanges updatePreeditString(byte[] newPreeditStringUtf8, int newPreeditStringCursorBeginUtf8Byte, int newPreeditStringCursorEndUtf8Byte) {
|
||||
this.doUpdatePreeditString = true;
|
||||
this.newPreeditStringUtf8 = newPreeditStringUtf8;
|
||||
this.newPreeditStringCursorBeginUtf8Byte = newPreeditStringCursorBeginUtf8Byte;
|
||||
this.newPreeditStringCursorEndUtf8Byte = newPreeditStringCursorEndUtf8Byte;
|
||||
this.cachedResultPreeditString = null;
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return {@code null} if there are no changes in the preedit string
|
||||
* (i.e. {@link #updatePreeditString(byte[], int, int)} hasn't been called);
|
||||
* an instance of JavaPreeditString otherwise.
|
||||
* @see JavaPreeditString
|
||||
*/
|
||||
public JavaPreeditString getPreeditString() {
|
||||
if (cachedResultPreeditString != null) {
|
||||
return cachedResultPreeditString;
|
||||
}
|
||||
|
||||
cachedResultPreeditString = doUpdatePreeditString
|
||||
? JavaPreeditString.fromWaylandPreeditString(newPreeditStringUtf8, newPreeditStringCursorBeginUtf8Byte, newPreeditStringCursorEndUtf8Byte)
|
||||
: null;
|
||||
|
||||
return cachedResultPreeditString;
|
||||
}
|
||||
|
||||
|
||||
public IncomingChanges updateCommitString(byte[] newCommitStringUtf8) {
|
||||
this.doUpdateCommitString = true;
|
||||
this.newCommitStringUtf8 = newCommitStringUtf8;
|
||||
this.cachedResultCommitString = null;
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return {@code null} if there are no changes in the commit string
|
||||
* (i.e. {@link #updateCommitString(byte[])} hasn't been called);
|
||||
* an instance of JavaCommitString otherwise.
|
||||
* @see JavaCommitString
|
||||
*/
|
||||
public JavaCommitString getCommitString() {
|
||||
if (cachedResultCommitString != null) {
|
||||
return cachedResultCommitString;
|
||||
}
|
||||
|
||||
cachedResultCommitString = doUpdateCommitString
|
||||
? JavaCommitString.fromWaylandCommitString(newCommitStringUtf8)
|
||||
: null;
|
||||
|
||||
return cachedResultCommitString;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
IncomingChanges that = (IncomingChanges) o;
|
||||
return doUpdatePreeditString == that.doUpdatePreeditString &&
|
||||
newPreeditStringCursorBeginUtf8Byte == that.newPreeditStringCursorBeginUtf8Byte &&
|
||||
newPreeditStringCursorEndUtf8Byte == that.newPreeditStringCursorEndUtf8Byte &&
|
||||
doUpdateCommitString == that.doUpdateCommitString &&
|
||||
Arrays.equals(newPreeditStringUtf8, that.newPreeditStringUtf8) &&
|
||||
Arrays.equals(newCommitStringUtf8, that.newCommitStringUtf8);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(
|
||||
doUpdatePreeditString,
|
||||
Arrays.hashCode(newPreeditStringUtf8),
|
||||
newPreeditStringCursorBeginUtf8Byte,
|
||||
newPreeditStringCursorEndUtf8Byte,
|
||||
doUpdateCommitString,
|
||||
Arrays.hashCode(newCommitStringUtf8)
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
// zwp_text_input_v3::preedit_string
|
||||
private boolean doUpdatePreeditString = false;
|
||||
private byte[] newPreeditStringUtf8 = null;
|
||||
private int newPreeditStringCursorBeginUtf8Byte = 0;
|
||||
private int newPreeditStringCursorEndUtf8Byte = 0;
|
||||
private JavaPreeditString cachedResultPreeditString = null;
|
||||
|
||||
// zwp_text_input_v3::commit_string
|
||||
private boolean doUpdateCommitString = false;
|
||||
private byte[] newCommitStringUtf8 = null;
|
||||
private JavaCommitString cachedResultCommitString = null;
|
||||
}
|
||||
@@ -1,199 +0,0 @@
|
||||
/*
|
||||
* 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.im.text_input_unstable_v3;
|
||||
|
||||
import java.awt.Rectangle;
|
||||
import java.util.Objects;
|
||||
|
||||
|
||||
/**
|
||||
* This class encapsulates the entire state of an input context represented by an instance of {@code zwp_text_input_v3}.
|
||||
*
|
||||
* @see StateOfEnabled
|
||||
*/
|
||||
final class InputContextState {
|
||||
/** pointer to a native context {@code zwp_text_input_v3} */
|
||||
public final long nativeContextPtr;
|
||||
|
||||
|
||||
public InputContextState(long nativeContextPtr) {
|
||||
assert(nativeContextPtr != 0);
|
||||
|
||||
this.nativeContextPtr = nativeContextPtr;
|
||||
}
|
||||
|
||||
|
||||
/** @return 0 if the input context hasn't entered a surface yet. Otherwise, the native pointer to the surface. */
|
||||
public long getCurrentWlSurfacePtr() {
|
||||
return currentWlSurfacePtr;
|
||||
}
|
||||
|
||||
public void setCurrentWlSurfacePtr(long currentWlSurfacePtr) {
|
||||
this.currentWlSurfacePtr = currentWlSurfacePtr;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Notifies the InputContext that a set of changes has been sent and committed to the compositor
|
||||
* via a {@code zwp_text_input_v3::commit} request. The InputContext reacts by incrementing its commit counter.
|
||||
*
|
||||
* @param changes represents the set of changes that have been sent and followed by a 'commit' request.
|
||||
* Must not be {@code null} (but can be empty, which means only the 'commit' request has been issued).
|
||||
*
|
||||
* @return a new instance of {@link OutgoingBeingCommittedChanges} consisting of
|
||||
* the passed changes and the new value of the commit counter.
|
||||
*
|
||||
* @throws NullPointerException if {@code changes} is {@code null}.
|
||||
*
|
||||
* @see OutgoingChanges
|
||||
*/
|
||||
public OutgoingBeingCommittedChanges syncWithCommittedOutgoingChanges(final OutgoingChanges changes) {
|
||||
Objects.requireNonNull(changes, "changes");
|
||||
|
||||
// zwp_text_input_v3::done natively uses uint32_t for the serial,
|
||||
// so it can't get greater than 0xFFFFFFFF.
|
||||
this.commitCounter = (this.commitCounter + 1) % 0x100000000L;
|
||||
|
||||
return new OutgoingBeingCommittedChanges(changes, this.commitCounter);
|
||||
}
|
||||
|
||||
public long getCommitCounter() {
|
||||
return commitCounter;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* This class represents the extended state of an {@code InputContextState} that only exists when the context
|
||||
* is enabled.
|
||||
*
|
||||
* @param textChangeCause the property set via a {@code zwp_text_input_v3::set_text_change_cause} request. Must not be {@code null}.
|
||||
* @param contentHint the property set via a {@code zwp_text_input_v3::set_content_type} request.
|
||||
* @param contentPurpose the property set via a {@code zwp_text_input_v3::set_content_type} request. Must not be {@code null}.
|
||||
* @param cursorRectangle the property set via a {@code zwp_text_input_v3::set_cursor_rectangle} request.
|
||||
* {@code null} means "the text input does not support describing the cursor area".
|
||||
*/
|
||||
public record StateOfEnabled(
|
||||
// zwp_text_input_v3::set_text_change_cause
|
||||
ChangeCause textChangeCause,
|
||||
// zwp_text_input_v3::set_content_type.hint
|
||||
int contentHint,
|
||||
// zwp_text_input_v3::set_content_type.purpose
|
||||
ContentPurpose contentPurpose,
|
||||
// zwp_text_input_v3::set_cursor_rectangle
|
||||
Rectangle cursorRectangle
|
||||
) {
|
||||
public StateOfEnabled {
|
||||
Objects.requireNonNull(textChangeCause, "textChangeCause");
|
||||
Objects.requireNonNull(contentPurpose, "contentPurpose");
|
||||
}
|
||||
}
|
||||
|
||||
public StateOfEnabled getCurrentStateOfEnabled() {
|
||||
return stateOfEnabled;
|
||||
}
|
||||
|
||||
public boolean isEnabled() {
|
||||
return getCurrentStateOfEnabled() != null;
|
||||
}
|
||||
|
||||
/**
|
||||
* NB: if you want to call setEnabledState(null), consider using {@code wlHandleContextGotDisabled()} of
|
||||
* the owning {@link WLInputMethodZwpTextInputV3}.
|
||||
*
|
||||
* @param newState {@code null} to mark the InputContext as disabled,
|
||||
* otherwise the InputContext will be marked as enabled and having the state as
|
||||
* specified in the parameter.
|
||||
*/
|
||||
public void setEnabledState(StateOfEnabled newState) {
|
||||
this.stateOfEnabled = newState;
|
||||
}
|
||||
|
||||
|
||||
public void syncWithAppliedIncomingChanges(final JavaPreeditString appliedPreeditString, final JavaCommitString appliedCommitString, final long doneSerial) {
|
||||
this.latestAppliedPreeditString = Objects.requireNonNull(appliedPreeditString, "appliedPreeditString");
|
||||
this.latestAppliedCommitString = Objects.requireNonNull(appliedCommitString, "appliedCommitString");
|
||||
this.latestDoneSerial = doneSerial;
|
||||
}
|
||||
|
||||
public JavaPreeditString getLatestAppliedPreeditString() {
|
||||
return latestAppliedPreeditString;
|
||||
}
|
||||
|
||||
public JavaCommitString getLatestAppliedCommitString() {
|
||||
return latestAppliedCommitString;
|
||||
}
|
||||
|
||||
public long getLatestDoneSerial() {
|
||||
return latestDoneSerial;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
final StringBuilder sb = new StringBuilder(512);
|
||||
sb.append("InputContextState@").append(System.identityHashCode(this));
|
||||
sb.append('{');
|
||||
sb.append("nativeContextPtr=0x").append(Long.toHexString(nativeContextPtr));
|
||||
sb.append(", currentWlSurfacePtr=0x").append(Long.toHexString(currentWlSurfacePtr));
|
||||
sb.append(", commitCounter=").append(commitCounter);
|
||||
sb.append(", latestDoneSerial=").append(latestDoneSerial);
|
||||
sb.append(", stateOfEnabled=").append(stateOfEnabled);
|
||||
sb.append(", latestAppliedPreeditString=").append(latestAppliedPreeditString);
|
||||
sb.append(", latestAppliedCommitString=").append(latestAppliedCommitString);
|
||||
sb.append('}');
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
|
||||
// zwp_text_input_v3::enter.surface / zwp_text_input_v3::leave.surface
|
||||
private long currentWlSurfacePtr = 0;
|
||||
// zwp_text_input_v3::commit
|
||||
/**
|
||||
* How many times changes to this context have been committed (through {@code zwp_text_input_v3::commit}).
|
||||
* Essentially, it means the most actual version of the context's state.
|
||||
*/
|
||||
private long commitCounter = 0;
|
||||
// zwp_text_input_v3::done.serial
|
||||
/**
|
||||
* The {@code serial} parameter of the latest {@code zwp_text_input_v3::done} event received.
|
||||
* Essentially, it means the latest version of the context's state known/confirmed by the compositor.
|
||||
*/
|
||||
private long latestDoneSerial = 0;
|
||||
/** {@code null} if the InputContextState is disabled. */
|
||||
private StateOfEnabled stateOfEnabled = null;
|
||||
/**
|
||||
* The latest preedit string applied as a result of the latest {@code zwp_text_input_v3::done} event received.
|
||||
* Must never be {@code null} ; if a {@code zwp_text_input_v3::done} event wasn't preceded by a
|
||||
* {@code zwp_text_input_v3::preedit_string} event, the field should be set to {@link PropertiesInitials#PREEDIT_STRING}.
|
||||
*/
|
||||
private JavaPreeditString latestAppliedPreeditString = PropertiesInitials.PREEDIT_STRING;
|
||||
/**
|
||||
* The latest commit string applied as a result of the latest {@code zwp_text_input_v3::done} event received.
|
||||
* Must never be {@code null} ; if a {@code zwp_text_input_v3::done} event wasn't preceded by a
|
||||
* {@code zwp_text_input_v3::commit_string} event, the field should be set to {@link PropertiesInitials#COMMIT_STRING}.
|
||||
*/
|
||||
private JavaCommitString latestAppliedCommitString = PropertiesInitials.COMMIT_STRING;
|
||||
}
|
||||
@@ -1,41 +0,0 @@
|
||||
/*
|
||||
* 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.im.text_input_unstable_v3;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
record JavaCommitString(String text) {
|
||||
public JavaCommitString {
|
||||
Objects.requireNonNull(text, "text");
|
||||
}
|
||||
|
||||
public static final JavaCommitString EMPTY = new JavaCommitString("");
|
||||
|
||||
/** Never returns {@code null}. */
|
||||
public static JavaCommitString fromWaylandCommitString(byte[] utf8Bytes) {
|
||||
return new JavaCommitString(Utilities.utf8BytesToJavaString(utf8Bytes));
|
||||
}
|
||||
}
|
||||
@@ -1,105 +0,0 @@
|
||||
/*
|
||||
* 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.im.text_input_unstable_v3;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* This class represents the result of a conversion of a UTF-8 preedit string received in a
|
||||
* {@code zwp_text_input_v3::preedit_string} event to a Java UTF-16 string.
|
||||
* If {@link #cursorBeginCodeUnit} and/or {@link #cursorEndCodeUnit} point at UTF-16 surrogate pairs,
|
||||
* they're guaranteed to point at the very beginning of them as long as {@link #fromWaylandPreeditString} is
|
||||
* used to perform the conversion.
|
||||
* <p>
|
||||
* {@link #fromWaylandPreeditString} never returns {@code null}.
|
||||
* <p>
|
||||
* See the specification of {@code zwp_text_input_v3::preedit_string} event for more info about
|
||||
* cursor_begin, cursor_end values.
|
||||
*
|
||||
* @param text The preedit text string. Mustn't be {@code null} (use an empty string instead).
|
||||
* @param cursorBeginCodeUnit UTF-16 equivalent of {@code preedit_string.cursor_begin}.
|
||||
* @param cursorEndCodeUnit UTF-16 equivalent of {@code preedit_string.cursor_end}.
|
||||
* It's not explicitly stated in the protocol specification, but it seems to be a valid
|
||||
* situation when cursor_end < cursor_begin, which means
|
||||
* the highlight extends to the right from the caret
|
||||
* (e.g., when the text gets selected with Shift + Left Arrow).
|
||||
*/
|
||||
record JavaPreeditString(String text, int cursorBeginCodeUnit, int cursorEndCodeUnit) {
|
||||
public JavaPreeditString {
|
||||
Objects.requireNonNull(text, "text");
|
||||
}
|
||||
|
||||
public static final JavaPreeditString EMPTY = new JavaPreeditString("", 0, 0);
|
||||
public static final JavaPreeditString EMPTY_NO_CARET = new JavaPreeditString("", -1, -1);
|
||||
|
||||
public static JavaPreeditString fromWaylandPreeditString(
|
||||
final byte[] utf8Bytes,
|
||||
final int cursorBeginUtf8Byte,
|
||||
final int cursorEndUtf8Byte
|
||||
) {
|
||||
// Java's UTF-8 -> UTF-16 conversion doesn't like trailing NUL codepoints, so let's trim them
|
||||
final int utf8BytesWithoutNulLength = Utilities.getLengthOfUtf8BytesWithoutTrailingNULs(utf8Bytes);
|
||||
|
||||
// cursorBeginUtf8Byte, cursorEndUtf8Byte normalized relatively to the valid values range.
|
||||
final int fixedCursorBeginUtf8Byte;
|
||||
final int fixedCursorEndUtf8Byte;
|
||||
if (cursorBeginUtf8Byte < 0 || cursorEndUtf8Byte < 0) {
|
||||
fixedCursorBeginUtf8Byte = fixedCursorEndUtf8Byte = -1;
|
||||
} else {
|
||||
// 0 <= cursorBeginUtf8Byte <= fixedCursorBeginUtf8Byte <= utf8BytesWithoutNulLength
|
||||
fixedCursorBeginUtf8Byte = Math.min(cursorBeginUtf8Byte, utf8BytesWithoutNulLength);
|
||||
// 0 <= cursorEndUtf8Byte <= fixedCursorEndUtf8Byte <= utf8BytesWithoutNulLength
|
||||
fixedCursorEndUtf8Byte = Math.min(cursorEndUtf8Byte, utf8BytesWithoutNulLength);
|
||||
}
|
||||
|
||||
final var resultText = Utilities.utf8BytesToJavaString(utf8Bytes, 0, utf8BytesWithoutNulLength);
|
||||
|
||||
if (fixedCursorBeginUtf8Byte < 0 || fixedCursorEndUtf8Byte < 0) {
|
||||
return new JavaPreeditString(resultText, -1, -1);
|
||||
}
|
||||
|
||||
if (resultText == null) {
|
||||
assert(fixedCursorBeginUtf8Byte == 0);
|
||||
assert(fixedCursorEndUtf8Byte == 0);
|
||||
|
||||
return JavaPreeditString.EMPTY;
|
||||
}
|
||||
|
||||
final String javaPrefixBeforeCursorBegin = (fixedCursorBeginUtf8Byte == 0)
|
||||
? ""
|
||||
: Utilities.utf8BytesToJavaString(utf8Bytes, 0, fixedCursorBeginUtf8Byte);
|
||||
|
||||
final String javaPrefixBeforeCursorEnd = (fixedCursorEndUtf8Byte == 0)
|
||||
? ""
|
||||
: Utilities.utf8BytesToJavaString(utf8Bytes, 0, fixedCursorEndUtf8Byte);
|
||||
|
||||
return new JavaPreeditString(
|
||||
resultText,
|
||||
javaPrefixBeforeCursorBegin.length(),
|
||||
javaPrefixBeforeCursorEnd.length()
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -1,46 +0,0 @@
|
||||
/*
|
||||
* 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.im.text_input_unstable_v3;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
|
||||
/**
|
||||
* This class is intended to keep changes after they get committed and until they actually get applied.
|
||||
*
|
||||
* @param changeSet changes that have been sent and committed to the compositor,
|
||||
* but not yet confirmed by it (via a {@code zwp_text_input_v3::done} event).
|
||||
* Must not be {@code null}.
|
||||
* @param commitCounter the number of times a {@code zwp_text_input_v3::commit} request has been issued to
|
||||
* the corresponding {@link InputContextState}.
|
||||
*
|
||||
* @see OutgoingChanges
|
||||
*/
|
||||
record OutgoingBeingCommittedChanges(OutgoingChanges changeSet, long commitCounter) {
|
||||
public OutgoingBeingCommittedChanges {
|
||||
Objects.requireNonNull(changeSet, "changeSet");
|
||||
}
|
||||
}
|
||||
@@ -1,166 +0,0 @@
|
||||
/*
|
||||
* 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.im.text_input_unstable_v3;
|
||||
|
||||
import java.awt.Rectangle;
|
||||
import java.util.Objects;
|
||||
|
||||
|
||||
/**
|
||||
* This class is intended to accumulate changes for an {@link InputContextState} until
|
||||
* they're sent via the set of requests
|
||||
* {@code zwp_text_input_v3::enable}, {@code zwp_text_input_v3::disable}, {@code zwp_text_input_v3::set_*}
|
||||
* and commited via {@code zwp_text_input_v3::commit}.
|
||||
* <p>
|
||||
* The reason of having to accumulate changes instead of applying them as soon as they appear is the following
|
||||
* part of the {@code zpw_text_input_v3::done(serial)} event specification:
|
||||
* {@code
|
||||
* When the client receives a done event with a serial different than the number of past commit requests,
|
||||
* it must proceed with evaluating and applying the changes as normal, except it should not change the
|
||||
* current state of the zwp_text_input_v3 object. All pending state requests [...]
|
||||
* on the zwp_text_input_v3 object should be sent and committed after receiving a
|
||||
* zwp_text_input_v3.done event with a matching serial.
|
||||
* }
|
||||
*<p>
|
||||
* All the properties this class includes are nullable where {@code null} means absence of this property change.
|
||||
* In other words, if a property is null, the corresponding {@code zwp_text_input_v3::set_...} shouldn't be
|
||||
* called when processing this instance of OutgoingChanges.
|
||||
* <p>
|
||||
* The modifier methods return {@code this} for method chaining.
|
||||
*/
|
||||
final class OutgoingChanges
|
||||
{
|
||||
// zwp_text_input_v3::enable / zwp_text_input_v3::disable
|
||||
private Boolean newEnabled = null;
|
||||
|
||||
// zwp_text_input_v3::set_text_change_cause
|
||||
private ChangeCause newTextChangeCause = null;
|
||||
|
||||
// zwp_text_input_v3::set_content_type
|
||||
private Integer newContentTypeHint = null;
|
||||
private ContentPurpose newContentTypePurpose = null;
|
||||
|
||||
// zwp_text_input_v3::set_cursor_rectangle
|
||||
private Rectangle newCursorRectangle = null;
|
||||
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
final StringBuilder sb = new StringBuilder(256);
|
||||
sb.append("OutgoingChanges@").append(System.identityHashCode(this));
|
||||
sb.append('[');
|
||||
sb.append("newEnabled=").append(newEnabled);
|
||||
sb.append(", newTextChangeCause=").append(newTextChangeCause);
|
||||
sb.append(", newContentTypeHint=").append(newContentTypeHint);
|
||||
sb.append(", newContentTypePurpose=").append(newContentTypePurpose);
|
||||
sb.append(", newCursorRectangle=").append(newCursorRectangle);
|
||||
sb.append(']');
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
|
||||
public OutgoingChanges setEnabledState(Boolean newEnabled) {
|
||||
this.newEnabled = newEnabled;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Boolean getEnabledState() { return newEnabled; }
|
||||
|
||||
|
||||
public OutgoingChanges setTextChangeCause(ChangeCause newTextChangeCause) {
|
||||
this.newTextChangeCause = newTextChangeCause;
|
||||
return this;
|
||||
}
|
||||
|
||||
public ChangeCause getTextChangeCause() { return newTextChangeCause; }
|
||||
|
||||
|
||||
/**
|
||||
* Both parameters have to be {@code null} or not null simultaneously.
|
||||
*
|
||||
* @throws NullPointerException if one of the parameters is {@code null} while the other one is not.
|
||||
*/
|
||||
public OutgoingChanges setContentType(Integer newContentTypeHint, ContentPurpose newContentTypePurpose) {
|
||||
if (newContentTypeHint == null && newContentTypePurpose == null) {
|
||||
this.newContentTypeHint = null;
|
||||
this.newContentTypePurpose = null;
|
||||
} else {
|
||||
final var contentHintAllMask =
|
||||
ContentHint.NONE.intMask |
|
||||
ContentHint.COMPLETION.intMask |
|
||||
ContentHint.SPELLCHECK.intMask |
|
||||
ContentHint.AUTO_CAPITALIZATION.intMask |
|
||||
ContentHint.LOWERCASE.intMask |
|
||||
ContentHint.UPPERCASE.intMask |
|
||||
ContentHint.TITLECASE.intMask |
|
||||
ContentHint.HIDDEN_TEXT.intMask |
|
||||
ContentHint.SENSITIVE_DATA.intMask |
|
||||
ContentHint.LATIN.intMask |
|
||||
ContentHint.MULTILINE.intMask;
|
||||
|
||||
if ( (Objects.requireNonNull(newContentTypeHint, "newContentTypeHint") & ~contentHintAllMask) != 0 ) {
|
||||
throw new IllegalArgumentException(String.format("newContentTypeHint=%d has invalid bits set", newContentTypeHint));
|
||||
}
|
||||
|
||||
this.newContentTypeHint = newContentTypeHint;
|
||||
this.newContentTypePurpose = Objects.requireNonNull(newContentTypePurpose, "newContentTypePurpose");
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
public Integer getContentTypeHint() { return newContentTypeHint; }
|
||||
public ContentPurpose getContentTypePurpose() { return newContentTypePurpose; }
|
||||
|
||||
|
||||
public OutgoingChanges setCursorRectangle(Rectangle newCursorRectangle) {
|
||||
this.newCursorRectangle = newCursorRectangle;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Rectangle getCursorRectangle() { return newCursorRectangle; }
|
||||
|
||||
|
||||
public OutgoingChanges appendChangesFrom(OutgoingChanges src) {
|
||||
if (src == null) return this;
|
||||
|
||||
if (getTextChangeCause() == null) {
|
||||
setTextChangeCause(src.getTextChangeCause());
|
||||
}
|
||||
if (getContentTypeHint() == null) {
|
||||
setContentType(src.getContentTypeHint(), src.getContentTypePurpose());
|
||||
}
|
||||
if (getCursorRectangle() == null) {
|
||||
setCursorRectangle(src.getCursorRectangle());
|
||||
}
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
public boolean isEmpty() {
|
||||
return (getEnabledState() == null && getTextChangeCause() == null && getContentTypeHint() == null && getCursorRectangle() == null);
|
||||
}
|
||||
}
|
||||
@@ -1,50 +0,0 @@
|
||||
/*
|
||||
* 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.im.text_input_unstable_v3;
|
||||
|
||||
import java.awt.Rectangle;
|
||||
|
||||
|
||||
interface PropertiesInitials {
|
||||
/** {@code zwp_text_input_v3::set_text_change_cause} */
|
||||
ChangeCause TEXT_CHANGE_CAUSE = ChangeCause.INPUT_METHOD;
|
||||
/** {@code zwp_text_input_v3::set_content_type} (hint) */
|
||||
int CONTENT_HINT = ContentHint.NONE.intMask;
|
||||
/** {@code zwp_text_input_v3::set_content_type} (purpose) */
|
||||
ContentPurpose CONTENT_PURPOSE = ContentPurpose.NORMAL;
|
||||
/**
|
||||
* {@code zwp_text_input_v3::set_cursor_rectangle}.
|
||||
* <p>
|
||||
* The initial values describing a cursor rectangle are empty.
|
||||
* That means the text input does not support describing the cursor area.
|
||||
* If the empty values get applied, subsequent attempts to change them may have no effect.
|
||||
*/
|
||||
Rectangle CURSOR_RECTANGLE = null;
|
||||
/** {@code zwp_text_input_v3::preedit_string} */
|
||||
JavaPreeditString PREEDIT_STRING = new JavaPreeditString("", 0, 0);
|
||||
/** {@code zwp_text_input_v3::commit_string} */
|
||||
JavaCommitString COMMIT_STRING = new JavaCommitString("");
|
||||
}
|
||||
@@ -1,59 +0,0 @@
|
||||
/*
|
||||
* 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.im.text_input_unstable_v3;
|
||||
|
||||
import java.nio.charset.StandardCharsets;
|
||||
|
||||
|
||||
interface Utilities {
|
||||
static int getLengthOfUtf8BytesWithoutTrailingNULs(final byte[] utf8Bytes) {
|
||||
int lastNonNulIndex = (utf8Bytes == null) ? -1 : utf8Bytes.length - 1;
|
||||
for (; lastNonNulIndex >= 0; --lastNonNulIndex) {
|
||||
if (utf8Bytes[lastNonNulIndex] != 0) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return (lastNonNulIndex < 0) ? 0 : lastNonNulIndex + 1;
|
||||
}
|
||||
|
||||
static String utf8BytesToJavaString(final byte[] utf8Bytes) {
|
||||
if (utf8Bytes == null) {
|
||||
return "";
|
||||
}
|
||||
|
||||
return utf8BytesToJavaString(
|
||||
utf8Bytes,
|
||||
0,
|
||||
// Java's UTF-8 -> UTF-16 conversion doesn't like trailing NUL codepoints, so let's trim them
|
||||
getLengthOfUtf8BytesWithoutTrailingNULs(utf8Bytes)
|
||||
);
|
||||
}
|
||||
|
||||
static String utf8BytesToJavaString(final byte[] utf8Bytes, final int offset, final int length) {
|
||||
return utf8Bytes == null ? "" : new String(utf8Bytes, offset, length, StandardCharsets.UTF_8);
|
||||
}
|
||||
}
|
||||
@@ -1,203 +0,0 @@
|
||||
/*
|
||||
* 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.im.text_input_unstable_v3;
|
||||
|
||||
import sun.awt.wl.WLToolkit;
|
||||
import sun.util.logging.PlatformLogger;
|
||||
|
||||
import java.awt.AWTException;
|
||||
import java.awt.Image;
|
||||
import java.awt.Toolkit;
|
||||
import java.awt.im.spi.InputMethod;
|
||||
import java.awt.im.spi.InputMethodDescriptor;
|
||||
import java.util.Locale;
|
||||
|
||||
|
||||
public final class WLInputMethodDescriptorZwpTextInputV3 implements InputMethodDescriptor {
|
||||
|
||||
// See java.text.MessageFormat for the formatting syntax
|
||||
private static final PlatformLogger log = PlatformLogger.getLogger("sun.awt.wl.im.text_input_unstable_v3.WLInputMethodDescriptorZwpTextInputV3");
|
||||
|
||||
|
||||
public static boolean isAvailableOnPlatform() {
|
||||
return initAndGetIsAvailableOnPlatform();
|
||||
}
|
||||
|
||||
public static WLInputMethodDescriptorZwpTextInputV3 getInstanceIfAvailableOnPlatform() {
|
||||
if (!isAvailableOnPlatform()) {
|
||||
return null;
|
||||
}
|
||||
return new WLInputMethodDescriptorZwpTextInputV3();
|
||||
}
|
||||
|
||||
|
||||
/* java.awt.im.spi.InputMethodDescriptor methods section */
|
||||
|
||||
@Override
|
||||
public Locale[] getAvailableLocales() throws AWTException {
|
||||
ensureIsAvailableOnPlatform();
|
||||
return getAvailableLocalesInternal();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasDynamicLocaleList() {
|
||||
// Since the return value of {@link #getAvailableLocales()} doesn't currently change over time,
|
||||
// it doesn't make sense to return true here.
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getInputMethodDisplayName(Locale inputLocale, Locale displayLanguage) {
|
||||
assert isAvailableOnPlatform();
|
||||
|
||||
// This is how it's implemented in all other Toolkits.
|
||||
//
|
||||
// We ignore the input locale.
|
||||
// When displaying for the default locale, rely on the localized AWT properties;
|
||||
// for any other locale, fall back to English.
|
||||
String name = "System Input Methods";
|
||||
if (Locale.getDefault().equals(displayLanguage)) {
|
||||
name = Toolkit.getProperty("AWT.HostInputMethodDisplayName", name);
|
||||
}
|
||||
return name;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Image getInputMethodIcon(Locale inputLocale) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public InputMethod createInputMethod() throws Exception {
|
||||
// NB: we should avoid returning null from this method because the calling code isn't really ready to get null
|
||||
|
||||
ensureIsAvailableOnPlatform();
|
||||
|
||||
final var result = new WLInputMethodZwpTextInputV3();
|
||||
|
||||
if (log.isLoggable(PlatformLogger.Level.FINE)) {
|
||||
log.fine("createInputMethod(): result={0}.", result);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
/* java.lang.Object methods section */
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return String.format("WLInputMethodDescriptorZwpTextInputV3@%d", System.identityHashCode(this));
|
||||
}
|
||||
|
||||
|
||||
/* Implementation details section */
|
||||
|
||||
/** Used as the return value for {@link #getAvailableLocales()}. */
|
||||
private volatile static Locale toolkitStartupLocale = null;
|
||||
|
||||
private volatile static Boolean isAvailableOnPlatform = null;
|
||||
|
||||
|
||||
static Locale[] getAvailableLocalesInternal() {
|
||||
// This is how it's implemented in XToolkit.
|
||||
//
|
||||
// A better implementation would be obtaining all currently installed and enabled input sources
|
||||
// (like on GNOME Settings -> Keyboard -> Input Sources) and mapping them to locales.
|
||||
// However, there seem no universal Wayland API for that, so it seems can't be implemented reliably.
|
||||
//
|
||||
// So leaving as is at the moment.
|
||||
//
|
||||
// TODO: research how to implement this better along with {@link #hasDynamicLocaleList}
|
||||
|
||||
return new Locale[]{ (Locale)initAndGetToolkitStartupLocale().clone() };
|
||||
}
|
||||
|
||||
private static Locale initAndGetToolkitStartupLocale() {
|
||||
if (toolkitStartupLocale == null) {
|
||||
synchronized (WLInputMethodDescriptorZwpTextInputV3.class) {
|
||||
if (toolkitStartupLocale == null) {
|
||||
toolkitStartupLocale = WLToolkit.getStartupLocale();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (log.isLoggable(PlatformLogger.Level.CONFIG)) {
|
||||
log.config("initAndGetToolkitStartupLocale(): toolkitStartupLocale={0}.", toolkitStartupLocale);
|
||||
}
|
||||
|
||||
return toolkitStartupLocale;
|
||||
}
|
||||
|
||||
private static boolean initAndGetIsAvailableOnPlatform() {
|
||||
if (isAvailableOnPlatform == null) {
|
||||
synchronized (WLInputMethodDescriptorZwpTextInputV3.class) {
|
||||
try {
|
||||
if (isAvailableOnPlatform == null) {
|
||||
isAvailableOnPlatform = checkIfAvailableOnPlatform();
|
||||
}
|
||||
} catch (Exception err) {
|
||||
if (log.isLoggable(PlatformLogger.Level.WARNING)) {
|
||||
log.warning("Failed to check whether the IM protocol is supported on the system", err);
|
||||
}
|
||||
isAvailableOnPlatform = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (log.isLoggable(PlatformLogger.Level.CONFIG)) {
|
||||
log.config("initAndGetIsAvailableOnPlatform(): isAvailableOnPlatform={0}.", isAvailableOnPlatform);
|
||||
}
|
||||
|
||||
return isAvailableOnPlatform;
|
||||
}
|
||||
|
||||
private static void ensureIsAvailableOnPlatform() throws AWTException {
|
||||
if (!isAvailableOnPlatform()) {
|
||||
throw new AWTException("sun.awt.wl.im.text_input_unstable_v3.WLInputMethodZwpTextInputV3 is not supported on this system");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private WLInputMethodDescriptorZwpTextInputV3() {
|
||||
assert isAvailableOnPlatform();
|
||||
|
||||
initAndGetToolkitStartupLocale();
|
||||
}
|
||||
|
||||
|
||||
/* JNI downcalls section */
|
||||
|
||||
/**
|
||||
* This method checks if {@link WLInputMethodZwpTextInputV3} can function on this system.
|
||||
* Basically, it means the Wayland compositor supports a minimal sufficient subset of the required protocols
|
||||
* (currently the set only includes the "text-input-unstable-v3" protocol).
|
||||
*
|
||||
* @return true if {@link WLInputMethodZwpTextInputV3} can function on this system, false otherwise.
|
||||
* @see <a href="https://wayland.app/protocols/text-input-unstable-v3">text-input-unstable-v3</a>
|
||||
*/
|
||||
private static native boolean checkIfAvailableOnPlatform();
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,85 @@
|
||||
/*
|
||||
* Copyright (c) 2003, 2023, Oracle and/or its affiliates. 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.
|
||||
*/
|
||||
|
||||
|
||||
package sun.java2d;
|
||||
|
||||
import java.awt.GraphicsConfiguration;
|
||||
import java.awt.Image;
|
||||
|
||||
import sun.awt.X11GraphicsConfig;
|
||||
import sun.awt.image.SunVolatileImage;
|
||||
import sun.awt.image.SurfaceManager;
|
||||
import sun.awt.image.VolatileSurfaceManager;
|
||||
import sun.java2d.opengl.GLXGraphicsConfig;
|
||||
import sun.java2d.opengl.GLXVolatileSurfaceManager;
|
||||
import sun.java2d.vulkan.VKOffscreenGraphicsConfig;
|
||||
import sun.java2d.vulkan.WLVKGraphicsConfig;
|
||||
import sun.java2d.vulkan.VKVolatileSurfaceManager;
|
||||
import sun.java2d.wl.WLVolatileSurfaceManager;
|
||||
import sun.java2d.x11.X11VolatileSurfaceManager;
|
||||
import sun.java2d.xr.*;
|
||||
|
||||
/**
|
||||
* The SurfaceManagerFactory that creates VolatileSurfaceManager
|
||||
* implementations for the Unix volatile images.
|
||||
*/
|
||||
public class UnixSurfaceManagerFactory extends SurfaceManagerFactory {
|
||||
|
||||
/**
|
||||
* Creates a new instance of a VolatileSurfaceManager given any
|
||||
* arbitrary SunVolatileImage. An optional context Object can be supplied
|
||||
* as a way for the caller to pass pipeline-specific context data to
|
||||
* the VolatileSurfaceManager (such as a backbuffer handle, for example).
|
||||
*
|
||||
* For Unix platforms, this method returns either an X11- or a GLX-
|
||||
* specific VolatileSurfaceManager based on the GraphicsConfiguration
|
||||
* under which the SunVolatileImage was created.
|
||||
*/
|
||||
public VolatileSurfaceManager createVolatileManager(SunVolatileImage vImg,
|
||||
Object context)
|
||||
{
|
||||
GraphicsConfiguration gc = vImg.getGraphicsConfig();
|
||||
|
||||
if (gc instanceof GLXGraphicsConfig) {
|
||||
return new GLXVolatileSurfaceManager(vImg, context);
|
||||
} else if(gc instanceof XRGraphicsConfig) {
|
||||
return new XRVolatileSurfaceManager(vImg, context);
|
||||
} else if (gc instanceof X11GraphicsConfig){
|
||||
return new X11VolatileSurfaceManager(vImg, context);
|
||||
} else if (gc instanceof WLVKGraphicsConfig) {
|
||||
return new VKVolatileSurfaceManager(vImg, context);
|
||||
} else if (gc instanceof VKOffscreenGraphicsConfig) {
|
||||
return new VKVolatileSurfaceManager(vImg, context);
|
||||
} else {
|
||||
return new WLVolatileSurfaceManager(vImg, context);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public SurfaceManager createTextureWrapperSurfaceManager(GraphicsConfiguration gc, Image image, long texture) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
}
|
||||
@@ -49,7 +49,6 @@ import sun.awt.X11GraphicsEnvironment;
|
||||
import sun.awt.image.OffScreenImage;
|
||||
import sun.awt.image.SunVolatileImage;
|
||||
import sun.awt.image.SurfaceManager;
|
||||
import sun.awt.image.VolatileSurfaceManager;
|
||||
import sun.java2d.SunGraphics2D;
|
||||
import sun.java2d.Surface;
|
||||
import sun.java2d.SurfaceData;
|
||||
@@ -73,8 +72,7 @@ public final class GLXGraphicsConfig
|
||||
private long pConfigInfo;
|
||||
private ContextCapabilities oglCaps;
|
||||
private final OGLContext context;
|
||||
private final SurfaceManager.ProxyCache surfaceDataProxyCache =
|
||||
new SurfaceManager.ProxyCache();
|
||||
private final SurfaceManager.ProxyCache surfaceDataProxyCache = new SurfaceManager.ProxyCache();
|
||||
|
||||
private static native long getGLXConfigInfo(int screennum, int visualnum);
|
||||
private static native int getOGLCapabilities(long configInfo);
|
||||
@@ -415,10 +413,4 @@ public final class GLXGraphicsConfig
|
||||
public ContextCapabilities getContextCapabilities() {
|
||||
return oglCaps;
|
||||
}
|
||||
|
||||
@Override
|
||||
public VolatileSurfaceManager createVolatileManager(SunVolatileImage image,
|
||||
Object context) {
|
||||
return new GLXVolatileSurfaceManager(image, context);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -47,8 +47,11 @@ public final class WLVKGraphicsConfig extends WLGraphicsConfig
|
||||
|
||||
private final VKGraphicsConfig offscreenConfig;
|
||||
|
||||
public WLVKGraphicsConfig(VKGraphicsConfig offscreenConfig, WLGraphicsDevice device) {
|
||||
super(device);
|
||||
public WLVKGraphicsConfig(VKGraphicsConfig offscreenConfig, WLGraphicsDevice device,
|
||||
int x, int y, int xLogical, int yLogical,
|
||||
int width, int height, int widthLogical, int heightLogical,
|
||||
int scale) {
|
||||
super(device, x, y, xLogical, yLogical, width, height, widthLogical, heightLogical, scale);
|
||||
this.offscreenConfig = offscreenConfig;
|
||||
}
|
||||
|
||||
@@ -62,8 +65,11 @@ public final class WLVKGraphicsConfig extends WLGraphicsConfig
|
||||
return getEffectiveScale();
|
||||
}
|
||||
|
||||
public static WLVKGraphicsConfig getConfig(VKGraphicsConfig offscreenConfig, WLGraphicsDevice device) {
|
||||
return new WLVKGraphicsConfig(offscreenConfig, device);
|
||||
public static WLVKGraphicsConfig getConfig(VKGraphicsConfig offscreenConfig, WLGraphicsDevice device,
|
||||
int x, int y, int xLogical, int yLogical,
|
||||
int width, int height, int widthLogical, int heightLogical,
|
||||
int scale) {
|
||||
return new WLVKGraphicsConfig(offscreenConfig, device, x, y, xLogical, yLogical, width, height, widthLogical, heightLogical, scale);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -30,14 +30,11 @@ import sun.awt.X11GraphicsConfig;
|
||||
import sun.awt.X11GraphicsDevice;
|
||||
import sun.awt.X11GraphicsEnvironment;
|
||||
import sun.awt.image.SurfaceManager;
|
||||
import sun.awt.image.SunVolatileImage;
|
||||
import sun.awt.image.VolatileSurfaceManager;
|
||||
import sun.java2d.SurfaceData;
|
||||
|
||||
public class XRGraphicsConfig extends X11GraphicsConfig implements
|
||||
SurfaceManager.ProxiedGraphicsConfig {
|
||||
private final SurfaceManager.ProxyCache surfaceDataProxyCache =
|
||||
new SurfaceManager.ProxyCache();
|
||||
private final SurfaceManager.ProxyCache surfaceDataProxyCache = new SurfaceManager.ProxyCache();
|
||||
|
||||
private XRGraphicsConfig(X11GraphicsDevice device, int visualnum,
|
||||
int depth, int colormap, boolean doubleBuffer) {
|
||||
@@ -62,10 +59,4 @@ public class XRGraphicsConfig extends X11GraphicsConfig implements
|
||||
public SurfaceManager.ProxyCache getSurfaceDataProxyCache() {
|
||||
return surfaceDataProxyCache;
|
||||
}
|
||||
|
||||
@Override
|
||||
public VolatileSurfaceManager createVolatileManager(SunVolatileImage image,
|
||||
Object context) {
|
||||
return new XRVolatileSurfaceManager(image, context);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -643,19 +643,8 @@ JNIEXPORT void JNICALL Java_sun_awt_wl_GtkFrameDecoration_nativePaintTitleBar
|
||||
jint pixel_width = ceil(width * scale);
|
||||
jint pixel_height = ceil(height * scale);
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
unsigned char *buffer = (*env)->GetPrimitiveArrayCritical(env, dest, 0);
|
||||
if (!buffer) {
|
||||
if (is_copy) {
|
||||
JNU_ReleaseStringPlatformChars(env, title, title_c_str);
|
||||
}
|
||||
JNU_ThrowOutOfMemoryError(env, "Could not get image buffer");
|
||||
return;
|
||||
}
|
||||
@@ -671,19 +660,25 @@ JNIEXPORT void JNICALL Java_sun_awt_wl_GtkFrameDecoration_nativePaintTitleBar
|
||||
|
||||
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);
|
||||
|
||||
if (is_copy) {
|
||||
JNU_ReleaseStringPlatformChars(env, title, title_c_str);
|
||||
}
|
||||
|
||||
p_cairo_destroy(cr);
|
||||
p_cairo_surface_destroy(surface);
|
||||
}
|
||||
|
||||
@@ -34,6 +34,7 @@
|
||||
#include "sun_awt_wl_WLDataOffer.h"
|
||||
#include "wayland-client-protocol.h"
|
||||
|
||||
|
||||
// Types
|
||||
|
||||
enum DataTransferProtocol
|
||||
@@ -270,6 +271,9 @@ DataSource_setDnDActions(const struct DataSource *source, uint32_t actions);
|
||||
static struct DataOffer *
|
||||
DataOffer_create(struct DataDevice *dataDevice, enum DataTransferProtocol protocol, void *waylandObject);
|
||||
|
||||
static void
|
||||
DataOffer_destroy(struct DataOffer *offer);
|
||||
|
||||
static void
|
||||
DataOffer_receive(struct DataOffer *offer, const char *mime, int fd);
|
||||
|
||||
@@ -330,7 +334,7 @@ DataOffer_create(struct DataDevice *dataDevice, enum DataTransferProtocol protoc
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Cleared in DataOffer.destroy()
|
||||
// Cleared in DataOffer_destroy
|
||||
jobject globalRef = (*env)->NewGlobalRef(env, obj);
|
||||
|
||||
EXCEPTION_CLEAR(env);
|
||||
@@ -341,23 +345,50 @@ DataOffer_create(struct DataDevice *dataDevice, enum DataTransferProtocol protoc
|
||||
}
|
||||
|
||||
offer->javaObject = globalRef;
|
||||
offer->protocol = protocol;
|
||||
|
||||
if (protocol == DATA_TRANSFER_PROTOCOL_WAYLAND) {
|
||||
struct wl_data_offer *wlDataOffer = waylandObject;
|
||||
offer->wlDataOffer = wlDataOffer;
|
||||
|
||||
wl_data_offer_add_listener(wlDataOffer, &wlDataOfferListener, offer);
|
||||
|
||||
offer->wlDataOffer = wlDataOffer;
|
||||
offer->protocol = DATA_TRANSFER_PROTOCOL_WAYLAND;
|
||||
}
|
||||
|
||||
if (protocol == DATA_TRANSFER_PROTOCOL_PRIMARY_SELECTION) {
|
||||
struct zwp_primary_selection_offer_v1 *zwpPrimarySelectionOffer = waylandObject;
|
||||
offer->zwpPrimarySelectionOffer = zwpPrimarySelectionOffer;
|
||||
|
||||
zwp_primary_selection_offer_v1_add_listener(zwpPrimarySelectionOffer, &zwpPrimarySelectionOfferListener, offer);
|
||||
offer->zwpPrimarySelectionOffer = zwpPrimarySelectionOffer;
|
||||
offer->protocol = DATA_TRANSFER_PROTOCOL_PRIMARY_SELECTION;
|
||||
}
|
||||
|
||||
return offer;
|
||||
}
|
||||
|
||||
static void
|
||||
DataOffer_destroy(struct DataOffer *offer)
|
||||
{
|
||||
if (offer == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (offer->javaObject != NULL) {
|
||||
JNIEnv *env = getEnv();
|
||||
assert(env != NULL);
|
||||
(*env)->DeleteGlobalRef(env, offer->javaObject);
|
||||
offer->javaObject = NULL;
|
||||
}
|
||||
|
||||
if (offer->protocol == DATA_TRANSFER_PROTOCOL_WAYLAND) {
|
||||
wl_data_offer_destroy(offer->wlDataOffer);
|
||||
} else if (offer->protocol == DATA_TRANSFER_PROTOCOL_PRIMARY_SELECTION) {
|
||||
zwp_primary_selection_offer_v1_destroy(offer->zwpPrimarySelectionOffer);
|
||||
}
|
||||
|
||||
free(offer);
|
||||
}
|
||||
|
||||
static void
|
||||
DataOffer_receive(struct DataOffer *offer, const char *mime, int fd)
|
||||
{
|
||||
@@ -953,53 +984,36 @@ Java_sun_awt_wl_WLDataSource_initNative(JNIEnv *env, jobject javaObject, jlong d
|
||||
protocol = DATA_TRANSFER_PROTOCOL_WAYLAND;
|
||||
}
|
||||
|
||||
dataSource->protocol = protocol;
|
||||
|
||||
if (protocol == DATA_TRANSFER_PROTOCOL_WAYLAND) {
|
||||
// To avoid race conditions when setting the dispatch queue,
|
||||
// it's necessary to do this dance with wl_proxy_create_wrapper.
|
||||
// See the docs for wl_proxy_create_wrapper for more details
|
||||
|
||||
struct wl_data_device_manager* dmWrapper = wl_proxy_create_wrapper(wl_ddm);
|
||||
struct wl_data_source *wlDataSource = NULL;
|
||||
|
||||
if (dmWrapper != NULL) {
|
||||
wl_proxy_set_queue((struct wl_proxy *) dmWrapper, dataDevice->dataSourceQueue);
|
||||
wlDataSource = wl_data_device_manager_create_data_source(dmWrapper);
|
||||
wl_proxy_wrapper_destroy(dmWrapper);
|
||||
}
|
||||
|
||||
struct wl_data_source *wlDataSource = wl_data_device_manager_create_data_source(wl_ddm);
|
||||
if (wlDataSource == NULL) {
|
||||
free(dataSource);
|
||||
JNU_ThrowByName(env, "java/awt/AWTError", "Wayland error creating wl_data_source proxy");
|
||||
return 0;
|
||||
}
|
||||
|
||||
dataSource->wlDataSource = wlDataSource;
|
||||
|
||||
wl_proxy_set_queue((struct wl_proxy *) wlDataSource, dataDevice->dataSourceQueue);
|
||||
wl_data_source_add_listener(wlDataSource, &wl_data_source_listener, dataSource);
|
||||
|
||||
dataSource->protocol = DATA_TRANSFER_PROTOCOL_WAYLAND;
|
||||
dataSource->wlDataSource = wlDataSource;
|
||||
}
|
||||
|
||||
if (protocol == DATA_TRANSFER_PROTOCOL_PRIMARY_SELECTION) {
|
||||
struct zwp_primary_selection_device_manager_v1 *dmWrapper = wl_proxy_create_wrapper(zwp_selection_dm);
|
||||
struct zwp_primary_selection_source_v1 *zwpPrimarySelectionSource = NULL;
|
||||
|
||||
if (dmWrapper != NULL) {
|
||||
wl_proxy_set_queue((struct wl_proxy *) dmWrapper, dataDevice->dataSourceQueue);
|
||||
zwpPrimarySelectionSource = zwp_primary_selection_device_manager_v1_create_source(dmWrapper);
|
||||
wl_proxy_wrapper_destroy(dmWrapper);
|
||||
}
|
||||
|
||||
struct zwp_primary_selection_source_v1 *zwpPrimarySelectionSource =
|
||||
zwp_primary_selection_device_manager_v1_create_source(zwp_selection_dm);
|
||||
if (zwpPrimarySelectionSource == NULL) {
|
||||
free(dataSource);
|
||||
JNU_ThrowByName(env, "java/awt/AWTError", "Wayland error creating zwp_primary_selection_source_v1 proxy");
|
||||
return 0;
|
||||
}
|
||||
|
||||
dataSource->zwpPrimarySelectionSource = zwpPrimarySelectionSource;
|
||||
|
||||
wl_proxy_set_queue((struct wl_proxy *) zwpPrimarySelectionSource, dataDevice->dataSourceQueue);
|
||||
zwp_primary_selection_source_v1_add_listener(zwpPrimarySelectionSource,
|
||||
&zwp_primary_selection_source_v1_listener, dataSource);
|
||||
|
||||
dataSource->protocol = DATA_TRANSFER_PROTOCOL_PRIMARY_SELECTION;
|
||||
dataSource->zwpPrimarySelectionSource = zwpPrimarySelectionSource;
|
||||
}
|
||||
|
||||
return ptr_to_jlong(dataSource);
|
||||
@@ -1026,6 +1040,11 @@ Java_sun_awt_wl_WLDataSource_destroyImpl(JNIEnv *env, jclass clazz, jlong native
|
||||
return;
|
||||
}
|
||||
|
||||
if (source->javaObject != NULL) {
|
||||
(*env)->DeleteGlobalRef(env, source->javaObject);
|
||||
source->javaObject = NULL;
|
||||
}
|
||||
|
||||
if (source->protocol == DATA_TRANSFER_PROTOCOL_WAYLAND) {
|
||||
wl_data_source_destroy(source->wlDataSource);
|
||||
} else if (source->protocol == DATA_TRANSFER_PROTOCOL_PRIMARY_SELECTION) {
|
||||
@@ -1040,11 +1059,6 @@ Java_sun_awt_wl_WLDataSource_destroyImpl(JNIEnv *env, jclass clazz, jlong native
|
||||
wl_surface_destroy(source->dragIcon);
|
||||
}
|
||||
|
||||
if (source->javaObject != NULL) {
|
||||
(*env)->DeleteGlobalRef(env, source->javaObject);
|
||||
source->javaObject = NULL;
|
||||
}
|
||||
|
||||
free(source);
|
||||
}
|
||||
|
||||
@@ -1059,8 +1073,7 @@ Java_sun_awt_wl_WLDataSource_setDnDActionsImpl(JNIEnv *env,
|
||||
}
|
||||
|
||||
JNIEXPORT void JNICALL Java_sun_awt_wl_WLDataSource_setDnDIconImpl
|
||||
(JNIEnv * env, jclass clazz, jlong nativePtr, jint scale,
|
||||
jint width, jint height, jint offsetX, jint offsetY, jintArray pixels)
|
||||
(JNIEnv * env, jclass clazz, jlong nativePtr, jint width, jint height, jint offsetX, jint offsetY, jintArray pixels)
|
||||
{
|
||||
struct DataSource *source = jlong_to_ptr(nativePtr);
|
||||
|
||||
@@ -1113,10 +1126,6 @@ JNIEXPORT void JNICALL Java_sun_awt_wl_WLDataSource_setDnDIconImpl
|
||||
wl_surface_attach(source->dragIcon, source->dragIconBuffer, offsetX, offsetY);
|
||||
#endif
|
||||
|
||||
if (scale >= 1) {
|
||||
wl_surface_set_buffer_scale(source->dragIcon, scale);
|
||||
}
|
||||
|
||||
wl_surface_damage_buffer(source->dragIcon, 0, 0, width, height);
|
||||
|
||||
// NOTE: we still need to commit the surface, this is done immediately after start_drag
|
||||
@@ -1125,25 +1134,8 @@ JNIEXPORT void JNICALL Java_sun_awt_wl_WLDataSource_setDnDIconImpl
|
||||
JNIEXPORT void JNICALL
|
||||
Java_sun_awt_wl_WLDataOffer_destroyImpl(JNIEnv *env, jclass clazz, jlong nativePtr)
|
||||
{
|
||||
assert(env != NULL);
|
||||
struct DataOffer *offer = jlong_to_ptr(nativePtr);
|
||||
|
||||
if (offer == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (offer->protocol == DATA_TRANSFER_PROTOCOL_WAYLAND) {
|
||||
wl_data_offer_destroy(offer->wlDataOffer);
|
||||
} else if (offer->protocol == DATA_TRANSFER_PROTOCOL_PRIMARY_SELECTION) {
|
||||
zwp_primary_selection_offer_v1_destroy(offer->zwpPrimarySelectionOffer);
|
||||
}
|
||||
|
||||
if (offer->javaObject != NULL) {
|
||||
(*env)->DeleteGlobalRef(env, offer->javaObject);
|
||||
offer->javaObject = NULL;
|
||||
}
|
||||
|
||||
free(offer);
|
||||
DataOffer_destroy(offer);
|
||||
}
|
||||
|
||||
JNIEXPORT void JNICALL
|
||||
|
||||
@@ -43,6 +43,8 @@ typedef struct WLOutput {
|
||||
|
||||
int32_t x;
|
||||
int32_t y;
|
||||
int32_t x_logical;
|
||||
int32_t y_logical;
|
||||
int32_t width;
|
||||
int32_t height;
|
||||
int32_t width_logical;
|
||||
@@ -57,8 +59,6 @@ typedef struct WLOutput {
|
||||
char * make;
|
||||
char * model;
|
||||
char * name;
|
||||
|
||||
bool offset_known; // whether x and y were set by xdg_output
|
||||
} WLOutput;
|
||||
|
||||
static jclass geClass;
|
||||
@@ -83,13 +83,10 @@ wl_output_geometry(
|
||||
{
|
||||
WLOutput *output = data;
|
||||
|
||||
if (!output->offset_known) {
|
||||
// Ubuntu 22.04 has a bug that prevent Mutter from sending out updates to (x, y) in this
|
||||
// geometry event. So we prefer to learn offset from xdg_output that will override
|
||||
// (x, y) from this event.
|
||||
output->x = x;
|
||||
output->y = y;
|
||||
}
|
||||
// TODO: there's also a recommended, but unstable interface xdg_output;
|
||||
// we may want to switch to that one day.
|
||||
output->x = x;
|
||||
output->y = y;
|
||||
output->subpixel = subpixel;
|
||||
output->transform = transform;
|
||||
output->width_mm = physical_width;
|
||||
@@ -164,6 +161,8 @@ NotifyOutputConfigured(WLOutput* output)
|
||||
output->id,
|
||||
output->x,
|
||||
output->y,
|
||||
output->x_logical,
|
||||
output->y_logical,
|
||||
output->width,
|
||||
output->height,
|
||||
output->width_logical,
|
||||
@@ -174,8 +173,6 @@ NotifyOutputConfigured(WLOutput* output)
|
||||
(jint)output->transform,
|
||||
(jint)output->scale);
|
||||
JNU_CHECK_EXCEPTION(env);
|
||||
|
||||
output->offset_known = false;
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -221,12 +218,8 @@ static void
|
||||
zxdg_output_logical_position(void *data, struct zxdg_output_v1 *zxdg_output_v1, int32_t x, int32_t y)
|
||||
{
|
||||
WLOutput * output = data;
|
||||
output->x = x;
|
||||
output->y = y;
|
||||
|
||||
// Prevent the geometry event from overriding these values with potentially incorrect ones;
|
||||
// see wl_output_geometry().
|
||||
output->offset_known = true;
|
||||
output->x_logical = x;
|
||||
output->y_logical = y;
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -264,7 +257,7 @@ WLGraphicsEnvironment_initIDs
|
||||
CHECK_NULL_RETURN(
|
||||
notifyOutputConfiguredMID = (*env)->GetMethodID(env, clazz,
|
||||
"notifyOutputConfigured",
|
||||
"(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;IIIIIIIIIIII)V"),
|
||||
"(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;IIIIIIIIIIIIII)V"),
|
||||
JNI_FALSE);
|
||||
CHECK_NULL_RETURN(
|
||||
notifyOutputDestroyedMID = (*env)->GetMethodID(env, clazz,
|
||||
|
||||
@@ -75,7 +75,6 @@ struct wl_seat *wl_seat = NULL;
|
||||
|
||||
struct wl_keyboard *wl_keyboard; // optional, check for NULL before use
|
||||
struct wl_pointer *wl_pointer; // optional, check for NULL before use
|
||||
struct zwp_relative_pointer_manager_v1* relative_pointer_manager; // optional, check for NULL before use
|
||||
|
||||
#define MAX_CURSOR_SCALE 100
|
||||
struct wl_cursor_theme *cursor_themes[MAX_CURSOR_SCALE] = {NULL};
|
||||
@@ -84,8 +83,6 @@ struct wl_data_device_manager *wl_ddm = NULL;
|
||||
struct zwp_primary_selection_device_manager_v1 *zwp_selection_dm = NULL; // optional, check for NULL before use
|
||||
struct zxdg_output_manager_v1 *zxdg_output_manager_v1 = NULL; // optional, check for NULL before use
|
||||
|
||||
struct zwp_text_input_manager_v3 *zwp_text_input_manager = NULL; // optional, check for NULL before use
|
||||
|
||||
static uint32_t num_of_outstanding_sync = 0;
|
||||
|
||||
// This group of definitions corresponds to declarations from awt.h
|
||||
@@ -126,7 +123,6 @@ static jmethodID dispatchKeyboardKeyEventMID;
|
||||
static jmethodID dispatchKeyboardModifiersEventMID;
|
||||
static jmethodID dispatchKeyboardEnterEventMID;
|
||||
static jmethodID dispatchKeyboardLeaveEventMID;
|
||||
static jmethodID dispatchRelativePointerEventMID;
|
||||
|
||||
JNIEnv *getEnv() {
|
||||
JNIEnv *env;
|
||||
@@ -463,31 +459,6 @@ static const struct wl_keyboard_listener wl_keyboard_listener = {
|
||||
.key = wl_keyboard_key
|
||||
};
|
||||
|
||||
static void
|
||||
wl_relative_motion(void *data,
|
||||
struct zwp_relative_pointer_v1 *zwp_relative_pointer_v1,
|
||||
uint32_t utime_hi,
|
||||
uint32_t utime_lo,
|
||||
wl_fixed_t dx,
|
||||
wl_fixed_t dy,
|
||||
wl_fixed_t dx_unaccel,
|
||||
wl_fixed_t dy_unaccel)
|
||||
{
|
||||
double ddx = wl_fixed_to_double(dx);
|
||||
double ddy = wl_fixed_to_double(dy);
|
||||
JNIEnv* env = getEnv();
|
||||
|
||||
(*env)->CallStaticVoidMethod(env,
|
||||
tkClass,
|
||||
dispatchRelativePointerEventMID,
|
||||
ddx, ddy);
|
||||
JNU_CHECK_EXCEPTION(env);
|
||||
}
|
||||
|
||||
static const struct zwp_relative_pointer_v1_listener relative_pointer_listener = {
|
||||
.relative_motion = wl_relative_motion
|
||||
};
|
||||
|
||||
static void
|
||||
wl_seat_capabilities(void *data, struct wl_seat *wl_seat, uint32_t capabilities)
|
||||
{
|
||||
@@ -498,14 +469,6 @@ wl_seat_capabilities(void *data, struct wl_seat *wl_seat, uint32_t capabilities)
|
||||
wl_pointer = wl_seat_get_pointer(wl_seat);
|
||||
if (wl_pointer != NULL) {
|
||||
wl_pointer_add_listener(wl_pointer, &wl_pointer_listener, NULL);
|
||||
if (relative_pointer_manager != NULL) {
|
||||
struct zwp_relative_pointer_v1* rptr
|
||||
= zwp_relative_pointer_manager_v1_get_relative_pointer(relative_pointer_manager,
|
||||
wl_pointer);
|
||||
if (rptr != NULL) {
|
||||
zwp_relative_pointer_v1_add_listener(rptr, &relative_pointer_listener, NULL);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if (!has_pointer && wl_pointer != NULL) {
|
||||
wl_pointer_release(wl_pointer);
|
||||
@@ -598,8 +561,6 @@ registry_global(void *data, struct wl_registry *wl_registry,
|
||||
xdg_activation_v1 = wl_registry_bind(wl_registry, name, &xdg_activation_v1_interface, 1);
|
||||
} else if (strcmp(interface, gtk_shell1_interface.name) == 0) {
|
||||
gtk_shell1 = wl_registry_bind(wl_registry, name, >k_shell1_interface, 1);
|
||||
} else if (strcmp(interface, zwp_relative_pointer_manager_v1_interface.name) == 0) {
|
||||
relative_pointer_manager = wl_registry_bind(wl_registry, name, &zwp_relative_pointer_manager_v1_interface, 1);
|
||||
} else if (strcmp(interface, wl_data_device_manager_interface.name) == 0) {
|
||||
wl_ddm = wl_registry_bind(wl_registry, name,&wl_data_device_manager_interface, 3);
|
||||
} else if (strcmp(interface, zwp_primary_selection_device_manager_v1_interface.name) == 0) {
|
||||
@@ -612,14 +573,6 @@ registry_global(void *data, struct wl_registry *wl_registry,
|
||||
WLOutputXdgOutputManagerBecameAvailable();
|
||||
process_new_listener_before_end_of_init();
|
||||
}
|
||||
} else if (strcmp(interface, zwp_text_input_manager_v3_interface.name) == 0) {
|
||||
// If the requested version is higher than the provided one by the compositor,
|
||||
// the event loop may shut down as soon as it gets launched (wl_display_dispatch will return -1),
|
||||
// so let's protect from this since the component being obtained is not vital for work.
|
||||
const uint32_t versionToBind = 1;
|
||||
if (versionToBind <= version) {
|
||||
zwp_text_input_manager = wl_registry_bind(wl_registry, name, &zwp_text_input_manager_v3_interface, versionToBind);
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef WAKEFIELD_ROBOT
|
||||
@@ -753,10 +706,6 @@ initJavaRefs(JNIEnv *env, jclass clazz)
|
||||
"dispatchKeyboardModifiersEvent",
|
||||
"(J)V"),
|
||||
JNI_FALSE);
|
||||
CHECK_NULL_RETURN(dispatchRelativePointerEventMID = (*env)->GetStaticMethodID(env, tkClass,
|
||||
"dispatchRelativePointerEvent",
|
||||
"(DD)V"),
|
||||
JNI_FALSE);
|
||||
|
||||
jclass wlgeClass = (*env)->FindClass(env, "sun/awt/wl/WLGraphicsEnvironment");
|
||||
CHECK_NULL_RETURN(wlgeClass, JNI_FALSE);
|
||||
|
||||
@@ -25,14 +25,11 @@
|
||||
|
||||
#include <wayland-client.h>
|
||||
#include <wayland-cursor.h>
|
||||
|
||||
#include "xdg-shell-client-protocol.h"
|
||||
#include "xdg-activation-v1-client-protocol.h"
|
||||
#include "xdg-output-unstable-v1-client-protocol.h"
|
||||
#include "primary-selection-client-protocol.h"
|
||||
#include "viewporter-client-protocol.h"
|
||||
#include "relative-pointer-unstable-v1-client-protocol.h"
|
||||
#include "im/text-input-unstable-v3/text-input-unstable-v3-client-protocol.h"
|
||||
#include "jvm_md.h"
|
||||
#include "jni_util.h"
|
||||
|
||||
@@ -68,8 +65,6 @@ extern struct wl_cursor_theme *wl_cursor_theme;
|
||||
extern struct wl_data_device_manager *wl_ddm;
|
||||
extern struct zwp_primary_selection_device_manager_v1 *zwp_selection_dm; // optional, check for NULL before use
|
||||
extern struct zxdg_output_manager_v1 *zxdg_output_manager_v1; // optional, check for NULL before use
|
||||
extern struct zwp_relative_pointer_manager_v1* relative_pointer_manager;
|
||||
extern struct zwp_text_input_manager_v3 *zwp_text_input_manager; // optional, check for NULL before use
|
||||
|
||||
JNIEnv *getEnv();
|
||||
|
||||
|
||||
@@ -1,687 +0,0 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include "sun_awt_wl_im_text_input_unstable_v3_WLInputMethodDescriptorZwpTextInputV3.h"
|
||||
#include "sun_awt_wl_im_text_input_unstable_v3_WLInputMethodZwpTextInputV3.h"
|
||||
#include "WLToolkit.h" // wl_seat, zwp_text_input_*, uint[...]_t, int[...]_t
|
||||
#include "JNIUtilities.h"
|
||||
|
||||
#include <stdbool.h> // bool, true, false
|
||||
#include <string.h> // memset, strlen
|
||||
#include <stdlib.h> // malloc, free
|
||||
#include <assert.h> // assert
|
||||
|
||||
|
||||
static bool checkIfTheImplementationIsAvailable() {
|
||||
return (zwp_text_input_manager == NULL) ? false : true;
|
||||
}
|
||||
|
||||
static struct {
|
||||
jclass wlInputMethodClass;
|
||||
|
||||
/// `sun.awt.wl.im.text_input_unstable_v3.WLInputMethodZwpTextInputV3#zwp_text_input_v3_onEnter`
|
||||
jmethodID mID_tiOnEnter;
|
||||
/// `sun.awt.wl.im.text_input_unstable_v3.WLInputMethodZwpTextInputV3#zwp_text_input_v3_onLeave`
|
||||
jmethodID mID_tiOnLeave;
|
||||
/// `sun.awt.wl.im.text_input_unstable_v3.WLInputMethodZwpTextInputV3#zwp_text_input_v3_onPreeditString`
|
||||
jmethodID mID_tiOnPreeditString;
|
||||
/// `sun.awt.wl.im.text_input_unstable_v3.WLInputMethodZwpTextInputV3#zwp_text_input_v3_onCommitString`
|
||||
jmethodID mID_tiOnCommitString;
|
||||
/// `sun.awt.wl.im.text_input_unstable_v3.WLInputMethodZwpTextInputV3#zwp_text_input_v3_onDeleteSurroundingText`
|
||||
jmethodID mID_tiOnDeleteSurroundingText;
|
||||
/// `sun.awt.wl.im.text_input_unstable_v3.WLInputMethodZwpTextInputV3#zwp_text_input_v3_onDone`
|
||||
jmethodID mID_tiOnDone;
|
||||
} jniIDs = {0};
|
||||
|
||||
|
||||
// ================================================= IMContext section ================================================
|
||||
static void IMContext_zwp_text_input_v3_onEnter(void*, struct zwp_text_input_v3*, struct wl_surface*);
|
||||
static void IMContext_zwp_text_input_v3_onLeave(void*, struct zwp_text_input_v3*, struct wl_surface*);
|
||||
static void IMContext_zwp_text_input_v3_onPreeditString(void*, struct zwp_text_input_v3*, const char*, int32_t, int32_t);
|
||||
static void IMContext_zwp_text_input_v3_onCommitString(void*, struct zwp_text_input_v3*, const char*);
|
||||
static void IMContext_zwp_text_input_v3_onDeleteSurroundingText(void*, struct zwp_text_input_v3*, uint32_t, uint32_t);
|
||||
static void IMContext_zwp_text_input_v3_onDone(void*, struct zwp_text_input_v3*, uint32_t);
|
||||
|
||||
static const struct zwp_text_input_v3_listener IMContext_zwp_text_input_v3_listener = {
|
||||
.enter = &IMContext_zwp_text_input_v3_onEnter,
|
||||
.leave = &IMContext_zwp_text_input_v3_onLeave,
|
||||
.preedit_string = &IMContext_zwp_text_input_v3_onPreeditString,
|
||||
.commit_string = &IMContext_zwp_text_input_v3_onCommitString,
|
||||
.delete_surrounding_text = &IMContext_zwp_text_input_v3_onDeleteSurroundingText,
|
||||
.done = &IMContext_zwp_text_input_v3_onDone,
|
||||
};
|
||||
|
||||
/**
|
||||
* The native-side counterpart of `sun.awt.wl.im.text_input_unstable_v3.WLInputMethodZwpTextInputV3`.
|
||||
* On Java side these contexts are created and destroyed through
|
||||
* `WLInputMethod#createNativeContext` and `WLInputMethod#destroyNativeContext` respectively.
|
||||
*
|
||||
* `IMContext` and `WLInputMethodZwpTextInputV3` are related in a 1:1 ratio - an instance of `WLInputMethodZwpTextInputV3` holds no more than 1
|
||||
* instance of `IMContext` and an instance of `IMContext` only belongs to 1 instance of `WLInputMethodZwpTextInputV3`.
|
||||
*/
|
||||
struct IMContext {
|
||||
/// A global reference to the instance of `sun.awt.wl.im.text_input_unstable_v3.WLInputMethodZwpTextInputV3` owning this instance of `IMContext`.
|
||||
jobject wlInputMethodOwner;
|
||||
|
||||
/// Represents an input context for the entire `text-input-unstable-v3` protocol.
|
||||
struct zwp_text_input_v3 *textInput;
|
||||
};
|
||||
|
||||
/**
|
||||
* Creates and fully initializes an instance of `struct IMContext`.
|
||||
*
|
||||
* @param wlInputMethodOwnerRefToCopy a reference to the owning instance of `sun.awt.wl.im.text_input_unstable_v3.WLInputMethodZwpTextInputV3`.
|
||||
* NB: the reference will be copied via `NewGlobalRef` and no longer used.
|
||||
* @return `null` if it has failed to create or completely initialize a new instance.
|
||||
* In this case a corresponding exception of class `java.awt.AWTException` or of an unchecked exception class
|
||||
* will be raised in @p env
|
||||
*/
|
||||
static struct IMContext* IMContext_Create(JNIEnv * const env, jobject wlInputMethodOwnerRefToCopy) {
|
||||
struct wl_seat * const wlSeat = wl_seat;
|
||||
struct zwp_text_input_manager_v3 * const textInputManager = zwp_text_input_manager;
|
||||
|
||||
struct IMContext *result = NULL;
|
||||
jobject wlInputMethodOwner = NULL;
|
||||
struct zwp_text_input_v3 *textInput = NULL;
|
||||
|
||||
if (wlSeat == NULL) {
|
||||
JNU_ThrowByName(env, "java/awt/AWTException", "IMContext_Create: no wl_seat is available");
|
||||
goto failure;
|
||||
}
|
||||
|
||||
if (textInputManager == NULL) {
|
||||
JNU_ThrowNullPointerException(env, "IMContext_Create: textInputManager is NULL");
|
||||
goto failure;
|
||||
}
|
||||
|
||||
wlInputMethodOwner = (*env)->NewGlobalRef(env, wlInputMethodOwnerRefToCopy);
|
||||
if (wlInputMethodOwner == NULL) {
|
||||
if ((*env)->ExceptionCheck(env) == JNI_FALSE) {
|
||||
JNU_ThrowOutOfMemoryError(env, "IMContext_Create: NewGlobalRef(wlInputMethodOwnerRefToCopy) failed");
|
||||
}
|
||||
goto failure;
|
||||
}
|
||||
|
||||
wlInputMethodOwnerRefToCopy = NULL; // To avoid misusages
|
||||
|
||||
result = malloc(sizeof(struct IMContext));
|
||||
if (result == NULL) {
|
||||
JNU_ThrowOutOfMemoryError(env, "IMContext_Create: malloc(sizeof(struct IMContext)) failed");
|
||||
goto failure;
|
||||
}
|
||||
|
||||
textInput = zwp_text_input_manager_v3_get_text_input(textInputManager, wlSeat);
|
||||
if (textInput == NULL) {
|
||||
JNU_ThrowByName(env, "java/awt/AWTException", "IMContext_Create: failed to obtain a new instance of zwp_text_input_v3");
|
||||
goto failure;
|
||||
}
|
||||
|
||||
// WLToolkit dispatches (almost) all native Wayland events on EDT, not on its thread.
|
||||
// If it didn't, the callbacks being set here might be called even before this function finishes, hence even before
|
||||
// the constructor of `sun.awt.wl.im.text_input_unstable_v3.WLInputMethodZwpTextInputV3` finishes (because the constructor gets called on the
|
||||
// EDT rather than on the toolkit thread).
|
||||
// In that case we would have to take it into account while implementing the callbacks and
|
||||
// `WLInputMethodZwpTextInputV3` class in general.
|
||||
zwp_text_input_v3_add_listener(textInput, &IMContext_zwp_text_input_v3_listener, result);
|
||||
|
||||
(void)memset(result, 0, sizeof(struct IMContext));
|
||||
|
||||
result->wlInputMethodOwner = wlInputMethodOwner;
|
||||
result->textInput = textInput;
|
||||
|
||||
return result;
|
||||
|
||||
failure:
|
||||
if (textInput != NULL) {
|
||||
zwp_text_input_v3_destroy(textInput);
|
||||
textInput = NULL;
|
||||
}
|
||||
|
||||
if (result != NULL) {
|
||||
free(result);
|
||||
result = NULL;
|
||||
}
|
||||
|
||||
if (wlInputMethodOwner != NULL) {
|
||||
(*env)->DeleteGlobalRef(env, wlInputMethodOwner);
|
||||
wlInputMethodOwner = NULL;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/// Destroys the context previously created by IMContext_Create
|
||||
static void IMContext_Destroy(JNIEnv * const env, struct IMContext * const imContext) {
|
||||
assert(env != NULL);
|
||||
assert(imContext != NULL);
|
||||
|
||||
if (imContext->textInput != NULL) {
|
||||
zwp_text_input_v3_destroy(imContext->textInput);
|
||||
imContext->textInput = NULL;
|
||||
}
|
||||
|
||||
if (imContext->wlInputMethodOwner != NULL) {
|
||||
(*env)->DeleteGlobalRef(env, imContext->wlInputMethodOwner);
|
||||
imContext->wlInputMethodOwner = NULL;
|
||||
}
|
||||
|
||||
free(imContext);
|
||||
}
|
||||
|
||||
|
||||
// The IMContext_zwp_text_input_v3_on* callbacks are supposed to be as a thin bridge to
|
||||
// `WLInputMethodZwpTextInputV3`'s JNI upcalls as possible in terms of contained logic.
|
||||
// Generally they should only invoke the corresponding upcalls with the received parameters.
|
||||
//
|
||||
// Exceptions after making JNI upcalls to WLInputMethodZwpTextInputV3 are checked (via JNU_CHECK_EXCEPTION),
|
||||
// but not suppressed on a purpose: all the corresponding Java methods already handles any java.lang.Exception.
|
||||
// So if an exception leaves any of those methods, it's something really strange and it's better to let WLToolkit
|
||||
// get to know about it rather than log and try to continue the normal path.
|
||||
// The checks are just made to suppress -Xcheck:jni warnings.
|
||||
|
||||
static void IMContext_zwp_text_input_v3_onEnter(
|
||||
void * const ctx,
|
||||
struct zwp_text_input_v3 * const textInput,
|
||||
struct wl_surface * const surface
|
||||
) {
|
||||
const struct IMContext * const imContext = ctx;
|
||||
JNIEnv *env = NULL;
|
||||
|
||||
if (imContext == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
env = getEnv();
|
||||
if (env == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
(*env)->CallVoidMethod(env, imContext->wlInputMethodOwner, jniIDs.mID_tiOnEnter, ptr_to_jlong(surface));
|
||||
JNU_CHECK_EXCEPTION(env);
|
||||
}
|
||||
|
||||
static void IMContext_zwp_text_input_v3_onLeave(
|
||||
void * const ctx,
|
||||
struct zwp_text_input_v3 * const textInput,
|
||||
struct wl_surface * const surface
|
||||
) {
|
||||
const struct IMContext * const imContext = ctx;
|
||||
JNIEnv *env = NULL;
|
||||
|
||||
if (imContext == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
env = getEnv();
|
||||
if (env == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
(*env)->CallVoidMethod(env, imContext->wlInputMethodOwner, jniIDs.mID_tiOnLeave, ptr_to_jlong(surface));
|
||||
JNU_CHECK_EXCEPTION(env);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Converts a UTF-8 string to a Java byte array, throwing an OutOfMemoryError if the allocation fails. Another kind
|
||||
* of exceptions may also appear, according to the implementation of 'NewByteArray' and 'SetByteArrayRegion'.
|
||||
* Regardless of the returned value, always check 'env->ExceptionCheck()' after each call of this function.
|
||||
*
|
||||
* @param utf8Str UTF-8 string to convert.
|
||||
* @param utf8StrSizeInBytes size of the UTF-8 string in bytes, or a negative value to ask the function to
|
||||
* calculate it manually.
|
||||
* @param env JNI environment. Mustn't be NULL.
|
||||
* @param oomMessage message to use in the OutOfMemoryError exception if it appears. Mustn't be NULL.
|
||||
*
|
||||
* @return a local JNI reference to a Java byte array or NULL if 'utf8Str' is NULL,
|
||||
* an exception occurred,
|
||||
* or 'NewByteArray' returned NULL for some other reason.
|
||||
*/
|
||||
static jbyteArray utf8StrToJByteArrayOrThrowOOM(
|
||||
const char * const utf8Str,
|
||||
ssize_t utf8StrSizeInBytes,
|
||||
JNIEnv * const env,
|
||||
const char * const oomMessage
|
||||
) {
|
||||
jbyteArray result = NULL;
|
||||
|
||||
assert(env != NULL);
|
||||
assert(oomMessage != NULL);
|
||||
|
||||
if (utf8Str == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (utf8StrSizeInBytes < 0) {
|
||||
// Let's believe there's a trailing NUL codepoint (otherwise we can't calculate the string's size), and
|
||||
// there are no NUL codepoints in the middle, though it's possible in general for UTF-8.
|
||||
utf8StrSizeInBytes = (ssize_t)(strlen(utf8Str) + 1);
|
||||
}
|
||||
|
||||
result = (*env)->NewByteArray(env, (jsize)utf8StrSizeInBytes);
|
||||
if (result == NULL) {
|
||||
if ((*env)->ExceptionCheck(env) == JNI_FALSE) {
|
||||
JNU_ThrowOutOfMemoryError(env, oomMessage);
|
||||
}
|
||||
} else {
|
||||
(*env)->SetByteArrayRegion(
|
||||
env,
|
||||
result,
|
||||
0,
|
||||
(jsize)utf8StrSizeInBytes,
|
||||
(const jbyte*)utf8Str
|
||||
);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
static void IMContext_zwp_text_input_v3_onPreeditString(
|
||||
void * const ctx,
|
||||
struct zwp_text_input_v3 * const textInput,
|
||||
const char * const preeditStringUtf8,
|
||||
const int32_t cursorBeginUtf8Byte,
|
||||
const int32_t cursorEndUtf8Byte
|
||||
) {
|
||||
const struct IMContext * const imContext = ctx;
|
||||
JNIEnv *env = NULL;
|
||||
jbyteArray preeditStringUtf8Bytes = NULL;
|
||||
|
||||
if (imContext == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
env = getEnv();
|
||||
if (env == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
// may still be NULL
|
||||
preeditStringUtf8Bytes = utf8StrToJByteArrayOrThrowOOM(
|
||||
preeditStringUtf8,
|
||||
// the zwp_text_input_v3::preedit_string event doesn't provide the length or size of the string separately,
|
||||
// asking the function to manually calculate it.
|
||||
-1,
|
||||
env,
|
||||
"IMContext_zwp_text_input_v3_onPreeditString: failed to allocate a new Java byte array"
|
||||
);
|
||||
|
||||
if ((*env)->ExceptionCheck(env) == JNI_TRUE) {
|
||||
return;
|
||||
}
|
||||
|
||||
(*env)->CallVoidMethod(
|
||||
env,
|
||||
imContext->wlInputMethodOwner,
|
||||
jniIDs.mID_tiOnPreeditString,
|
||||
preeditStringUtf8Bytes,
|
||||
(jint)cursorBeginUtf8Byte,
|
||||
(jint)cursorEndUtf8Byte
|
||||
);
|
||||
JNU_CHECK_EXCEPTION(env);
|
||||
}
|
||||
|
||||
static void IMContext_zwp_text_input_v3_onCommitString(
|
||||
void * const ctx,
|
||||
struct zwp_text_input_v3 * const textInput,
|
||||
const char * const commitStringUtf8
|
||||
) {
|
||||
const struct IMContext * const imContext = ctx;
|
||||
JNIEnv *env = NULL;
|
||||
jbyteArray commitStringUtf8Bytes = NULL;
|
||||
|
||||
if (imContext == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
env = getEnv();
|
||||
if (env == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
// may still be NULL
|
||||
commitStringUtf8Bytes = utf8StrToJByteArrayOrThrowOOM(
|
||||
commitStringUtf8,
|
||||
// the zwp_text_input_v3::commit_string event doesn't provide the length or size of the string separately,
|
||||
// asking the function to manually calculate it.
|
||||
-1,
|
||||
env,
|
||||
"IMContext_zwp_text_input_v3_onCommitString: failed to allocate a new Java byte array"
|
||||
);
|
||||
|
||||
if ((*env)->ExceptionCheck(env) == JNI_TRUE) {
|
||||
return;
|
||||
}
|
||||
|
||||
(*env)->CallVoidMethod(env, imContext->wlInputMethodOwner, jniIDs.mID_tiOnCommitString, commitStringUtf8Bytes);
|
||||
JNU_CHECK_EXCEPTION(env);
|
||||
}
|
||||
|
||||
static void IMContext_zwp_text_input_v3_onDeleteSurroundingText(
|
||||
void * const ctx,
|
||||
struct zwp_text_input_v3 * const textInput,
|
||||
const uint32_t numberOfUtf8BytesBeforeToDelete,
|
||||
const uint32_t numberOfUtf8BytesAfterToDelete
|
||||
) {
|
||||
const struct IMContext * const imContext = ctx;
|
||||
JNIEnv *env = NULL;
|
||||
|
||||
if (imContext == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
env = getEnv();
|
||||
if (env == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ((*env)->ExceptionCheck(env) == JNI_TRUE) {
|
||||
return;
|
||||
}
|
||||
|
||||
(*env)->CallVoidMethod(
|
||||
env,
|
||||
imContext->wlInputMethodOwner,
|
||||
jniIDs.mID_tiOnDeleteSurroundingText,
|
||||
(jlong)numberOfUtf8BytesBeforeToDelete,
|
||||
(jlong)numberOfUtf8BytesAfterToDelete
|
||||
);
|
||||
JNU_CHECK_EXCEPTION(env);
|
||||
}
|
||||
|
||||
static void IMContext_zwp_text_input_v3_onDone(
|
||||
void *const ctx,
|
||||
struct zwp_text_input_v3 * const textInput,
|
||||
const uint32_t serial
|
||||
) {
|
||||
const struct IMContext * const imContext = ctx;
|
||||
JNIEnv *env = NULL;
|
||||
|
||||
if (imContext == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
env = getEnv();
|
||||
if (env == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
(*env)->CallVoidMethod(env, imContext->wlInputMethodOwner, jniIDs.mID_tiOnDone, (jlong)serial);
|
||||
JNU_CHECK_EXCEPTION(env);
|
||||
}
|
||||
// ============================================= END of IMContext section =============================================
|
||||
|
||||
|
||||
// =============================================== JNI downcalls section ==============================================
|
||||
|
||||
JNIEXPORT jboolean JNICALL
|
||||
Java_sun_awt_wl_im_text_1input_1unstable_1v3_WLInputMethodDescriptorZwpTextInputV3_checkIfAvailableOnPlatform(JNIEnv * const env, const jclass clazz) {
|
||||
return checkIfTheImplementationIsAvailable() ? JNI_TRUE : JNI_FALSE;
|
||||
}
|
||||
|
||||
|
||||
JNIEXPORT void JNICALL
|
||||
Java_sun_awt_wl_im_text_1input_1unstable_1v3_WLInputMethodZwpTextInputV3_initIDs(JNIEnv * const env, const jclass clazz) {
|
||||
CHECK_NULL_THROW_OOME(
|
||||
env,
|
||||
jniIDs.wlInputMethodClass = (*env)->NewGlobalRef(env, clazz),
|
||||
"Allocation of a global reference to sun.awt.wl.im.text_input_unstable_v3.WLInputMethodZwpTextInputV3 class failed"
|
||||
);
|
||||
|
||||
jniIDs.mID_tiOnEnter =
|
||||
(*env)->GetMethodID(env, jniIDs.wlInputMethodClass, "zwp_text_input_v3_onEnter", "(J)V");
|
||||
if (jniIDs.mID_tiOnEnter == NULL) {
|
||||
// DeleteGlobalRef is one of the few JNI functions that are safe to call while there's a pending exception
|
||||
(*env)->DeleteGlobalRef(env, jniIDs.wlInputMethodClass);
|
||||
(void)memset(&jniIDs, 0, sizeof(jniIDs));
|
||||
return;
|
||||
}
|
||||
|
||||
jniIDs.mID_tiOnLeave =
|
||||
(*env)->GetMethodID(env, jniIDs.wlInputMethodClass, "zwp_text_input_v3_onLeave", "(J)V");
|
||||
if (jniIDs.mID_tiOnLeave == NULL) {
|
||||
(*env)->DeleteGlobalRef(env, jniIDs.wlInputMethodClass);
|
||||
(void)memset(&jniIDs, 0, sizeof(jniIDs));
|
||||
return;
|
||||
}
|
||||
|
||||
jniIDs.mID_tiOnPreeditString =
|
||||
(*env)->GetMethodID(env, jniIDs.wlInputMethodClass, "zwp_text_input_v3_onPreeditString", "([BII)V");
|
||||
if (jniIDs.mID_tiOnPreeditString == NULL) {
|
||||
(*env)->DeleteGlobalRef(env, jniIDs.wlInputMethodClass);
|
||||
(void)memset(&jniIDs, 0, sizeof(jniIDs));
|
||||
return;
|
||||
}
|
||||
|
||||
jniIDs.mID_tiOnCommitString =
|
||||
(*env)->GetMethodID(env, jniIDs.wlInputMethodClass, "zwp_text_input_v3_onCommitString", "([B)V");
|
||||
if (jniIDs.mID_tiOnCommitString == NULL) {
|
||||
(*env)->DeleteGlobalRef(env, jniIDs.wlInputMethodClass);
|
||||
(void)memset(&jniIDs, 0, sizeof(jniIDs));
|
||||
return;
|
||||
}
|
||||
|
||||
jniIDs.mID_tiOnDeleteSurroundingText =
|
||||
(*env)->GetMethodID(env, jniIDs.wlInputMethodClass, "zwp_text_input_v3_onDeleteSurroundingText", "(JJ)V");
|
||||
if (jniIDs.mID_tiOnDeleteSurroundingText == NULL) {
|
||||
(*env)->DeleteGlobalRef(env, jniIDs.wlInputMethodClass);
|
||||
(void)memset(&jniIDs, 0, sizeof(jniIDs));
|
||||
return;
|
||||
}
|
||||
|
||||
jniIDs.mID_tiOnDone =
|
||||
(*env)->GetMethodID(env, jniIDs.wlInputMethodClass, "zwp_text_input_v3_onDone", "(J)V");
|
||||
if (jniIDs.mID_tiOnDone == NULL) {
|
||||
(*env)->DeleteGlobalRef(env, jniIDs.wlInputMethodClass);
|
||||
(void)memset(&jniIDs, 0, sizeof(jniIDs));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
JNIEXPORT jlong JNICALL
|
||||
Java_sun_awt_wl_im_text_1input_1unstable_1v3_WLInputMethodZwpTextInputV3_createNativeContext(JNIEnv * const env, const jobject self) {
|
||||
struct IMContext *result = NULL;
|
||||
|
||||
if (!checkIfTheImplementationIsAvailable()) {
|
||||
JNU_ThrowByName(env, "java/awt/AWTException", "sun.awt.wl.im.text_input_unstable_v3.WLInputMethodZwpTextInputV3 is not supported on this system");
|
||||
return 0;
|
||||
}
|
||||
|
||||
result = IMContext_Create(env, self);
|
||||
|
||||
return ptr_to_jlong(result);
|
||||
}
|
||||
|
||||
JNIEXPORT void JNICALL
|
||||
Java_sun_awt_wl_im_text_1input_1unstable_1v3_WLInputMethodZwpTextInputV3_disposeNativeContext(
|
||||
JNIEnv * const env,
|
||||
const jclass clazz,
|
||||
const jlong contextPtr
|
||||
) {
|
||||
struct IMContext *imContext = jlong_to_ptr(contextPtr);
|
||||
|
||||
if (imContext == NULL) {
|
||||
JNU_ThrowNullPointerException(env, "contextPtr");
|
||||
return;
|
||||
}
|
||||
|
||||
IMContext_Destroy(env, imContext);
|
||||
imContext = NULL;
|
||||
}
|
||||
|
||||
JNIEXPORT void JNICALL
|
||||
Java_sun_awt_wl_im_text_1input_1unstable_1v3_WLInputMethodZwpTextInputV3_zwp_1text_1input_1v3_1enable(
|
||||
JNIEnv * const env,
|
||||
const jobject self,
|
||||
const jlong contextPtr
|
||||
) {
|
||||
const struct IMContext * const imContext = jlong_to_ptr(contextPtr);
|
||||
struct zwp_text_input_v3 *textInput = NULL;
|
||||
|
||||
if (imContext == NULL) {
|
||||
JNU_ThrowNullPointerException(env, "contextPtr");
|
||||
return;
|
||||
}
|
||||
|
||||
textInput = imContext->textInput;
|
||||
if (textInput == NULL) {
|
||||
JNU_ThrowByName(env, "java/lang/IllegalStateException", "textInput == NULL");
|
||||
return;
|
||||
}
|
||||
|
||||
zwp_text_input_v3_enable(textInput);
|
||||
}
|
||||
|
||||
JNIEXPORT void JNICALL
|
||||
Java_sun_awt_wl_im_text_1input_1unstable_1v3_WLInputMethodZwpTextInputV3_zwp_1text_1input_1v3_1disable(
|
||||
JNIEnv * const env,
|
||||
const jobject self,
|
||||
const jlong contextPtr
|
||||
) {
|
||||
const struct IMContext * const imContext = jlong_to_ptr(contextPtr);
|
||||
struct zwp_text_input_v3 *textInput = NULL;
|
||||
|
||||
if (imContext == NULL) {
|
||||
JNU_ThrowNullPointerException(env, "contextPtr");
|
||||
return;
|
||||
}
|
||||
|
||||
textInput = imContext->textInput;
|
||||
if (textInput == NULL) {
|
||||
JNU_ThrowByName(env, "java/lang/IllegalStateException", "textInput == NULL");
|
||||
return;
|
||||
}
|
||||
|
||||
zwp_text_input_v3_disable(textInput);
|
||||
}
|
||||
|
||||
JNIEXPORT void JNICALL
|
||||
Java_sun_awt_wl_im_text_1input_1unstable_1v3_WLInputMethodZwpTextInputV3_zwp_1text_1input_1v3_1set_1cursor_1rectangle(
|
||||
JNIEnv * const env,
|
||||
const jobject self,
|
||||
const jlong contextPtr,
|
||||
const jint surfaceLocalX,
|
||||
const jint surfaceLocalY,
|
||||
const jint width,
|
||||
const jint height
|
||||
) {
|
||||
const struct IMContext * const imContext = jlong_to_ptr(contextPtr);
|
||||
struct zwp_text_input_v3 *textInput = NULL;
|
||||
|
||||
if (imContext == NULL) {
|
||||
JNU_ThrowNullPointerException(env, "contextPtr");
|
||||
return;
|
||||
}
|
||||
|
||||
textInput = imContext->textInput;
|
||||
if (textInput == NULL) {
|
||||
JNU_ThrowByName(env, "java/lang/IllegalStateException", "textInput == NULL");
|
||||
return;
|
||||
}
|
||||
|
||||
zwp_text_input_v3_set_cursor_rectangle(
|
||||
textInput,
|
||||
(int32_t)surfaceLocalX,
|
||||
(int32_t)surfaceLocalY,
|
||||
(int32_t)width,
|
||||
(int32_t)height
|
||||
);
|
||||
}
|
||||
|
||||
JNIEXPORT void JNICALL
|
||||
Java_sun_awt_wl_im_text_1input_1unstable_1v3_WLInputMethodZwpTextInputV3_zwp_1text_1input_1v3_1set_1content_1type(
|
||||
JNIEnv * const env,
|
||||
const jobject self,
|
||||
const jlong contextPtr,
|
||||
const jint hint,
|
||||
const jint purpose
|
||||
) {
|
||||
const struct IMContext * const imContext = jlong_to_ptr(contextPtr);
|
||||
struct zwp_text_input_v3 *textInput = NULL;
|
||||
|
||||
if (imContext == NULL) {
|
||||
JNU_ThrowNullPointerException(env, "contextPtr");
|
||||
return;
|
||||
}
|
||||
|
||||
textInput = imContext->textInput;
|
||||
if (textInput == NULL) {
|
||||
JNU_ThrowByName(env, "java/lang/IllegalStateException", "textInput == NULL");
|
||||
return;
|
||||
}
|
||||
|
||||
zwp_text_input_v3_set_content_type(textInput, (uint32_t)hint, (uint32_t)purpose);
|
||||
}
|
||||
|
||||
JNIEXPORT void JNICALL
|
||||
Java_sun_awt_wl_im_text_1input_1unstable_1v3_WLInputMethodZwpTextInputV3_zwp_1text_1input_1v3_1set_1text_1change_1cause(
|
||||
JNIEnv * const env,
|
||||
const jobject self,
|
||||
const jlong contextPtr,
|
||||
const jint changeCause
|
||||
) {
|
||||
const struct IMContext * const imContext = jlong_to_ptr(contextPtr);
|
||||
struct zwp_text_input_v3 *textInput = NULL;
|
||||
|
||||
if (imContext == NULL) {
|
||||
JNU_ThrowNullPointerException(env, "contextPtr");
|
||||
return;
|
||||
}
|
||||
|
||||
textInput = imContext->textInput;
|
||||
if (textInput == NULL) {
|
||||
JNU_ThrowByName(env, "java/lang/IllegalStateException", "textInput == NULL");
|
||||
return;
|
||||
}
|
||||
|
||||
zwp_text_input_v3_set_text_change_cause(textInput, (uint32_t)changeCause);
|
||||
}
|
||||
|
||||
JNIEXPORT void JNICALL
|
||||
Java_sun_awt_wl_im_text_1input_1unstable_1v3_WLInputMethodZwpTextInputV3_zwp_1text_1input_1v3_1commit(
|
||||
JNIEnv * const env,
|
||||
const jobject self,
|
||||
const jlong contextPtr
|
||||
) {
|
||||
const struct IMContext * const imContext = jlong_to_ptr(contextPtr);
|
||||
struct zwp_text_input_v3 *textInput = NULL;
|
||||
|
||||
if (imContext == NULL) {
|
||||
JNU_ThrowNullPointerException(env, "contextPtr");
|
||||
return;
|
||||
}
|
||||
|
||||
textInput = imContext->textInput;
|
||||
if (textInput == NULL) {
|
||||
JNU_ThrowByName(env, "java/lang/IllegalStateException", "textInput == NULL");
|
||||
return;
|
||||
}
|
||||
|
||||
zwp_text_input_v3_commit(textInput);
|
||||
}
|
||||
|
||||
// =========================================== END of JNI downcalls section ===========================================
|
||||
@@ -1,825 +0,0 @@
|
||||
/* Generated by wayland-scanner 1.19.0 */
|
||||
|
||||
#ifndef TEXT_INPUT_UNSTABLE_V3_CLIENT_PROTOCOL_H
|
||||
#define TEXT_INPUT_UNSTABLE_V3_CLIENT_PROTOCOL_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
#include "wayland-client.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @page page_text_input_unstable_v3 The text_input_unstable_v3 protocol
|
||||
* Protocol for composing text
|
||||
*
|
||||
* @section page_desc_text_input_unstable_v3 Description
|
||||
*
|
||||
* This protocol allows compositors to act as input methods and to send text
|
||||
* to applications. A text input object is used to manage state of what are
|
||||
* typically text entry fields in the application.
|
||||
*
|
||||
* This document adheres to the RFC 2119 when using words like "must",
|
||||
* "should", "may", etc.
|
||||
*
|
||||
* Warning! The protocol described in this file is experimental and
|
||||
* backward incompatible changes may be made. Backward compatible changes
|
||||
* may be added together with the corresponding interface version bump.
|
||||
* Backward incompatible changes are done by bumping the version number in
|
||||
* the protocol and interface names and resetting the interface version.
|
||||
* Once the protocol is to be declared stable, the 'z' prefix and the
|
||||
* version number in the protocol and interface names are removed and the
|
||||
* interface version number is reset.
|
||||
*
|
||||
* @section page_ifaces_text_input_unstable_v3 Interfaces
|
||||
* - @subpage page_iface_zwp_text_input_v3 - text input
|
||||
* - @subpage page_iface_zwp_text_input_manager_v3 - text input manager
|
||||
* @section page_copyright_text_input_unstable_v3 Copyright
|
||||
* <pre>
|
||||
*
|
||||
* Copyright © 2012, 2013 Intel Corporation
|
||||
* Copyright © 2015, 2016 Jan Arne Petersen
|
||||
* Copyright © 2017, 2018 Red Hat, Inc.
|
||||
* Copyright © 2018 Purism SPC
|
||||
*
|
||||
* Permission to use, copy, modify, distribute, and sell this
|
||||
* software and its documentation for any purpose is hereby granted
|
||||
* without fee, provided that the above copyright notice appear in
|
||||
* all copies and that both that copyright notice and this permission
|
||||
* notice appear in supporting documentation, and that the name of
|
||||
* the copyright holders not be used in advertising or publicity
|
||||
* pertaining to distribution of the software without specific,
|
||||
* written prior permission. The copyright holders make no
|
||||
* representations about the suitability of this software for any
|
||||
* purpose. It is provided "as is" without express or implied
|
||||
* warranty.
|
||||
*
|
||||
* THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
|
||||
* SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
||||
* FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||
* SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
|
||||
* AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
|
||||
* ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
|
||||
* THIS SOFTWARE.
|
||||
* </pre>
|
||||
*/
|
||||
struct wl_seat;
|
||||
struct wl_surface;
|
||||
struct zwp_text_input_manager_v3;
|
||||
struct zwp_text_input_v3;
|
||||
|
||||
#ifndef ZWP_TEXT_INPUT_V3_INTERFACE
|
||||
#define ZWP_TEXT_INPUT_V3_INTERFACE
|
||||
/**
|
||||
* @page page_iface_zwp_text_input_v3 zwp_text_input_v3
|
||||
* @section page_iface_zwp_text_input_v3_desc Description
|
||||
*
|
||||
* The zwp_text_input_v3 interface represents text input and input methods
|
||||
* associated with a seat. It provides enter/leave events to follow the
|
||||
* text input focus for a seat.
|
||||
*
|
||||
* Requests are used to enable/disable the text-input object and set
|
||||
* state information like surrounding and selected text or the content type.
|
||||
* The information about the entered text is sent to the text-input object
|
||||
* via the preedit_string and commit_string events.
|
||||
*
|
||||
* Text is valid UTF-8 encoded, indices and lengths are in bytes. Indices
|
||||
* must not point to middle bytes inside a code point: they must either
|
||||
* point to the first byte of a code point or to the end of the buffer.
|
||||
* Lengths must be measured between two valid indices.
|
||||
*
|
||||
* Focus moving throughout surfaces will result in the emission of
|
||||
* zwp_text_input_v3.enter and zwp_text_input_v3.leave events. The focused
|
||||
* surface must commit zwp_text_input_v3.enable and
|
||||
* zwp_text_input_v3.disable requests as the keyboard focus moves across
|
||||
* editable and non-editable elements of the UI. Those two requests are not
|
||||
* expected to be paired with each other, the compositor must be able to
|
||||
* handle consecutive series of the same request.
|
||||
*
|
||||
* State is sent by the state requests (set_surrounding_text,
|
||||
* set_content_type and set_cursor_rectangle) and a commit request. After an
|
||||
* enter event or disable request all state information is invalidated and
|
||||
* needs to be resent by the client.
|
||||
* @section page_iface_zwp_text_input_v3_api API
|
||||
* See @ref iface_zwp_text_input_v3.
|
||||
*/
|
||||
/**
|
||||
* @defgroup iface_zwp_text_input_v3 The zwp_text_input_v3 interface
|
||||
*
|
||||
* The zwp_text_input_v3 interface represents text input and input methods
|
||||
* associated with a seat. It provides enter/leave events to follow the
|
||||
* text input focus for a seat.
|
||||
*
|
||||
* Requests are used to enable/disable the text-input object and set
|
||||
* state information like surrounding and selected text or the content type.
|
||||
* The information about the entered text is sent to the text-input object
|
||||
* via the preedit_string and commit_string events.
|
||||
*
|
||||
* Text is valid UTF-8 encoded, indices and lengths are in bytes. Indices
|
||||
* must not point to middle bytes inside a code point: they must either
|
||||
* point to the first byte of a code point or to the end of the buffer.
|
||||
* Lengths must be measured between two valid indices.
|
||||
*
|
||||
* Focus moving throughout surfaces will result in the emission of
|
||||
* zwp_text_input_v3.enter and zwp_text_input_v3.leave events. The focused
|
||||
* surface must commit zwp_text_input_v3.enable and
|
||||
* zwp_text_input_v3.disable requests as the keyboard focus moves across
|
||||
* editable and non-editable elements of the UI. Those two requests are not
|
||||
* expected to be paired with each other, the compositor must be able to
|
||||
* handle consecutive series of the same request.
|
||||
*
|
||||
* State is sent by the state requests (set_surrounding_text,
|
||||
* set_content_type and set_cursor_rectangle) and a commit request. After an
|
||||
* enter event or disable request all state information is invalidated and
|
||||
* needs to be resent by the client.
|
||||
*/
|
||||
extern const struct wl_interface zwp_text_input_v3_interface;
|
||||
#endif
|
||||
#ifndef ZWP_TEXT_INPUT_MANAGER_V3_INTERFACE
|
||||
#define ZWP_TEXT_INPUT_MANAGER_V3_INTERFACE
|
||||
/**
|
||||
* @page page_iface_zwp_text_input_manager_v3 zwp_text_input_manager_v3
|
||||
* @section page_iface_zwp_text_input_manager_v3_desc Description
|
||||
*
|
||||
* A factory for text-input objects. This object is a global singleton.
|
||||
* @section page_iface_zwp_text_input_manager_v3_api API
|
||||
* See @ref iface_zwp_text_input_manager_v3.
|
||||
*/
|
||||
/**
|
||||
* @defgroup iface_zwp_text_input_manager_v3 The zwp_text_input_manager_v3 interface
|
||||
*
|
||||
* A factory for text-input objects. This object is a global singleton.
|
||||
*/
|
||||
extern const struct wl_interface zwp_text_input_manager_v3_interface;
|
||||
#endif
|
||||
|
||||
#ifndef ZWP_TEXT_INPUT_V3_CHANGE_CAUSE_ENUM
|
||||
#define ZWP_TEXT_INPUT_V3_CHANGE_CAUSE_ENUM
|
||||
/**
|
||||
* @ingroup iface_zwp_text_input_v3
|
||||
* text change reason
|
||||
*
|
||||
* Reason for the change of surrounding text or cursor posision.
|
||||
*/
|
||||
enum zwp_text_input_v3_change_cause {
|
||||
/**
|
||||
* input method caused the change
|
||||
*/
|
||||
ZWP_TEXT_INPUT_V3_CHANGE_CAUSE_INPUT_METHOD = 0,
|
||||
/**
|
||||
* something else than the input method caused the change
|
||||
*/
|
||||
ZWP_TEXT_INPUT_V3_CHANGE_CAUSE_OTHER = 1,
|
||||
};
|
||||
#endif /* ZWP_TEXT_INPUT_V3_CHANGE_CAUSE_ENUM */
|
||||
|
||||
#ifndef ZWP_TEXT_INPUT_V3_CONTENT_HINT_ENUM
|
||||
#define ZWP_TEXT_INPUT_V3_CONTENT_HINT_ENUM
|
||||
/**
|
||||
* @ingroup iface_zwp_text_input_v3
|
||||
* content hint
|
||||
*
|
||||
* Content hint is a bitmask to allow to modify the behavior of the text
|
||||
* input.
|
||||
*/
|
||||
enum zwp_text_input_v3_content_hint {
|
||||
/**
|
||||
* no special behavior
|
||||
*/
|
||||
ZWP_TEXT_INPUT_V3_CONTENT_HINT_NONE = 0x0,
|
||||
/**
|
||||
* suggest word completions
|
||||
*/
|
||||
ZWP_TEXT_INPUT_V3_CONTENT_HINT_COMPLETION = 0x1,
|
||||
/**
|
||||
* suggest word corrections
|
||||
*/
|
||||
ZWP_TEXT_INPUT_V3_CONTENT_HINT_SPELLCHECK = 0x2,
|
||||
/**
|
||||
* switch to uppercase letters at the start of a sentence
|
||||
*/
|
||||
ZWP_TEXT_INPUT_V3_CONTENT_HINT_AUTO_CAPITALIZATION = 0x4,
|
||||
/**
|
||||
* prefer lowercase letters
|
||||
*/
|
||||
ZWP_TEXT_INPUT_V3_CONTENT_HINT_LOWERCASE = 0x8,
|
||||
/**
|
||||
* prefer uppercase letters
|
||||
*/
|
||||
ZWP_TEXT_INPUT_V3_CONTENT_HINT_UPPERCASE = 0x10,
|
||||
/**
|
||||
* prefer casing for titles and headings (can be language dependent)
|
||||
*/
|
||||
ZWP_TEXT_INPUT_V3_CONTENT_HINT_TITLECASE = 0x20,
|
||||
/**
|
||||
* characters should be hidden
|
||||
*/
|
||||
ZWP_TEXT_INPUT_V3_CONTENT_HINT_HIDDEN_TEXT = 0x40,
|
||||
/**
|
||||
* typed text should not be stored
|
||||
*/
|
||||
ZWP_TEXT_INPUT_V3_CONTENT_HINT_SENSITIVE_DATA = 0x80,
|
||||
/**
|
||||
* just Latin characters should be entered
|
||||
*/
|
||||
ZWP_TEXT_INPUT_V3_CONTENT_HINT_LATIN = 0x100,
|
||||
/**
|
||||
* the text input is multiline
|
||||
*/
|
||||
ZWP_TEXT_INPUT_V3_CONTENT_HINT_MULTILINE = 0x200,
|
||||
};
|
||||
#endif /* ZWP_TEXT_INPUT_V3_CONTENT_HINT_ENUM */
|
||||
|
||||
#ifndef ZWP_TEXT_INPUT_V3_CONTENT_PURPOSE_ENUM
|
||||
#define ZWP_TEXT_INPUT_V3_CONTENT_PURPOSE_ENUM
|
||||
/**
|
||||
* @ingroup iface_zwp_text_input_v3
|
||||
* content purpose
|
||||
*
|
||||
* The content purpose allows to specify the primary purpose of a text
|
||||
* input.
|
||||
*
|
||||
* This allows an input method to show special purpose input panels with
|
||||
* extra characters or to disallow some characters.
|
||||
*/
|
||||
enum zwp_text_input_v3_content_purpose {
|
||||
/**
|
||||
* default input, allowing all characters
|
||||
*/
|
||||
ZWP_TEXT_INPUT_V3_CONTENT_PURPOSE_NORMAL = 0,
|
||||
/**
|
||||
* allow only alphabetic characters
|
||||
*/
|
||||
ZWP_TEXT_INPUT_V3_CONTENT_PURPOSE_ALPHA = 1,
|
||||
/**
|
||||
* allow only digits
|
||||
*/
|
||||
ZWP_TEXT_INPUT_V3_CONTENT_PURPOSE_DIGITS = 2,
|
||||
/**
|
||||
* input a number (including decimal separator and sign)
|
||||
*/
|
||||
ZWP_TEXT_INPUT_V3_CONTENT_PURPOSE_NUMBER = 3,
|
||||
/**
|
||||
* input a phone number
|
||||
*/
|
||||
ZWP_TEXT_INPUT_V3_CONTENT_PURPOSE_PHONE = 4,
|
||||
/**
|
||||
* input an URL
|
||||
*/
|
||||
ZWP_TEXT_INPUT_V3_CONTENT_PURPOSE_URL = 5,
|
||||
/**
|
||||
* input an email address
|
||||
*/
|
||||
ZWP_TEXT_INPUT_V3_CONTENT_PURPOSE_EMAIL = 6,
|
||||
/**
|
||||
* input a name of a person
|
||||
*/
|
||||
ZWP_TEXT_INPUT_V3_CONTENT_PURPOSE_NAME = 7,
|
||||
/**
|
||||
* input a password (combine with sensitive_data hint)
|
||||
*/
|
||||
ZWP_TEXT_INPUT_V3_CONTENT_PURPOSE_PASSWORD = 8,
|
||||
/**
|
||||
* input is a numeric password (combine with sensitive_data hint)
|
||||
*/
|
||||
ZWP_TEXT_INPUT_V3_CONTENT_PURPOSE_PIN = 9,
|
||||
/**
|
||||
* input a date
|
||||
*/
|
||||
ZWP_TEXT_INPUT_V3_CONTENT_PURPOSE_DATE = 10,
|
||||
/**
|
||||
* input a time
|
||||
*/
|
||||
ZWP_TEXT_INPUT_V3_CONTENT_PURPOSE_TIME = 11,
|
||||
/**
|
||||
* input a date and time
|
||||
*/
|
||||
ZWP_TEXT_INPUT_V3_CONTENT_PURPOSE_DATETIME = 12,
|
||||
/**
|
||||
* input for a terminal
|
||||
*/
|
||||
ZWP_TEXT_INPUT_V3_CONTENT_PURPOSE_TERMINAL = 13,
|
||||
};
|
||||
#endif /* ZWP_TEXT_INPUT_V3_CONTENT_PURPOSE_ENUM */
|
||||
|
||||
/**
|
||||
* @ingroup iface_zwp_text_input_v3
|
||||
* @struct zwp_text_input_v3_listener
|
||||
*/
|
||||
struct zwp_text_input_v3_listener {
|
||||
/**
|
||||
* enter event
|
||||
*
|
||||
* Notification that this seat's text-input focus is on a certain
|
||||
* surface.
|
||||
*
|
||||
* When the seat has the keyboard capability the text-input focus
|
||||
* follows the keyboard focus. This event sets the current surface
|
||||
* for the text-input object.
|
||||
*/
|
||||
void (*enter)(void *data,
|
||||
struct zwp_text_input_v3 *zwp_text_input_v3,
|
||||
struct wl_surface *surface);
|
||||
/**
|
||||
* leave event
|
||||
*
|
||||
* Notification that this seat's text-input focus is no longer on
|
||||
* a certain surface. The client should reset any preedit string
|
||||
* previously set.
|
||||
*
|
||||
* The leave notification clears the current surface. It is sent
|
||||
* before the enter notification for the new focus.
|
||||
*
|
||||
* When the seat has the keyboard capability the text-input focus
|
||||
* follows the keyboard focus.
|
||||
*/
|
||||
void (*leave)(void *data,
|
||||
struct zwp_text_input_v3 *zwp_text_input_v3,
|
||||
struct wl_surface *surface);
|
||||
/**
|
||||
* pre-edit
|
||||
*
|
||||
* Notify when a new composing text (pre-edit) should be set at
|
||||
* the current cursor position. Any previously set composing text
|
||||
* must be removed. Any previously existing selected text must be
|
||||
* removed.
|
||||
*
|
||||
* The argument text contains the pre-edit string buffer.
|
||||
*
|
||||
* The parameters cursor_begin and cursor_end are counted in bytes
|
||||
* relative to the beginning of the submitted text buffer. Cursor
|
||||
* should be hidden when both are equal to -1.
|
||||
*
|
||||
* They could be represented by the client as a line if both values
|
||||
* are the same, or as a text highlight otherwise.
|
||||
*
|
||||
* Values set with this event are double-buffered. They must be
|
||||
* applied and reset to initial on the next zwp_text_input_v3.done
|
||||
* event.
|
||||
*
|
||||
* The initial value of text is an empty string, and cursor_begin,
|
||||
* cursor_end and cursor_hidden are all 0.
|
||||
*/
|
||||
void (*preedit_string)(void *data,
|
||||
struct zwp_text_input_v3 *zwp_text_input_v3,
|
||||
const char *text,
|
||||
int32_t cursor_begin,
|
||||
int32_t cursor_end);
|
||||
/**
|
||||
* text commit
|
||||
*
|
||||
* Notify when text should be inserted into the editor widget.
|
||||
* The text to commit could be either just a single character after
|
||||
* a key press or the result of some composing (pre-edit).
|
||||
*
|
||||
* Values set with this event are double-buffered. They must be
|
||||
* applied and reset to initial on the next zwp_text_input_v3.done
|
||||
* event.
|
||||
*
|
||||
* The initial value of text is an empty string.
|
||||
*/
|
||||
void (*commit_string)(void *data,
|
||||
struct zwp_text_input_v3 *zwp_text_input_v3,
|
||||
const char *text);
|
||||
/**
|
||||
* delete surrounding text
|
||||
*
|
||||
* Notify when the text around the current cursor position should
|
||||
* be deleted.
|
||||
*
|
||||
* Before_length and after_length are the number of bytes before
|
||||
* and after the current cursor index (excluding the selection) to
|
||||
* delete.
|
||||
*
|
||||
* If a preedit text is present, in effect before_length is counted
|
||||
* from the beginning of it, and after_length from its end (see
|
||||
* done event sequence).
|
||||
*
|
||||
* Values set with this event are double-buffered. They must be
|
||||
* applied and reset to initial on the next zwp_text_input_v3.done
|
||||
* event.
|
||||
*
|
||||
* The initial values of both before_length and after_length are 0.
|
||||
* @param before_length length of text before current cursor position
|
||||
* @param after_length length of text after current cursor position
|
||||
*/
|
||||
void (*delete_surrounding_text)(void *data,
|
||||
struct zwp_text_input_v3 *zwp_text_input_v3,
|
||||
uint32_t before_length,
|
||||
uint32_t after_length);
|
||||
/**
|
||||
* apply changes
|
||||
*
|
||||
* Instruct the application to apply changes to state requested
|
||||
* by the preedit_string, commit_string and delete_surrounding_text
|
||||
* events. The state relating to these events is double-buffered,
|
||||
* and each one modifies the pending state. This event replaces the
|
||||
* current state with the pending state.
|
||||
*
|
||||
* The application must proceed by evaluating the changes in the
|
||||
* following order:
|
||||
*
|
||||
* 1. Replace existing preedit string with the cursor. 2. Delete
|
||||
* requested surrounding text. 3. Insert commit string with the
|
||||
* cursor at its end. 4. Calculate surrounding text to send. 5.
|
||||
* Insert new preedit text in cursor position. 6. Place cursor
|
||||
* inside preedit text.
|
||||
*
|
||||
* The serial number reflects the last state of the
|
||||
* zwp_text_input_v3 object known to the compositor. The value of
|
||||
* the serial argument must be equal to the number of commit
|
||||
* requests already issued on that object. When the client receives
|
||||
* a done event with a serial different than the number of past
|
||||
* commit requests, it must proceed as normal, except it should not
|
||||
* change the current state of the zwp_text_input_v3 object.
|
||||
*/
|
||||
void (*done)(void *data,
|
||||
struct zwp_text_input_v3 *zwp_text_input_v3,
|
||||
uint32_t serial);
|
||||
};
|
||||
|
||||
/**
|
||||
* @ingroup iface_zwp_text_input_v3
|
||||
*/
|
||||
static inline int
|
||||
zwp_text_input_v3_add_listener(struct zwp_text_input_v3 *zwp_text_input_v3,
|
||||
const struct zwp_text_input_v3_listener *listener, void *data)
|
||||
{
|
||||
return wl_proxy_add_listener((struct wl_proxy *) zwp_text_input_v3,
|
||||
(void (**)(void)) listener, data);
|
||||
}
|
||||
|
||||
#define ZWP_TEXT_INPUT_V3_DESTROY 0
|
||||
#define ZWP_TEXT_INPUT_V3_ENABLE 1
|
||||
#define ZWP_TEXT_INPUT_V3_DISABLE 2
|
||||
#define ZWP_TEXT_INPUT_V3_SET_SURROUNDING_TEXT 3
|
||||
#define ZWP_TEXT_INPUT_V3_SET_TEXT_CHANGE_CAUSE 4
|
||||
#define ZWP_TEXT_INPUT_V3_SET_CONTENT_TYPE 5
|
||||
#define ZWP_TEXT_INPUT_V3_SET_CURSOR_RECTANGLE 6
|
||||
#define ZWP_TEXT_INPUT_V3_COMMIT 7
|
||||
|
||||
/**
|
||||
* @ingroup iface_zwp_text_input_v3
|
||||
*/
|
||||
#define ZWP_TEXT_INPUT_V3_ENTER_SINCE_VERSION 1
|
||||
/**
|
||||
* @ingroup iface_zwp_text_input_v3
|
||||
*/
|
||||
#define ZWP_TEXT_INPUT_V3_LEAVE_SINCE_VERSION 1
|
||||
/**
|
||||
* @ingroup iface_zwp_text_input_v3
|
||||
*/
|
||||
#define ZWP_TEXT_INPUT_V3_PREEDIT_STRING_SINCE_VERSION 1
|
||||
/**
|
||||
* @ingroup iface_zwp_text_input_v3
|
||||
*/
|
||||
#define ZWP_TEXT_INPUT_V3_COMMIT_STRING_SINCE_VERSION 1
|
||||
/**
|
||||
* @ingroup iface_zwp_text_input_v3
|
||||
*/
|
||||
#define ZWP_TEXT_INPUT_V3_DELETE_SURROUNDING_TEXT_SINCE_VERSION 1
|
||||
/**
|
||||
* @ingroup iface_zwp_text_input_v3
|
||||
*/
|
||||
#define ZWP_TEXT_INPUT_V3_DONE_SINCE_VERSION 1
|
||||
|
||||
/**
|
||||
* @ingroup iface_zwp_text_input_v3
|
||||
*/
|
||||
#define ZWP_TEXT_INPUT_V3_DESTROY_SINCE_VERSION 1
|
||||
/**
|
||||
* @ingroup iface_zwp_text_input_v3
|
||||
*/
|
||||
#define ZWP_TEXT_INPUT_V3_ENABLE_SINCE_VERSION 1
|
||||
/**
|
||||
* @ingroup iface_zwp_text_input_v3
|
||||
*/
|
||||
#define ZWP_TEXT_INPUT_V3_DISABLE_SINCE_VERSION 1
|
||||
/**
|
||||
* @ingroup iface_zwp_text_input_v3
|
||||
*/
|
||||
#define ZWP_TEXT_INPUT_V3_SET_SURROUNDING_TEXT_SINCE_VERSION 1
|
||||
/**
|
||||
* @ingroup iface_zwp_text_input_v3
|
||||
*/
|
||||
#define ZWP_TEXT_INPUT_V3_SET_TEXT_CHANGE_CAUSE_SINCE_VERSION 1
|
||||
/**
|
||||
* @ingroup iface_zwp_text_input_v3
|
||||
*/
|
||||
#define ZWP_TEXT_INPUT_V3_SET_CONTENT_TYPE_SINCE_VERSION 1
|
||||
/**
|
||||
* @ingroup iface_zwp_text_input_v3
|
||||
*/
|
||||
#define ZWP_TEXT_INPUT_V3_SET_CURSOR_RECTANGLE_SINCE_VERSION 1
|
||||
/**
|
||||
* @ingroup iface_zwp_text_input_v3
|
||||
*/
|
||||
#define ZWP_TEXT_INPUT_V3_COMMIT_SINCE_VERSION 1
|
||||
|
||||
/** @ingroup iface_zwp_text_input_v3 */
|
||||
static inline void
|
||||
zwp_text_input_v3_set_user_data(struct zwp_text_input_v3 *zwp_text_input_v3, void *user_data)
|
||||
{
|
||||
wl_proxy_set_user_data((struct wl_proxy *) zwp_text_input_v3, user_data);
|
||||
}
|
||||
|
||||
/** @ingroup iface_zwp_text_input_v3 */
|
||||
static inline void *
|
||||
zwp_text_input_v3_get_user_data(struct zwp_text_input_v3 *zwp_text_input_v3)
|
||||
{
|
||||
return wl_proxy_get_user_data((struct wl_proxy *) zwp_text_input_v3);
|
||||
}
|
||||
|
||||
static inline uint32_t
|
||||
zwp_text_input_v3_get_version(struct zwp_text_input_v3 *zwp_text_input_v3)
|
||||
{
|
||||
return wl_proxy_get_version((struct wl_proxy *) zwp_text_input_v3);
|
||||
}
|
||||
|
||||
/**
|
||||
* @ingroup iface_zwp_text_input_v3
|
||||
*
|
||||
* Destroy the wp_text_input object. Also disables all surfaces enabled
|
||||
* through this wp_text_input object.
|
||||
*/
|
||||
static inline void
|
||||
zwp_text_input_v3_destroy(struct zwp_text_input_v3 *zwp_text_input_v3)
|
||||
{
|
||||
wl_proxy_marshal((struct wl_proxy *) zwp_text_input_v3,
|
||||
ZWP_TEXT_INPUT_V3_DESTROY);
|
||||
|
||||
wl_proxy_destroy((struct wl_proxy *) zwp_text_input_v3);
|
||||
}
|
||||
|
||||
/**
|
||||
* @ingroup iface_zwp_text_input_v3
|
||||
*
|
||||
* Requests text input on the surface previously obtained from the enter
|
||||
* event.
|
||||
*
|
||||
* This request must be issued every time the active text input changes
|
||||
* to a new one, including within the current surface. Use
|
||||
* zwp_text_input_v3.disable when there is no longer any input focus on
|
||||
* the current surface.
|
||||
*
|
||||
* This request resets all state associated with previous enable, disable,
|
||||
* set_surrounding_text, set_text_change_cause, set_content_type, and
|
||||
* set_cursor_rectangle requests, as well as the state associated with
|
||||
* preedit_string, commit_string, and delete_surrounding_text events.
|
||||
*
|
||||
* The set_surrounding_text, set_content_type and set_cursor_rectangle
|
||||
* requests must follow if the text input supports the necessary
|
||||
* functionality.
|
||||
*
|
||||
* State set with this request is double-buffered. It will get applied on
|
||||
* the next zwp_text_input_v3.commit request, and stay valid until the
|
||||
* next committed enable or disable request.
|
||||
*
|
||||
* The changes must be applied by the compositor after issuing a
|
||||
* zwp_text_input_v3.commit request.
|
||||
*/
|
||||
static inline void
|
||||
zwp_text_input_v3_enable(struct zwp_text_input_v3 *zwp_text_input_v3)
|
||||
{
|
||||
wl_proxy_marshal((struct wl_proxy *) zwp_text_input_v3,
|
||||
ZWP_TEXT_INPUT_V3_ENABLE);
|
||||
}
|
||||
|
||||
/**
|
||||
* @ingroup iface_zwp_text_input_v3
|
||||
*
|
||||
* Explicitly disable text input on the current surface (typically when
|
||||
* there is no focus on any text entry inside the surface).
|
||||
*
|
||||
* State set with this request is double-buffered. It will get applied on
|
||||
* the next zwp_text_input_v3.commit request.
|
||||
*/
|
||||
static inline void
|
||||
zwp_text_input_v3_disable(struct zwp_text_input_v3 *zwp_text_input_v3)
|
||||
{
|
||||
wl_proxy_marshal((struct wl_proxy *) zwp_text_input_v3,
|
||||
ZWP_TEXT_INPUT_V3_DISABLE);
|
||||
}
|
||||
|
||||
/**
|
||||
* @ingroup iface_zwp_text_input_v3
|
||||
*
|
||||
* Sets the surrounding plain text around the input, excluding the preedit
|
||||
* text.
|
||||
*
|
||||
* The client should notify the compositor of any changes in any of the
|
||||
* values carried with this request, including changes caused by handling
|
||||
* incoming text-input events as well as changes caused by other
|
||||
* mechanisms like keyboard typing.
|
||||
*
|
||||
* If the client is unaware of the text around the cursor, it should not
|
||||
* issue this request, to signify lack of support to the compositor.
|
||||
*
|
||||
* Text is UTF-8 encoded, and should include the cursor position, the
|
||||
* complete selection and additional characters before and after them.
|
||||
* There is a maximum length of wayland messages, so text can not be
|
||||
* longer than 4000 bytes.
|
||||
*
|
||||
* Cursor is the byte offset of the cursor within text buffer.
|
||||
*
|
||||
* Anchor is the byte offset of the selection anchor within text buffer.
|
||||
* If there is no selected text, anchor is the same as cursor.
|
||||
*
|
||||
* If any preedit text is present, it is replaced with a cursor for the
|
||||
* purpose of this event.
|
||||
*
|
||||
* Values set with this request are double-buffered. They will get applied
|
||||
* on the next zwp_text_input_v3.commit request, and stay valid until the
|
||||
* next committed enable or disable request.
|
||||
*
|
||||
* The initial state for affected fields is empty, meaning that the text
|
||||
* input does not support sending surrounding text. If the empty values
|
||||
* get applied, subsequent attempts to change them may have no effect.
|
||||
*/
|
||||
static inline void
|
||||
zwp_text_input_v3_set_surrounding_text(struct zwp_text_input_v3 *zwp_text_input_v3, const char *text, int32_t cursor, int32_t anchor)
|
||||
{
|
||||
wl_proxy_marshal((struct wl_proxy *) zwp_text_input_v3,
|
||||
ZWP_TEXT_INPUT_V3_SET_SURROUNDING_TEXT, text, cursor, anchor);
|
||||
}
|
||||
|
||||
/**
|
||||
* @ingroup iface_zwp_text_input_v3
|
||||
*
|
||||
* Tells the compositor why the text surrounding the cursor changed.
|
||||
*
|
||||
* Whenever the client detects an external change in text, cursor, or
|
||||
* anchor posision, it must issue this request to the compositor. This
|
||||
* request is intended to give the input method a chance to update the
|
||||
* preedit text in an appropriate way, e.g. by removing it when the user
|
||||
* starts typing with a keyboard.
|
||||
*
|
||||
* cause describes the source of the change.
|
||||
*
|
||||
* The value set with this request is double-buffered. It must be applied
|
||||
* and reset to initial at the next zwp_text_input_v3.commit request.
|
||||
*
|
||||
* The initial value of cause is input_method.
|
||||
*/
|
||||
static inline void
|
||||
zwp_text_input_v3_set_text_change_cause(struct zwp_text_input_v3 *zwp_text_input_v3, uint32_t cause)
|
||||
{
|
||||
wl_proxy_marshal((struct wl_proxy *) zwp_text_input_v3,
|
||||
ZWP_TEXT_INPUT_V3_SET_TEXT_CHANGE_CAUSE, cause);
|
||||
}
|
||||
|
||||
/**
|
||||
* @ingroup iface_zwp_text_input_v3
|
||||
*
|
||||
* Sets the content purpose and content hint. While the purpose is the
|
||||
* basic purpose of an input field, the hint flags allow to modify some of
|
||||
* the behavior.
|
||||
*
|
||||
* Values set with this request are double-buffered. They will get applied
|
||||
* on the next zwp_text_input_v3.commit request.
|
||||
* Subsequent attempts to update them may have no effect. The values
|
||||
* remain valid until the next committed enable or disable request.
|
||||
*
|
||||
* The initial value for hint is none, and the initial value for purpose
|
||||
* is normal.
|
||||
*/
|
||||
static inline void
|
||||
zwp_text_input_v3_set_content_type(struct zwp_text_input_v3 *zwp_text_input_v3, uint32_t hint, uint32_t purpose)
|
||||
{
|
||||
wl_proxy_marshal((struct wl_proxy *) zwp_text_input_v3,
|
||||
ZWP_TEXT_INPUT_V3_SET_CONTENT_TYPE, hint, purpose);
|
||||
}
|
||||
|
||||
/**
|
||||
* @ingroup iface_zwp_text_input_v3
|
||||
*
|
||||
* Marks an area around the cursor as a x, y, width, height rectangle in
|
||||
* surface local coordinates.
|
||||
*
|
||||
* Allows the compositor to put a window with word suggestions near the
|
||||
* cursor, without obstructing the text being input.
|
||||
*
|
||||
* If the client is unaware of the position of edited text, it should not
|
||||
* issue this request, to signify lack of support to the compositor.
|
||||
*
|
||||
* Values set with this request are double-buffered. They will get applied
|
||||
* on the next zwp_text_input_v3.commit request, and stay valid until the
|
||||
* next committed enable or disable request.
|
||||
*
|
||||
* The initial values describing a cursor rectangle are empty. That means
|
||||
* the text input does not support describing the cursor area. If the
|
||||
* empty values get applied, subsequent attempts to change them may have
|
||||
* no effect.
|
||||
*/
|
||||
static inline void
|
||||
zwp_text_input_v3_set_cursor_rectangle(struct zwp_text_input_v3 *zwp_text_input_v3, int32_t x, int32_t y, int32_t width, int32_t height)
|
||||
{
|
||||
wl_proxy_marshal((struct wl_proxy *) zwp_text_input_v3,
|
||||
ZWP_TEXT_INPUT_V3_SET_CURSOR_RECTANGLE, x, y, width, height);
|
||||
}
|
||||
|
||||
/**
|
||||
* @ingroup iface_zwp_text_input_v3
|
||||
*
|
||||
* Atomically applies state changes recently sent to the compositor.
|
||||
*
|
||||
* The commit request establishes and updates the state of the client, and
|
||||
* must be issued after any changes to apply them.
|
||||
*
|
||||
* Text input state (enabled status, content purpose, content hint,
|
||||
* surrounding text and change cause, cursor rectangle) is conceptually
|
||||
* double-buffered within the context of a text input, i.e. between a
|
||||
* committed enable request and the following committed enable or disable
|
||||
* request.
|
||||
*
|
||||
* Protocol requests modify the pending state, as opposed to the current
|
||||
* state in use by the input method. A commit request atomically applies
|
||||
* all pending state, replacing the current state. After commit, the new
|
||||
* pending state is as documented for each related request.
|
||||
*
|
||||
* Requests are applied in the order of arrival.
|
||||
*
|
||||
* Neither current nor pending state are modified unless noted otherwise.
|
||||
*
|
||||
* The compositor must count the number of commit requests coming from
|
||||
* each zwp_text_input_v3 object and use the count as the serial in done
|
||||
* events.
|
||||
*/
|
||||
static inline void
|
||||
zwp_text_input_v3_commit(struct zwp_text_input_v3 *zwp_text_input_v3)
|
||||
{
|
||||
wl_proxy_marshal((struct wl_proxy *) zwp_text_input_v3,
|
||||
ZWP_TEXT_INPUT_V3_COMMIT);
|
||||
}
|
||||
|
||||
#define ZWP_TEXT_INPUT_MANAGER_V3_DESTROY 0
|
||||
#define ZWP_TEXT_INPUT_MANAGER_V3_GET_TEXT_INPUT 1
|
||||
|
||||
|
||||
/**
|
||||
* @ingroup iface_zwp_text_input_manager_v3
|
||||
*/
|
||||
#define ZWP_TEXT_INPUT_MANAGER_V3_DESTROY_SINCE_VERSION 1
|
||||
/**
|
||||
* @ingroup iface_zwp_text_input_manager_v3
|
||||
*/
|
||||
#define ZWP_TEXT_INPUT_MANAGER_V3_GET_TEXT_INPUT_SINCE_VERSION 1
|
||||
|
||||
/** @ingroup iface_zwp_text_input_manager_v3 */
|
||||
static inline void
|
||||
zwp_text_input_manager_v3_set_user_data(struct zwp_text_input_manager_v3 *zwp_text_input_manager_v3, void *user_data)
|
||||
{
|
||||
wl_proxy_set_user_data((struct wl_proxy *) zwp_text_input_manager_v3, user_data);
|
||||
}
|
||||
|
||||
/** @ingroup iface_zwp_text_input_manager_v3 */
|
||||
static inline void *
|
||||
zwp_text_input_manager_v3_get_user_data(struct zwp_text_input_manager_v3 *zwp_text_input_manager_v3)
|
||||
{
|
||||
return wl_proxy_get_user_data((struct wl_proxy *) zwp_text_input_manager_v3);
|
||||
}
|
||||
|
||||
static inline uint32_t
|
||||
zwp_text_input_manager_v3_get_version(struct zwp_text_input_manager_v3 *zwp_text_input_manager_v3)
|
||||
{
|
||||
return wl_proxy_get_version((struct wl_proxy *) zwp_text_input_manager_v3);
|
||||
}
|
||||
|
||||
/**
|
||||
* @ingroup iface_zwp_text_input_manager_v3
|
||||
*
|
||||
* Destroy the wp_text_input_manager object.
|
||||
*/
|
||||
static inline void
|
||||
zwp_text_input_manager_v3_destroy(struct zwp_text_input_manager_v3 *zwp_text_input_manager_v3)
|
||||
{
|
||||
wl_proxy_marshal((struct wl_proxy *) zwp_text_input_manager_v3,
|
||||
ZWP_TEXT_INPUT_MANAGER_V3_DESTROY);
|
||||
|
||||
wl_proxy_destroy((struct wl_proxy *) zwp_text_input_manager_v3);
|
||||
}
|
||||
|
||||
/**
|
||||
* @ingroup iface_zwp_text_input_manager_v3
|
||||
*
|
||||
* Creates a new text-input object for a given seat.
|
||||
*/
|
||||
static inline struct zwp_text_input_v3 *
|
||||
zwp_text_input_manager_v3_get_text_input(struct zwp_text_input_manager_v3 *zwp_text_input_manager_v3, struct wl_seat *seat)
|
||||
{
|
||||
struct wl_proxy *id;
|
||||
|
||||
id = wl_proxy_marshal_constructor((struct wl_proxy *) zwp_text_input_manager_v3,
|
||||
ZWP_TEXT_INPUT_MANAGER_V3_GET_TEXT_INPUT, &zwp_text_input_v3_interface, NULL, seat);
|
||||
|
||||
return (struct zwp_text_input_v3 *) id;
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user