Full-screen mode with Mac OS X

I have just released D-Zone II for PC and Mac OS X, actually the press releases go out next week but the game is ready for download. I had one minor problem that I wondered if anyone had experienced here. On Windows the game runs fine in 640x480 full screen, however on Mac OS X it succeeds in opening in 640x480 full screen and showing the game, however the application’s window is not in focus and so there is no keyboard and limited mouse interaction. I am thus releasing the Mac version with the game running in a little window for now, which is not great.

I looked at the API for the ‘Component’ class and found that you have to make sure the Component (I’m using JFrame but that doesn’t matter, it could be JWindow or even Window) has to be ‘displayable’, ‘focusable’ and ‘visible’ before it can be put in focus. You can enquire these three properties by calling isFocusable(), etc, as part of the Component API. What I was finding was that under both Windows and Mac OS X, these three properties were true! However, when I call ‘setFocus()’ the application still stayed out of focus for Mac OS X.

This appears to be a bug with the Mac OS X implementation of Java (I am using 1.4.2). Has anyone had any experience with this?

Best regards
Julian Cochran

PS: I have the code below that allows you to open the screen in 640x480 full screen. It works fine with PC AND ALSO under Mac OS X, however with Mac OS X it causes the application to be out of focus so there is no keyboard response - so receiving focus when running in full screen mode is essentially the problem.

I’d like to resolve this so that I can release D-Zone II for Java rather than making it a Windows-only game… (!!)

/**

  • Changes the display mode and returns true if successful or false if not succesful.
  • This method changes myWindow to full screen mode. The intention is that
  • myWindow extends JWindow (rather than JFrame) so that no title bar is shown.
    */
    public static DisplayMode setDisplayModeForDefaultDevice(Window myWindow, int x, int y, int bitDepth, int refreshRate) {
    DisplayMode newDisplayMode = new DisplayMode(x, y, bitDepth, refreshRate);

GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment();
GraphicsDevice myDevice = ge.getDefaultScreenDevice();
DisplayMode oldDisplayMode = myDevice.getDisplayMode();
try {
myDevice.setFullScreenWindow(myWindow);
myDevice.setDisplayMode(newDisplayMode);
} catch (Exception e) {
return null;
}
return newDisplayMode;
// Ideally run the following when the application ends:
// myDevice.setDisplayMode(oldDisplayMode);
// myDevice.setFullScreenWindow(null);
}

Best regards
Julian

It works for me with a JFrame.
The code goes roughly (and with a few ommisions):

// Create new jframe
final JFrame frame = new JFrame();

// Make sure it exits
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

// Remove borders, turn off automatic repaint and make sure it’s not resizable.
frame.setUndecorated(true);
frame.setIgnoreRepaint(true);
frame.setResizable(false);

// Set as fullscreen window
device.setFullScreenWindow(frame);

// Attempt display mode
device.setDisplayMode(displayMode);

With regards to input, I add my listeners to:

JFrame frameToAddListenersTo = (JFrame)device.getFullScreenWindow();

Hope it helps, if you haven’t already found the solution.
Feel free to ask me more questions if you need to :slight_smile:

Thanks a million, I was using a JFrame also (to host the whole app) so I should be able to use this code exactly. It looks like you are doing a couple of extra things in particular ignoring the repaint on the full screen JFrame.

My code is:

// Setup the display.
JFrame frame = this;
JFrame frameToAddListenersTo = null;
DisplayMode displayMode = new DisplayMode(640, 480, 32, 60);
GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment();
GraphicsDevice device = ge.getDefaultScreenDevice();
Global.oldDisplayMode = device.getDisplayMode();

frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
// Remove borders, turn off automatic repaint and make sure it’s not resizable.
frame.setUndecorated(true);
frame.setIgnoreRepaint(true);
frame.setResizable(false);
// Set as fullscreen window
device.setFullScreenWindow(frame);
// Attempt display mode
device.setDisplayMode(displayMode);
// For full screen mode, add the listeners to the device rather than the JFrame.
frameToAddListenersTo = (JFrame)device.getFullScreenWindow();
// Ideally run the following when the application ends:
// myDevice.setDisplayMode(Global.oldDisplayMode);
// myDevice.setFullScreenWindow(null);
frameToAddListenersTo = frame;
// Add the listeners.
frameToAddListenersTo.addWindowListener(new WindowAdapter() {
public void windowClosing(WindowEvent e) {
System.exit(0);
}
});
frameToAddListenersTo.addMouseListener(frame);
frameToAddListenersTo.addMouseMotionListener(frame);
frameToAddListenersTo.addKeyListener(
new KeyAdapter() {
UserIOBuffer userIOBuffer = Reference.wasl.userIOBuffer;
public void keyTyped(KeyEvent e) { userIOBuffer.addKeyTypedEvent(e.getKeyChar()); }
public void keyPressed(KeyEvent e) { userIOBuffer.addKeyPressedEvent(e.getKeyCode()); }
public void keyReleased(KeyEvent e) { userIOBuffer.addKeyReleasedEvent(e.getKeyCode()); }
}
);

I tried to compile this however and I could not get it to work because when adding the listeners I get:

addMouseListener(java.awt.event.MouseListener) in java.awt.Component cannot be applied to (javax.swing.JFrame)
frameToAddListenersTo.addMouseListener(frame);

Previously adding the listeners to the main application was easy because I could specify the main application JFrame as ‘class MainApplication extends JFrame implements MouseListener, MouseMotionListener’ but when deriving the JFrame in the way you have done I don’t know how to add the listeners to it. Can you help?

Best regards
Julian

Ignore my last paragraph above about my theory. I actually just don’t know how to add the listeners in my code example so that it compiles.

Best regards
Julian

Regarding using a Window or Frame for fullscreen operation :-

Heres a quote from setFullScreenWindow() in 1.5’s Javadoc.

[quote]Parameters:
w - a window to use as the full-screen window; null if returning to windowed mode. Some platforms expect the fullscreen window to be a top-level component (i.e., a Frame); therefore it is preferable to use a Frame here rather than a Window.
[/quote]
Seems to me that the method signature should be changed as a compatibilty fix.

It may brake old code, but seeing as fullscreen was never very reliable in 1.4.x anyway, it seems logical to change it now (i.e. 1.5) rather than later when there will likely be more code dependant on the flaw.

For isntance, I dread to think what will happen if you try to send a modal Dialog into fullscreen =/

For now I have just added the listeners in the way I did previously (but that will have to be solved, how did you do it Osak?) so I could at least test Osak’s code above however by including the line

frame.setIgnoreRepaint(true);

I am just getting a grey screen when I run the game. What do I need to have the screen update?

The 1.4.2 documentation for setIgnoreRepaint(…) has:

[i]Sets whether or not paint messages received from the operating system should be ignored. This does not affect paint events generated in software by the AWT, unless they are an immediate response to an OS-level paint message.

This is useful, for example, if running under full-screen mode and better performance is desired, or if page-flipping is used as the buffer strategy. [/i]

That sounds like a good idea, but adding setIgnoreRepaint to my application went a bit too far so I’m not even getting the first update and just the grey screen.

Regards
Julian

Ahh yes. My code was taken a bit out of context.
So it’s more like

Component compToAddListenersTo = (Component)device.getFullScreenWindow();

And then add your listeners to the component.

Hope it works :slight_smile:

Otherwise page me again, and I’ll try to make a working example :slight_smile:

And with regards to Java 1.5 we don’t have it on OS X because the Apple folks are keeping it a big secret. It’s supposed to be on the beta of the next version of OS X.
Java 1.4.2 keeps breaking as new releases come along. Until I changed to using the getFullscreenWindow() for all screen access I got gray screen too with code that worked on the previous version. And we still got NO HARDWARE ACCELERATION DAMMIT!. Oh well. That’s life I guess :slight_smile:

Have you tested with the Developer Previews of Java 1.4.2 Update 1 for the Mac?

It is worth it.

Do you have a download I can test in fullscreen mode? If there are bugs in the OS X fullscreen code I would like to report them ASAP.

