1 /* 2 * Copyright (c) 2005, 2018, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 package sun.awt.X11; 27 28 import java.awt.*; 29 import java.awt.peer.SystemTrayPeer; 30 import sun.awt.SunToolkit; 31 import sun.awt.AppContext; 32 import sun.awt.AWTAccessor; 33 import sun.util.logging.PlatformLogger; 34 35 public class XSystemTrayPeer implements SystemTrayPeer, XMSelectionListener { 36 private static final PlatformLogger log = PlatformLogger.getLogger("sun.awt.X11.XSystemTrayPeer"); 37 38 SystemTray target; 39 static XSystemTrayPeer peerInstance; // there is only one SystemTray peer per application 40 41 private volatile boolean available; 42 private final XMSelection selection = new XMSelection("_NET_SYSTEM_TRAY"); 43 44 private static final int SCREEN = 0; 45 private static final String SYSTEM_TRAY_PROPERTY_NAME = "systemTray"; 46 private static final XAtom _NET_SYSTEM_TRAY = XAtom.get("_NET_SYSTEM_TRAY_S" + SCREEN); 47 private static final XAtom _XEMBED_INFO = XAtom.get("_XEMBED_INFO"); 48 private static final XAtom _NET_SYSTEM_TRAY_OPCODE = XAtom.get("_NET_SYSTEM_TRAY_OPCODE"); 49 private static final XAtom _NET_WM_ICON = XAtom.get("_NET_WM_ICON"); 50 private static final long SYSTEM_TRAY_REQUEST_DOCK = 0; 51 52 XSystemTrayPeer(SystemTray target) { 53 this.target = target; 54 peerInstance = this; 55 56 selection.addSelectionListener(this); 57 58 long selection_owner = selection.getOwner(SCREEN); 59 available = (selection_owner != XConstants.None); 60 61 if (log.isLoggable(PlatformLogger.Level.FINE)) { 62 log.fine(" check if system tray is available. selection owner: " + selection_owner); 63 } 64 } 65 66 public void ownerChanged(int screen, XMSelection sel, long newOwner, long data, long timestamp) { 67 if (screen != SCREEN) { 68 return; 69 } 70 if (!available) { 71 available = true; 72 firePropertyChange(SYSTEM_TRAY_PROPERTY_NAME, null, target); 73 } else { 74 removeTrayPeers(); 75 } 76 createTrayPeers(); 77 } 78 79 public void ownerDeath(int screen, XMSelection sel, long deadOwner) { 80 if (screen != SCREEN) { 81 return; 82 } 83 if (available) { 84 available = false; 85 firePropertyChange(SYSTEM_TRAY_PROPERTY_NAME, target, null); 86 removeTrayPeers(); 87 } 88 } 89 90 public void selectionChanged(int screen, XMSelection sel, long owner, XPropertyEvent event) { 91 } 92 93 public Dimension getTrayIconSize() { 94 return new Dimension(XTrayIconPeer.TRAY_ICON_HEIGHT, XTrayIconPeer.TRAY_ICON_WIDTH); 95 } 96 97 boolean isAvailable() { 98 return available; 99 } 100 101 void dispose() { 102 selection.removeSelectionListener(this); 103 } 104 105 // *********************************************************************** 106 // *********************************************************************** 107 108 void addTrayIcon(XTrayIconPeer tiPeer) throws AWTException { 109 long selection_owner = selection.getOwner(SCREEN); 110 111 if (log.isLoggable(PlatformLogger.Level.FINE)) { 112 log.fine(" send SYSTEM_TRAY_REQUEST_DOCK message to owner: " + selection_owner); 113 } 114 115 if (selection_owner == XConstants.None) { 116 throw new AWTException("TrayIcon couldn't be displayed."); 117 } 118 119 long tray_window = tiPeer.getWindow(); 120 long[] data = new long[] {XEmbedHelper.XEMBED_VERSION, XEmbedHelper.XEMBED_MAPPED}; 121 long data_ptr = Native.card32ToData(data); 122 123 _XEMBED_INFO.setAtomData(tray_window, data_ptr, data.length); 124 125 sendMessage(selection_owner, SYSTEM_TRAY_REQUEST_DOCK, tray_window, 0, 0); 126 } 127 128 void sendMessage(long win, long msg, long data1, long data2, long data3) { 129 XClientMessageEvent xev = new XClientMessageEvent(); 130 131 try { 132 xev.set_type(XConstants.ClientMessage); 133 xev.set_window(win); 134 xev.set_format(32); 135 xev.set_message_type(_NET_SYSTEM_TRAY_OPCODE.getAtom()); 136 xev.set_data(0, 0); 137 xev.set_data(1, msg); 138 xev.set_data(2, data1); 139 xev.set_data(3, data2); 140 xev.set_data(4, data3); 141 142 XToolkit.awtLock(); 143 try { 144 XlibWrapper.XSendEvent(XToolkit.getDisplay(), win, false, 145 XConstants.NoEventMask, xev.pData); 146 } finally { 147 XToolkit.awtUnlock(); 148 } 149 } finally { 150 xev.dispose(); 151 } 152 } 153 154 static XSystemTrayPeer getPeerInstance() { 155 return peerInstance; 156 } 157 158 private void firePropertyChange(final String propertyName, 159 final Object oldValue, 160 final Object newValue) { 161 Runnable runnable = new Runnable() { 162 public void run() { 163 AWTAccessor.getSystemTrayAccessor() 164 .firePropertyChange(target, propertyName, oldValue, newValue); 165 } 166 }; 167 invokeOnEachAppContext(runnable); 168 } 169 170 private void createTrayPeers() { 171 Runnable runnable = new Runnable() { 172 public void run() { 173 TrayIcon[] icons = target.getTrayIcons(); 174 try { 175 for (TrayIcon ti : icons) { 176 AWTAccessor.getTrayIconAccessor().addNotify(ti); 177 } 178 } catch (AWTException e) { 179 } 180 } 181 }; 182 invokeOnEachAppContext(runnable); 183 } 184 185 private void removeTrayPeers() { 186 Runnable runnable = new Runnable() { 187 public void run() { 188 TrayIcon[] icons = target.getTrayIcons(); 189 for (TrayIcon ti : icons) { 190 AWTAccessor.getTrayIconAccessor().removeNotify(ti); 191 } 192 } 193 }; 194 invokeOnEachAppContext(runnable); 195 } 196 197 private void invokeOnEachAppContext(Runnable runnable) { 198 for (AppContext appContext : AppContext.getAppContexts()) { 199 SunToolkit.invokeLaterOnAppContext(appContext, runnable); 200 } 201 } 202 203 }