Fullscreen/Windowed mode toggling

I’ve looked through the various JavaGaming posts (including the Balls.jar example) and the Java Forums. I can’t seem to find any information on how to correctly toggle between Fullscreen (and undecorated) and Windowed (and decorated) modes.

I have tried a few different ways. I have tried using 2 JFrames (one decorated and one not) as well as using the addNotify/removeNotify so that I could call setUndecorated on a single JFrame. In either case, it sometimes goes blank when switching back into Fullscreen, even though the Active Rendering loop continues to process.

Does anyone have a simplistic example of how to switch back and forth between the two modes?

Have you tried the latest 1.5beta? (3 i think?)

Its bugged to hell in 1.4.x.

The most important thing you have to remember, is that you must do the display changing from within your main rendering loop.
If you try and do it in the eventdispatch Thread (i.e. from a [key/mouse]press), and your main render Thread is still running - you will end up with horrible things happening.

I am using 1.5.0b2 right now. I looked through the docs on b3, but it did not appear there were any changes to the FSEM handling.

I was however doing the mode change from the mouseListener… hmm, I will take a look at that.

OMG!

Switching still causes a crash - not only that but it leaves my machine in an unstable state. (anything vaguely related to explorer [Word, ControlPanel, etc] all cause a explorer to hang)


import java.awt.*;
import java.awt.event.*;
import java.awt.image.*;

public class FullscreenSwitchTest extends Frame implements KeyListener
{
   volatile boolean change = true;
   volatile boolean running = true;
   
   public void keyPressed(KeyEvent ke)
   {
      if(ke.getKeyCode()==KeyEvent.VK_ESCAPE)
      {
         change = false;
         running = false;
      }
      else
      {
         change = true;
      }
   }
   
   public void keyReleased(KeyEvent ke){}
   public void keyTyped(KeyEvent ke){}
   
   public FullscreenSwitchTest()
   {
      boolean fullscreen = true;
      addKeyListener(this);
      GraphicsDevice gd = GraphicsEnvironment.getLocalGraphicsEnvironment().getDefaultScreenDevice();
      
      while(running)
      {
         if(change)
         {
            fullscreen=!fullscreen;
            
            dispose();
            if(fullscreen)
            {
               setUndecorated(true);
               gd.setFullScreenWindow(this);
               gd.setDisplayMode(new DisplayMode(800,600,32,0));
            }
            else
            {
               setUndecorated(false);
               setBounds(0,0,800,600);
               setVisible(true);
            }
            change = false;
         }
      }
   }   
  
   public static void main(String [] args)
   {
      new FullscreenSwitchTest();
   }
}

The code works initially.

I 1st get windowed.
Then it goes to fullscreen.
Then back to windowed.
Then the next change to fullscreen causes this :-

[quote]Exception in thread “main” java.lang.NullPointerException: peer
at sun.awt.Win32GraphicsDevice.configDisplayMode(Native Method)
at sun.awt.Win32GraphicsDevice.setDisplayMode(Win32GraphicsDevice.java:3
93)
at FullscreenSwitchTest.(FullscreenSwitchTest.java:43)
at FullscreenSwitchTest.main(FullscreenSwitchTest.java:58)
[/quote]
Not sure what version im running, its 1.5beta something (either 1 or 2)

Rather disturbing realy, no BufferStrategy, infact no rendering at all :S
I hate to think how many more bugs will be unleashed if I add a createBufferStrategy in there :S

Heh… and I almost started a thread some days ago for asking if that works now :slight_smile:

I have a test, which is a derivative from the infamous Balls,which automatically changes to and from fullscreen mode for all display modes available, and that thing runs through a whole night of switching… =)

I’d post the code (which is quite different from the original balls now…), if only I had the time to create a project on java.net

I’m not saying that there’s no bug there, though… Please file one…

and that thing runs through a whole night of switching… =)

Hope you turned the monitor off. Massive mode switching is kinda “unhealthy” :wink:

