1 /* 2 * Copyright (c) 2003, 2013, 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 /* 27 * This code is ported to XAWT from MAWT based on awt_mgrsel.c 28 * code written originally by Valeriy Ushakov 29 * Author : Bino George 30 */ 31 32 package sun.awt.X11; 33 34 import java.util.*; 35 import sun.util.logging.PlatformLogger; 36 37 public class XMSelection { 38 39 /* 40 * A method for a subsytem to express its interest in a certain 41 * manager selection. 42 * 43 * If owner changes, the ownerChanged of the XMSelectionListener 44 * will be called with the screen 45 * number and the new owning window when onwership is established, or 46 * None if the owner is gone. 47 * 48 * Events in extra_mask are selected for on owning windows (exsiting 49 * ones and on new owners when established) and otherEvent of the 50 * XMWSelectionListener will be called with the screen number and an event. 51 * 52 * The function returns an array of current owners. The size of the 53 * array is ScreenCount(awt_display). The array is "owned" by this 54 * module and should be considered by the caller as read-only. 55 */ 56 57 58 private static PlatformLogger log = PlatformLogger.getLogger("sun.awt.X11.XMSelection"); 59 /* Name of the selection */ 60 String selectionName; 61 62 /* list of listeners to be called for events */ 63 Vector<XMSelectionListener> listeners; 64 65 /* X atom array (one per screen) for this selection */ 66 XAtom atoms[]; 67 68 /* Window ids of selection owners */ 69 long owners[]; 70 71 /* event mask to set */ 72 long eventMask; 73 74 static int numScreens; 75 76 static XAtom XA_MANAGER; 77 78 static HashMap<Long, XMSelection> selectionMap; 79 80 static { 81 long display = XToolkit.getDisplay(); 82 XToolkit.awtLock(); 83 try { 84 numScreens = XlibWrapper.ScreenCount(display); 85 } finally { 86 XToolkit.awtUnlock(); 87 } 88 XA_MANAGER = XAtom.get("MANAGER"); 89 for (int screen = 0; screen < numScreens ; screen ++) { 90 initScreen(display,screen); 91 } 92 93 selectionMap = new HashMap<>(); 94 } 95 96 static void initScreen(long display, final int screen) { 97 XToolkit.awtLock(); 98 try { 99 long root = XlibWrapper.RootWindow(display,screen); 100 XWindowAttributes wattr = new XWindowAttributes(); 101 try{ 102 XlibWrapper.XGetWindowAttributes(display, root, wattr.pData); 103 XlibWrapper.XSelectInput(display, root, 104 XConstants.StructureNotifyMask | 105 wattr.get_your_event_mask()); 106 } finally { 107 wattr.dispose(); 108 } 109 XToolkit.addEventDispatcher(root, 110 new XEventDispatcher() { 111 public void dispatchEvent(XEvent ev) { 112 processRootEvent(ev, screen); 113 } 114 }); 115 116 } finally { 117 XToolkit.awtUnlock(); 118 } 119 } 120 121 122 public int getNumberOfScreens() { 123 return numScreens; 124 } 125 126 void select(long extra_mask) { 127 eventMask = extra_mask; 128 for (int screen = 0; screen < numScreens ; screen ++) { 129 selectPerScreen(screen,extra_mask); 130 } 131 } 132 133 void resetOwner(long owner, final int screen) { 134 XToolkit.awtLock(); 135 try { 136 long display = XToolkit.getDisplay(); 137 synchronized(this) { 138 setOwner(owner, screen); 139 if (log.isLoggable(PlatformLogger.Level.FINE)) { 140 log.fine("New Selection Owner for screen " + screen + " = " + owner ); 141 } 142 XlibWrapper.XSelectInput(display, owner, XConstants.StructureNotifyMask | eventMask); 143 XToolkit.addEventDispatcher(owner, 144 new XEventDispatcher() { 145 public void dispatchEvent(XEvent ev) { 146 dispatchSelectionEvent(ev, screen); 147 } 148 }); 149 150 } 151 } finally { 152 XToolkit.awtUnlock(); 153 } 154 } 155 156 void selectPerScreen(final int screen, long extra_mask) { 157 XToolkit.awtLock(); 158 try { 159 try { 160 long display = XToolkit.getDisplay(); 161 if (log.isLoggable(PlatformLogger.Level.FINE)) { 162 log.fine("Grabbing XServer"); 163 } 164 XlibWrapper.XGrabServer(display); 165 166 synchronized(this) { 167 String selection_name = getName()+"_S"+screen; 168 if (log.isLoggable(PlatformLogger.Level.FINE)) { 169 log.fine("Screen = " + screen + " selection name = " + selection_name); 170 } 171 XAtom atom = XAtom.get(selection_name); 172 selectionMap.put(Long.valueOf(atom.getAtom()),this); // add mapping from atom to the instance of XMSelection 173 setAtom(atom,screen); 174 long owner = XlibWrapper.XGetSelectionOwner(display, atom.getAtom()); 175 if (owner != 0) { 176 setOwner(owner, screen); 177 if (log.isLoggable(PlatformLogger.Level.FINE)) { 178 log.fine("Selection Owner for screen " + screen + " = " + owner ); 179 } 180 XlibWrapper.XSelectInput(display, owner, XConstants.StructureNotifyMask | extra_mask); 181 XToolkit.addEventDispatcher(owner, 182 new XEventDispatcher() { 183 public void dispatchEvent(XEvent ev) { 184 dispatchSelectionEvent(ev, screen); 185 } 186 }); 187 } 188 } 189 } 190 catch (Exception e) { 191 e.printStackTrace(); 192 } 193 finally { 194 if (log.isLoggable(PlatformLogger.Level.FINE)) { 195 log.fine("UnGrabbing XServer"); 196 } 197 XlibWrapper.XUngrabServer(XToolkit.getDisplay()); 198 } 199 } finally { 200 XToolkit.awtUnlock(); 201 } 202 } 203 204 205 static boolean processClientMessage(XEvent xev, int screen) { 206 XClientMessageEvent xce = xev.get_xclient(); 207 if (xce.get_message_type() == XA_MANAGER.getAtom()) { 208 if (log.isLoggable(PlatformLogger.Level.FINE)) { 209 log.fine("client messags = " + xce); 210 } 211 long timestamp = xce.get_data(0); 212 long atom = xce.get_data(1); 213 long owner = xce.get_data(2); 214 long data = xce.get_data(3); 215 216 XMSelection sel = getInstance(atom); 217 if (sel != null) { 218 sel.resetOwner(owner,screen); 219 sel.dispatchOwnerChangedEvent(xev,screen,owner,data, timestamp); 220 } 221 } 222 return false; 223 } 224 225 static boolean processRootEvent(XEvent xev, int screen) { 226 switch (xev.get_type()) { 227 case XConstants.ClientMessage: { 228 return processClientMessage(xev, screen); 229 } 230 } 231 232 return false; 233 234 } 235 236 237 static XMSelection getInstance(long selection) { 238 return selectionMap.get(Long.valueOf(selection)); 239 } 240 241 242 /* 243 * Default constructor specifies PropertyChangeMask as well 244 */ 245 246 public XMSelection (String selname) { 247 this(selname, XConstants.PropertyChangeMask); 248 } 249 250 251 /* 252 * Some users may not need to know about selection changes, 253 * just owner ship changes, They would specify a zero extra mask. 254 */ 255 256 public XMSelection (String selname, long extraMask) { 257 258 synchronized (this) { 259 selectionName = selname; 260 atoms = new XAtom[getNumberOfScreens()]; 261 owners = new long[getNumberOfScreens()]; 262 } 263 select(extraMask); 264 } 265 266 267 268 public synchronized void addSelectionListener(XMSelectionListener listener) { 269 if (listeners == null) { 270 listeners = new Vector<>(); 271 } 272 listeners.add(listener); 273 } 274 275 public synchronized void removeSelectionListener(XMSelectionListener listener) { 276 if (listeners != null) { 277 listeners.remove(listener); 278 } 279 } 280 281 synchronized Collection<XMSelectionListener> getListeners() { 282 return listeners; 283 } 284 285 synchronized XAtom getAtom(int screen) { 286 if (atoms != null) { 287 return atoms[screen]; 288 } 289 return null; 290 } 291 292 synchronized void setAtom(XAtom a, int screen) { 293 if (atoms != null) { 294 atoms[screen] = a; 295 } 296 } 297 298 synchronized long getOwner(int screen) { 299 if (owners != null) { 300 return owners[screen]; 301 } 302 return 0; 303 } 304 305 synchronized void setOwner(long owner, int screen) { 306 if (owners != null) { 307 owners[screen] = owner; 308 } 309 } 310 311 synchronized String getName() { 312 return selectionName; 313 } 314 315 316 synchronized void dispatchSelectionChanged( XPropertyEvent ev, int screen) { 317 if (log.isLoggable(PlatformLogger.Level.FINE)) { 318 log.fine("Selection Changed : Screen = " + screen + "Event =" + ev); 319 } 320 if (listeners != null) { 321 Iterator<XMSelectionListener> iter = listeners.iterator(); 322 while (iter.hasNext()) { 323 XMSelectionListener disp = iter.next(); 324 disp.selectionChanged(screen, this, ev.get_window(), ev); 325 } 326 } 327 } 328 329 synchronized void dispatchOwnerDeath(XDestroyWindowEvent de, int screen) { 330 if (log.isLoggable(PlatformLogger.Level.FINE)) { 331 log.fine("Owner dead : Screen = " + screen + "Event =" + de); 332 } 333 if (listeners != null) { 334 Iterator<XMSelectionListener> iter = listeners.iterator(); 335 while (iter.hasNext()) { 336 XMSelectionListener disp = iter.next(); 337 disp.ownerDeath(screen, this, de.get_window()); 338 339 } 340 } 341 } 342 343 void dispatchSelectionEvent(XEvent xev, int screen) { 344 if (log.isLoggable(PlatformLogger.Level.FINE)) { 345 log.fine("Event =" + xev); 346 } 347 if (xev.get_type() == XConstants.DestroyNotify) { 348 XDestroyWindowEvent de = xev.get_xdestroywindow(); 349 dispatchOwnerDeath( de, screen); 350 } 351 else if (xev.get_type() == XConstants.PropertyNotify) { 352 XPropertyEvent xpe = xev.get_xproperty(); 353 dispatchSelectionChanged( xpe, screen); 354 } 355 } 356 357 358 synchronized void dispatchOwnerChangedEvent(XEvent ev, int screen, long owner, long data, long timestamp) { 359 if (listeners != null) { 360 Iterator<XMSelectionListener> iter = listeners.iterator(); 361 while (iter.hasNext()) { 362 XMSelectionListener disp = iter.next(); 363 disp.ownerChanged(screen,this, owner, data, timestamp); 364 } 365 } 366 } 367 368 369 }