XSettings.java revision 2362
0N/A/*
0N/A * Copyright (c) 2003, 2004, Oracle and/or its affiliates. All rights reserved.
0N/A * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
0N/A *
0N/A * This code is free software; you can redistribute it and/or modify it
0N/A * under the terms of the GNU General Public License version 2 only, as
0N/A * published by the Free Software Foundation. Oracle designates this
0N/A * particular file as subject to the "Classpath" exception as provided
0N/A * by Oracle in the LICENSE file that accompanied this code.
0N/A *
0N/A * This code is distributed in the hope that it will be useful, but WITHOUT
0N/A * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
0N/A * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
0N/A * version 2 for more details (a copy is included in the LICENSE file that
0N/A * accompanied this code).
0N/A *
0N/A * You should have received a copy of the GNU General Public License version
0N/A * 2 along with this work; if not, write to the Free Software Foundation,
0N/A * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
0N/A *
0N/A * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
0N/A * or visit www.oracle.com if you need additional information or have any
0N/A * questions.
0N/A */
0N/A
0N/Apackage sun.awt;
0N/A
0N/Aimport java.awt.Color;
0N/A
0N/Aimport java.io.UnsupportedEncodingException;
0N/A
0N/Aimport java.util.HashMap;
0N/Aimport java.util.Map;
0N/A
0N/A
0N/A/**
0N/A * Per-screen XSETTINGS.
0N/A */
0N/Apublic class XSettings {
0N/A
0N/A /**
0N/A */
0N/A private long serial = -1;
0N/A
0N/A
0N/A /**
0N/A * Update these settings with <code>data</code> obtained from
0N/A * XSETTINGS manager.
0N/A *
0N/A * @param data settings data obtained from
0N/A * <code>_XSETTINGS_SETTINGS</code> window property of the
0N/A * settings manager.
0N/A * @return a <code>Map</code> of changed settings.
0N/A */
0N/A public Map update(byte[] data) {
0N/A return (new Update(data)).update();
0N/A }
0N/A
0N/A
0N/A /**
0N/A * TBS ...
0N/A */
0N/A class Update {
0N/A
0N/A /* byte order mark */
0N/A private static final int LITTLE_ENDIAN = 0;
0N/A private static final int BIG_ENDIAN = 1;
0N/A
0N/A /* setting type */
0N/A private static final int TYPE_INTEGER = 0;
0N/A private static final int TYPE_STRING = 1;
0N/A private static final int TYPE_COLOR = 2;
0N/A
0N/A private byte[] data;
0N/A private int dlen;
0N/A private int idx;
0N/A private boolean isLittle;
0N/A private long serial = -1;
0N/A private int nsettings = 0;
0N/A private boolean isValid;
0N/A
0N/A private HashMap updatedSettings;
0N/A
0N/A
0N/A /**
0N/A * Construct an Update object for the data read from
0N/A * <code>_XSETTINGS_SETTINGS</code> property of the XSETTINGS
0N/A * selection owner.
0N/A *
0N/A * @param data <code>_XSETTINGS_SETTINGS</code> contents.
0N/A */
0N/A Update(byte[] data) {
0N/A this.data = data;
0N/A
0N/A dlen = data.length;
0N/A if (dlen < 12) {
0N/A // XXX: debug trace?
0N/A return;
0N/A }
0N/A
0N/A // first byte gives endianness of the data
0N/A // next 3 bytes are unused (pad to 32 bit)
0N/A idx = 0;
0N/A isLittle = (getCARD8() == LITTLE_ENDIAN);
0N/A
0N/A idx = 4;
0N/A serial = getCARD32();
0N/A
0N/A // N_SETTINGS is actually CARD32 (i.e. unsigned), but
0N/A // since java doesn't have an unsigned int type, and
0N/A // N_SETTINGS cannot realistically exceed 2^31 (so we
0N/A // gonna use int anyway), just read it as INT32.
0N/A idx = 8;
0N/A nsettings = getINT32();
0N/A
0N/A updatedSettings = new HashMap();
0N/A
0N/A isValid = true;
0N/A }
0N/A
0N/A
0N/A private void needBytes(int n)
0N/A throws IndexOutOfBoundsException
0N/A {
0N/A if (idx + n <= dlen) {
0N/A return;
0N/A }
0N/A
0N/A throw new IndexOutOfBoundsException("at " + idx
0N/A + " need " + n
0N/A + " length " + dlen);
0N/A }
0N/A
0N/A
0N/A private int getCARD8()
0N/A throws IndexOutOfBoundsException
0N/A {
0N/A needBytes(1);
0N/A
0N/A int val = data[idx] & 0xff;
0N/A
0N/A ++idx;
0N/A return val;
0N/A }
0N/A
0N/A
0N/A private int getCARD16()
0N/A throws IndexOutOfBoundsException
0N/A {
0N/A needBytes(2);
0N/A
0N/A int val;
0N/A if (isLittle) {
0N/A val = ((data[idx + 0] & 0xff) )
0N/A | ((data[idx + 1] & 0xff) << 8);
0N/A } else {
0N/A val = ((data[idx + 0] & 0xff) << 8)
0N/A | ((data[idx + 1] & 0xff) );
0N/A }
0N/A
0N/A idx += 2;
0N/A return val;
0N/A }
0N/A
0N/A
0N/A private int getINT32()
0N/A throws IndexOutOfBoundsException
0N/A {
0N/A needBytes(4);
0N/A
0N/A int val;
0N/A if (isLittle) {
0N/A val = ((data[idx + 0] & 0xff) )
0N/A | ((data[idx + 1] & 0xff) << 8)
0N/A | ((data[idx + 2] & 0xff) << 16)
0N/A | ((data[idx + 3] & 0xff) << 24);
0N/A } else {
val = ((data[idx + 0] & 0xff) << 24)
| ((data[idx + 1] & 0xff) << 16)
| ((data[idx + 2] & 0xff) << 8)
| ((data[idx + 3] & 0xff) << 0);
}
idx += 4;
return val;
}
private long getCARD32()
throws IndexOutOfBoundsException
{
return getINT32() & 0x00000000ffffffffL;
}
private String getString(int len)
throws IndexOutOfBoundsException
{
needBytes(len);
String str = null;
try {
str = new String(data, idx, len, "UTF-8");
} catch (UnsupportedEncodingException e) {
// XXX: cannot happen, "UTF-8" is always supported
}
idx = (idx + len + 3) & ~0x3;
return str;
}
/**
* Update settings.
*/
public Map update() {
if (!isValid) {
return null;
}
synchronized (XSettings.this) {
long currentSerial = XSettings.this.serial;
if (this.serial <= currentSerial) {
return null;
}
for (int i = 0; i < nsettings && idx < dlen; ++i) {
updateOne(currentSerial);
}
XSettings.this.serial = this.serial;
}
return updatedSettings;
}
/**
* Parses a particular x setting.
*
* @exception IndexOutOfBoundsException if there isn't enough
* data for a setting.
*/
private void updateOne(long currentSerial)
throws IndexOutOfBoundsException,
IllegalArgumentException
{
int type = getCARD8();
++idx; // pad to next CARD16
// save position of the property name, skip to serial
int nameLen = getCARD16();
int nameIdx = idx;
// check if we should bother
idx = (idx + nameLen + 3) & ~0x3; // pad to 32 bit
long lastChanged = getCARD32();
// Avoid constructing garbage for properties that has not
// changed, skip the data for this property.
if (lastChanged <= currentSerial) { // skip
if (type == TYPE_INTEGER) {
idx += 4;
} else if (type == TYPE_STRING) {
int len = getINT32();
idx = (idx + len + 3) & ~0x3;
} else if (type == TYPE_COLOR) {
idx += 8; // 4 CARD16
} else {
throw new IllegalArgumentException("Unknown type: "
+ type);
}
return;
}
idx = nameIdx;
String name = getString(nameLen);
idx += 4; // skip serial, parsed above
Object value = null;
if (type == TYPE_INTEGER) {
value = Integer.valueOf(getINT32());
}
else if (type == TYPE_STRING) {
value = getString(getINT32());
}
else if (type == TYPE_COLOR) {
int r = getCARD16();
int g = getCARD16();
int b = getCARD16();
int a = getCARD16();
value = new Color(r / 65535.0f,
g / 65535.0f,
b / 65535.0f,
a / 65535.0f);
}
else {
throw new IllegalArgumentException("Unknown type: " + type);
}
if (name == null) {
// dtrace???
return;
}
updatedSettings.put(name, value);
}
} // class XSettings.Update
}