[quote]>Hope you turned the monitor off. Massive mode switching is kinda “unhealthy” :wink:
[/quote]
Since when? Re-syncing a clock is hardly a big deal. What is your justification for this statement?

[quote]I have a test, which is a derivative from the infamous Balls,which automatically changes to and from fullscreen mode for all display modes available, and that thing runs through a whole night of switching… =)
[/quote]
You know, I tried the original Balls.jar, and it worked OK – but windowed mode was still fullscreen (ie: no decorations)…

[quote]I’d post the code (which is quite different from the original balls now…), if only I had the time to create a project on java.net

I’m not saying that there’s no bug there, though… Please file one…
[/quote]
How do I find that code?

Thanks.

[quote]Since when?
[/quote]
Since… always? :slight_smile:

I mean resolution changes (with a CRT).

Ok, I got it working. I had been trying to extend JFrame and either modify it or use it with another protected instance of JFrame.

I looked over the Balls.jar example a few times, and couldn’t find where setFullScreen was actually doing anything. I realized that SOME of the source files were not included. Using FrontEndPlus, I reversed the other class files (specifically GameFrame), and saw where those changes were.

The way I got it working (clean and fast) was to NOT extend JFrame (like GameFrame) and maintain 2 protected JFrames. The other key was to remove the Insets for the Windowed frame, as below (an extension of JFrame that has this method):


      public Rectangle getInsetBounds()
      {
            Rectangle bounds = this.getBounds();
            Insets fi = this.getInsets();
            return new Rectangle(
                  bounds.x + fi.left,
                  bounds.y + fi.top,
                  bounds.width - (fi.left + fi.right),
                  bounds.height - (fi.top + fi.bottom)
            );
      }

I would like to say, for any Sun developers who might be watching this, that I think it would be of great benefit (and cleanness of code) to be able to toggle between fullscreen and windowed modes on a single JFrame. The gfxDevice.setFullScreen(boolean) does not allow for this because of the inability to call setUndecorated(boolean) after the Peer has been created (without calling removeNotify/addNotify).

Thanks everyone for the assistance.

I’ve got my post snippet above working too.

It seems there are still 2 bugs present in the disposing of Frames.

This is the bug exposed by my previous code snippet.

If you dispose of a window before it has EVER been made displayable, it will die the second time you try and go into fullscreen mode.
i.e.

APP. START

dispose
goto Windowed
dispose
goto Fullscreen
dispose
goto Windowed
dispose
goto Fullscreen causes APP. DEATH

I fixed the problem above, by wrapping the dispose() in an ‘if(isDisplayable())’ so the initial call to dispose() is avoided.
This fixes the crash experienced above… however.

It appears that calling dispose() on a window that is currently in fullscreen exclusive mode is still abit ‘iffy’.

Occasionally when going from fullscreen to windowed mode, it will fail to restore the desktop resolution.
This can be fixed by adding a setFullscreenWindow(null), before calling dispose().

It so happens that the fix for problem 2) also fixes the problem experienced in 1), so the ‘if(isDisplayable())’ wrapping around dispose() can be eliminated.
Doing this leaves the code below as the absolute bare minimum that will successfully switch fullscreen<->windowed on my machine.


import java.awt.*;
import java.awt.event.*;
import java.awt.image.*;
public class FullscreenSwitchTest extends Frame implements KeyListener
{
   volatile boolean change = true;
   volatile boolean running = true;
   
   public void keyPressed(KeyEvent ke)
   {
      if(ke.getKeyCode()==KeyEvent.VK_ESCAPE)
      {
         change = false;
         running = false;
      }
      else
      {
         change = true;
      }
   }
   
   public void keyReleased(KeyEvent ke){}
   public void keyTyped(KeyEvent ke){}
   
