/* * Copyright 2003-2004 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. */ package sun.awt; import java.awt.Color; import java.io.UnsupportedEncodingException; import java.util.HashMap; import java.util.Map; /** * Per-screen XSETTINGS. */ public class XSettings { /** */ private long serial = -1; /** * Update these settings with <code>data</code> obtained from * XSETTINGS manager. * * @param data settings data obtained from * <code>_XSETTINGS_SETTINGS</code> window property of the * settings manager. * @return a <code>Map</code> of changed settings. */ public Map update(byte[] data) { return (new Update(data)).update(); } /** * TBS ... */ class Update { /* byte order mark */ private static final int LITTLE_ENDIAN = 0; private static final int BIG_ENDIAN = 1; /* setting type */ private static final int TYPE_INTEGER = 0; private static final int TYPE_STRING = 1; private static final int TYPE_COLOR = 2; private byte[] data; private int dlen; private int idx; private boolean isLittle; private long serial = -1; private int nsettings = 0; private boolean isValid; private HashMap updatedSettings; /** * Construct an Update object for the data read from * <code>_XSETTINGS_SETTINGS</code> property of the XSETTINGS * selection owner. * * @param data <code>_XSETTINGS_SETTINGS</code> contents. */ Update(byte[] data) { this.data = data; dlen = data.length; if (dlen < 12) { // XXX: debug trace? return; } // first byte gives endianness of the data // next 3 bytes are unused (pad to 32 bit) idx = 0; isLittle = (getCARD8() == LITTLE_ENDIAN); idx = 4; serial = getCARD32(); // N_SETTINGS is actually CARD32 (i.e. unsigned), but // since java doesn't have an unsigned int type, and // N_SETTINGS cannot realistically exceed 2^31 (so we // gonna use int anyway), just read it as INT32. idx = 8; nsettings = getINT32(); updatedSettings = new HashMap(); isValid = true; } private void needBytes(int n) throws IndexOutOfBoundsException { if (idx + n <= dlen) { return; } throw new IndexOutOfBoundsException("at " + idx + " need " + n + " length " + dlen); } private int getCARD8() throws IndexOutOfBoundsException { needBytes(1); int val = data[idx] & 0xff; ++idx; return val; } private int getCARD16() throws IndexOutOfBoundsException { needBytes(2); int val; if (isLittle) { val = ((data[idx + 0] & 0xff) ) | ((data[idx + 1] & 0xff) << 8); } else { val = ((data[idx + 0] & 0xff) << 8) | ((data[idx + 1] & 0xff) ); } idx += 2; return val; } private int getINT32() throws IndexOutOfBoundsException { needBytes(4); int val; if (isLittle) { val = ((data[idx + 0] & 0xff) ) | ((data[idx + 1] & 0xff) << 8) | ((data[idx + 2] & 0xff) << 16) | ((data[idx + 3] & 0xff) << 24); } 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 }