JOGL v2.6.0-rc-20250721
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 #mmToInch(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 #mmToInch(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*/] mmToInch(final float[/*2*/] ppmm) {
268 ppmm[0] *= 25.4f;
269 ppmm[1] *= 25.4f;
270 return ppmm;
271 }
272 /**
273 * Converts [1/mm] to [1/inch]
274 * @param ppmm [1/mm] value
275 * @return return [1/inch] value
276 */
277 public static float mmToInch(float ppmm) {
278 ppmm *= 25.4f;
279 return ppmm;
280 }
281
282 /**
283 * Converts [1/inch] to [1/mm] in place
284 * @param ppinch float[2] [1/inch] value
285 * @return return [1/mm] value
286 */
287 public static float[/*2*/] inchToMM(final float[/*2*/] ppinch) {
288 ppinch[0] /= 25.4f;
289 ppinch[1] /= 25.4f;
290 return ppinch;
291 }
292 /**
293 * Converts [1/inch] to [1/mm]
294 * @param ppinch [1/inch] value
295 * @return return [1/mm] value
296 */
297 public static float inchToMM(float ppinch) {
298 ppinch /= 25.4f;
299 return ppinch;
300 }
301
302 /**
303 * Returns the immutable original {@link com.jogamp.newt.MonitorMode}, as used at NEWT initialization.
304 * <p>
305 * The returned {@link MonitorMode} is element of the lists {@link #getSupportedModes()} and {@link Screen#getMonitorModes()}.
306 * </p>
307 */
309 return originalMode;
310 }
311
312 /**
313 * Returns a list of immutable {@link MonitorMode}s supported by this monitor.
314 * <p>
315 * The list is ordered in descending order,
316 * see {@link MonitorMode#compareTo(MonitorMode)}.
317 * </p>
318 * <p>
319 * Use w/ care, it's not a copy!
320 * </p>
321 */
322 public final List<MonitorMode> getSupportedModes() {
323 return supportedModes.getData();
324 }
325
326 /**
327 * Returns the current {@link RectangleImmutable rectangular} portion
328 * of the <b>rotated</b> virtual {@link Screen} size in pixel units
329 * represented by this monitor, i.e. top-left origin and size.
330 * @see #getPixelScale()
331 * @see Screen#getViewport()
332 */
334 return viewportPU;
335 }
336
337 /**
338 * Returns the current {@link RectangleImmutable rectangular} portion
339 * of the <b>rotated</b> virtual {@link Screen} size in window units
340 * represented by this monitor, i.e. top-left origin and size.
341 * @see #getPixelScale()
342 * @see Screen#getViewportInWindowUnits()
343 */
345 return viewportWU;
346 }
347
348 /**
349 * Returns the current <b>rotated</b> pixel-scale
350 * of this monitor, i.e. horizontal and vertical.
351 * @see #getViewportInWindowUnits()
352 * @see #getViewport()
353 * @see ScalableSurface#getMaximumSurfaceScale(float[])
354 */
355 public float[] getPixelScale(final float[] result) {
356 System.arraycopy(pixelScale, 0, result, 0, 2);
357 return result;
358 }
359
360 /**
361 * Returns <code>true</code> if given screen coordinates in pixel units
362 * are contained by this {@link #getViewport() viewport}, otherwise <code>false</code>.
363 * @param x x-coord in pixel units
364 * @param y y-coord in pixel units
365 */
366 public final boolean contains(final int x, final int y) {
367 return x >= viewportPU.getX() &&
369 y >= viewportPU.getY() &&
371 }
372
373 /**
374 * Calculates the union of the given monitor's {@link #getViewport() viewport} in pixel- and window units.
375 * @param viewport storage for result in pixel units, maybe null
376 * @param viewportInWindowUnits storage for result in window units, maybe null
377 * @param monitors given list of monitors
378 */
379 public static void unionOfViewports(final Rectangle viewport, final Rectangle viewportInWindowUnits, final List<MonitorDevice> monitors) {
380 int x1PU=Integer.MAX_VALUE, y1PU=Integer.MAX_VALUE;
381 int x2PU=Integer.MIN_VALUE, y2PU=Integer.MIN_VALUE;
382 int x1WU=Integer.MAX_VALUE, y1WU=Integer.MAX_VALUE;
383 int x2WU=Integer.MIN_VALUE, y2WU=Integer.MIN_VALUE;
384 for(int i=monitors.size()-1; i>=0; i--) {
385 if( null != viewport ) {
386 final RectangleImmutable viewPU = monitors.get(i).getViewport();
387 x1PU = Math.min(x1PU, viewPU.getX());
388 x2PU = Math.max(x2PU, viewPU.getX() + viewPU.getWidth());
389 y1PU = Math.min(y1PU, viewPU.getY());
390 y2PU = Math.max(y2PU, viewPU.getY() + viewPU.getHeight());
391 }
392 if( null != viewportInWindowUnits ) {
393 final RectangleImmutable viewWU = monitors.get(i).getViewportInWindowUnits();
394 x1WU = Math.min(x1WU, viewWU.getX());
395 x2WU = Math.max(x2WU, viewWU.getX() + viewWU.getWidth());
396 y1WU = Math.min(y1WU, viewWU.getY());
397 y2WU = Math.max(y2WU, viewWU.getY() + viewWU.getHeight());
398 }
399 }
400 if( null != viewport ) {
401 viewport.set(x1PU, y1PU, x2PU - x1PU, y2PU - y1PU);
402 }
403 if( null != viewportInWindowUnits ) {
404 viewportInWindowUnits.set(x1WU, y1WU, x2WU - x1WU, y2WU - y1WU);
405 }
406 }
407
408 public final boolean isOriginalMode() {
409 return currentMode.hashCode() == originalMode.hashCode();
410 }
411
412 /**
413 * Returns <code>true</true> if the {@link MonitorMode}
414 * has been changed programmatic via this API <i>only</i>, otherwise <code>false</code>.
415 * <p>
416 * Note: We cannot guarantee that we won't interfere w/ another running
417 * application's screen mode change or vice versa.
418 * </p>
419 */
420 public final boolean isModeChangedByUs() {
421 return modeChanged && !isOriginalMode();
422 }
423
424 /**
425 * Returns the cached current {@link MonitorMode} w/o native query.
426 * <p>
427 * The returned {@link MonitorMode} is element of the lists {@link #getSupportedModes()} and {@link Screen#getMonitorModes()}.
428 * </p>
429 * @see #queryCurrentMode()
430 */
432 return currentMode;
433 }
434
435 /**
436 * Returns the current {@link MonitorMode} resulting from a native query.
437 * <p>
438 * The returned {@link MonitorMode} is element of the lists {@link #getSupportedModes()} and {@link Screen#getMonitorModes()}.
439 * </p>
440 * @throws IllegalStateException if the {@link #getScreen() associated screen} is not {@link Screen#isNativeValid() valid natively}.
441 * @see #getCurrentMode()
442 */
443 public abstract MonitorMode queryCurrentMode() throws IllegalStateException;
444
445 /**
446 * Set the current {@link com.jogamp.newt.MonitorMode}.
447 * <p>This method is <a href="Window.html#lifecycleHeavy">lifecycle heavy</a>.</p>
448 * @param mode to be made current, must be element of the list {@link #getSupportedModes()} and {@link Screen#getMonitorModes()}.
449 * @return true if successful, otherwise false
450 * @throws IllegalStateException if the {@link #getScreen() associated screen} is not {@link Screen#isNativeValid() valid natively}.
451 */
452 public abstract boolean setCurrentMode(MonitorMode mode) throws IllegalStateException;
453
454 @Override
455 public String toString() {
456 boolean preComma = false;
457 final StringBuilder sb = new StringBuilder();
458 sb.append("Monitor[Id ").append(Display.toHexString(nativeId)).append(" [");
459 {
460 if( !name.isEmpty() ) {
461 if( preComma ) {
462 sb.append(", ");
463 }
464 sb.append("name ").append("'").append(name).append("'");
465 preComma = true;
466 }
467 if( nativeHandle != nativeId ) {
468 if( preComma ) {
469 sb.append(", ");
470 }
471 sb.append("handle ").append(Display.toHexString(nativeHandle));
472 preComma = true;
473 }
474 if( isClone() ) {
475 if( preComma ) {
476 sb.append(", ");
477 }
478 sb.append("clone");
479 preComma = true;
480 }
481 if( isPrimary() ) {
482 if( preComma ) {
483 sb.append(", ");
484 }
485 sb.append("primary");
486 }
487 }
488 preComma = false;
489 sb.append("], ").append(sizeMM).append(" mm, pixelScale [").append(pixelScale[0]).append(", ")
490 .append(pixelScale[1]).append("], viewport[pixel ").append(viewportPU).append(", window ").append(viewportWU)
491 .append("], orig ").append(originalMode).append(", curr ")
492 .append(currentMode).append(", modeChanged ").append(modeChanged).append(", modeCount ")
493 .append(supportedModes.size()).append("]");
494 return sb.toString();
495 }
496}
497
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
static float[] mmToInch(final float[] ppmm)
Converts [1/mm] to [1/inch] in place.
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.
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.
static float mmToInch(float ppmm)
Converts [1/mm] to [1/inch].
static float inchToMM(float ppinch)
Converts [1/inch] to [1/mm].
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.
static float[] inchToMM(final float[] ppinch)
Converts [1/inch] to [1/mm] in place.
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.