   public FullscreenSwitchTest()
   {
      boolean fullscreen = true;
      addKeyListener(this);
      GraphicsDevice gd = GraphicsEnvironment.getLocalGraphicsEnvironment().getDefaultScreenDevice();      
      while(running)
      {
         if(change)
         {
            fullscreen=!fullscreen;
            

            gd.setFullScreenWindow(null);//this line fixes 2 bugs.
            
            dispose();
            
            setUndecorated(fullscreen);
            if(fullscreen)
            {
               gd.setFullScreenWindow(this);
               gd.setDisplayMode(new DisplayMode(800,600,32,0));
            }
            else
            {
               setBounds(0,0,800,600);
               setVisible(true);
            }
            change = false;
         }
      }
   }   
  
   public static void main(String [] args)
   {
      new FullscreenSwitchTest();
   }
}

[quote]It seems there are still 2 bugs present in the disposing of Frames.
[/quote]
I am not currently overriding dispose() at all. I do however have the RuntimeShutdownHook (from http://fivedots.coe.psu.ac.th/~ad/jg/ch03/index.html):

called during init:


            readyForTermination();

and then…


      protected void readyForTermination()
      {
            Runtime.getRuntime().addShutdownHook(
                  new Thread()
                  {
                        public void run()
                        {
                              fpsTimer.end();
                              setFullScreen(false);
                        }
                  }
            );
      }

this ensures that it is back in the original windowed display mode.

[quote]The way I got it working (clean and fast) was to NOT extend JFrame (like GameFrame) and maintain 2 protected JFrames. The other key was to remove the Insets for the Windowed frame, as below (an extension of JFrame that has this method):
[/quote]
One slight problem with this is that the Insets are not set if you call:


JFrame.setDefaultLookAndFeelDecorated(true);

I added a comment about this to this bug report:
http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=5050922

As a side note, when using a KeyListener to switch modes (with ALT-ENTER), it is necessary to put the code in keyReleased instead of keyTyped, as the keyTyped never gets an “ALT-ENTER” key.


            public void keyReleased(KeyEvent event)
            {
                  if(event.isAltDown() && (event.getKeyCode() == VK_ENTER))
                        toggleFullScreen();
            }

I don’t believe it until I hear a rational explanation. What is a resolution change going to do that will cause ‘wear’ ?

Are you referring to a potential de-Gauss triggered by the resolution change? That would involve a surge of power I suppose, but I find it is a bit of a stretch to imply that would be what wears out the monitor.

[quote]I don’t believe it until I hear a rational explanation. What is a resolution change going to do that will cause ‘wear’ ?

Are you referring to a potential de-Gauss triggered by the resolution change? That would involve a surge of power I suppose, but I find it is a bit of a stretch to imply that would be what wears out the monitor.
[/quote]
Well, it makes a klicking noise (“line transformator”(?) changing freq) and all old dos/vesa games (which determined the best mode by brute force) asked you to turn the monitor off before starting the test.

Switching a lightbulb on/off for a while kills it… and you can also kill a console that way… or trash the savegames on a cardridge. They are all build for doing that (whatsoever) every once in awhile, but not the whole time.

So you are basing this claim on “a clicking noise” and the fact that a lightbulb burns out faster if you turn it on and off more often?

As I understand it older monitors could be damaged if given bad sync values - which is probably why some old software asked you to turn it off while it was ‘trying things out’.

I think chances are a few days of sync changes between legitimate display modes are unlikely to cause a noticeable problem. (Given that all use will cause SOME wear, and that this could be using components that aren’t normally used that often, I would have to admit that some amount of wear will happen… but I don’t think it will be what kills it.

I was just about to ask this same question. I have been struggling the entire wknd and mine works more or less. Though sometimes still if you switch it gives problems.Generally, disposing a Frame used for fullscreen gives problems. You also seem to lose BufferStrategy buffers. In the end I just decided to give up and create a new Frame everytime I switch to fullscreen. This seems to hold up as long as you don’t switch to much, tho sometimes the VM still crashes.
/SPAM
download my game at http://members.fortunecity.com/btenterprises
/spam (sorry i couldnt help myself)