blob: 500545ec0d1abb06eb697f4e2e3fd7061306a72b [file] [log] [blame]
J. Duke319a3b92007-12-01 00:00:00 +00001/*
2 * Copyright 2003-2004 Sun Microsystems, Inc. All Rights Reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation. Sun designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Sun in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
22 * CA 95054 USA or visit www.sun.com if you need additional information or
23 * have any questions.
24 */
25
26package sun.awt;
27
28import java.awt.Color;
29
30import java.io.UnsupportedEncodingException;
31
32import java.util.HashMap;
33import java.util.Map;
34
35
36/**
37 * Per-screen XSETTINGS.
38 */
39public class XSettings {
40
41 /**
42 */
43 private long serial = -1;
44
45
46 /**
47 * Update these settings with <code>data</code> obtained from
48 * XSETTINGS manager.
49 *
50 * @param data settings data obtained from
51 * <code>_XSETTINGS_SETTINGS</code> window property of the
52 * settings manager.
53 * @return a <code>Map</code> of changed settings.
54 */
55 public Map update(byte[] data) {
56 return (new Update(data)).update();
57 }
58
59
60 /**
61 * TBS ...
62 */
63 class Update {
64
65 /* byte order mark */
66 private static final int LITTLE_ENDIAN = 0;
67 private static final int BIG_ENDIAN = 1;
68
69 /* setting type */
70 private static final int TYPE_INTEGER = 0;
71 private static final int TYPE_STRING = 1;
72 private static final int TYPE_COLOR = 2;
73
74 private byte[] data;
75 private int dlen;
76 private int idx;
77 private boolean isLittle;
78 private long serial = -1;
79 private int nsettings = 0;
80 private boolean isValid;
81
82 private HashMap updatedSettings;
83
84
85 /**
86 * Construct an Update object for the data read from
87 * <code>_XSETTINGS_SETTINGS</code> property of the XSETTINGS
88 * selection owner.
89 *
90 * @param data <code>_XSETTINGS_SETTINGS</code> contents.
91 */
92 Update(byte[] data) {
93 this.data = data;
94
95 dlen = data.length;
96 if (dlen < 12) {
97 // XXX: debug trace?
98 return;
99 }
100
101 // first byte gives endianness of the data
102 // next 3 bytes are unused (pad to 32 bit)
103 idx = 0;
104 isLittle = (getCARD8() == LITTLE_ENDIAN);
105
106 idx = 4;
107 serial = getCARD32();
108
109 // N_SETTINGS is actually CARD32 (i.e. unsigned), but
110 // since java doesn't have an unsigned int type, and
111 // N_SETTINGS cannot realistically exceed 2^31 (so we
112 // gonna use int anyway), just read it as INT32.
113 idx = 8;
114 nsettings = getINT32();
115
116 updatedSettings = new HashMap();
117
118 isValid = true;
119 }
120
121
122 private void needBytes(int n)
123 throws IndexOutOfBoundsException
124 {
125 if (idx + n <= dlen) {
126 return;
127 }
128
129 throw new IndexOutOfBoundsException("at " + idx
130 + " need " + n
131 + " length " + dlen);
132 }
133
134
135 private int getCARD8()
136 throws IndexOutOfBoundsException
137 {
138 needBytes(1);
139
140 int val = data[idx] & 0xff;
141
142 ++idx;
143 return val;
144 }
145
146
147 private int getCARD16()
148 throws IndexOutOfBoundsException
149 {
150 needBytes(2);
151
152 int val;
153 if (isLittle) {
154 val = ((data[idx + 0] & 0xff) )
155 | ((data[idx + 1] & 0xff) << 8);
156 } else {
157 val = ((data[idx + 0] & 0xff) << 8)
158 | ((data[idx + 1] & 0xff) );
159 }
160
161 idx += 2;
162 return val;
163 }
164
165
166 private int getINT32()
167 throws IndexOutOfBoundsException
168 {
169 needBytes(4);
170
171 int val;
172 if (isLittle) {
173 val = ((data[idx + 0] & 0xff) )
174 | ((data[idx + 1] & 0xff) << 8)
175 | ((data[idx + 2] & 0xff) << 16)
176 | ((data[idx + 3] & 0xff) << 24);
177 } else {
178 val = ((data[idx + 0] & 0xff) << 24)
179 | ((data[idx + 1] & 0xff) << 16)
180 | ((data[idx + 2] & 0xff) << 8)
181 | ((data[idx + 3] & 0xff) << 0);
182 }
183
184 idx += 4;
185 return val;
186 }
187
188
189 private long getCARD32()
190 throws IndexOutOfBoundsException
191 {
192 return getINT32() & 0x00000000ffffffffL;
193 }
194
195
196 private String getString(int len)
197 throws IndexOutOfBoundsException
198 {
199 needBytes(len);
200
201 String str = null;
202 try {
203 str = new String(data, idx, len, "UTF-8");
204 } catch (UnsupportedEncodingException e) {
205 // XXX: cannot happen, "UTF-8" is always supported
206 }
207
208 idx = (idx + len + 3) & ~0x3;
209 return str;
210 }
211
212
213 /**
214 * Update settings.
215 */
216 public Map update() {
217 if (!isValid) {
218 return null;
219 }
220
221 synchronized (XSettings.this) {
222 long currentSerial = XSettings.this.serial;
223
224 if (this.serial <= currentSerial) {
225 return null;
226 }
227
228 for (int i = 0; i < nsettings && idx < dlen; ++i) {
229 updateOne(currentSerial);
230 }
231
232 XSettings.this.serial = this.serial;
233 }
234
235 return updatedSettings;
236 }
237
238
239 /**
240 * Parses a particular x setting.
241 *
242 * @exception IndexOutOfBoundsException if there isn't enough
243 * data for a setting.
244 */
245 private void updateOne(long currentSerial)
246 throws IndexOutOfBoundsException,
247 IllegalArgumentException
248 {
249 int type = getCARD8();
250 ++idx; // pad to next CARD16
251
252 // save position of the property name, skip to serial
253 int nameLen = getCARD16();
254 int nameIdx = idx;
255
256 // check if we should bother
257 idx = (idx + nameLen + 3) & ~0x3; // pad to 32 bit
258 long lastChanged = getCARD32();
259
260 // Avoid constructing garbage for properties that has not
261 // changed, skip the data for this property.
262 if (lastChanged <= currentSerial) { // skip
263 if (type == TYPE_INTEGER) {
264 idx += 4;
265 } else if (type == TYPE_STRING) {
266 int len = getINT32();
267 idx = (idx + len + 3) & ~0x3;
268 } else if (type == TYPE_COLOR) {
269 idx += 8; // 4 CARD16
270 } else {
271 throw new IllegalArgumentException("Unknown type: "
272 + type);
273 }
274
275 return;
276 }
277
278 idx = nameIdx;
279 String name = getString(nameLen);
280 idx += 4; // skip serial, parsed above
281
282 Object value = null;
283 if (type == TYPE_INTEGER) {
284 value = Integer.valueOf(getINT32());
285 }
286 else if (type == TYPE_STRING) {
287 value = getString(getINT32());
288 }
289 else if (type == TYPE_COLOR) {
290 int r = getCARD16();
291 int g = getCARD16();
292 int b = getCARD16();
293 int a = getCARD16();
294
295 value = new Color(r / 65535.0f,
296 g / 65535.0f,
297 b / 65535.0f,
298 a / 65535.0f);
299 }
300 else {
301 throw new IllegalArgumentException("Unknown type: " + type);
302 }
303
304 if (name == null) {
305 // dtrace???
306 return;
307 }
308
309 updatedSettings.put(name, value);
310 }
311
312 } // class XSettings.Update
313}