0N/A/*
2362N/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
2362N/A * published by the Free Software Foundation. Oracle designates this
0N/A * particular file as subject to the "Classpath" exception as provided
2362N/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 *
2362N/A * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
2362N/A * or visit www.oracle.com if you need additional information or have any
2362N/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 {
0N/A val = ((data[idx + 0] & 0xff) << 24)
0N/A | ((data[idx + 1] & 0xff) << 16)
0N/A | ((data[idx + 2] & 0xff) << 8)
0N/A | ((data[idx + 3] & 0xff) << 0);
0N/A }
0N/A
0N/A idx += 4;
0N/A return val;
0N/A }
0N/A
0N/A
0N/A private long getCARD32()
0N/A throws IndexOutOfBoundsException
0N/A {
0N/A return getINT32() & 0x00000000ffffffffL;
0N/A }
0N/A
0N/A
0N/A private String getString(int len)
0N/A throws IndexOutOfBoundsException
0N/A {
0N/A needBytes(len);
0N/A
0N/A String str = null;
0N/A try {
0N/A str = new String(data, idx, len, "UTF-8");
0N/A } catch (UnsupportedEncodingException e) {
0N/A // XXX: cannot happen, "UTF-8" is always supported
0N/A }
0N/A
0N/A idx = (idx + len + 3) & ~0x3;
0N/A return str;
0N/A }
0N/A
0N/A
0N/A /**
0N/A * Update settings.
0N/A */
0N/A public Map update() {
0N/A if (!isValid) {
0N/A return null;
0N/A }
0N/A
0N/A synchronized (XSettings.this) {
0N/A long currentSerial = XSettings.this.serial;
0N/A
0N/A if (this.serial <= currentSerial) {
0N/A return null;
0N/A }
0N/A
0N/A for (int i = 0; i < nsettings && idx < dlen; ++i) {
0N/A updateOne(currentSerial);
0N/A }
0N/A
0N/A XSettings.this.serial = this.serial;
0N/A }
0N/A
0N/A return updatedSettings;
0N/A }
0N/A
0N/A
0N/A /**
0N/A * Parses a particular x setting.
0N/A *
0N/A * @exception IndexOutOfBoundsException if there isn't enough
0N/A * data for a setting.
0N/A */
0N/A private void updateOne(long currentSerial)
0N/A throws IndexOutOfBoundsException,
0N/A IllegalArgumentException
0N/A {
0N/A int type = getCARD8();
0N/A ++idx; // pad to next CARD16
0N/A
0N/A // save position of the property name, skip to serial
0N/A int nameLen = getCARD16();
0N/A int nameIdx = idx;
0N/A
0N/A // check if we should bother
0N/A idx = (idx + nameLen + 3) & ~0x3; // pad to 32 bit
0N/A long lastChanged = getCARD32();
0N/A
0N/A // Avoid constructing garbage for properties that has not
0N/A // changed, skip the data for this property.
0N/A if (lastChanged <= currentSerial) { // skip
0N/A if (type == TYPE_INTEGER) {
0N/A idx += 4;
0N/A } else if (type == TYPE_STRING) {
0N/A int len = getINT32();
0N/A idx = (idx + len + 3) & ~0x3;
0N/A } else if (type == TYPE_COLOR) {
0N/A idx += 8; // 4 CARD16
0N/A } else {
0N/A throw new IllegalArgumentException("Unknown type: "
0N/A + type);
0N/A }
0N/A
0N/A return;
0N/A }
0N/A
0N/A idx = nameIdx;
0N/A String name = getString(nameLen);
0N/A idx += 4; // skip serial, parsed above
0N/A
0N/A Object value = null;
0N/A if (type == TYPE_INTEGER) {
0N/A value = Integer.valueOf(getINT32());
0N/A }
0N/A else if (type == TYPE_STRING) {
0N/A value = getString(getINT32());
0N/A }
0N/A else if (type == TYPE_COLOR) {
0N/A int r = getCARD16();
0N/A int g = getCARD16();
0N/A int b = getCARD16();
0N/A int a = getCARD16();
0N/A
0N/A value = new Color(r / 65535.0f,
0N/A g / 65535.0f,
0N/A b / 65535.0f,
0N/A a / 65535.0f);
0N/A }
0N/A else {
0N/A throw new IllegalArgumentException("Unknown type: " + type);
0N/A }
0N/A
0N/A if (name == null) {
0N/A // dtrace???
0N/A return;
0N/A }
0N/A
0N/A updatedSettings.put(name, value);
0N/A }
0N/A
0N/A } // class XSettings.Update
0N/A}