Spec-Zone .ru
спецификации, руководства, описания, API
|
001/* 002 * Copyright (c) 2009, 2013, Oracle and/or its affiliates. All rights reserved. 003 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 004 * 005 * This code is free software; you can redistribute it and/or modify it 006 * under the terms of the GNU General Public License version 2 only, as 007 * published by the Free Software Foundation. Oracle designates this 008 * particular file as subject to the "Classpath" exception as provided 009 * by Oracle in the LICENSE file that accompanied this code. 010 * 011 * This code is distributed in the hope that it will be useful, but WITHOUT 012 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 013 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 014 * version 2 for more details (a copy is included in the LICENSE file that 015 * accompanied this code). 016 * 017 * You should have received a copy of the GNU General Public License version 018 * 2 along with this work; if not, write to the Free Software Foundation, 019 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 020 * 021 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 022 * or visit www.oracle.com if you need additional information or have any 023 * questions. 024 */ 025 026package javafx.stage; 027 028import java.util.List; 029import java.util.concurrent.atomic.AtomicBoolean; 030 031import javafx.collections.FXCollections; 032import javafx.collections.ObservableList; 033import javafx.geometry.Rectangle2D; 034 035import com.sun.javafx.tk.ScreenConfigurationAccessor; 036import com.sun.javafx.tk.TKScreenConfigurationListener; 037import com.sun.javafx.tk.Toolkit; 038 039/** 040 * Describes the characteristics of a graphics destination such as monitor. 041 * In a virtual device multi-screen environment in which the desktop area 042 * could span multiple physical screen devices, the bounds of the 043 * {@code Screen} objects are relative to the {@code Screen.primary}. 044 * 045 * <p> 046 * For example: 047 * <pre><code> 048 * Rectangle2D primaryScreenBounds = Screen.getPrimary().getVisualBounds(); 049 * 050 * //set Stage boundaries to visible bounds of the main screen 051 * stage.setX(primaryScreenBounds.getMinX()); 052 * stage.setY(primaryScreenBounds.getMinY()); 053 * stage.setWidth(primaryScreenBounds.getWidth()); 054 * stage.setHeight(primaryScreenBounds.getHeight()); 055 * 056 * stage.show(); 057 * </code></pre> 058 * </p> 059 */ 060public final class Screen { 061 062 private static final AtomicBoolean configurationDirty = 063 new AtomicBoolean(true); 064 065 private static final ScreenConfigurationAccessor accessor; 066 067 private static Screen primary; 068 private static final ObservableList<Screen> screens = 069 FXCollections.<Screen>observableArrayList(); 070 private static final ObservableList<Screen> unmodifiableScreens = 071 FXCollections.unmodifiableObservableList(screens); 072 073 static { 074 accessor = Toolkit.getToolkit().setScreenConfigurationListener(new TKScreenConfigurationListener() { 075 @Override public void screenConfigurationChanged() { 076 updateConfiguration(); 077 } 078 }); 079 } 080 081 private Screen() { 082 } 083 084 private static void checkDirty() { 085 if (configurationDirty.compareAndSet(true, false)) { 086 updateConfiguration(); 087 } 088 } 089 090 private static void updateConfiguration() { 091 Object primaryScreen = Toolkit.getToolkit().getPrimaryScreen(); 092 Screen screenTmp = nativeToScreen(primaryScreen, Screen.primary); 093 if (screenTmp != null) { 094 Screen.primary = screenTmp; 095 } 096 097 List<?> screens = Toolkit.getToolkit().getScreens(); 098 // go through the list of new screens, see if they match the 099 // existing list; if they do reuse the list; if they don't 100 // at least try to reuse some of the old ones 101 ObservableList<Screen> newScreens = FXCollections.<Screen>observableArrayList(); 102 // if the size of the new and the old one are different just 103 // recreate the list 104 boolean canKeepOld = (Screen.screens.size() == screens.size()); 105 for (int i = 0; i < screens.size(); i++) { 106 Object obj = screens.get(i); 107 Screen origScreen = null; 108 if (canKeepOld) { 109 origScreen = Screen.screens.get(i); 110 } 111 Screen newScreen = nativeToScreen(obj, origScreen); 112 if (newScreen != null) { 113 if (canKeepOld) { 114 canKeepOld = false; 115 newScreens.clear(); 116 newScreens.addAll(Screen.screens.subList(0, i)); 117 } 118 newScreens.add(newScreen); 119 } 120 } 121 if (!canKeepOld) { 122 Screen.screens.clear(); 123 Screen.screens.addAll(newScreens); 124 } 125 126 configurationDirty.set(false); 127 } 128 129 // returns null if the new one is to be equal the old one 130 private static Screen nativeToScreen(Object obj, Screen screen) { 131 int minX = accessor.getMinX(obj); 132 int minY = accessor.getMinY(obj); 133 int width = accessor.getWidth(obj); 134 int height = accessor.getHeight(obj); 135 int visualMinX = accessor.getVisualMinX(obj); 136 int visualMinY = accessor.getVisualMinY(obj); 137 int visualWidth = accessor.getVisualWidth(obj); 138 int visualHeight = accessor.getVisualHeight(obj); 139 double dpi = accessor.getDPI(obj); 140 if ((screen == null) || 141 (screen.bounds.getMinX() != minX) || 142 (screen.bounds.getMinY() != minY) || 143 (screen.bounds.getWidth() != width) || 144 (screen.bounds.getHeight() != height) || 145 (screen.visualBounds.getMinX() != visualMinX) || 146 (screen.visualBounds.getMinY() != visualMinY) || 147 (screen.visualBounds.getWidth() != visualWidth) || 148 (screen.visualBounds.getHeight() != visualHeight) || 149 (screen.dpi != dpi)) 150 { 151 Screen s = new Screen(); 152 s.bounds = new Rectangle2D(minX, minY, width, height); 153 s.visualBounds = new Rectangle2D(visualMinX, visualMinY, visualWidth, visualHeight); 154 s.dpi = dpi; 155 return s; 156 } else { 157 return null; 158 } 159 } 160 161 /** 162 * The primary {@code Screen}. 163 */ 164 public static Screen getPrimary() { 165 checkDirty(); 166 return primary; 167 } 168 169 /** 170 * The observable list of currently available {@code Screens}. 171 */ 172 public static ObservableList<Screen> getScreens() { 173 checkDirty(); 174 return unmodifiableScreens; 175 } 176 177 /** 178 * Returns a ObservableList of {@code Screens} that intersects the provided rectangle. 179 * 180 * @param x the x coordinate of the upper-left corner of the specified 181 * rectangular area 182 * @param y the y coordinate of the upper-left corner of the specified 183 * rectangular area 184 * @param width the width of the specified rectangular area 185 * @param height the height of the specified rectangular area 186 * @return a ObservableList of {@code Screens} for which {@code Screen.bounds} 187 * intersects the provided rectangle 188 */ 189 public static ObservableList<Screen> getScreensForRectangle( 190 double x, double y, double width, double height) 191 { 192 checkDirty(); 193 ObservableList<Screen> results = FXCollections.<Screen>observableArrayList(); 194 for (Screen screen : screens) { 195 if (screen.bounds.intersects(x, y, width, height)) { 196 results.add(screen); 197 } 198 } 199 return results; 200 } 201 202 /** 203 * Returns a ObservableList of {@code Screens} that intersects the provided rectangle. 204 * 205 * @param r The specified {@code Rectangle2D} 206 * @return a ObservableList of {@code Screens} for which {@code Screen.bounds} 207 * intersects the provided rectangle 208 */ 209 public static ObservableList<Screen> getScreensForRectangle(Rectangle2D r) { 210 checkDirty(); 211 return getScreensForRectangle(r.getMinX(), r.getMinY(), r.getWidth(), r.getHeight()); 212 } 213 214 /** 215 * The bounds of this {@code Screen}. 216 */ 217 private Rectangle2D bounds = Rectangle2D.EMPTY; 218 /** 219 * Gets the bounds of this {@code Screen}. 220 * @return The bounds of this {@code Screen} 221 */ 222 public final Rectangle2D getBounds() { 223 return bounds; 224 } 225 226 /** 227 * The visual bounds of this {@code Screen}. 228 * 229 * These bounds account for objects in the native windowing system such as 230 * task bars and menu bars. These bounds are contained by {@code Screen.bounds}. 231 */ 232 private Rectangle2D visualBounds = Rectangle2D.EMPTY; 233 /** 234 * Gets the visual bounds of this {@code Screen}. 235 * 236 * These bounds account for objects in the native windowing system such as 237 * task bars and menu bars. These bounds are contained by {@code Screen.bounds}. 238 * @return The visual bounds of this {@code Screen} 239 */ 240 public final Rectangle2D getVisualBounds() { 241 return visualBounds; 242 } 243 244 /** 245 * The resolution (dots per inch) of this {@code Screen}. 246 */ 247 private double dpi; 248 /** 249 * Gets the resolution (dots per inch) of this {@code Screen}. 250 * @return The resolution of this @{code Screen} 251 */ 252 public final double getDpi() { 253 return dpi; 254 } 255 256 /** 257 * Returns a hash code for this {@code Screen} object. 258 * @return a hash code for this {@code Screen} object. 259 */ 260 @Override public int hashCode() { 261 long bits = 7L; 262 bits = 37L * bits + bounds.hashCode(); 263 bits = 37L * bits + visualBounds.hashCode(); 264 bits = 37L * bits + Double.doubleToLongBits(dpi); 265 return (int) (bits ^ (bits >> 32)); 266 } 267 268 /** 269 * Indicates whether some other object is "equal to" this one. 270 * @param obj the reference object with which to compare. 271 * @return {@code true} if this object is equal to the {@code obj} argument; {@code false} otherwise. 272 */ 273 @Override public boolean equals(Object obj) { 274 if (obj == this) return true; 275 if (obj instanceof Screen) { 276 Screen other = (Screen) obj; 277 return (bounds == null ? other.bounds == null : bounds.equals(other.bounds)) 278 && (visualBounds == null ? other.visualBounds == null : visualBounds.equals(other.visualBounds)) 279 && other.dpi == dpi; 280 } else return false; 281 } 282 283 /** 284 * Returns a string representation of this {@code Screen} object. 285 * @return a string representation of this {@code Screen} object. 286 */ 287 @Override public String toString() { 288 return super.toString() + "bounds:" + bounds + " visualBounds:" + visualBounds + " dpi:" + dpi; 289 } 290}