1 /*
2  * Copyright (c) 2003, 2013, Oracle and/or its affiliates. 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.  Oracle designates this
8  * particular file as subject to the "Classpath" exception as provided
9  * by Oracle 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22  * or visit www.oracle.com if you need additional information or have any
23  * questions.
24  */
25 
26 package sun.awt.X11;
27 
28 import java.util.*;
29 import jdk.internal.misc.Unsafe;
30 
31 public class WindowPropertyGetter {
32     private static Unsafe unsafe = XlibWrapper.unsafe;
33     private final long actual_type = unsafe.allocateMemory(8);
34     private final long actual_format = unsafe.allocateMemory(4);
35     private final long nitems_ptr = unsafe.allocateMemory(8);
36     private final long bytes_after = unsafe.allocateMemory(8);
37     private final long data = unsafe.allocateMemory(8);
38     private final long window;
39     private final XAtom property;
40     private final long offset;
41     private final long length;
42     private final boolean auto_delete;
43     private final long type;
44     private boolean executed = false;
WindowPropertyGetter(long window, XAtom property, long offset, long length, boolean auto_delete, long type)45     public WindowPropertyGetter(long window, XAtom property, long offset,
46                                 long length, boolean auto_delete, long type)
47     {
48         if (property.getAtom() == 0) {
49             throw new IllegalArgumentException("Property ATOM should be initialized first:" + property);
50         }
51         // Zero is AnyPropertyType.
52         // if (type == 0) {
53         //     throw new IllegalArgumentException("Type ATOM shouldn't be zero");
54         // }
55         if (window == 0) {
56             throw new IllegalArgumentException("Window must not be zero");
57         }
58         this.window = window;
59         this.property = property;
60         this.offset = offset;
61         this.length = length;
62         this.auto_delete = auto_delete;
63         this.type = type;
64 
65         Native.putLong(data, 0);
66         sun.java2d.Disposer.addRecord(this, disposer = new UnsafeXDisposerRecord("WindowPropertyGetter", new long[] {actual_type,
67                                                                                  actual_format, nitems_ptr, bytes_after}, new long[] {data}));
68     }
69     UnsafeXDisposerRecord disposer;
WindowPropertyGetter(long window, XAtom property, long offset, long length, boolean auto_delete, XAtom type)70     public WindowPropertyGetter(long window, XAtom property, long offset,
71                                 long length, boolean auto_delete, XAtom type)
72     {
73         this(window, property, offset, length, auto_delete, type.getAtom());
74     }
execute()75     public int execute() {
76         return execute(null);
77     }
execute(XErrorHandler errorHandler)78     public int execute(XErrorHandler errorHandler) {
79 
80         XToolkit.awtLock();
81         try {
82             if (isDisposed()) {
83                 throw new IllegalStateException("Disposed");
84             }
85             if (executed) {
86                 throw new IllegalStateException("Already executed");
87             }
88             executed = true;
89 
90             if (isCachingSupported() && isCached()) {
91                 readFromCache();
92                 return XConstants.Success;
93             }
94 
95             // Fix for performance problem - IgnodeBadWindowHandler is
96             // used too much without reason, just ignore it
97             if (errorHandler instanceof XErrorHandler.IgnoreBadWindowHandler) {
98                 errorHandler = null;
99             }
100 
101             if (errorHandler != null) {
102                 XErrorHandlerUtil.WITH_XERROR_HANDLER(errorHandler);
103             }
104             Native.putLong(data, 0);
105             int status = XlibWrapper.XGetWindowProperty(XToolkit.getDisplay(), window, property.getAtom(),
106                                                         offset, length, (auto_delete?1:0), type,
107                                                         actual_type, actual_format, nitems_ptr,
108                                                         bytes_after, data);
109             if (isCachingSupported() &&  status == XConstants.Success && getData() != 0 && isCacheableProperty(property)) {
110                 // Property has some data, we cache them
111                 cacheProperty();
112             }
113 
114             if (errorHandler != null) {
115                 XErrorHandlerUtil.RESTORE_XERROR_HANDLER();
116             }
117             return status;
118         } finally {
119             XToolkit.awtUnlock();
120         }
121     }
122 
isExecuted()123     public boolean isExecuted() {
124         return executed;
125     }
126 
isDisposed()127     public boolean isDisposed() {
128         return disposer.disposed;
129     }
130 
getActualFormat()131     public int getActualFormat() {
132         if (isDisposed()) {
133             throw new IllegalStateException("Disposed");
134         }
135         if (!executed) {
136             throw new IllegalStateException("Not executed");
137         }
138         return unsafe.getInt(actual_format);
139     }
getActualType()140     public long getActualType() {
141         if (isDisposed()) {
142             throw new IllegalStateException("Disposed");
143         }
144         if (!executed) {
145             throw new IllegalStateException("Not executed");
146         }
147         return XAtom.getAtom(actual_type);
148     }
getNumberOfItems()149     public int getNumberOfItems() {
150         if (isDisposed()) {
151             throw new IllegalStateException("Disposed");
152         }
153         if (!executed) {
154             throw new IllegalStateException("Not executed");
155         }
156         return (int)Native.getLong(nitems_ptr);
157     }
getData()158     public long getData() {
159         if (isDisposed()) {
160             throw new IllegalStateException("Disposed");
161         }
162         return Native.getLong(data);
163     }
getBytesAfter()164     public long getBytesAfter() {
165         if (isDisposed()) {
166             throw new IllegalStateException("Disposed");
167         }
168         if (!executed) {
169             throw new IllegalStateException("Not executed");
170         }
171         return Native.getLong(bytes_after);
172     }
dispose()173     public void dispose() {
174         XToolkit.awtLock();
175         try {
176             if (isDisposed()) {
177                 return;
178             }
179             disposer.dispose();
180         } finally {
181             XToolkit.awtUnlock();
182         }
183     }
184 
isCachingSupported()185     static boolean isCachingSupported() {
186         return XPropertyCache.isCachingSupported();
187     }
188 
189     static Set<XAtom> cacheableProperties = new HashSet<XAtom>(Arrays.asList(new XAtom[] {
190             XAtom.get("_NET_WM_STATE"), XAtom.get("WM_STATE"), XAtom.get("_MOTIF_WM_HINTS")}));
191 
isCacheableProperty(XAtom property)192     static boolean isCacheableProperty(XAtom property) {
193         return cacheableProperties.contains(property);
194     }
195 
isCached()196     boolean isCached() {
197         return XPropertyCache.isCached(window, property);
198     }
199 
getDataLength()200     int getDataLength() {
201         return getActualFormat() / 8 * getNumberOfItems();
202     }
203 
readFromCache()204     void readFromCache() {
205         property.putAtom(actual_type);
206         XPropertyCache.PropertyCacheEntry entry = XPropertyCache.getCacheEntry(window, property);
207         Native.putInt(actual_format, entry.getFormat());
208         Native.putLong(nitems_ptr, entry.getNumberOfItems());
209         Native.putLong(bytes_after, entry.getBytesAfter());
210         Native.putLong(data, unsafe.allocateMemory(getDataLength()));
211         XlibWrapper.memcpy(getData(), entry.getData(), getDataLength());
212     }
213 
cacheProperty()214     void cacheProperty() {
215         XPropertyCache.storeCache(
216             new XPropertyCache.PropertyCacheEntry(getActualFormat(),
217                                                   getNumberOfItems(),
218                                                   getBytesAfter(),
219                                                   getData(),
220                                                   getDataLength()),
221             window,
222             property);
223     }
224 
225 }
226