001: /*
002: * Copyright 2003-2007 Sun Microsystems, Inc. All Rights Reserved.
003: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
004: *
005: * This code is free software; you can redistribute it and/or modify it
006: * under the terms of the GNU General Public License version 2 only, as
007: * published by the Free Software Foundation. Sun designates this
008: * particular file as subject to the "Classpath" exception as provided
009: * by Sun in the LICENSE file that accompanied this code.
010: *
011: * This code is distributed in the hope that it will be useful, but WITHOUT
012: * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
013: * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
014: * version 2 for more details (a copy is included in the LICENSE file that
015: * accompanied this code).
016: *
017: * You should have received a copy of the GNU General Public License version
018: * 2 along with this work; if not, write to the Free Software Foundation,
019: * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
020: *
021: * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
022: * CA 95054 USA or visit www.sun.com if you need additional information or
023: * have any questions.
024: */
025:
026: /*
027: * This code is ported to XAWT from MAWT based on awt_mgrsel.c
028: * code written originally by Valeriy Ushakov
029: * Author : Bino George
030: */
031:
032: package sun.awt.X11;
033:
034: import java.util.*;
035: import java.util.logging.*;
036:
037: public class XMSelection {
038:
039: /*
040: * A method for a subsytem to express its interest in a certain
041: * manager selection.
042: *
043: * If owner changes, the ownerChanged of the XMSelectionListener
044: * will be called with the screen
045: * number and the new owning window when onwership is established, or
046: * None if the owner is gone.
047: *
048: * Events in extra_mask are selected for on owning windows (exsiting
049: * ones and on new owners when established) and otherEvent of the
050: * XMWSelectionListener will be called with the screen number and an event.
051: *
052: * The function returns an array of current owners. The size of the
053: * array is ScreenCount(awt_display). The array is "owned" by this
054: * module and should be considered by the caller as read-only.
055: */
056:
057: private static Logger log = Logger
058: .getLogger("sun.awt.X11.XMSelection");
059: /* Name of the selection */
060: String selectionName;
061:
062: /* list of listeners to be called for events */
063: Vector listeners;
064:
065: /* X atom array (one per screen) for this selection */
066: XAtom atoms[];
067:
068: /* Window ids of selection owners */
069: long owners[];
070:
071: /* event mask to set */
072: long eventMask;
073:
074: static int numScreens;
075:
076: static XAtom XA_MANAGER;
077:
078: static HashMap selectionMap;
079:
080: static {
081: long display = XToolkit.getDisplay();
082: XToolkit.awtLock();
083: try {
084: numScreens = XlibWrapper.ScreenCount(display);
085: } finally {
086: XToolkit.awtUnlock();
087: }
088: XA_MANAGER = XAtom.get("MANAGER");
089: for (int screen = 0; screen < numScreens; screen++) {
090: initScreen(display, screen);
091: }
092:
093: selectionMap = new HashMap();
094: }
095:
096: static void initScreen(long display, final int screen) {
097: XToolkit.awtLock();
098: try {
099: long root = XlibWrapper.RootWindow(display, screen);
100: XlibWrapper.XSelectInput(display, root,
101: XlibWrapper.StructureNotifyMask);
102: XToolkit.addEventDispatcher(root, new XEventDispatcher() {
103: public void dispatchEvent(XEvent ev) {
104: processRootEvent(ev, screen);
105: }
106: });
107:
108: } finally {
109: XToolkit.awtUnlock();
110: }
111: }
112:
113: public int getNumberOfScreens() {
114: return numScreens;
115: }
116:
117: void select(long extra_mask) {
118: eventMask = extra_mask;
119: for (int screen = 0; screen < numScreens; screen++) {
120: selectPerScreen(screen, extra_mask);
121: }
122: }
123:
124: void resetOwner(long owner, final int screen) {
125: XToolkit.awtLock();
126: try {
127: long display = XToolkit.getDisplay();
128: synchronized (this ) {
129: setOwner(owner, screen);
130: if (log.isLoggable(Level.FINE))
131: log.fine("New Selection Owner for screen " + screen
132: + " = " + owner);
133: XlibWrapper.XSelectInput(display, owner,
134: XlibWrapper.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(Level.FINE))
154: log.fine("Grabbing XServer");
155: XlibWrapper.XGrabServer(display);
156:
157: synchronized (this ) {
158: String selection_name = getName() + "_S" + screen;
159: if (log.isLoggable(Level.FINE))
160: log
161: .fine("Screen = " + screen
162: + " selection name = "
163: + selection_name);
164: XAtom atom = XAtom.get(selection_name);
165: selectionMap
166: .put(Long.valueOf(atom.getAtom()), this ); // add mapping from atom to the instance of XMSelection
167: setAtom(atom, screen);
168: long owner = XlibWrapper.XGetSelectionOwner(
169: display, atom.getAtom());
170: if (owner != 0) {
171: setOwner(owner, screen);
172: if (log.isLoggable(Level.FINE))
173: log.fine("Selection Owner for screen "
174: + screen + " = " + owner);
175: XlibWrapper.XSelectInput(display, owner,
176: XlibWrapper.StructureNotifyMask
177: | extra_mask);
178: XToolkit.addEventDispatcher(owner,
179: new XEventDispatcher() {
180: public void dispatchEvent(XEvent ev) {
181: dispatchSelectionEvent(ev,
182: screen);
183: }
184: });
185: }
186: }
187: } catch (Exception e) {
188: e.printStackTrace();
189: } finally {
190: if (log.isLoggable(Level.FINE))
191: log.fine("UnGrabbing XServer");
192: XlibWrapper.XUngrabServer(XToolkit.getDisplay());
193: }
194: } finally {
195: XToolkit.awtUnlock();
196: }
197: }
198:
199: static boolean processClientMessage(XEvent xev, int screen) {
200: XClientMessageEvent xce = xev.get_xclient();
201: if (xce.get_message_type() == XA_MANAGER.getAtom()) {
202: if (log.isLoggable(Level.FINE))
203: log.fine("client messags = " + xce);
204: long timestamp = xce.get_data(0);
205: long atom = xce.get_data(1);
206: long owner = xce.get_data(2);
207: long data = xce.get_data(3);
208:
209: XMSelection sel = getInstance(atom);
210: if (sel != null) {
211: sel.resetOwner(owner, screen);
212: sel.dispatchOwnerChangedEvent(xev, screen, owner, data,
213: timestamp);
214: }
215: }
216: return false;
217: }
218:
219: static boolean processRootEvent(XEvent xev, int screen) {
220: switch (xev.get_type()) {
221: case XlibWrapper.ClientMessage: {
222: return processClientMessage(xev, screen);
223: }
224: }
225:
226: return false;
227:
228: }
229:
230: static XMSelection getInstance(long selection) {
231: return (XMSelection) selectionMap.get(Long.valueOf(selection));
232: }
233:
234: /*
235: * Default constructor specifies PropertyChangeMask as well
236: */
237:
238: public XMSelection(String selname) {
239: this (selname, XlibWrapper.PropertyChangeMask);
240: }
241:
242: /*
243: * Some users may not need to know about selection changes,
244: * just owner ship changes, They would specify a zero extra mask.
245: */
246:
247: public XMSelection(String selname, long extraMask) {
248:
249: synchronized (this ) {
250: selectionName = selname;
251: atoms = new XAtom[getNumberOfScreens()];
252: owners = new long[getNumberOfScreens()];
253: }
254: select(extraMask);
255: }
256:
257: public synchronized void addSelectionListener(
258: XMSelectionListener listener) {
259: if (listeners == null) {
260: listeners = new Vector();
261: }
262: listeners.add(listener);
263: }
264:
265: public synchronized void removeSelectionListener(
266: XMSelectionListener listener) {
267: if (listeners == null) {
268: listeners.remove(listener);
269: }
270: }
271:
272: synchronized Collection getListeners() {
273: return listeners;
274: }
275:
276: synchronized XAtom getAtom(int screen) {
277: if (atoms != null) {
278: return atoms[screen];
279: }
280: return null;
281: }
282:
283: synchronized void setAtom(XAtom a, int screen) {
284: if (atoms != null) {
285: atoms[screen] = a;
286: }
287: }
288:
289: synchronized long getOwner(int screen) {
290: if (owners != null) {
291: return owners[screen];
292: }
293: return 0;
294: }
295:
296: synchronized void setOwner(long owner, int screen) {
297: if (owners != null) {
298: owners[screen] = owner;
299: }
300: }
301:
302: synchronized String getName() {
303: return selectionName;
304: }
305:
306: synchronized void dispatchSelectionChanged(XPropertyEvent ev,
307: int screen) {
308: if (log.isLoggable(Level.FINE))
309: log.fine("Selection Changed : Screen = " + screen
310: + "Event =" + ev);
311: if (listeners != null) {
312: Iterator iter = listeners.iterator();
313: while (iter.hasNext()) {
314: XMSelectionListener disp = (XMSelectionListener) iter
315: .next();
316: disp
317: .selectionChanged(screen, this ,
318: ev.get_window(), ev);
319: }
320: }
321: }
322:
323: synchronized void dispatchOwnerDeath(XDestroyWindowEvent de,
324: int screen) {
325: if (log.isLoggable(Level.FINE))
326: log
327: .fine("Owner dead : Screen = " + screen + "Event ="
328: + de);
329: if (listeners != null) {
330: Iterator iter = listeners.iterator();
331: while (iter.hasNext()) {
332: XMSelectionListener disp = (XMSelectionListener) iter
333: .next();
334: disp.ownerDeath(screen, this , de.get_window());
335:
336: }
337: }
338: }
339:
340: void dispatchSelectionEvent(XEvent xev, int screen) {
341: if (log.isLoggable(Level.FINE))
342: log.fine("Event =" + xev);
343: if (xev.get_type() == XlibWrapper.DestroyNotify) {
344: XDestroyWindowEvent de = xev.get_xdestroywindow();
345: dispatchOwnerDeath(de, screen);
346: } else if (xev.get_type() == XlibWrapper.PropertyNotify) {
347: XPropertyEvent xpe = xev.get_xproperty();
348: dispatchSelectionChanged(xpe, screen);
349: }
350: }
351:
352: synchronized void dispatchOwnerChangedEvent(XEvent ev, int screen,
353: long owner, long data, long timestamp) {
354: if (listeners != null) {
355: Iterator iter = listeners.iterator();
356: while (iter.hasNext()) {
357: XMSelectionListener disp = (XMSelectionListener) iter
358: .next();
359: disp.ownerChanged(screen, this, owner, data, timestamp);
360: }
361: }
362: }
363:
364: }
|