JOGL v2.6.0-rc-20250706
JOGL, High-Performance Graphics Binding for Java™ (public API).
MonitorMode.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.Comparator;
32
33import com.jogamp.nativewindow.util.DimensionImmutable;
34import com.jogamp.nativewindow.util.RectangleImmutable;
35import com.jogamp.nativewindow.util.SurfaceSize;
36
37import com.jogamp.newt.util.MonitorModeUtil;
38
39
40/**
41 * Immutable MonitorMode Class, consisting of it's read only components:<br>
42 * <ul>
43 * <li>nativeId</li>
44 * <li>{@link SizeAndRRate}, consist out of non rotated {@link #getSurfaceSize() surface size}, {@link #getRefreshRate() refresh rate} and {@link #getFlags() flags}.</li>
45 * <li><code>rotation</code>, measured counter clockwise (CCW)</li>
46 * </ul>
47 *
48 * <i>Aquire and filter MonitorMode</i><br>
49 * <ul>
50 * <li>{@link MonitorDevice} Selection:
51 * <ul>
52 * <li>A List of all {@link MonitorDevice}s is accessible via {@link Screen#getMonitorDevices()}.</li>
53 * <li>The main monitor used by a windows is accessible via {@link Window#getMainMonitor()}.</li>
54 * <li>The main monitor covering an arbitrary rectangle is accessible via {@link Screen#getMainMonitor(RectangleImmutable)}.</li>
55 * </ul></li>
56 * <li>The current MonitorMode can be obtained via {@link MonitorDevice#getCurrentMode()}.</li>
57 * <li>The original MonitorMode can be obtained via {@link MonitorDevice#getOriginalMode()}.</li>
58 * <li>{@link MonitorMode} Filtering:
59 * <ul>
60 * <li>A {@link MonitorDevice}'s MonitorModes is accessible via {@link MonitorDevice#getSupportedModes()}.</li>
61 * <li>You may utilize {@link MonitorModeUtil} to filter and select a desired MonitorMode.</li>
62 * </ul></li>
63 * </ul>
64 * <br>
65 *
66 * <i>Changing MonitorMode</i><br>
67 * <ul>
68 * <li> Use {@link MonitorDevice#setCurrentMode(MonitorMode)}
69 * to change the current MonitorMode for all {@link Screen}s referenced via the {@link Screen#getFQName() full qualified name (FQN)}.</li>
70 * <li> The {@link MonitorDevice#getOriginalMode() original mode} is restored when
71 * <ul>
72 * <li>the last FQN referenced Screen closes.</li>
73 * <li>the JVM shuts down.</li>
74 * </ul></li>
75 * </ul>
76 * <br>
77 * Example for changing the MonitorMode:
78 * <pre>
79 // Pick the monitor:
80 // Either the one used by a window ..
81 MonitorDevice monitor = window.getMainMonitor();
82
83 // Or arbitrary from the list ..
84 List<MonitorDevice> allMonitor = getMonitorDevices();
85 MonitorDevice monitor = allMonitor.get(0);
86
87 // Current and original modes ..
88 MonitorMode mmCurrent = monitor.queryCurrentMode();
89 MonitorMode mmOrig = monitor.getOriginalMode();
90
91 // Target resolution in pixel units
92 DimensionImmutable res = new Dimension(800, 600);
93
94 // Target refresh rate shall be similar to current one ..
95 float freq = mmCurrent.getRefreshRate();
96
97 // Target rotation shall be similar to current one
98 int rot = mmCurrent.getRotation();
99
100 // Filter criterias sequential out of all available MonitorMode of the chosen MonitorDevice
101 List<MonitorMode> monitorModes = monitor.getSupportedModes();
102 monitorModes = MonitorModeUtil.filterByFlags(monitorModes, 0); // no interlace, double-scan etc
103 monitorModes = MonitorModeUtil.filterByRotation(monitorModes, rot);
104 monitorModes = MonitorModeUtil.filterByResolution(monitorModes, res);
105 monitorModes = MonitorModeUtil.filterByRate(monitorModes, freq);
106 monitorModes = MonitorModeUtil.getHighestAvailableBpp(monitorModes);
107
108 // pick 1st one and set to current ..
109 MonitorMode mm = monitorModes.get(0);
110 monitor.setCurrentMode(mm);
111 * </pre>
112 */
113public class MonitorMode implements Comparable<MonitorMode> {
114
115 /** Comparator for 2 {@link MonitorMode}s, following comparison order as described in {@link MonitorMode#compareTo(MonitorMode)}, returning the ascending order. */
116 public static final Comparator<MonitorMode> monitorModeComparator = new Comparator<MonitorMode>() {
117 @Override
118 public int compare(final MonitorMode mm1, final MonitorMode mm2) {
119 return mm1.compareTo(mm2);
120 } };
121
122 /** Comparator for 2 {@link MonitorMode}s, following comparison order as described in {@link MonitorMode#compareTo(MonitorMode)}, returning the descending order. */
123 public static final Comparator<MonitorMode> monitorModeComparatorInv = new Comparator<MonitorMode>() {
124 @Override
125 public int compare(final MonitorMode mm1, final MonitorMode mm2) {
126 return mm2.compareTo(mm1);
127 } };
128
129 /**
130 * Immutable <i>surfaceSize, flags and refreshRate</i> Class, consisting of it's read only components:<br>
131 * <ul>
132 * <li>nativeId</li>
133 * <li>{@link SurfaceSize} surface memory size</li>
134 * <li><code>flags</code></li>
135 * <li><code>refresh rate</code></li>
136 * </ul>
137 */
138 public static class SizeAndRRate implements Comparable<SizeAndRRate> {
139 /** Non rotated surface size in pixel units */
141 /** Mode bitfield flags, i.e. {@link #FLAG_DOUBLESCAN}, {@link #FLAG_INTERLACE}, .. */
142 public final int flags;
143 /** Vertical refresh rate */
144 public final float refreshRate;
145 public final int hashCode;
146
147 public SizeAndRRate(final SurfaceSize surfaceSize, final float refreshRate, final int flags) {
148 if(null==surfaceSize) {
149 throw new IllegalArgumentException("surfaceSize must be set ("+surfaceSize+")");
150 }
151 this.surfaceSize=surfaceSize;
152 this.flags = flags;
153 this.refreshRate=refreshRate;
154 this.hashCode = getHashCode();
155 }
156
157 private final static String STR_INTERLACE = "Interlace";
158 private final static String STR_DOUBLESCAN = "DoubleScan";
159 private final static String STR_SEP = ", ";
160
161 public static final StringBuilder flags2String(final int flags) {
162 final StringBuilder sb = new StringBuilder();
163 boolean sp = false;
164 if( 0 != ( flags & FLAG_INTERLACE ) ) {
165 sb.append(STR_INTERLACE);
166 sp = true;
167 }
168 if( 0 != ( flags & FLAG_DOUBLESCAN ) ) {
169 if( sp ) {
170 sb.append(STR_SEP);
171 }
172 sb.append(STR_DOUBLESCAN);
173 sp = true;
174 }
175 return sb;
176 }
177 @Override
178 public final String toString() {
179 return surfaceSize+" @ "+refreshRate+" Hz, flags ["+flags2String(flags).toString()+"]";
180 }
181
182 /**
183 * <p>
184 * Compares {@link SurfaceSize#compareTo(SurfaceSize) surfaceSize} 1st, then {@link #flags}, then {@link #refreshRate}.
185 * </p>
186 * <p>
187 * Flags are compared as follows:
188 * <pre>
189 * NONE > DOUBLESCAN > INTERLACE
190 * </pre>
191 * </p>
192 * <p>
193 * Refresh rate differences of &lt; 0.01 are considered equal (epsilon).
194 * </p>
195 * {@inheritDoc}
196 */
197 @Override
198 public int compareTo(final SizeAndRRate sszr) {
199 final int rssz = surfaceSize.compareTo(sszr.surfaceSize);
200 if( 0 != rssz ) {
201 return rssz;
202 }
203 final int tflags = 0 == flags ? Integer.MAX_VALUE : flags; // normalize NONE
204 final int xflags = 0 == sszr.flags ? Integer.MAX_VALUE : sszr.flags; // normalize NONE
205 if( tflags == xflags ) {
206 final float refreshEpsilon = 0.01f; // reasonable sorting granularity of refresh rate
207 final float drate = refreshRate - sszr.refreshRate;
208 if( Math.abs(drate) < refreshEpsilon ) {
209 return 0;
210 } else if( drate > refreshEpsilon ) {
211 return 1;
212 } else {
213 return -1;
214 }
215 } else {
216 if(tflags > xflags) {
217 return 1;
218 } else if(tflags < xflags) {
219 return -1;
220 }
221 return 0;
222 }
223 }
224
225 /**
226 * Tests equality of two {@link SizeAndRRate} objects
227 * by evaluating equality of it's components:<br/>
228 * <ul>
229 * <li><code>surfaceSize</code></li>
230 * <li><code>refreshRate</code></li>
231 * <li><code>flags</code></li>
232 * </ul>
233 */
234 @Override
235 public final boolean equals(final Object obj) {
236 if (this == obj) { return true; }
237 if (obj instanceof SizeAndRRate) {
238 final SizeAndRRate p = (SizeAndRRate)obj;
239 return surfaceSize.equals(p.surfaceSize) &&
240 flags == p.flags &&
241 refreshRate == p.refreshRate ;
242 }
243 return false;
244 }
245
246 /**
247 * Returns a combined hash code of it's elements:<br/>
248 * <ul>
249 * <li><code>surfaceSize</code></li>
250 * <li><code>flags</code></li>
251 * <li><code>refreshRate</code></li>
252 * </ul>
253 */
254 @Override
255 public final int hashCode() {
256 return hashCode;
257 }
258 private final int getHashCode() {
259 // 31 * x == (x << 5) - x
260 int hash = 31 + surfaceSize.hashCode();
261 hash = ((hash << 5) - hash) + flags;
262 hash = ((hash << 5) - hash) + (int)(refreshRate*100.0f);
263 return hash;
264 }
265 }
266
267 /** zero rotation, compared to normal settings */
268 public static final int ROTATE_0 = 0;
269
270 /** 90 degrees CCW rotation */
271 public static final int ROTATE_90 = 90;
272
273 /** 180 degrees CCW rotation */
274 public static final int ROTATE_180 = 180;
275
276 /** 270 degrees CCW rotation */
277 public static final int ROTATE_270 = 270;
278
279 /** Frame is split into two fields. See {@link #getFlags()}. */
280 public static final int FLAG_INTERLACE = 1 << 0;
281
282 /** Lines are doubled. See {@link #getFlags()}. */
283 public static final int FLAG_DOUBLESCAN = 1 << 1;
284
285 /** The immutable native Id of this instance, which may not be unique. */
286 private final int nativeId;
287 private final SizeAndRRate sizeAndRRate;
288 private final int rotation;
289 private final int hashCode;
290
291 public static boolean isRotationValid(final int rotation) {
292 return rotation == MonitorMode.ROTATE_0 || rotation == MonitorMode.ROTATE_90 ||
293 rotation == MonitorMode.ROTATE_180 || rotation == MonitorMode.ROTATE_270 ;
294 }
295
296 /**
297 * @param sizeAndRRate the surface size and refresh rate mode
298 * @param rotation the screen rotation, measured counter clockwise (CCW)
299 */
300 public MonitorMode(final int nativeId, final SizeAndRRate sizeAndRRate, final int rotation) {
301 if ( !isRotationValid(rotation) ) {
302 throw new RuntimeException("invalid rotation: "+rotation);
303 }
304 this.nativeId = nativeId;
305 this.sizeAndRRate = sizeAndRRate;
306 this.rotation = rotation;
307 this.hashCode = getHashCode();
308 }
309
310 /**
311 * Creates a user instance w/o {@link #getId() identity} to filter our matching modes w/ identity.
312 * <p>
313 * See {@link com.jogamp.newt.util.MonitorModeUtil} for filter utilities.
314 * </p>
315 * @param surfaceSize
316 * @param refreshRate
317 * @param flags
318 * @param rotation
319 */
320 public MonitorMode(final SurfaceSize surfaceSize, final float refreshRate, final int flags, final int rotation) {
321 this(0, new SizeAndRRate(surfaceSize, refreshRate, flags), rotation);
322 }
323
324 /** @return the immutable native Id of this mode, may not be unique, may be 0. */
325 public final int getId() { return nativeId; }
326
327 /** Returns the <i>surfaceSize and refreshRate</i> instance. */
329 return sizeAndRRate;
330 }
331
332 /** Returns the unrotated {@link SurfaceSize} */
334 return sizeAndRRate.surfaceSize;
335 }
336
337 /** Returns the vertical refresh rate. */
338 public final float getRefreshRate() {
339 return sizeAndRRate.refreshRate;
340 }
341
342 /** Returns bitfield w/ flags, i.e. {@link #FLAG_DOUBLESCAN}, {@link #FLAG_INTERLACE}, .. */
343 public final int getFlags() {
344 return sizeAndRRate.flags;
345 }
346
347 /** Returns the CCW rotation of this mode */
348 public final int getRotation() {
349 return rotation;
350 }
351
352 /** Returns the rotated screen width in pixel units,
353 * derived from <code>getMonitorMode().getSurfaceSize().getResolution()</code>
354 * and <code>getRotation()</code>
355 */
356 public final int getRotatedWidth() {
357 return getRotatedWH(true);
358 }
359
360 /** Returns the rotated screen height in pixel units,
361 * derived from <code>getMonitorMode().getSurfaceSize().getResolution()</code>
362 * and <code>getRotation()</code>
363 */
364 public final int getRotatedHeight() {
365 return getRotatedWH(false);
366 }
367
368 @Override
369 public final String toString() {
370 return "[Id "+Display.toHexString(nativeId)+", " + sizeAndRRate + ", " + rotation + " degr]";
371 }
372
373 /**
374 * <p>
375 * Compares {@link SizeAndRRate#compareTo(SizeAndRRate) sizeAndRRate} 1st, then {@link #rotation}.
376 * </p>
377 * <p>
378 * Rotation is compared inverted, i.e. <code>360 - rotation</code>,
379 * so the lowest rotation reflects a higher value.
380 * </p>
381 * <p>
382 * Order of comparing MonitorMode:
383 * <ul>
384 * <li>resolution</li>
385 * <li>bits per pixel</li>
386 * <li>flags</li>
387 * <li>refresh rate</li>
388 * <li>rotation</li>
389 * </ul>
390 * </p>
391 * {@inheritDoc}
392 */
393 @Override
394 public int compareTo(final MonitorMode mm) {
395 final int c = sizeAndRRate.compareTo(mm.sizeAndRRate);
396 if( 0 != c ) {
397 return c;
398 }
399 final int trot = 360 - rotation; // normalize rotation
400 final int xrot = 360 - mm.rotation; // normalize rotation
401 if(trot > xrot) {
402 return 1;
403 } else if(trot < xrot) {
404 return -1;
405 }
406 return 0;
407 }
408
409 /**
410 * Tests equality of two {@link MonitorMode} objects
411 * by evaluating equality of it's components:<br/>
412 * <ul>
413 * <li><code>nativeId</code></li>
414 * <li><code>sizeAndRRate</code></li>
415 * <li><code>rotation</code></li>
416 * </ul>
417 */
418 @Override
419 public final boolean equals(final Object obj) {
420 if (this == obj) { return true; }
421 if (obj instanceof MonitorMode) {
422 final MonitorMode sm = (MonitorMode)obj;
423 return sm.nativeId == this.nativeId &&
424 sm.sizeAndRRate.equals(sizeAndRRate) &&
425 sm.rotation == this.rotation ;
426 }
427 return false;
428 }
429
430 /**
431 * Returns a combined hash code of it's elements:<br/>
432 * <ul>
433 * <li><code>nativeId</code></li>
434 * <li><code>sizeAndRRate</code></li>
435 * <li><code>rotation</code></li>
436 * </ul>
437 */
438 @Override
439 public final int hashCode() {
440 return hashCode;
441 }
442 private final int getHashCode() {
443 // 31 * x == (x << 5) - x
444 int hash = 31 + getId();
445 hash = ((hash << 5) - hash) + sizeAndRRate.hashCode();
446 hash = ((hash << 5) - hash) + getRotation();
447 return hash;
448 }
449
450 private final int getRotatedWH(final boolean width) {
451 final DimensionImmutable d = sizeAndRRate.surfaceSize.getResolution();
452 final boolean swap = MonitorMode.ROTATE_90 == rotation || MonitorMode.ROTATE_270 == rotation ;
453 if ( ( width && swap ) || ( !width && !swap ) ) {
454 return d.getHeight();
455 }
456 return d.getWidth();
457 }
458}
Immutable SurfaceSize Class, consisting of it's read only components:
final boolean equals(final Object obj)
Checks whether two size objects are equal.
final DimensionImmutable getResolution()
Returns the resolution in pixel units.
int compareTo(final SurfaceSize ssz)
static String toHexString(final int hex)
Definition: Display.java:463
Immutable surfaceSize, flags and refreshRate Class, consisting of it's read only components:
final int hashCode()
Returns a combined hash code of it's elements:
final int flags
Mode bitfield flags, i.e.
SizeAndRRate(final SurfaceSize surfaceSize, final float refreshRate, final int flags)
int compareTo(final SizeAndRRate sszr)
final SurfaceSize surfaceSize
Non rotated surface size in pixel units.
static final StringBuilder flags2String(final int flags)
final boolean equals(final Object obj)
Tests equality of two SizeAndRRate objects by evaluating equality of it's components:
final float refreshRate
Vertical refresh rate.
Immutable MonitorMode Class, consisting of it's read only components:
static final int FLAG_DOUBLESCAN
Lines are doubled.
static final int ROTATE_90
90 degrees CCW rotation
final int getFlags()
Returns bitfield w/ flags, i.e.
final boolean equals(final Object obj)
Tests equality of two MonitorMode objects by evaluating equality of it's components:
static final Comparator< MonitorMode > monitorModeComparatorInv
Comparator for 2 MonitorModes, following comparison order as described in MonitorMode#compareTo(Monit...
final SizeAndRRate getSizeAndRRate()
Returns the surfaceSize and refreshRate instance.
MonitorMode(final SurfaceSize surfaceSize, final float refreshRate, final int flags, final int rotation)
Creates a user instance w/o identity to filter our matching modes w/ identity.
static final int FLAG_INTERLACE
Frame is split into two fields.
MonitorMode(final int nativeId, final SizeAndRRate sizeAndRRate, final int rotation)
final SurfaceSize getSurfaceSize()
Returns the unrotated SurfaceSize.
static boolean isRotationValid(final int rotation)
static final Comparator< MonitorMode > monitorModeComparator
Comparator for 2 MonitorModes, following comparison order as described in MonitorMode#compareTo(Monit...
final int getRotatedHeight()
Returns the rotated screen height in pixel units, derived from getMonitorMode().getSurfaceSize()....
final int hashCode()
Returns a combined hash code of it's elements:
final int getRotatedWidth()
Returns the rotated screen width in pixel units, derived from getMonitorMode().getSurfaceSize()....
final int getRotation()
Returns the CCW rotation of this mode.
static final int ROTATE_0
zero rotation, compared to normal settings
int compareTo(final MonitorMode mm)
final float getRefreshRate()
Returns the vertical refresh rate.
static final int ROTATE_270
270 degrees CCW rotation
static final int ROTATE_180
180 degrees CCW rotation