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;
  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;
  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     }
  75     public int execute() {
  76         return execute(null);
  77     }
  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 
 123     public boolean isExecuted() {
 124         return executed;
 125     }
 126 
 127     public boolean isDisposed() {
 128         return disposer.disposed;
 129     }
 130 
 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     }
 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     }
 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     }
 158     public long getData() {
 159         if (isDisposed()) {
 160             throw new IllegalStateException("Disposed");
 161         }
 162         return Native.getLong(data);
 163     }
 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     }
 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 
 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 
 192     static boolean isCacheableProperty(XAtom property) {
 193         return cacheableProperties.contains(property);
 194     }
 195 
 196     boolean isCached() {
 197         return XPropertyCache.isCached(window, property);
 198     }
 199 
 200     int getDataLength() {
 201         return getActualFormat() / 8 * getNumberOfItems();
 202     }
 203 
 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 
 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 }