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