diff --git a/src/java.desktop/unix/classes/sun/awt/UNIXToolkit.java b/src/java.desktop/unix/classes/sun/awt/UNIXToolkit.java index 31764c74948..d785823ea8e 100644 --- a/src/java.desktop/unix/classes/sun/awt/UNIXToolkit.java +++ b/src/java.desktop/unix/classes/sun/awt/UNIXToolkit.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2004, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2004, 2024, 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 @@ -26,8 +26,12 @@ import java.awt.RenderingHints; import static java.awt.RenderingHints.*; +import static java.util.concurrent.TimeUnit.SECONDS; import java.awt.color.ColorSpace; import java.awt.image.*; +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStreamReader; import java.security.AccessController; import java.security.PrivilegedAction; @@ -214,6 +218,72 @@ protected Object lazilyLoadGTKIcon(String longname) { return img; } + private static volatile Boolean shouldDisableSystemTray = null; + + /** + * There is an issue displaying the xembed icons in appIndicators + * area with certain Gnome Shell versions. + * To avoid any loss of quality of service, we are disabling + * SystemTray support in such cases. + * + * @return true if system tray should be disabled + */ + public boolean shouldDisableSystemTray() { + Boolean result = shouldDisableSystemTray; + if (result == null) { + synchronized (GTK_LOCK) { + result = shouldDisableSystemTray; + if (result == null) { + if ("gnome".equals(getDesktop())) { + @SuppressWarnings("removal") + Integer gnomeShellMajorVersion = + AccessController + .doPrivileged((PrivilegedAction) + this::getGnomeShellMajorVersion); + + if (gnomeShellMajorVersion == null + || gnomeShellMajorVersion < 45) { + + return shouldDisableSystemTray = true; + } + } + shouldDisableSystemTray = result = false; + } + } + } + return result; + } + + private Integer getGnomeShellMajorVersion() { + try { + Process process = + new ProcessBuilder("/usr/bin/gnome-shell", "--version") + .start(); + try (InputStreamReader isr = new InputStreamReader(process.getInputStream()); + BufferedReader reader = new BufferedReader(isr)) { + + if (process.waitFor(2, SECONDS) && process.exitValue() == 0) { + String line = reader.readLine(); + if (line != null) { + String[] versionComponents = line + .replaceAll("[^\\d.]", "") + .split("\\."); + + if (versionComponents.length >= 1) { + return Integer.parseInt(versionComponents[0]); + } + } + } + } + } catch (IOException + | InterruptedException + | IllegalThreadStateException + | NumberFormatException ignored) { + } + + return null; + } + /** * Returns a BufferedImage which contains the Gtk icon requested. If no * such icon exists or an error occurs loading the icon the result will diff --git a/src/java.desktop/unix/classes/sun/awt/X11/XSystemTrayPeer.java b/src/java.desktop/unix/classes/sun/awt/X11/XSystemTrayPeer.java index 1a9d040616e..cdbb74ddac1 100644 --- a/src/java.desktop/unix/classes/sun/awt/X11/XSystemTrayPeer.java +++ b/src/java.desktop/unix/classes/sun/awt/X11/XSystemTrayPeer.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2024, 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 @@ -30,6 +30,7 @@ import sun.awt.SunToolkit; import sun.awt.AppContext; import sun.awt.AWTAccessor; +import sun.awt.UNIXToolkit; import sun.util.logging.PlatformLogger; public class XSystemTrayPeer implements SystemTrayPeer, XMSelectionListener { @@ -48,22 +49,32 @@ public class XSystemTrayPeer implements SystemTrayPeer, XMSelectionListener { private static final XAtom _NET_SYSTEM_TRAY_OPCODE = XAtom.get("_NET_SYSTEM_TRAY_OPCODE"); private static final XAtom _NET_WM_ICON = XAtom.get("_NET_WM_ICON"); private static final long SYSTEM_TRAY_REQUEST_DOCK = 0; + private final boolean shouldDisableSystemTray; XSystemTrayPeer(SystemTray target) { this.target = target; peerInstance = this; - selection.addSelectionListener(this); + UNIXToolkit tk = (UNIXToolkit)Toolkit.getDefaultToolkit(); + shouldDisableSystemTray = tk.shouldDisableSystemTray(); - long selection_owner = selection.getOwner(SCREEN); - available = (selection_owner != XConstants.None); + if (!shouldDisableSystemTray) { + selection.addSelectionListener(this); - if (log.isLoggable(PlatformLogger.Level.FINE)) { - log.fine(" check if system tray is available. selection owner: " + selection_owner); + long selection_owner = selection.getOwner(SCREEN); + available = (selection_owner != XConstants.None); + + if (log.isLoggable(PlatformLogger.Level.FINE)) { + log.fine(" check if system tray is available. selection owner: " + selection_owner); + } } } public void ownerChanged(int screen, XMSelection sel, long newOwner, long data, long timestamp) { + if (shouldDisableSystemTray) { + return; + } + if (screen != SCREEN) { return; } @@ -77,6 +88,10 @@ public void ownerChanged(int screen, XMSelection sel, long newOwner, long data, } public void ownerDeath(int screen, XMSelection sel, long deadOwner) { + if (shouldDisableSystemTray) { + return; + } + if (screen != SCREEN) { return; }