i’ve been playing around with changing DisplayModes, and found that when combined with BufferStrategy its not just unstable, it simply doesn’t work!
here is some cutdown code that demonstrates the sort of problems encountered.
also, in FullScreenFrame there are 2 lines (105 & 106) neither of which should be needed. However, by adding 1 or other (or both) of them I can get it to partially work. (but with allsorts of low-level exceptions being thrown up in native code)
Can some1 reassure me that its Sun code that is broken, not mine!
(A friend has also independantly attempted to solve the same problem, but hes come across the same bugs and crashes as well ??? )
FullScreenFrame.java
import java.awt.*;
import java.awt.image.*;
import java.awt.event.*;
public class FullScreenFrame extends Frame
{
private GraphicsDevice screenDevice;
private DisplayMode defaultMode;
boolean isWindowed = true;
String [] modeNames; //this is a String representation of each of the supported display modes
DisplayMode [] modes; //this is the [] of supported display modes
public FullScreenFrame(JavaMonster jm, GraphicsDevice gd)
{
super("F12 windowed/fullScreen toggle | UP/DOWN ARROWS cycle to new resolution | ENTER apply new resolution");
if(gd==null) gd = GraphicsEnvironment.getLocalGraphicsEnvironment().getDefaultScreenDevice();
this.screenDevice = gd;
this.defaultMode = gd.getDisplayMode(); // bad assumption made here. Needs fixing before I forget
/* 'just for debug' */
addKeyListener(jm);
addMouseListener(jm);
addWindowListener(jm);
/*end of 'just for debug' */
setIgnoreRepaint(true);
setResizable(false);
setLayout(null);
enableInputMethods(false);
//this code initialises the modes [] and modeNames []
// it also identifies the index of the default mode (defaultModeNumber)
modes = screenDevice.getDisplayModes();
modeNames = new String[modes.length];
for(int i = 0;i < modes.length;i++)
{
if(modes[i].equals(defaultMode)) defaultModeNumber = i;
DisplayMode cdm = modes[i];
modeNames[i] = "("+(i+1)+"/" + modes.length +")"+
cdm.getWidth()+"x"+cdm.getHeight()+"x"+
cdm.getBitDepth()+"@ "+cdm.getRefreshRate();
}
}
int defaultModeNumber;
public int getDefaultModeNumber()
{
return defaultModeNumber;
}
public int getModeCount()
{
return modes.length;
}
public boolean isFullScreen()
{
return !isWindowed;
}
public String getModeName(int mode)
{
return modeNames[mode];
}
//allows calling by index (just a lazy method)
public BufferStrategy setDisplayMode(boolean fullScreen, int mode)
{
return setDisplayMode(fullScreen, modes[mode]);
}
// sets the display mode of this Frame
// if the frame is not already visible,
// it will also be made visible
public BufferStrategy setDisplayMode(boolean fullScreen, DisplayMode dm)
{
System.out.println("Changing to "+ (fullScreen?"Full Screen ":"Window ") +
dm.getWidth() + "x" + dm.getHeight() + "x" + dm.getBitDepth());
if(fullScreen && screenDevice.isFullScreenSupported()) //switching to fullscreen mode (if its supported)
{
if(isWindowed)
{
dispose(); //dispose of the window ...
setUndecorated(true); //...so the decoration can be removed
screenDevice.setFullScreenWindow(this);
}
if(screenDevice.isDisplayChangeSupported() && !screenDevice.getDisplayMode().equals(dm))
{
screenDevice.setDisplayMode(dm);
createBufferStrategy();
}
else if(isWindowed) createBufferStrategy();
isWindowed = false;
}
else //we are changing to window mode
{
if(!isWindowed)
{
//screenDevice.setDisplayMode(defaultMode); //this line shouldn't be needed
//screenDevice.setFullScreenWindow(null); // this line shouldn't be needed
dispose(); //dispose of the window...
setUndecorated(false); //...so it can be changed to a decorated window
isWindowed=true;
}
Rectangle screenSize = screenDevice.getDefaultConfiguration().getBounds();
setBounds(screenSize.x + (screenSize.width -dm.getWidth())/2,
screenSize.y + (screenSize.height-dm.getHeight())/2,
dm.getWidth(), dm.getHeight()); //centres the window
if(!isVisible())
{
show();
createBufferStrategy();
}
}
return getBufferStrategy();
}
public static final boolean USE_BASIC_BUFFERSTRATEGY_ONLY = false;
private void createBufferStrategy()
{
if(USE_BASIC_BUFFERSTRATEGY_ONLY) return;
createBufferStrategy(2);
}
}
JavaMonster.java
import java.util.Random;
import java.awt.event.*;
import java.awt.image.*;
import java.awt.*;
import java.io.*;
class JavaMonster implements Runnable, MouseListener, WindowListener, KeyListener
{
boolean running = true; //just afew flags for changing mode
boolean changeToFullScreen = false;
boolean changeMode = false;
int currentMode;
int nextMode;
int modeChange=0;
FullScreenFrame fsf;
Random random = new Random();
BufferStrategy strategy;
public JavaMonster()
{
fsf = new FullScreenFrame(this,null);
nextMode = currentMode = fsf.getDefaultModeNumber();
strategy = fsf.setDisplayMode(false,currentMode);
new Thread(this).start();
}
public void run()
{
while(running)
{
if(modeChange!=0)
{
nextMode+=modeChange;
if(nextMode<0 || nextMode >= fsf.getModeCount()) nextMode-=modeChange;
modeChange=0;
}
if(changeMode)
{
strategy = fsf.setDisplayMode(changeToFullScreen,nextMode);
currentMode = nextMode;
changeMode = false;
}
Graphics2D g2 = (Graphics2D)strategy.getDrawGraphics();
g2.setColor(new Color(random.nextInt(255),random.nextInt(255),random.nextInt(255)));
g2.fillRect(0,0,fsf.getWidth(),fsf.getHeight());
g2.setColor(Color.black);
g2.drawString("Current Mode = " + fsf.getModeName(currentMode) + (changeToFullScreen?" FullScreen":" Windowed"), 20, 50);
g2.drawString("Next Mode = " + fsf.getModeName(nextMode) + (changeToFullScreen?" FullScreen":" Windowed"), 20, 80);
g2.dispose();
strategy.show();
try
{
Thread.currentThread().sleep(500);
}
catch(Exception e){}
}
fsf.dispose();
}
public static void main(String [] args) throws Exception
{
new JavaMonster();
}
//debug listeners
public void mouseClicked(MouseEvent e) {}
public void mouseEntered(MouseEvent e) {}
public void mouseExited(MouseEvent e) {}
public void mousePressed(MouseEvent e) {}
public void mouseReleased(MouseEvent e) {}
public void mouseDragged(MouseEvent e) {}
public void mouseMoved(MouseEvent e) {}
public void keyPressed(KeyEvent e)
{
switch(e.getKeyCode())
{
case KeyEvent.VK_ESCAPE: //Escape to kill the Thread (and eventually dispose of the Window)
running = false;
return;
case KeyEvent.VK_UP: //up arrow to cycle up through supported resolutions
modeChange=1;
return;
case KeyEvent.VK_DOWN: //down arrow to cycle down through supported resolutions
modeChange=-1;
}
}
public void keyReleased(KeyEvent e)
{
switch(e.getKeyCode())
{
case KeyEvent.VK_F12: //F12 toggles FullScreen
changeToFullScreen=!changeToFullScreen;
/* follows through */
case KeyEvent.VK_ENTER: //Enter to apply new resolution selection
changeMode=true;
}
}
public void keyTyped(KeyEvent e) {}
public void windowClosing(WindowEvent e)
{
System.out.println("Window closing");
running = false;
}
public void windowActivated(WindowEvent e) {System.out.println("Window activated");}
public void windowClosed(WindowEvent e) {System.out.println("Window closed");}
public void windowDeactivated(WindowEvent e) {System.out.println("Window deactivated");}
public void windowDeiconified(WindowEvent e) {System.out.println("Window deiconified");}
public void windowIconified(WindowEvent e) {System.out.println("Window iconified");}
public void windowOpened(WindowEvent e) {System.out.println("Window opened");}
}