/*
* Copyright 2003-2007 Sun Microsystems, Inc. All Rights Reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Sun designates this
* particular file as subject to the "Classpath" exception as provided
* by Sun in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
* CA 95054 USA or visit www.sun.com if you need additional information or
* have any questions.
*/
/*
* This code is ported to XAWT from MAWT based on awt_mgrsel.c
* code written originally by Valeriy Ushakov
* Author : Bino George
*/
package sun.awt.X11;
import java.util.*;
import java.util.logging.*;
public class XMSelection {
/*
* A method for a subsytem to express its interest in a certain
* manager selection.
*
* If owner changes, the ownerChanged of the XMSelectionListener
* will be called with the screen
* number and the new owning window when onwership is established, or
* None if the owner is gone.
*
* Events in extra_mask are selected for on owning windows (exsiting
* ones and on new owners when established) and otherEvent of the
* XMWSelectionListener will be called with the screen number and an event.
*
* The function returns an array of current owners. The size of the
* array is ScreenCount(awt_display). The array is "owned" by this
* module and should be considered by the caller as read-only.
*/
private static Logger log = Logger.getLogger("sun.awt.X11.XMSelection");
/* Name of the selection */
String selectionName;
/* list of listeners to be called for events */
Vector listeners;
/* X atom array (one per screen) for this selection */
XAtom atoms[];
/* Window ids of selection owners */
long owners[];
/* event mask to set */
long eventMask;
static int numScreens;
static XAtom XA_MANAGER;
static HashMap selectionMap;
static {
long display = XToolkit.getDisplay();
XToolkit.awtLock();
try {
numScreens = XlibWrapper.ScreenCount(display);
} finally {
XToolkit.awtUnlock();
}
XA_MANAGER = XAtom.get("MANAGER");
for (int screen = 0; screen < numScreens ; screen ++) {
initScreen(display,screen);
}
selectionMap = new HashMap();
}
static void initScreen(long display, final int screen) {
XToolkit.awtLock();
try {
long root = XlibWrapper.RootWindow(display,screen);
XlibWrapper.XSelectInput(display, root, XlibWrapper.StructureNotifyMask);
XToolkit.addEventDispatcher(root,
new XEventDispatcher() {
public void dispatchEvent(XEvent ev) {
processRootEvent(ev, screen);
}
});
} finally {
XToolkit.awtUnlock();
}
}
public int getNumberOfScreens() {
return numScreens;
}
void select(long extra_mask) {
eventMask = extra_mask;
for (int screen = 0; screen < numScreens ; screen ++) {
selectPerScreen(screen,extra_mask);
}
}
void resetOwner(long owner, final int screen) {
XToolkit.awtLock();
try {
long display = XToolkit.getDisplay();
synchronized(this) {
setOwner(owner, screen);
if (log.isLoggable(Level.FINE)) log.fine("New Selection Owner for screen " + screen + " = " + owner );
XlibWrapper.XSelectInput(display, owner, XlibWrapper.StructureNotifyMask | eventMask);
XToolkit.addEventDispatcher(owner,
new XEventDispatcher() {
public void dispatchEvent(XEvent ev) {
dispatchSelectionEvent(ev, screen);
}
});
}
} finally {
XToolkit.awtUnlock();
}
}
void selectPerScreen(final int screen, long extra_mask) {
XToolkit.awtLock();
try {
try {
long display = XToolkit.getDisplay();
if (log.isLoggable(Level.FINE)) log.fine("Grabbing XServer");
XlibWrapper.XGrabServer(display);
synchronized(this) {
String selection_name = getName()+"_S"+screen;
if (log.isLoggable(Level.FINE)) log.fine("Screen = " + screen + " selection name = " + selection_name);
XAtom atom = XAtom.get(selection_name);
selectionMap.put(Long.valueOf(atom.getAtom()),this); // add mapping from atom to the instance of XMSelection
setAtom(atom,screen);
long owner = XlibWrapper.XGetSelectionOwner(display, atom.getAtom());
if (owner != 0) {
setOwner(owner, screen);
if (log.isLoggable(Level.FINE)) log.fine("Selection Owner for screen " + screen + " = " + owner );
XlibWrapper.XSelectInput(display, owner, XlibWrapper.StructureNotifyMask | extra_mask);
XToolkit.addEventDispatcher(owner,
new XEventDispatcher() {
public void dispatchEvent(XEvent ev) {
dispatchSelectionEvent(ev, screen);
}
});
}
}
}
catch (Exception e) {
e.printStackTrace();
}
finally {
if (log.isLoggable(Level.FINE)) log.fine("UnGrabbing XServer");
XlibWrapper.XUngrabServer(XToolkit.getDisplay());
}
} finally {
XToolkit.awtUnlock();
}
}
static boolean processClientMessage(XEvent xev, int screen) {
XClientMessageEvent xce = xev.get_xclient();
if (xce.get_message_type() == XA_MANAGER.getAtom()) {
if (log.isLoggable(Level.FINE)) log.fine("client messags = " + xce);
long timestamp = xce.get_data(0);
long atom = xce.get_data(1);
long owner = xce.get_data(2);
long data = xce.get_data(3);
XMSelection sel = getInstance(atom);
if (sel != null) {
sel.resetOwner(owner,screen);
sel.dispatchOwnerChangedEvent(xev,screen,owner,data, timestamp);
}
}
return false;
}
static boolean processRootEvent(XEvent xev, int screen) {
switch (xev.get_type()) {
case XlibWrapper.ClientMessage: {
return processClientMessage(xev, screen);
}
}
return false;
}
static XMSelection getInstance(long selection) {
return (XMSelection) selectionMap.get(Long.valueOf(selection));
}
/*
* Default constructor specifies PropertyChangeMask as well
*/
public XMSelection (String selname) {
this(selname, XlibWrapper.PropertyChangeMask);
}
/*
* Some users may not need to know about selection changes,
* just owner ship changes, They would specify a zero extra mask.
*/
public XMSelection (String selname, long extraMask) {
synchronized (this) {
selectionName = selname;
atoms = new XAtom[getNumberOfScreens()];
owners = new long[getNumberOfScreens()];
}
select(extraMask);
}
public synchronized void addSelectionListener(XMSelectionListener listener) {
if (listeners == null) {
listeners = new Vector();
}
listeners.add(listener);
}
public synchronized void removeSelectionListener(XMSelectionListener listener) {
if (listeners != null) {
listeners.remove(listener);
}
}
synchronized Collection getListeners() {
return listeners;
}
synchronized XAtom getAtom(int screen) {
if (atoms != null) {
return atoms[screen];
}
return null;
}
synchronized void setAtom(XAtom a, int screen) {
if (atoms != null) {
atoms[screen] = a;
}
}
synchronized long getOwner(int screen) {
if (owners != null) {
return owners[screen];
}
return 0;
}
synchronized void setOwner(long owner, int screen) {
if (owners != null) {
owners[screen] = owner;
}
}
synchronized String getName() {
return selectionName;
}
synchronized void dispatchSelectionChanged( XPropertyEvent ev, int screen) {
if (log.isLoggable(Level.FINE)) log.fine("Selection Changed : Screen = " + screen + "Event =" + ev);
if (listeners != null) {
Iterator iter = listeners.iterator();
while (iter.hasNext()) {
XMSelectionListener disp = (XMSelectionListener) iter.next();
disp.selectionChanged(screen, this, ev.get_window(), ev);
}
}
}
synchronized void dispatchOwnerDeath(XDestroyWindowEvent de, int screen) {
if (log.isLoggable(Level.FINE)) log.fine("Owner dead : Screen = " + screen + "Event =" + de);
if (listeners != null) {
Iterator iter = listeners.iterator();
while (iter.hasNext()) {
XMSelectionListener disp = (XMSelectionListener) iter.next();
disp.ownerDeath(screen, this, de.get_window());
}
}
}
void dispatchSelectionEvent(XEvent xev, int screen) {
if (log.isLoggable(Level.FINE)) log.fine("Event =" + xev);
if (xev.get_type() == XlibWrapper.DestroyNotify) {
XDestroyWindowEvent de = xev.get_xdestroywindow();
dispatchOwnerDeath( de, screen);
}
else if (xev.get_type() == XlibWrapper.PropertyNotify) {
XPropertyEvent xpe = xev.get_xproperty();
dispatchSelectionChanged( xpe, screen);
}
}
synchronized void dispatchOwnerChangedEvent(XEvent ev, int screen, long owner, long data, long timestamp) {
if (listeners != null) {
Iterator iter = listeners.iterator();
while (iter.hasNext()) {
XMSelectionListener disp = (XMSelectionListener) iter.next();
disp.ownerChanged(screen,this, owner, data, timestamp);
}
}
}
}