JOGL v2.6.0-rc-20250712
JOGL, High-Performance Graphics Binding for Java™ (public API).
MonitorDevice.java
Go to the documentation of this file.
1/**
2 * Copyright 2013 JogAmp Community. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without modification, are
5 * permitted provided that the following conditions are met:
6 *
7 * 1. Redistributions of source code must retain the above copyright notice, this list of
8 * conditions and the following disclaimer.
9 *
10 * 2. Redistributions in binary form must reproduce the above copyright notice, this list
11 * of conditions and the following disclaimer in the documentation and/or other materials
12 * provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY JogAmp Community ``AS IS'' AND ANY EXPRESS OR IMPLIED
15 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
16 * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JogAmp Community OR
17 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
18 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
19 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
20 * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
21 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
22 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
23 *
24 * The views and conclusions contained in the software and documentation are those of the
25 * authors and should not be interpreted as representing official policies, either expressed
26 * or implied, of JogAmp Community.
27 */
28
29package com.jogamp.newt;
30
31import java.util.List;
32
33import com.jogamp.nativewindow.ScalableSurface;
34import com.jogamp.nativewindow.util.DimensionImmutable;
35import com.jogamp.nativewindow.util.Rectangle;
36import com.jogamp.nativewindow.util.RectangleImmutable;
37import com.jogamp.nativewindow.util.SurfaceSize;
38import com.jogamp.common.util.ArrayHashSet;
39
40/**
41 * Visual output device, i.e. a CRT, LED ..consisting of it's components:<br>
42 * <ui>
43 * <li>Immutable
44 * <ul>
45 * <li>nativeId</li>
46 * <li>{@link DimensionImmutable} size in [mm]</li>
47 * <li>{@link MonitorMode} original mode</li>
48 * <li><code>List&lt;MonitorMode&gt;</code> supportedModes</li>
49 * </ul></li>
50 * <li>Mutable
51 * <ul>
52 * <li>{@link MonitorMode} current mode</li>
53 * <li>{@link RectangleImmutable} viewport (rotated)</li>
54 * <li>pixel-scale (rotated)</li>
55 * </ul></li>
56 * </ul>
57 * <p>
58 * All values of this interface are represented in pixel units, if not stated otherwise.
59 * </p>
60 */
61public abstract class MonitorDevice {
62 protected final Screen screen; // backref
63 protected final long nativeHandle; // unique monitor device long handle, implementation specific
64 protected final int nativeId; // unique monitor device integer Id, implementation specific
65 protected final String name; // optional monitor name, maybe an empty string
66 protected final DimensionImmutable sizeMM; // in [mm]
67 protected final MonitorMode originalMode;
68 protected final ArrayHashSet<MonitorMode> supportedModes; // FIXME: May need to support mutable mode, i.e. adding modes on the fly!
69 protected final float[] pixelScale;
70 protected final Rectangle viewportPU; // in pixel units
71 protected final Rectangle viewportWU; // in window units
72 protected boolean isClone;
73 protected boolean isPrimary;
75 protected boolean modeChanged;
76
77 public static enum Orientation {
82 above(-2);
83
84 public final int value;
85
86 private Orientation(final int v) {
87 value = v;
88 }
89 }
90
91 /**
92 * Returns the orientation of this monitor to the other
93 * @param other the other monitor
94 * @param move_diff int[2] to store the move delta for each axis from this-monitor to the other.
95 * @return Orientation of this-monitor to the other
96 */
97 public final Orientation getOrientationTo(final MonitorDevice other, final int move_diff[/*2*/]) {
98 Orientation orientation = Orientation.clone;
99 // Move from other -> this
100 if( null != other ) {
101 // Move from vp0 -> vp1
102 final RectangleImmutable vp0 = other.getViewport(); // pixel units
103 final RectangleImmutable vp1 = this.getViewport(); // pixel units
104 if( vp0.getY() == vp1.getY() || vp0.getY() + vp0.getHeight() - 1 == vp1.getY() + vp1.getHeight() - 1 ) {
105 // vp0.y == vp1.y, i.e. horizontal move
106 if( vp1.getX() > vp0.getX() + vp0.getWidth() - 1 ) {
107 // vp1 right-of vp0
108 move_diff[0] = vp1.getX() - ( vp0.getX() + vp0.getWidth() - 1 ); // > 0
109 orientation = Orientation.right_of;
110 } else if( vp1.getX() + vp1.getWidth() - 1 < vp0.getX() ) {
111 // vp1 left-of vp0
112 move_diff[0] = ( vp1.getX() + vp1.getWidth() - 1 ) - vp0.getX(); // < 0
113 orientation = Orientation.left_of;
114 } // else same .. i.e. clone
115 } else if( vp0.getX() == vp1.getX() || vp0.getX() + vp0.getWidth() - 1 == vp1.getX() + vp1.getWidth() - 1 ) {
116 // vp0.x == vp1.x, i.e. vertical move
117 if( vp1.getY() + vp0.getHeight() - 1 < vp0.getY() ) {
118 // vp1 above vp0
119 move_diff[1] = ( vp1.getY() + vp1.getHeight() - 1 ) - vp0.getY() ; // < 0
120 orientation = Orientation.above;
121 } else if( vp1.getY() > vp0.getY() + vp0.getHeight() - 1 ) {
122 // vp1 below vp0
123 move_diff[1] = vp1.getY() - ( vp0.getY() + vp0.getHeight() - 1 ); // > 0
124 orientation = Orientation.below;
125 }
126 }
127 }
128 return orientation;
129 }
130
131 /**
132 * @param screen associated {@link Screen}
133 * @param nativeHandle unique monitor device long handle, implementation specific
134 * @param nativeId unique monitor device integer Id, implementation specific
135 * @param name optional monitor name, maybe null
136 * @param isClone flag
137 * @param isPrimary flag
138 * @param sizeMM size in millimeters
139 * @param currentMode
140 * @param pixelScale pre-fetched current pixel-scale, maybe {@code null} for {@link ScalableSurface#IDENTITY_PIXELSCALE}.
141 * @param viewportPU viewport in pixel-units
142 * @param viewportWU viewport in window-units
143 * @param supportedModes all supported {@link MonitorMode}s
144 */
145 protected MonitorDevice(final Screen screen, final long nativeHandle, final int nativeId,
146 final String name, final boolean isClone,
147 final boolean isPrimary, final DimensionImmutable sizeMM, final MonitorMode currentMode,
148 final float[] pixelScale, final Rectangle viewportPU, final Rectangle viewportWU, final ArrayHashSet<MonitorMode> supportedModes) {
149 this.screen = screen;
150 this.nativeHandle = nativeHandle;
151 this.nativeId = nativeId;
152 this.name = null != name ? name : "";
153 this.sizeMM = sizeMM;
154 this.originalMode = currentMode;
155 this.supportedModes = supportedModes;
156 if( null != pixelScale ) {
157 this.pixelScale = new float[] { pixelScale[0], pixelScale[1] };
158 } else {
159 this.pixelScale = new float[] { ScalableSurface.IDENTITY_PIXELSCALE, ScalableSurface.IDENTITY_PIXELSCALE };
160 }
161 this.viewportPU = viewportPU;
162 this.viewportWU = viewportWU;
163
164 this.isClone = isClone;
165 this.isPrimary = isPrimary;
166 this.currentMode = currentMode;
167 this.modeChanged = false;
168 }
169
170 /** Returns the {@link Screen} owning this monitor. */
171 public final Screen getScreen() {
172 return screen;
173 }
174
175 /**
176 * Tests equality of two <code>MonitorDevice</code> objects
177 * by evaluating equality of it's components:<br>
178 * <ul>
179 * <li><code>nativeID</code></li>
180 * </ul>
181 * <br>
182 */
183 @Override
184 public final boolean equals(final Object obj) {
185 if (this == obj) { return true; }
186 if (obj instanceof MonitorDevice) {
187 final MonitorDevice md = (MonitorDevice)obj;
188 return md.nativeId == nativeId;
189 }
190 return false;
191 }
192
193 /**
194 * Returns a combined hash code of it's elements:<br>
195 * <ul>
196 * <li><code>nativeID</code></li>
197 * </ul>
198 */
199 @Override
200 public final int hashCode() {
201 return nativeId;
202 }
203
204 /** @return the immutable unique native long handle of this monitor device, implementation specific. */
205 public final long getHandle() { return nativeHandle; }
206
207 /** @return the immutable unique native integer Id of this monitor device, implementation specific. */
208 public final int getId() { return nativeId; }
209
210 /** @return optional monitor name, maybe an empty string but never null. */
211 public final String getName() { return name; }
212
213 /** @return {@code true} if this device represents a <i>clone</i>, otherwise return {@code false}. */
214 public final boolean isClone() { return isClone; }
215
216 /**
217 * Returns {@code true} if this device represents the <i>primary device</i>, otherwise return {@code false}.
218 * @see Screen#getPrimaryMonitor()
219 */
220 public final boolean isPrimary() { return isPrimary; }
221
222 /**
223 * @return the immutable monitor size in millimeters.
224 */
226 return sizeMM;
227 }
228
229 /**
230 * Returns the <i>pixels per millimeter</i> value according to the <i>current</i> {@link MonitorMode mode}'s
231 * {@link SurfaceSize#getResolution() surface resolution}.
232 * <p>
233 * To convert the result to <i>dpi</i>, i.e. dots-per-inch, multiply both components with <code>25.4f</code>,
234 * see {@link #perMMToPerInch(float[])}.
235 * </p>
236 * @param ppmmStore float[2] storage for the ppmm result
237 * @return the passed storage containing the ppmm for chaining
238 * @see #perMMToPerInch(float[])
239 */
240 public final float[] getPixelsPerMM(final float[] ppmmStore) {
241 return getPixelsPerMM(getCurrentMode(), ppmmStore);
242 }
243
244 /**
245 * Returns the <i>pixels per millimeter</i> value according to the given {@link MonitorMode mode}'s
246 * {@link SurfaceSize#getResolution() surface resolution}.
247 * <p>
248 * To convert the result to <i>dpi</i>, i.e. dots-per-inch, multiply both components with <code>25.4f</code>.
249 * </p>
250 * @param mode
251 * @param ppmmStore float[2] storage for the ppmm result
252 * @return the passed storage containing the ppmm for chaining
253 */
254 public final float[] getPixelsPerMM(final MonitorMode mode, final float[] ppmmStore) {
255 final DimensionImmutable sdim = getSizeMM();
256 final DimensionImmutable spix = mode.getSurfaceSize().getResolution();
257 ppmmStore[0] = (float)spix.getWidth() / (float)sdim.getWidth();
258 ppmmStore[1] = (float)spix.getHeight() / (float)sdim.getHeight();
259 return ppmmStore;
260 }
261
262 /**
263 * Converts [1/mm] to [1/inch] in place
264 * @param ppmm float[2] [1/mm] value
265 * @return return [1/inch] value
266 */
267 public static float[/*2*/] perMMToPerInch(final float[/*2*/] ppmm) {
268 ppmm[0] *= 25.4f;
269 ppmm[1] *= 25.4f;
270 return ppmm;
271 }
272
273 /**
274 * Returns the immutable original {@link com.jogamp.newt.MonitorMode}, as used at NEWT initialization.
275 * <p>
276 * The returned {@link MonitorMode} is element of the lists {@link #getSupportedModes()} and {@link Screen#getMonitorModes()}.
277 * </p>
278 */
280 return originalMode;
281 }
282
283 /**
284 * Returns a list of immutable {@link MonitorMode}s supported by this monitor.
285 * <p>
286 * The list is ordered in descending order,
287 * see {@link MonitorMode#compareTo(MonitorMode)}.
288 * </p>
289 * <p>
290 * Use w/ care, it's not a copy!
291 * </p>
292 */
293 public final List<MonitorMode> getSupportedModes() {
294 return supportedModes.getData();
295 }
296
297 /**
298 * Returns the current {@link RectangleImmutable rectangular} portion
299 * of the <b>rotated</b> virtual {@link Screen} size in pixel units
300 * represented by this monitor, i.e. top-left origin and size.
301 * @see #getPixelScale()
302 * @see Screen#getViewport()
303 */
305 return viewportPU;
306 }
307
308 /**
309 * Returns the current {@link RectangleImmutable rectangular} portion
310 * of the <b>rotated</b> virtual {@link Screen} size in window units
311 * represented by this monitor, i.e. top-left origin and size.
312 * @see #getPixelScale()
313 * @see Screen#getViewportInWindowUnits()
314 */
316 return viewportWU;
317 }
318
319 /**
320 * Returns the current <b>rotated</b> pixel-scale
321 * of this monitor, i.e. horizontal and vertical.
322 * @see #getViewportInWindowUnits()
323 * @see #getViewport()
324 * @see ScalableSurface#getMaximumSurfaceScale(float[])
325 */
326 public float[] getPixelScale(final float[] result) {
327 System.arraycopy(pixelScale, 0, result, 0, 2);
328 return result;
329 }
330
331 /**
332 * Returns <code>true</code> if given screen coordinates in pixel units
333 * are contained by this {@link #getViewport() viewport}, otherwise <code>false</code>.
334 * @param x x-coord in pixel units
335 * @param y y-coord in pixel units
336 */
337 public final boolean contains(final int x, final int y) {
338 return x >= viewportPU.getX() &&
340 y >= viewportPU.getY() &&
342 }
343
344 /**
345 * Calculates the union of the given monitor's {@link #getViewport() viewport} in pixel- and window units.
346 * @param viewport storage for result in pixel units, maybe null
347 * @param viewportInWindowUnits storage for result in window units, maybe null
348 * @param monitors given list of monitors
349 */
350 public static void unionOfViewports(final Rectangle viewport, final Rectangle viewportInWindowUnits, final List<MonitorDevice> monitors) {
351 int x1PU=Integer.MAX_VALUE, y1PU=Integer.MAX_VALUE;
352 int x2PU=Integer.MIN_VALUE, y2PU=Integer.MIN_VALUE;
353 int x1WU=Integer.MAX_VALUE, y1WU=Integer.MAX_VALUE;
354 int x2WU=Integer.MIN_VALUE, y2WU=Integer.MIN_VALUE;
355 for(int i=monitors.size()-1; i>=0; i--) {
356 if( null != viewport ) {
357 final RectangleImmutable viewPU = monitors.get(i).getViewport();
358 x1PU = Math.min(x1PU, viewPU.getX());
359 x2PU = Math.max(x2PU, viewPU.getX() + viewPU.getWidth());
360 y1PU = Math.min(y1PU, viewPU.getY());
361 y2PU = Math.max(y2PU, viewPU.getY() + viewPU.getHeight());
362 }
363 if( null != viewportInWindowUnits ) {
364 final RectangleImmutable viewWU = monitors.get(i).getViewportInWindowUnits();
365 x1WU = Math.min(x1WU, viewWU.getX());
366 x2WU = Math.max(x2WU, viewWU.getX() + viewWU.getWidth());
367 y1WU = Math.min(y1WU, viewWU.getY());
368 y2WU = Math.max(y2WU, viewWU.getY() + viewWU.getHeight());
369 }
370 }
371 if( null != viewport ) {
372 viewport.set(x1PU, y1PU, x2PU - x1PU, y2PU - y1PU);
373 }
374 if( null != viewportInWindowUnits ) {
375 viewportInWindowUnits.set(x1WU, y1WU, x2WU - x1WU, y2WU - y1WU);
376 }
377 }
378
379 public final boolean isOriginalMode() {
380 return currentMode.hashCode() == originalMode.hashCode();
381 }
382
383 /**
384 * Returns <code>true</true> if the {@link MonitorMode}
385 * has been changed programmatic via this API <i>only</i>, otherwise <code>false</code>.
386 * <p>
387 * Note: We cannot guarantee that we won't interfere w/ another running
388 * application's screen mode change or vice versa.
389 * </p>
390 */
391 public final boolean isModeChangedByUs() {
392 return modeChanged && !isOriginalMode();
393 }
394
395 /**
396 * Returns the cached current {@link MonitorMode} w/o native query.
397 * <p>
398 * The returned {@link MonitorMode} is element of the lists {@link #getSupportedModes()} and {@link Screen#getMonitorModes()}.
399 * </p>
400 * @see #queryCurrentMode()
401 */
403 return currentMode;
404 }
405
406 /**
407 * Returns the current {@link MonitorMode} resulting from a native query.
408 * <p>
409 * The returned {@link MonitorMode} is element of the lists {@link #getSupportedModes()} and {@link Screen#getMonitorModes()}.
410 * </p>
411 * @throws IllegalStateException if the {@link #getScreen() associated screen} is not {@link Screen#isNativeValid() valid natively}.
412 * @see #getCurrentMode()
413 */
414 public abstract MonitorMode queryCurrentMode() throws IllegalStateException;
415
416 /**
417 * Set the current {@link com.jogamp.newt.MonitorMode}.
418 * <p>This method is <a href="Window.html#lifecycleHeavy">lifecycle heavy</a>.</p>
419 * @param mode to be made current, must be element of the list {@link #getSupportedModes()} and {@link Screen#getMonitorModes()}.
420 * @return true if successful, otherwise false
421 * @throws IllegalStateException if the {@link #getScreen() associated screen} is not {@link Screen#isNativeValid() valid natively}.
422 */
423 public abstract boolean setCurrentMode(MonitorMode mode) throws IllegalStateException;
424
425 @Override
426 public String toString() {
427 boolean preComma = false;
428 final StringBuilder sb = new StringBuilder();
429 sb.append("Monitor[Id ").append(Display.toHexString(nativeId)).append(" [");
430 {
431 if( !name.isEmpty() ) {
432 if( preComma ) {
433 sb.append(", ");
434 }
435 sb.append("name ").append("'").append(name).append("'");
436 preComma = true;
437 }
438 if( nativeHandle != nativeId ) {
439 if( preComma ) {
440 sb.append(", ");
441 }
442 sb.append("handle ").append(Display.toHexString(nativeHandle));
443 preComma = true;
444 }
445 if( isClone() ) {
446 if( preComma ) {
447 sb.append(", ");
448 }
449 sb.append("clone");
450 preComma = true;
451 }
452 if( isPrimary() ) {
453 if( preComma ) {
454 sb.append(", ");
455 }
456 sb.append("primary");
457 }
458 }
459 preComma = false;
460 sb.append("], ").append(sizeMM).append(" mm, pixelScale [").append(pixelScale[0]).append(", ")
461 .append(pixelScale[1]).append("], viewport[pixel ").append(viewportPU).append(", window ").append(viewportWU)
462 .append("], orig ").append(originalMode).append(", curr ")
463 .append(currentMode).append(", modeChanged ").append(modeChanged).append(", modeCount ")
464 .append(supportedModes.size()).append("]");
465 return sb.toString();
466 }
467}
468
final int getX()
x-position, left of rectangle.
Definition: Rectangle.java:68
final int getY()
y-position, top of rectangle.
Definition: Rectangle.java:70
final Rectangle set(final int x, final int y, final int width, final int height)
Definition: Rectangle.java:76
final DimensionImmutable getResolution()
Returns the resolution in pixel units.
static String toHexString(final int hex)
Definition: Display.java:463
Visual output device, i.e.
final boolean contains(final int x, final int y)
Returns true if given screen coordinates in pixel units are contained by this viewport,...
final ArrayHashSet< MonitorMode > supportedModes
MonitorDevice(final Screen screen, final long nativeHandle, final int nativeId, final String name, final boolean isClone, final boolean isPrimary, final DimensionImmutable sizeMM, final MonitorMode currentMode, final float[] pixelScale, final Rectangle viewportPU, final Rectangle viewportWU, final ArrayHashSet< MonitorMode > supportedModes)
static void unionOfViewports(final Rectangle viewport, final Rectangle viewportInWindowUnits, final List< MonitorDevice > monitors)
Calculates the union of the given monitor's viewport in pixel- and window units.
final boolean equals(final Object obj)
Tests equality of two MonitorDevice objects by evaluating equality of it's components:
final int hashCode()
Returns a combined hash code of it's elements:
final DimensionImmutable getSizeMM()
final float[] getPixelsPerMM(final MonitorMode mode, final float[] ppmmStore)
Returns the pixels per millimeter value according to the given mode's surface resolution.
final boolean isPrimary()
Returns true if this device represents the primary device, otherwise return false.
final boolean isModeChangedByUs()
Returns true</true> if the MonitorMode has been changed programmatic via this API only,...
final MonitorMode getCurrentMode()
Returns the cached current MonitorMode w/o native query.
float[] getPixelScale(final float[] result)
Returns the current rotated pixel-scale of this monitor, i.e.
abstract MonitorMode queryCurrentMode()
Returns the current MonitorMode resulting from a native query.
static float[] perMMToPerInch(final float[] ppmm)
Converts [1/mm] to [1/inch] in place.
final MonitorMode originalMode
final RectangleImmutable getViewportInWindowUnits()
Returns the current rectangular portion of the rotated virtual Screen size in window units represente...
abstract boolean setCurrentMode(MonitorMode mode)
Set the current com.jogamp.newt.MonitorMode.
final float[] getPixelsPerMM(final float[] ppmmStore)
Returns the pixels per millimeter value according to the current mode's surface resolution.
final List< MonitorMode > getSupportedModes()
Returns a list of immutable MonitorModes supported by this monitor.
final DimensionImmutable sizeMM
final MonitorMode getOriginalMode()
Returns the immutable original com.jogamp.newt.MonitorMode, as used at NEWT initialization.
final RectangleImmutable getViewport()
Returns the current rectangular portion of the rotated virtual Screen size in pixel units represented...
final Screen getScreen()
Returns the Screen owning this monitor.
final Orientation getOrientationTo(final MonitorDevice other, final int move_diff[])
Returns the orientation of this monitor to the other.
Immutable MonitorMode Class, consisting of it's read only components:
final SurfaceSize getSurfaceSize()
Returns the unrotated SurfaceSize.
A screen may span multiple MonitorDevices representing their combined virtual size.
Definition: Screen.java:58
Adding mutable surface pixel scale property to implementing class, usually to a NativeSurface impleme...
static final float IDENTITY_PIXELSCALE
Setting surface-pixel-scale of {@value}, results in same pixel- and window-units.
Immutable Dimension Interface, consisting of it's read only components:
Immutable Rectangle interface, with its position on the top-left.
int getX()
x-position, left of rectangle.
int getY()
y-position, top of rectangle.