The limited preview of Java 5.0 that runs on the OS X 10.4 (Tiger) beta release was fairly crippled as far as UI is concerned. But the fact that it is there is great… It looks like the Apple release of Java 5 won’t be very far behind the Sun release this time around.

Thanks Ozak,

I worked out how to add the listners, as follows:

frameToAddListenersTo.addMouseListener(
   new MouseAdapter() {
      public void mousePressed(MouseEvent e)  { userIOBuffer.addMousePressedEvent(e);                   }
      public void mouseReleased(MouseEvent e) { userIOBuffer.addMouseReleasedEvent(e);                  }
      public void mouseClicked(MouseEvent e)  { userIOBuffer.addMouseClickedEvent(e);                   }
   }
);
frameToAddListenersTo.addMouseMotionListener(
   new MouseMotionAdapter() {
      UserIOBuffer userIOBuffer = Reference.wasl.userIOBuffer;
      public void mouseEntered(MouseEvent e)  { userIOBuffer.addMouseEnteredEvent(e.getX(), e.getY());  }
      public void mouseExited(MouseEvent e)   { userIOBuffer.addMouseExitedEvent(e.getX(), e.getY());   }
      public void mouseDragged(MouseEvent e)  { userIOBuffer.addMouseDraggedEvent(e.getX(), e.getY());  }
      public void mouseMoved(MouseEvent e)    { userIOBuffer.addMouseMovedEvent(e.getX(), e.getY());    }
   }
);
frameToAddListenersTo.addKeyListener(
   new KeyAdapter() {
     UserIOBuffer userIOBuffer = Reference.wasl.userIOBuffer;
     public void keyTyped(KeyEvent e)   { userIOBuffer.addKeyTypedEvent(e.getKeyChar());     }
     public void keyPressed(KeyEvent e) { userIOBuffer.addKeyPressedEvent(e.getKeyCode());   }
     public void keyReleased(KeyEvent e)     { userIOBuffer.addKeyReleasedEvent(e.getKeyCode());  }
   }
);

I can add the listeners to frameToAddListenersTo in that way, even though frameToAddListenersTo does not implement MouseListener, etc.

However the problem still persists that my code above (derived exactly from the code you gave at the very start) just produces a grey screen. I don’t have a clue how to update that screen. My paint(Graphics) method defined in the main application is:

public void paint(Graphics g) {
System.out.println(“paint(Graphics) was called”);
Graphics2D g2 = (Graphics2D) g;
if (graphicsInitialized)
g2.drawImage(bi, 0, 0, this);
}

And the text “paint(Graphics) was called” is never being outputted. My first thought was that I need to have that method defined within frameToAddListenersTo but I am not quite sure how to express that in code, but more importantly I think the problem runs deeper because I was having the grey screen as soon as I added

setIgnoreRepaint(true);

to the main application. Ozak, I might be needing your complete example!! :frowning:

Regards
Julian

Ahh yes. You’re using the paint call, so you can’t use setIgnoreRepaint(false) since that would mean that the paint function is never called.

Usually in fullscreen you do the painting yourself since it’s faster and more controlled than relying on the java paint update.
I could be wrong ofcourse and you’re doing it another way.
I’ll look into the sample after breakfast :slight_smile:

[quote]Do you have a download I can test in fullscreen mode? If there are bugs in the OS X fullscreen code I would like to report them ASAP.
[/quote]
Unfortunately no. I rewrote my engine to use fullscreen only as I could’nt get it to run in windowed and fullscreen.

At least the mouse button does not work in fullscreen mode was fixed in developer preview 2. (Although it was this release that caused the problem with a canvas in a JFrame in fullscreen)

Ahh. No need to write a sample. Check out the excellent source from David’s book: http://www.brackeen.com/javagamebook/

File an RFE ASAP before RC? LOL.

Oh, good call. Gotta try that…

[quote]Ahh. No need to write a sample. Check out the excellent source from David’s book: http://www.brackeen.com/javagamebook/
[/quote]
Be careful with that example. It seems some people on the apple java mail list have found issues with it. They are getting a NPE when exiting fullscreen. They found a simple enough workaround… you must be careful not to dispose the window before calling setFullscreenWindow(null) or something like that.

True enough :slight_smile: