package psychWithJava; /* * Final version: FullScreen.java * * currently final is based * on FullScreen3 from ch10. * * * 38+ methods * * hb, 06.06.02+ * * FullScreen is a class, which contains methods to present stimuli to observers * and get their behavioral responses in a psychophysics experiment. Requires * JRE 1.5+. * * Copyright (C) 2005-2006 Huseyin Boyaci * * This program is free software; you can redistribute it and/or modify it under * the terms of the GNU General Public License as published by the Free Software * Foundation; either version 2 of the License, or (at your option) any later * version. This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. * * See the GNU General Public License for more details. (http://www.gnu.org) You * should have received a copy of the GNU General Public License along with this * program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - * Suite 330, Boston, MA 02111-1307, USA. * */ import java.awt.*; import java.awt.event.KeyEvent; import java.awt.event.KeyListener; import java.awt.font.FontRenderContext; import java.awt.geom.Rectangle2D; import java.awt.image.BufferedImage; import java.util.concurrent.BlockingQueue; import java.util.concurrent.LinkedBlockingQueue; import java.util.concurrent.TimeUnit; import javax.swing.JFrame; /** * FullScreen class provides methods to display visual stimuli * and interact with the observer in full screen exclusive mode (FSEM). *

* FullScreen is capable of chosing the best available mode and * strategy on a particular software (OS) and hardware. By default the * user does not * have to change any of these strategies. However it provides * methods for expert users who wish to modify those strategies. Requires Java * SE 6.0 or higher. *

* Methods provided include: displayImage() to display images, * displayText() to display text, and * getKeyPressed() to get observer's keyboard responses. Because it * is inherited from the Java core class JFrame, all its methods * are also available, such as setForeground(). *

* See * Psychophysics Programming with Java * for more information and sample demo programs. *

* FullScreen class utilizes the * Full screen exclusive mode (FSEM), a feature of Java (after J2SE 1.4) * that allows * programmers to suspend the windowing system of the underlying OS, and * directly access the video card and draw on the screen. If exclusive full * screen is not supported a regular window is positioned at (0,0) and resized * to fit the whole screen to mimic full screen exclusive mode. Whether in full * screen exclusive mode or not, FullScreen usues active * rendering as opposed to passive rendering - in passive rendering the * underlying OS may intervene and send directives to the rendering program, * whereas in active rendering the program itself is responsible of drawing and * re-drawing the contents on the screen without the intervention of * OS's directives. *

* For more details, developers can see JSE API definitions at http://java.sun.com. See also * * Java 2D API, * * Full-Screen Exclusive Mode API tutorial, * Programmer's Guide to the Java 2D API, * * Painting in AWT and Swing, * * Trail: 2D Graphics, and * Java 2D new features in J2SE 5.0. *

* Note: Java 2D API (and rest of the entire platform) is improved with JSE 5.0, * and the FullScreen requires at least edition 6.0. * Java SE 6.0 is available on all * platforms (Linux, Mac OS X (only Tiger and later), and MS Windows). *

* Note: Real full screen exclusive mode is not supported on Linux in Java SE * 5.0, but it simulates the exclusive mode. However this situation is fixed * in edition 6. Now FSEM * on Linux works fine especially with opengl pipeline enabled. * To enable opengl pipeline user must specify the following * system property on the command line: * -Dsun.java2d.opengl=True. More information is available * at Psychophysics programming with Java. *

* Matlab and Mathematica development: *
* It is possible to create Java objects from within Matlab and Mathematica. You * can, therefore, create a Java object in Matlab or Mathematica and * invoke its methods. In other words, if you choose, you could use this package * with Matlab or Mathematica as a tool for psychophysics programming in a way much like the well known Psychtoolbox package is used with Matlab. * See * Psychophysics Programming with Java for more information. * * @see NormalWindow * @see BitsPP * * @author Huseyin Boyaci */ public class FullScreen extends JFrame implements KeyListener { private static final GraphicsEnvironment gEnvironment = GraphicsEnvironment .getLocalGraphicsEnvironment(); private static final GraphicsDevice[] gDevices = gEnvironment .getScreenDevices(); private GraphicsDevice gDevice; private GraphicsConfiguration gConfiguration; private final static int defaultNBuffers = 1; private final static Color defaultBgColor = Color.BLACK; private final static Color defaultFgColor = Color.LIGHT_GRAY; private final Font defaultFont = new Font("SansSerif", Font.BOLD, 36); private int nBuffers; private Color bgColor; private DisplayMode oldDisplayMode; private DisplayMode displayMode; private BlockingQueue keyTyped; private BlockingQueue whenKeyTyped; private BlockingQueue keyPressed; private BlockingQueue whenKeyPressed; private BlockingQueue keyReleased; private BlockingQueue whenKeyReleased; public void keyTyped(KeyEvent ke) { keyTyped.offer(String.valueOf(ke.getKeyChar())); whenKeyTyped.offer(ke.getWhen()); } public void keyReleased(KeyEvent ke) { keyReleased.offer(ke.getKeyCode()); whenKeyReleased.offer(ke.getWhen()); } public void keyPressed(KeyEvent ke) { if (ke.getKeyCode() == KeyEvent.VK_ESCAPE) { closeScreen(); System.exit(0); } else { keyPressed.offer(ke.getKeyCode()); whenKeyPressed.offer(ke.getWhen()); } } /** * Constructs a FullScreen object on the screen designated with * displayID. By default it uses a single video buffer and the current * display mode of the client's OS. * Once it is constructed, FullScreen captures the entire screen * immediately. At the end user's program must * terminate this mode and go back to system's default display. * To do this use the method closeScreen(). * * @param displayID a numerical id indicating the screen device * * @see #setDisplayMode(DisplayMode) * @see #setNBuffers(int) * @see #closeScreen() * */ public FullScreen(int displayID) { super(gDevices[displayID].getDefaultConfiguration()); // apple.awt.fullscreencapturealldisplays = false; gDevice = gDevices[displayID]; gConfiguration = gDevice.getDefaultConfiguration(); oldDisplayMode = gDevice.getDisplayMode(); displayMode = gDevice.getDisplayMode(); try { setUndecorated(true); setIgnoreRepaint(true); setResizable(false); setBackground(defaultBgColor); super.setBackground(defaultBgColor); setFont(defaultFont); setForeground(defaultFgColor); gDevice.setFullScreenWindow(this); setNBuffers(defaultNBuffers); Rectangle gcBounds = gConfiguration.getBounds(); int xoffs = gcBounds.x; int yoffs = gcBounds.y; int width = gcBounds.width; int height = gcBounds.height; setBounds(xoffs, yoffs, width, height); keyTyped = new LinkedBlockingQueue(); whenKeyTyped = new LinkedBlockingQueue(); keyPressed = new LinkedBlockingQueue(); whenKeyPressed = new LinkedBlockingQueue(); keyReleased = new LinkedBlockingQueue(); whenKeyReleased = new LinkedBlockingQueue(); addKeyListener(this); } finally {} } /** * * Constructs a FullScreen object on the default screen. * By default it uses a single video buffer and the current * display mode. Once it is constructed, FullScreen captures the entire screen * immediately. At the end user's program must * terminate this mode and go back to system's default display. * To do this use the method closeScreen(). * * @see #setDisplayMode(DisplayMode) * @see #setNBuffers(int) * @see #closeScreen() */ public FullScreen() { this(0); } /** * Sets number of video buffers (including the front (visible) one). * If the number is 1, it implies no back buffer. 2 implies * one front one back buffer (double buffering). * * @param n number of buffers requested; must not be less than 1 * * @see #getNBuffers() */ public void setNBuffers(int n) { try { createBufferStrategy(n); nBuffers = n; } catch (IllegalArgumentException e) { System.err.println("Exception in FullScreen.setNBuffers(): " + "requested number of Buffers is illegal - falling back to default"); createBufferStrategy(defaultNBuffers); } try { Thread.sleep(200); } catch (InterruptedException e) { Thread.currentThread().interrupt(); } } /** * Returns number of video buffers (including the front (visible) one) * currently used * by this FullScreen object. * * @return number of video buffers used by this FullScreen object * * @see #setNBuffers(int) */ public int getNBuffers() { return nBuffers; } /** * Updates the entire screen by bringing the back video buffer front (if there * exists a back buffer, if not it has no effect). * The methods in FullScreen class (displayImage(), displayText() * or blankScreen(), see below) always manipulate the video bufer, not * necessarily the screen. * In case there is a back video buffer those methods affect only the * back (invisible) buffer. After invoking those methods * user has to invoke the updateScreen() method to actually * bring the back buffer to front, in other words to make it actually visible * on the screen device. * * @see #displayImage(int, int, BufferedImage) * @see #displayText(int, int, String) * @see #blankScreen() * */ public void updateScreen() { if (getBufferStrategy().contentsLost()) setNBuffers(nBuffers); getBufferStrategy().show(); } /** * Displays a BufferedImage at the center of the screen. * Note that, in case there is a back video buffer * this method draws the image on the back buffer. In that case * user has to invoke the updateScreen() method * to actually display the image on the screen. * * @param bi BufferedImage to display * * @see #displayImage(int, int, BufferedImage) * @see #updateScreen() */ public void displayImage(BufferedImage bi) { if (bi != null) { double x = (getWidth() - bi.getWidth()) / 2; double y = (getHeight() - bi.getHeight()) / 2; displayImage((int) x, (int) y, bi); } } /** * Displays a BufferedImage at the specified position. * Note that, in case there is a back video buffer * this method draws the image on the back buffer. In that case * user has to invoke the updateScreen() method * to actually display the image on the screen. * * @param x horizontal offset of the upper left corner of the image from the * upper left corner of the screen * @param y vertical offset of the upper left corner of the image from the * upper left corner of the screen * @param bi BufferedImage to display * * @see #displayImage(BufferedImage) * @see #updateScreen() */ public void displayImage(int x, int y, BufferedImage bi) { Graphics2D g = (Graphics2D) getBufferStrategy().getDrawGraphics(); try { if (g != null && bi != null) g.drawImage(bi, x, y, null); } finally { g.dispose(); } } /** * Displays text at the center of the screen. * Note that, in case there is a back video buffer * this method draws the text on the back buffer. In that case * user has to invoke the updateScreen() method * to actually display the text on the screen. * * @param text a text message to display * * @see #displayText(int, int, String) * @see #updateScreen() */ public void displayText(String text) { Graphics2D g = (Graphics2D) getBufferStrategy().getDrawGraphics(); if (g != null && text != null) { Font font = getFont(); g.setFont(font); FontRenderContext context = g.getFontRenderContext(); Rectangle2D bounds = font.getStringBounds(text, context); double x = (getWidth() - bounds.getWidth()) / 2; double y = (getHeight() - bounds.getHeight()) / 2; double ascent = -bounds.getY(); double baseY = y + ascent; displayText((int) x, (int) baseY, text); } g.dispose(); } /** * Displays text at the specified position. * Note that, in case there is a back video buffer * this method draws the text on the back buffer. In that case * user has to invoke the updateScreen() method * to actually display the text on the screen. * * @param x horizontal offset of the upper left corner of the text from the * upper left corner of the screen * @param y vertical offset of the upper left corner of the text from the * upper left corner of the screen * @param text a text message to display * * @see #displayText(String) * @see #updateScreen() */ public void displayText(int x, int y, String text) { Graphics2D g = (Graphics2D) getBufferStrategy().getDrawGraphics(); try { if (g != null && text != null) { g.setFont(getFont()); g.setColor(getForeground()); g.drawString(text, x, y); } } finally { g.dispose(); } } /** * Blanks the whole screen using the current background color. * Note that, in case there is a back video buffer * this method blanks the back buffer. In that case * user has to invoke the updateScreen() method * to actually blank the screen. * * @see #updateScreen() * */ public void blankScreen() { Graphics2D g = (Graphics2D) getBufferStrategy().getDrawGraphics(); try { if (g != null) { g.setColor(getBackground()); g.fillRect(0, 0, getWidth(), getHeight()); } } finally { g.dispose(); } } /** * Returns the current background color. * * @return current background color * * @see #setBackground(Color) * */ public Color getBackground() { return bgColor; } /** * Sets the background color. * * @param bg new background color * * @see #getBackground() */ public void setBackground(Color bg) { bgColor = bg; } /** * Renders the cursor invisible. * * @see #showCursor() * */ public void hideCursor() { Cursor noCursor = null; Toolkit tk = Toolkit.getDefaultToolkit(); Dimension d = tk.getBestCursorSize(1, 1); if ((d.width | d.height) != 0) noCursor = tk.createCustomCursor(new BufferedImage(d.width, d.height, BufferedImage.TYPE_INT_ARGB), new Point(0, 0), "noCursor"); setCursor(noCursor); } /** * Renders the cursor visible using default cursor * * @see #hideCursor() * */ public void showCursor() { setCursor(new Cursor(Cursor.DEFAULT_CURSOR)); } /** * Closes the full screen exclusive mode screen. * This method performs also the * following additional steps: * It switches the resolution back to system setting (if it was altered), * releases all the screen resources to the operating system. * User must invoke this method to re-gain access to normal desktop. * * @see #FullScreen(int) * @see #FullScreen() * */ public void closeScreen() { if (gDevice.isDisplayChangeSupported()) setDisplayMode(oldDisplayMode); gDevice.setFullScreenWindow(null); dispose(); } /** * Returns the key typed by the observer within a specified amount of time. *

* If the specified wait time is * positive: This method either (i) returns the top element in the * keyTyped queue immediately if there is * at least one element in the keyTyped event queue or * (ii) waits up to the specified amount of time for an element * to become available. If no key is typed * within the specified amount of time * it returns null. *

* If the specified time is zero: Returns the top element in * the keyTyped event queue or null if queue is empty. *

* If the specified wait time is negative: This method * either returns the top element in the queue or if the queue is * empty it waits indefinetely untill the observer types a character. *

* In all cases, the element returned is removed from the event queue. *

* * General principles of event handling in FullScreen: * FullScreen captures the key events in a seperate Thread and stores * them in Thread safe BlockingQueue objects. Anytime observer * types, presses or releases a key, that key and the time of the * event are inserted to the end (tail) * of the respective queues. When one of the getKeyTyped(), getKeyPressed() * or getKeyReleased() methods is invoked, the top (head) of the respective * queue is retrived and removed. Similarly, getWhenKeyTyped(), * getWhenKeyPressed() and getWhenKeyReleased() methods retrive and remove * the head in event time queues. flushKeyTyped(), flushKeyPressed() and * flushKeyReleased() methods clear all queues, including the event time queues. *

* For more information and examples see * Psychophysics programming with Java. * * @param ms time in milliseconds to wait for a response * * @return the key typed * * @see #getKeyTyped() * @see #flushKeyTyped() * @see #getWhenKeyTyped() */ public String getKeyTyped(long ms) { String c = null; try { if (ms < 0) c = keyTyped.take(); else c = keyTyped.poll(ms, TimeUnit.MILLISECONDS); } catch (InterruptedException e) { Thread.currentThread().interrupt(); e.printStackTrace(); } return c; } /** * Returns the key typed by the observer. * Returns the top element in keyTyped * queue or null if queue is empty. Equivelent to invoking getKeyTyped(0). *

* The element returned is removed from the event queue. See also * general principles of event handling in FullScreen * above. *

* For more information and examples see * Psychophysics programming with Java. * * @return the key typed * * @see #getKeyTyped(long) * @see #flushKeyTyped() * @see #getWhenKeyTyped() */ public String getKeyTyped() { return keyTyped.poll(); } /** * Returns the time of the key typed event. * Returns the top element in the whenKeyTyped queue, * null if queue is empty. *

* The element returned is removed from the event queue. See also * general principles of event handling in FullScreen * above. *

* For more information see * Psychophysics programming with Java. * * @return the time of key typed event * * @see #getKeyTyped(long) * @see #flushKeyTyped() */ public Long getWhenKeyTyped() { return whenKeyTyped.poll(); } /** * Clears both keyTyped and whenKeyTyped queues. See also * general principles of event handling in FullScreen * above. *

* For more information and examples see * Psychophysics programming with Java. * * @see #getKeyTyped(long) * @see #getWhenKeyTyped() */ public void flushKeyTyped() { keyTyped.clear(); whenKeyTyped.clear(); } /** * Returns the key pressed by the observer within a specified amount of time. *

* If the specified wait time is * positive: This method either (i) returns the top element in the * keyPressed queue immediately if there is * at least one element in the keyPressed event queue or * (ii) waits up to the specified amount of time for an element * to become available. If no key is pressed * within the specified amount of time * it returns null. *

* If the specified time is zero: Returns the top element in * the keyPressed event queue or null if queue is empty. *

* If the specified wait time is negative: This method * either returns the top element in the queue or if the queue is * empty it waits indefinetely untill the observer presses a key. *

* In all cases, the element returned is removed from the event queue. * See also * general principles of event handling in FullScreen * above. *

* For more information and examples see * Psychophysics programming with Java. * * @param ms time in milliseconds to wait for a response * * @return numeric code of the key pressed * * @see #getKeyPressed() * @see #flushKeyPressed * @see #getWhenKeyPressed() */ public Integer getKeyPressed(long ms) { Integer c = null; try { if (ms < 0) c = keyPressed.take(); else c = keyPressed.poll(ms, TimeUnit.MILLISECONDS); } catch (InterruptedException e) { Thread.currentThread().interrupt(); e.printStackTrace(); } return c; } /** * Returns the key pressed by the observer. * Returns the top element in keyPressed * queue or null if queue is empty. Equivelent to invoking getKeyPressed(0). *

* The element returned is removed from the event queue. See also * general principles of event handling in FullScreen * above. *

* For more information and examples see * Psychophysics programming with Java. * * @return numeric code of the key pressed * * @see #getKeyPressed(long) * @see #flushKeyPressed() * @see #getWhenKeyPressed() */ public Integer getKeyPressed() { return keyPressed.poll(); } /** * Returns the time of the key pressed event. * Returns the top element in the whenKeyPressed queue, * null if queue is empty. *

* The element returned is removed from the event queue. See also * general principles of event handling in FullScreen * above. *

* For more information and examples see * Psychophysics programming with Java. * * @return the time of key pressed event * * @see #getKeyPressed(long) * @see #flushKeyPressed() */ public Long getWhenKeyPressed() { return whenKeyPressed.poll(); } /** * Clears both key pressed and when key pressed queues. * See also * general principles of event handling in FullScreen * above. *

* For more information and examples see * Psychophysics programming with Java. * * @see #getKeyPressed(long) * @see #getWhenKeyPressed() */ public void flushKeyPressed() { keyPressed.clear(); whenKeyPressed.clear(); } /** * Returns the key released by the observer within a specified amount of time. *

* If the specified wait time is * positive: This method either (i) returns the top element in the * keyReleased queue immediately if there is * at least one element in the keyReleased event queue or * (ii) waits up to the specified amount of time for an element * to become available. If no key is released * within the specified amount of time * it returns null. *

* If the specified time is zero: Returns the top element in * the keyReleased event queue or null if queue is empty. *

* If the specified wait time is negative: This method * either returns the top element in the queue or if the queue is * empty it waits indefinetely untill the observer releases a key. *

* In all cases, the element returned is removed from the event queue. * See also * general principles of event handling in FullScreen * above. *

* For more information and examples see * Psychophysics programming with Java. * * @param ms time in milliseconds to wait for a response * * @return numerical code of the key released * * @see #getKeyReleased() * @see #flushKeyReleased * @see #getWhenKeyReleased() */ public Integer getKeyReleased(long ms) { Integer c = null; try { if (ms < 0) c = keyReleased.take(); else c = keyReleased.poll(ms, TimeUnit.MILLISECONDS); } catch (InterruptedException e) { Thread.currentThread().interrupt(); e.printStackTrace(); } return c; } /** * Returns the key released by the observer. * Returns the top element in keyReleased * queue or null if queue is empty. Equivelent to invoking getKeyReleased(0). *

* The element returned is removed from the event queue. See also * general principles of event handling in FullScreen * above. *

* For more information and examples see * Psychophysics programming with Java. * * @return numerical code of the key released * * @see #getKeyReleased(long) * @see #flushKeyReleased() * @see #getWhenKeyReleased() */ public Integer getKeyReleased() { return keyReleased.poll(); } /** * Returns the time of the key released event. * Returns the top element in the whenKeyReleased queue, * null if queue is empty. *

* The element returned is removed from the event queue. See also * general principles of event handling in FullScreen * above. *

* For more information and examples see * Psychophysics programming with Java. * * @return the time of key released event * * @see #getKeyReleased(long) * @see #flushKeyReleased() */ public Long getWhenKeyReleased() { return whenKeyReleased.poll(); } /** * Clears both key released and when key released queues. * See also * general principles of event handling in FullScreen * above. *

* For more information and examples see * Psychophysics programming with Java. * * @see #getKeyReleased(long) * @see #getWhenKeyReleased() */ public void flushKeyReleased() { keyReleased.clear(); whenKeyReleased.clear(); } /** * Returns whether or not Full Screen Exclusive Mode (FSEM) is * supported on client's system. * * @return true if full screen exclusive mode is supported */ public boolean isFullScreenSupported() { return gDevice.isFullScreenSupported(); } /** * Sets a new DisplayMode: secreen resolution, vertical synchronization rate, * and color depth. If the requested DisplayMode is not applicable or * DisplayMode change is not supported it causes the * termination of the user's program, in order to avoid an erronous * experimental session. * * @param dm new display mode to apply * * @see #isDisplayChangeSupported() * @see #isDisplayModeAvailable(DisplayMode) */ public void setDisplayMode(DisplayMode dm) { if (displayMode.equals(dm)) return; else if (!gDevice.isDisplayChangeSupported() || dm == null) { System.err.println("Exception in FullScreen.setDisplayMode(): " + "Display Change not Supported or DisplayMode is null"); closeScreen(); System.exit(0); } else if (!isDisplayModeAvailable(dm)) { System.err.println("Exception in FullScreen.setDisplayMode(): " + "DisplayMode not available"); System.err.println(""); System.err.println("Supported DisplayModes are:"); String[] dms = reportDisplayModes(); for (int i = 0; i < dms.length; i++) { System.err.print(dms[i]); if ((i + 1) % 4 == 0) System.err.println(); } closeScreen(); System.exit(0); } else { try { gDevice.setDisplayMode(dm); displayMode = dm; setBounds(0, 0, dm.getWidth(), dm.getHeight()); Thread.sleep(200); } catch (InterruptedException e) { Thread.currentThread().interrupt(); } catch (RuntimeException e) { System.err.println("Exception in FullScreen.setDisplayMode(): " + "DisplayMode not available or " + "Display Change not Supported"); System.err.println(""); System.err.println("Supported DisplayModes are:"); String[] dms = reportDisplayModes(); for (int i = 0; i < dms.length; i++) { System.err.println(dms[i]); if ((i + 1) % 4 == 0) System.err.println(); } closeScreen(); System.exit(0); } } } /** * Returns whether or not given DisplayMode is applicable to client's screen. * * @param dm DisplayMode to check * * @return whether dm is applicable or not */ public boolean isDisplayModeAvailable(DisplayMode dm) { DisplayMode[] mds = gDevice.getDisplayModes(); for (int i = 0; i < mds.length; i++) { if (mds[i].getWidth() == dm.getWidth() && mds[i].getHeight() == dm.getHeight() && mds[i].getBitDepth() == dm.getBitDepth() && mds[i].getRefreshRate() == dm.getRefreshRate()) return true; } return false; } /** * Returns the current screen resolution, vertical * synchronization rate and color depth in a readable * form. * * @return current DisplayMode in readable form */ public String reportDisplayMode() { StringBuilder message = new StringBuilder(); if (displayMode.getBitDepth() == DisplayMode.BIT_DEPTH_MULTI) message.append(" Bit Depth = -1 (MULTIPLE) \n"); else message.append(" Bit Depth = " + displayMode.getBitDepth() + "\n"); message.append(" Width = " + displayMode.getWidth() + "\n"); message.append(" Height = " + displayMode.getHeight() + "\n"); if (displayMode.getRefreshRate() == DisplayMode.REFRESH_RATE_UNKNOWN) message.append(" Refresh Rate = 0 (unknown/unmodifiable) \n"); else message.append(" Refresh Rate = " + displayMode.getRefreshRate() + "\n"); return message.toString(); } /** * Returns the current DisplayMode. * * @return current DisplayMode */ public DisplayMode getDisplayMode() { return displayMode; } /** * Returns whether or not DisplayMode change is available on * client's system. * * @return true if DisplayMode change is available */ public boolean isDisplayChangeSupported() { return gDevice.isDisplayChangeSupported(); } /** * Reports all available DisplayMode parameters in a readable * format. * * @return all available DisplayMode parameters. */ public String[] reportDisplayModes() { DisplayMode[] dms = getDisplayModes(); String[] message = new String[dms.length]; for (int i = 0; i < dms.length; i++) { StringBuilder m = new StringBuilder("(" + dms[i].getWidth() + "," + dms[i].getHeight() + "," + dms[i].getBitDepth() + "," + dms[i].getRefreshRate() + ") "); message[i] = m.toString(); } return message; } /** * Returns all available DisplayModes on client's system. * * @return all available DisplayModes. */ public DisplayMode[] getDisplayModes() { return gDevice.getDisplayModes(); } }