mirror of
https://github.com/JetBrains/JetBrainsRuntime.git
synced 2025-12-06 01:19:28 +01:00
JBR-9483 Wayland: Support toplevel icons
This patch implements support for the xdg_toplevel_icon_v1 protocol. The image choosing logic is just to pick the largest square image for now. The image scale factor is also not set, since it's unclear if it's needed and how it interacts with multi-monitor setups. NOTE: this patch introduces a dependency on wayland-protocols 1.37+.
This commit is contained in:
@@ -33,6 +33,7 @@ WAYLAND_BASIC_PROTOCOL_FILES := \
|
||||
$(WAYLAND_PROTOCOLS_ROOT)/stable/viewporter/viewporter.xml \
|
||||
$(WAYLAND_PROTOCOLS_ROOT)/stable/xdg-shell/xdg-shell.xml \
|
||||
$(WAYLAND_PROTOCOLS_ROOT)/staging/xdg-activation/xdg-activation-v1.xml \
|
||||
$(WAYLAND_PROTOCOLS_ROOT)/staging/xdg-toplevel-icon/xdg-toplevel-icon-v1.xml \
|
||||
$(WAYLAND_PROTOCOLS_ROOT)/unstable/primary-selection/primary-selection-unstable-v1.xml \
|
||||
$(WAYLAND_PROTOCOLS_ROOT)/unstable/xdg-output/xdg-output-unstable-v1.xml \
|
||||
$(WAYLAND_PROTOCOLS_ROOT)/unstable/relative-pointer/relative-pointer-unstable-v1.xml \
|
||||
|
||||
@@ -899,6 +899,10 @@ public class WLComponentPeer implements ComponentPeer, WLSurfaceSizeListener {
|
||||
performLocked(() -> nativeShowWindowMenu(serial, nativePtr, xNative, yNative));
|
||||
}
|
||||
|
||||
void setIcon(int size, int[] pixels) {
|
||||
performLocked(() -> nativeSetIcon(nativePtr, size, pixels));
|
||||
}
|
||||
|
||||
@Override
|
||||
public ColorModel getColorModel() {
|
||||
GraphicsConfiguration graphicsConfig = target.getGraphicsConfiguration();
|
||||
@@ -1167,6 +1171,7 @@ public class WLComponentPeer implements ComponentPeer, WLSurfaceSizeListener {
|
||||
private native void nativeSetMinimumSize(long ptr, int width, int height);
|
||||
private native void nativeSetMaximumSize(long ptr, int width, int height);
|
||||
private native void nativeShowWindowMenu(long serial, long ptr, int x, int y);
|
||||
private native void nativeSetIcon(long ptr, int size, int[] pixels);
|
||||
|
||||
static long getNativePtrFor(Component component) {
|
||||
final ComponentAccessor acc = AWTAccessor.getComponentAccessor();
|
||||
|
||||
@@ -84,6 +84,7 @@ import java.awt.peer.WindowPeer;
|
||||
import java.security.AccessController;
|
||||
import java.security.PrivilegedAction;
|
||||
import java.util.Arrays;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
@@ -142,6 +143,11 @@ public class WLToolkit extends UNIXToolkit implements Runnable {
|
||||
|
||||
private static final boolean isKDE;
|
||||
|
||||
// NOTE: xdg_toplevel_icon_v1 is pretty much only supported on KDE, and KWin always sends 96px as the icon size,
|
||||
// regardless of the display resolution, scale, or anything else.
|
||||
// TODO: this is currently unused
|
||||
private static final java.util.List<Integer> preferredIconSizes = new ArrayList<>();
|
||||
|
||||
private static native void initIDs(long displayPtr);
|
||||
|
||||
static {
|
||||
@@ -1120,4 +1126,9 @@ public class WLToolkit extends UNIXToolkit implements Runnable {
|
||||
public static boolean isKDE() {
|
||||
return isKDE;
|
||||
}
|
||||
|
||||
// called from native
|
||||
private static void handleToplevelIconSize(int size) {
|
||||
preferredIconSizes.add(size);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -39,7 +39,9 @@ import java.awt.Color;
|
||||
import java.awt.Component;
|
||||
import java.awt.Dialog;
|
||||
import java.awt.Font;
|
||||
import java.awt.Graphics2D;
|
||||
import java.awt.GraphicsConfiguration;
|
||||
import java.awt.Image;
|
||||
import java.awt.Insets;
|
||||
import java.awt.Rectangle;
|
||||
import java.awt.RenderingHints;
|
||||
@@ -51,6 +53,7 @@ import java.awt.image.BufferedImage;
|
||||
import java.awt.peer.ComponentPeer;
|
||||
import java.awt.peer.WindowPeer;
|
||||
import java.lang.ref.WeakReference;
|
||||
import java.util.List;
|
||||
|
||||
public class WLWindowPeer extends WLComponentPeer implements WindowPeer, SurfacePixelGrabber {
|
||||
private static Font defaultFont;
|
||||
@@ -180,7 +183,38 @@ public class WLWindowPeer extends WLComponentPeer implements WindowPeer, Surface
|
||||
|
||||
@Override
|
||||
public void updateIconImages() {
|
||||
// No support for this from Wayland, icon is a desktop integration feature.
|
||||
List<Image> iconImages = getWindow().getIconImages();
|
||||
if (iconImages == null || iconImages.isEmpty()) {
|
||||
setIcon(0, null);
|
||||
return;
|
||||
}
|
||||
|
||||
Image image = iconImages.stream()
|
||||
.filter(x -> x.getWidth(null) > 0 && x.getHeight(null) > 0)
|
||||
.filter(x -> x.getWidth(null) == x.getHeight(null))
|
||||
.max((a, b) -> Integer.compare(a.getWidth(null), b.getWidth(null)))
|
||||
.orElse(null);
|
||||
if (image == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
int width = image.getWidth(null);
|
||||
int height = image.getHeight(null);
|
||||
int size = width;
|
||||
|
||||
BufferedImage bufferedImage;
|
||||
if (image instanceof BufferedImage && ((BufferedImage) image).getType() == BufferedImage.TYPE_INT_ARGB) {
|
||||
bufferedImage = (BufferedImage) image;
|
||||
} else {
|
||||
bufferedImage = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
|
||||
Graphics2D g = bufferedImage.createGraphics();
|
||||
g.drawImage(image, 0, 0, null);
|
||||
g.dispose();
|
||||
}
|
||||
|
||||
int[] pixels = new int[width * height];
|
||||
bufferedImage.getRGB(0, 0, width, height, pixels, 0, width);
|
||||
setIcon(size, pixels);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -36,6 +36,8 @@
|
||||
#include "WLGraphicsEnvironment.h"
|
||||
|
||||
#include "xdg-decoration-unstable-v1.h"
|
||||
#include <stdbool.h>
|
||||
|
||||
#ifdef WAKEFIELD_ROBOT
|
||||
#include "wakefield.h"
|
||||
#endif
|
||||
@@ -67,6 +69,9 @@ struct WLFrame {
|
||||
jboolean configuredActive;
|
||||
jboolean configuredMaximized;
|
||||
jboolean configuredFullscreen;
|
||||
|
||||
struct wl_buffer* iconBuffer;
|
||||
struct wl_shm_pool* iconPool;
|
||||
};
|
||||
|
||||
static void
|
||||
@@ -571,3 +576,57 @@ JNIEXPORT void JNICALL Java_sun_awt_wl_ServerSideFrameDecoration_disposeImpl
|
||||
}
|
||||
}
|
||||
|
||||
JNIEXPORT void JNICALL Java_sun_awt_wl_WLComponentPeer_nativeSetIcon
|
||||
(JNIEnv *env, jobject obj, jlong ptr, jint size, jobject pixelArray)
|
||||
{
|
||||
struct WLFrame *frame = jlong_to_ptr(ptr);
|
||||
if (frame == NULL || !frame->toplevel || xdg_toplevel_icon_manager == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
bool hasIcon = frame->iconBuffer != NULL;
|
||||
bool willHaveIcon = size > 0 && pixelArray != NULL;
|
||||
size_t iconByteSize = size * size * 4;
|
||||
|
||||
if (!willHaveIcon) {
|
||||
xdg_toplevel_icon_manager_v1_set_icon(xdg_toplevel_icon_manager, frame->xdg_toplevel, NULL);
|
||||
}
|
||||
|
||||
if (hasIcon) {
|
||||
if (frame->iconBuffer != NULL) {
|
||||
wl_buffer_destroy(frame->iconBuffer);
|
||||
frame->iconBuffer = NULL;
|
||||
}
|
||||
if (frame->iconPool != NULL) {
|
||||
wl_shm_pool_destroy(frame->iconPool);
|
||||
frame->iconPool = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
if (willHaveIcon) {
|
||||
void* poolData = NULL;
|
||||
struct wl_shm_pool* pool = CreateShmPool(iconByteSize, "toplevel_icon", &poolData, NULL);
|
||||
if (pool == NULL) {
|
||||
return;
|
||||
}
|
||||
(*env)->GetIntArrayRegion(env, pixelArray, 0, size * size, poolData);
|
||||
struct wl_buffer* buffer = wl_shm_pool_create_buffer(pool, 0, size, size, size * 4, WL_SHM_FORMAT_ARGB8888);
|
||||
if (buffer == NULL) {
|
||||
wl_shm_pool_destroy(pool);
|
||||
return;
|
||||
}
|
||||
|
||||
struct xdg_toplevel_icon_v1* icon = xdg_toplevel_icon_manager_v1_create_icon(xdg_toplevel_icon_manager);
|
||||
if (icon == NULL) {
|
||||
wl_buffer_destroy(buffer);
|
||||
wl_shm_pool_destroy(pool);
|
||||
return;
|
||||
}
|
||||
xdg_toplevel_icon_v1_add_buffer(icon, buffer, 1);
|
||||
xdg_toplevel_icon_manager_v1_set_icon(xdg_toplevel_icon_manager, frame->xdg_toplevel, icon);
|
||||
xdg_toplevel_icon_v1_destroy(icon);
|
||||
|
||||
frame->iconPool = pool;
|
||||
frame->iconBuffer = buffer;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -93,8 +93,10 @@ struct zwp_primary_selection_device_manager_v1 *zwp_selection_dm = NULL; // opti
|
||||
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
|
||||
struct xdg_toplevel_icon_manager_v1 *xdg_toplevel_icon_manager; // optional, check for NULL before use
|
||||
|
||||
static uint32_t num_of_outstanding_sync = 0;
|
||||
static bool waiting_for_xdg_toplevel_icon_manager_done = false;
|
||||
|
||||
// This group of definitions corresponds to declarations from awt.h
|
||||
jclass tkClass = NULL;
|
||||
@@ -135,6 +137,7 @@ static jmethodID dispatchKeyboardModifiersEventMID;
|
||||
static jmethodID dispatchKeyboardEnterEventMID;
|
||||
static jmethodID dispatchKeyboardLeaveEventMID;
|
||||
static jmethodID dispatchRelativePointerEventMID;
|
||||
static jmethodID handleToplevelIconSizeMID;
|
||||
|
||||
JNIEnv *getEnv() {
|
||||
JNIEnv *env;
|
||||
@@ -570,6 +573,36 @@ static const struct wl_seat_listener wl_seat_listener = {
|
||||
.name = wl_seat_name
|
||||
};
|
||||
|
||||
static void
|
||||
xdg_toplevel_icon_manager_icon_size(void *data,
|
||||
struct xdg_toplevel_icon_manager_v1 *xdg_toplevel_icon_manager_v1,
|
||||
int32_t size)
|
||||
{
|
||||
(void)data;
|
||||
(void)xdg_toplevel_icon_manager_v1;
|
||||
JNIEnv* env = getEnv();
|
||||
if (env == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
(*env)->CallStaticVoidMethod(env, tkClass, handleToplevelIconSizeMID, size);
|
||||
JNU_CHECK_EXCEPTION(env);
|
||||
}
|
||||
|
||||
static void
|
||||
xdg_toplevel_icon_manager_icon_size_done(void *data,
|
||||
struct xdg_toplevel_icon_manager_v1 *xdg_toplevel_icon_manager_v1)
|
||||
{
|
||||
(void)data;
|
||||
(void)xdg_toplevel_icon_manager_v1;
|
||||
waiting_for_xdg_toplevel_icon_manager_done = false;
|
||||
}
|
||||
|
||||
static const struct xdg_toplevel_icon_manager_v1_listener xdg_toplevel_icon_manager_v1_listener = {
|
||||
.icon_size = xdg_toplevel_icon_manager_icon_size,
|
||||
.done = xdg_toplevel_icon_manager_icon_size_done,
|
||||
};
|
||||
|
||||
static void
|
||||
registry_global(void *data, struct wl_registry *wl_registry,
|
||||
uint32_t name, const char *interface, uint32_t version)
|
||||
@@ -636,6 +669,12 @@ registry_global(void *data, struct wl_registry *wl_registry,
|
||||
}
|
||||
} else if (strcmp(interface, zxdg_decoration_manager_v1_interface.name) == 0) {
|
||||
xdg_decoration_manager = wl_registry_bind(wl_registry, name, &zxdg_decoration_manager_v1_interface, 1);
|
||||
} else if (strcmp(interface, xdg_toplevel_icon_manager_v1_interface.name) == 0) {
|
||||
xdg_toplevel_icon_manager = wl_registry_bind(wl_registry, name, &xdg_toplevel_icon_manager_v1_interface, 1);
|
||||
if (xdg_toplevel_icon_manager != NULL) {
|
||||
waiting_for_xdg_toplevel_icon_manager_done = true;
|
||||
xdg_toplevel_icon_manager_v1_add_listener(xdg_toplevel_icon_manager, &xdg_toplevel_icon_manager_v1_listener, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef WAKEFIELD_ROBOT
|
||||
@@ -710,6 +749,11 @@ initJavaRefs(JNIEnv *env, jclass clazz)
|
||||
"(Lsun/awt/wl/WLPointerEvent;)V"),
|
||||
JNI_FALSE);
|
||||
|
||||
CHECK_NULL_RETURN(handleToplevelIconSizeMID = (*env)->GetStaticMethodID(env, tkClass,
|
||||
"handleToplevelIconSize",
|
||||
"(I)V"),
|
||||
JNI_FALSE);
|
||||
|
||||
CHECK_NULL_RETURN(pointerEventClass = (*env)->FindClass(env,
|
||||
"sun/awt/wl/WLPointerEvent"),
|
||||
JNI_FALSE);
|
||||
@@ -844,7 +888,7 @@ getCursorTheme(int scale) {
|
||||
static void
|
||||
finalizeInit(JNIEnv *env) {
|
||||
// NB: we are NOT on EDT here so shouldn't dispatch EDT-sensitive stuff
|
||||
while (num_of_outstanding_sync > 0) {
|
||||
while (num_of_outstanding_sync > 0 || waiting_for_xdg_toplevel_icon_manager_done) {
|
||||
// There are outstanding events that carry information essential for the toolkit
|
||||
// to be fully operational, such as, for example, the number of outputs.
|
||||
// Those events were subscribed to when handling globals in registry_global().
|
||||
|
||||
@@ -33,7 +33,7 @@
|
||||
#include "relative-pointer-unstable-v1.h"
|
||||
#include "text-input-unstable-v3.h"
|
||||
#include "xdg-decoration-unstable-v1.h"
|
||||
|
||||
#include "xdg-toplevel-icon-v1.h"
|
||||
#include "jvm_md.h"
|
||||
#include "jni_util.h"
|
||||
|
||||
@@ -73,6 +73,7 @@ extern struct zxdg_output_manager_v1 *zxdg_output_manager_v1; // optional, check
|
||||
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
|
||||
extern struct zxdg_decoration_manager_v1* xdg_decoration_manager; // optional, check for NULL before use
|
||||
extern struct xdg_toplevel_icon_manager_v1 *xdg_toplevel_icon_manager; // optional, check for NULL before use
|
||||
|
||||
JNIEnv *getEnv();
|
||||
|
||||
|
||||
Reference in New Issue
Block a user