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 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 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 XlibWrapper.XSelectInput(display, root, XConstants.StructureNotifyMask); 101 XToolkit.addEventDispatcher(root, 102 new XEventDispatcher() { 103 public void dispatchEvent(XEvent ev) { 104 processRootEvent(ev, screen); 105 } 106 }); 107 108 } finally { 109 XToolkit.awtUnlock(); 110 } 111 } 112 113 114 public int getNumberOfScreens() { 115 return numScreens; 116 } 117 118 void select(long extra_mask) { 119 eventMask = extra_mask; 120 for (int screen = 0; screen < numScreens ; screen ++) { 121 selectPerScreen(screen,extra_mask); 122 } 123 } 124 125 void resetOwner(long owner, final int screen) { 126 XToolkit.awtLock(); 127 try { 128 long display = XToolkit.getDisplay(); 129 synchronized(this) { 130 setOwner(owner, screen); 131 if (log.isLoggable(PlatformLogger.Level.FINE)) { 132 log.fine("New Selection Owner for screen " + screen + " = " + owner ); 133 } 134 XlibWrapper.XSelectInput(display, owner, XConstants.StructureNotifyMask | eventMask); 135 XToolkit.addEventDispatcher(owner, 136 new XEventDispatcher() { 137 public void dispatchEvent(XEvent ev) { 138 dispatchSelectionEvent(ev, screen); 139 } 140 }); 141 142 } 143 } finally { 144 XToolkit.awtUnlock(); 145 } 146 } 147 148 void selectPerScreen(final int screen, long extra_mask) { 149 XToolkit.awtLock(); 150 try { 151 try { 152 long display = XToolkit.getDisplay(); 153 if (log.isLoggable(PlatformLogger.Level.FINE)) { 154 log.fine("Grabbing XServer"); 155 } 156 XlibWrapper.XGrabServer(display); 157 158 synchronized(this) { 159 String selection_name = getName()+"_S"+screen; 160 if (log.isLoggable(PlatformLogger.Level.FINE)) { 161 log.fine("Screen = " + screen + " selection name = " + selection_name); 162 } 163 XAtom atom = XAtom.get(selection_name); 164 selectionMap.put(Long.valueOf(atom.getAtom()),this); // add mapping from atom to the instance of XMSelection 165 setAtom(atom,screen); 166 long owner = XlibWrapper.XGetSelectionOwner(display, atom.getAtom()); 167 if (owner != 0) { 168 setOwner(owner, screen); 169 if (log.isLoggable(PlatformLogger.Level.FINE)) { 170 log.fine("Selection Owner for screen " + screen + " = " + owner ); 171 } 172 XlibWrapper.XSelectInput(display, owner, XConstants.StructureNotifyMask | extra_mask); 173 XToolkit.addEventDispatcher(owner, 174 new XEventDispatcher() { 175 public void dispatchEvent(XEvent ev) { 176 dispatchSelectionEvent(ev, screen); 177 } 178 }); 179 } 180 } 181 } 182 catch (Exception e) { 183 e.printStackTrace(); 184 } 185 finally { 186 if (log.isLoggable(PlatformLogger.Level.FINE)) { 187 log.fine("UnGrabbing XServer"); 188 } 189 XlibWrapper.XUngrabServer(XToolkit.getDisplay()); 190 } 191 } finally { 192 XToolkit.awtUnlock(); 193 } 194 } 195 196 197 static boolean processClientMessage(XEvent xev, int screen) { 198 XClientMessageEvent xce = xev.get_xclient(); 199 if (xce.get_message_type() == XA_MANAGER.getAtom()) { 200 if (log.isLoggable(PlatformLogger.Level.FINE)) { 201 log.fine("client messags = " + xce); 202 } 203 long timestamp = xce.get_data(0); 204 long atom = xce.get_data(1); 205 long owner = xce.get_data(2); 206 long data = xce.get_data(3); 207 208 XMSelection sel = getInstance(atom); 209 if (sel != null) { 210 sel.resetOwner(owner,screen); 211 sel.dispatchOwnerChangedEvent(xev,screen,owner,data, timestamp); 212 } 213 } 214 return false; 215 } 216 217 static boolean processRootEvent(XEvent xev, int screen) { 218 switch (xev.get_type()) { 219 case XConstants.ClientMessage: { 220 return processClientMessage(xev, screen); 221 } 222 } 223 224 return false; 225 226 } 227 228 229 static XMSelection getInstance(long selection) { 230 return (XMSelection) selectionMap.get(Long.valueOf(selection)); 231 } 232 233 234 /* 235 * Default constructor specifies PropertyChangeMask as well 236 */ 237 238 public XMSelection (String selname) { 239 this(selname, XConstants.PropertyChangeMask); 240 } 241 242 243 /* 244 * Some users may not need to know about selection changes, 245 * just owner ship changes, They would specify a zero extra mask. 246 */ 247 248 public XMSelection (String selname, long extraMask) { 249 250 synchronized (this) { 251 selectionName = selname; 252 atoms = new XAtom[getNumberOfScreens()]; 253 owners = new long[getNumberOfScreens()]; 254 } 255 select(extraMask); 256 } 257 258 259 260 public synchronized void addSelectionListener(XMSelectionListener listener) { 261 if (listeners == null) { 262 listeners = new Vector(); 263 } 264 listeners.add(listener); 265 } 266 267 public synchronized void removeSelectionListener(XMSelectionListener listener) { 268 if (listeners != null) { 269 listeners.remove(listener); 270 } 271 } 272 273 synchronized Collection getListeners() { 274 return listeners; 275 } 276 277 synchronized XAtom getAtom(int screen) { 278 if (atoms != null) { 279 return atoms[screen]; 280 } 281 return null; 282 } 283 284 synchronized void setAtom(XAtom a, int screen) { 285 if (atoms != null) { 286 atoms[screen] = a; 287 } 288 } 289 290 synchronized long getOwner(int screen) { 291 if (owners != null) { 292 return owners[screen]; 293 } 294 return 0; 295 } 296 297 synchronized void setOwner(long owner, int screen) { 298 if (owners != null) { 299 owners[screen] = owner; 300 } 301 } 302 303 synchronized String getName() { 304 return selectionName; 305 } 306 307 308 synchronized void dispatchSelectionChanged( XPropertyEvent ev, int screen) { 309 if (log.isLoggable(PlatformLogger.Level.FINE)) { 310 log.fine("Selection Changed : Screen = " + screen + "Event =" + ev); 311 } 312 if (listeners != null) { 313 Iterator iter = listeners.iterator(); 314 while (iter.hasNext()) { 315 XMSelectionListener disp = (XMSelectionListener) iter.next(); 316 disp.selectionChanged(screen, this, ev.get_window(), ev); 317 } 318 } 319 } 320 321 synchronized void dispatchOwnerDeath(XDestroyWindowEvent de, int screen) { 322 if (log.isLoggable(PlatformLogger.Level.FINE)) { 323 log.fine("Owner dead : Screen = " + screen + "Event =" + de); 324 } 325 if (listeners != null) { 326 Iterator iter = listeners.iterator(); 327 while (iter.hasNext()) { 328 XMSelectionListener disp = (XMSelectionListener) iter.next(); 329 disp.ownerDeath(screen, this, de.get_window()); 330 331 } 332 } 333 } 334 335 void dispatchSelectionEvent(XEvent xev, int screen) { 336 if (log.isLoggable(PlatformLogger.Level.FINE)) { 337 log.fine("Event =" + xev); 338 } 339 if (xev.get_type() == XConstants.DestroyNotify) { 340 XDestroyWindowEvent de = xev.get_xdestroywindow(); 341 dispatchOwnerDeath( de, screen); 342 } 343 else if (xev.get_type() == XConstants.PropertyNotify) { 344 XPropertyEvent xpe = xev.get_xproperty(); 345 dispatchSelectionChanged( xpe, screen); 346 } 347 } 348 349 350 synchronized void dispatchOwnerChangedEvent(XEvent ev, int screen, long owner, long data, long timestamp) { 351 if (listeners != null) { 352 Iterator iter = listeners.iterator(); 353 while (iter.hasNext()) { 354 XMSelectionListener disp = (XMSelectionListener) iter.next(); 355 disp.ownerChanged(screen,this, owner, data, timestamp); 356 } 357 } 358 } 359 360 361 }