Hot questions for Using Lightweight Java Game Library in awt

Question:

Hi I'm working on a group project and the code works on my teammate's PCs but I keep hitting MacOS specific errors. And this time I seem to be stuck (no easily Googleable answer).

In a previous post I discovered I need "-Djava.awt.headless=true" as VM setting to properly run my simulation. Now when I try to spawn in some JFrame they are all met with a lovely "java.awt.HeadlessException" Exception because of that VM flag.

Trying to achieve

I want to be able to spawn those JFrames on my MacBook also.

The problem

I need -Djava.awt.headless to be both true and false at the same time for my program to run properly on Mac. Which if I understand my problem correcly, means I have a big problem on my hands.

EDIT: running it in a VM on my Macbook allowed me to run the project properly. This is far from an ideal fix. I'm still searching for a solution to this obscure problem.

What I tried
  • not running with the VM option: the problem described in previous post occurs. Thus this is not a viable option
  • running with the VM option: this throws a -Djava.awt.headless when creating a JFrame.

Answer:

The best way to fix this may be by going back and solving your original problem a different way.

You must make sure that you are not initializing your BufferedImage in the main thread (GLFW thread), it MUST be done separately. It is hard to tell from your original question, but that looks like part of the cause there. Start a new thread to do the image processing instead.

See my solution and recommendation at the bottom of this answer for a quick summary, and also see here for someone else that had the same issue: Java Creating Instance of BufferedImage Freezes Program


A quick note on why your code works on Windows and not Mac: that is because both OS often run different implementations of openGL, and typically Mac can lag behind and miss out on a bunch of updates/changes that may solve problems like this one so that it doesn’t freeze when initializing a BufferedImage on the openGL thread.


If the above didn’t work then lets first look at what headless mode is. (Emphasis mine):

See link at bottom for full article and more info.

Headless mode is a system configuration in which the display device, keyboard, or mouse is lacking. Sounds unexpected, but actually you can perform different operations in this mode, even with graphic data.

Where it is applicable? Let's say that your application repeatedly generates a certain image, for example, a graphical authorization code that must be changed every time a user logs in to the system. When creating an image, your application needs neither the display nor the keyboard. Let's assume now that you have a mainframe or dedicated server on your project that has no display device, keyboard, or mouse. The ideal decision is to use this environment's substantial computing power for the visual as well as the nonvisual features. An image that was generated in the headless mode system then can be passed to the headful system for further rendering.

So when should headless mode be used:

On a machine that has no display device, keyboard, or mouse.

That is not you is it? However if that is you (LWJGL?), then lets look at how you can work with headless mode:

An image that was generated in the headless mode system then can be passed to the headful system for further rendering.

This means that you should have a special piece of headless code that does your headless image stuff, but then passes the image back to a normal JFrame with a head.

So why does it fail for you:

Many components are affected if a display device, keyboard, or mouse is not supported. An appropriate class constructor throws a HeadlessException

  • Button
  • Checkbox
  • Choice
  • Dialog
  • FileDialog
  • Frame
  • Label
  • List
  • Menu
  • MenuBar
  • MenuItem
  • PopupMenu
  • Scrollbar
  • ScrollPane
  • TextArea
  • TextField
  • Window

Solution to the problem:

some classes, such as Canvas or Panel, can be executed in headless mode.

Perfect, so we just need to be careful what is used in headless mode. You asked how you can both use and not use headless mode, well rather than globally setting headless mode with VM option -Djava.awt.headless you can do it programmatically within your code using System.setProperty("java.awt.headless", "true"); where needed. A JFrame should be normal (not Headless), but you can spawn a JPanel as headless without issue.

I recommend:

You create a normal headed main thread with no VM option that spawns JFrames, and then use that main thread to spawn a new child thread and set your LWJGL bits in that thread to be headless, and that way you can run your LWJGL code without issue, and at the same time you can still have JFrames from your main thread. Remember to make sure that the Buffered image is not done in the main LWJGL/OpenGL thread.


Headless info source: http://www.oracle.com/technetwork/articles/javase/headless-136834.html

Question:

I need to open a link in my web browser using Java, but the stipulation is that I can't use java.awt.Desktop to do it. The reason why is because I'm trying to do this from an LWJGL3 program, and using AWT in its context will cause the program to not work on Mac systems.

So basically, I need the functionality of Desktop.browse(URL) without AWT. Does anyone know of some third party application or something I can use that can do this (or how I can potentially do it myself).

Thank you!


Answer:

I found the answer to my question at these two links.

Open the links with pure Java: How to open the default webbrowser using java

A comment on the subject by the maintainer of LWJGL3: http://forum.lwjgl.org/index.php?topic=6872.0

Question:

I was looking for a way to properly choose the monitor I want to fullscreen on based on the position of the window prior to fullscreening.

I looked online for ages but couldn't find anything so I ended up trying a bunch of things until I got something working.

I figured someone eventually will try to look this problem up and I might as well share my solution.


Answer:

What I ended up doing is get the virtual screen coordinates of the center of the window using LWJGL2's Display class like so:

int x = Display.getX() + Display.getWidth()/2, 
    y = Display.getY() + Display.getHeight()/2;

I then used AWT to get all available monitors:

GraphicsEnvironment.getLocalGraphicsEnvironment().getScreenDevices()

I iterated through them and got their virtual bounds(and applied any DPI scaling they might have):

Rectangle bounds = screenDevice.getDefaultConfiguration().getDefaultTransform().createTransformedShape(screenDevice.getDefaultConfiguration().getBounds()).getBounds();

EDIT: Slightly altered line so it can support Windows' DPI scaling properly.

If the bounds contained the center of the window, it means that most of the window is probably within that monitor:

if(bounds.contains(x,y))
    return bounds; //getMonitorFromWindow()

Then to toggle between windowed borderless fullscreen and normal windowed in LibGDX I did the following:

// config is the LwjglApplicationConfiguration of the application

// upon changing using alt+enter
if(fullscreen) {
    config.resizable = false;
    Gdx.graphics.setUndecorated(true);
    Rectangle monitor = getMonitorFromWindow();
    // set to full screen in current monitor
    Gdx.graphics.setWindowedMode(monitor.width, monitor.height);
    Display.setLocation(monitor.x, monitor.y);
} else {
    config.resizable = true;
    Gdx.graphics.setUndecorated(false);
    Rectangle monitor = getMonitorFromWindow();
    // set to windowed centered in current monitor
    Gdx.graphics.setWindowedMode((int) (monitor.width * 0.8f), (int) (monitor.height * 0.8f));
    Display.setLocation(monitor.x + (int) (monitor.width * 0.1f), monitor.y + (int) (monitor.height * 0.1f));
}

I hope someone would find this useful.

Question:

I'm using Scala swing to display a window which needs to contain an LWJGL Display object. The only method I've found is it use an intermediary AWT Canvas instance to bind the Display object to and wrap inside a Frame:

object Run extends SimpleSwingApplication {

 System.setProperty("org.lwjgl.opengl.Window.undecorated", "true")

  val initialWindowSize = new Dimension(256, 240)

  lazy val top = new MainFrame {
    title = s"Nescala ${nescala.BuildInfo.version}"
    size = initialWindowSize

    visible = true

    peer.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE)
    peer.setFocusable(true)
    peer.setIgnoreRepaint(true)

    peer.add(canvas)

    peer.pack()
  }

  def canvas:Canvas = new Canvas {
    setPreferredSize(initialWindowSize)
    setSize(initialWindowSize)
    setFocusable(true)
    setIgnoreRepaint(true)
    requestFocus()
    setVisible(true)

    override def addNotify() = {
      super.addNotify()
      attachDisplay()
    }

    override def removeNotify() = {
      detachDisplay()
      super.removeNotify()
    }

    def attachDisplay(): Unit = {
      try {
        Display.setParent(this)
        Display.create

      } catch {
        case e:LWJGLException => e.printStackTrace()
      }
    }

    def detachDisplay():Unit = Display.destroy()
  }
}

However when the window is initialized and the display is attached it appears positioned beneath the top of the Canvas/Frame, possibly including the height of a titlebar: How can the Display be attached to the Canvas with the same dimensions? I was under the impression that the window dimensions were set from the parent, although I have tried to explicitly set a DisplayMode using the same values. Additionally, is it possible to use an LWJGL Display object without having a heavyweight AWT Canvas object set as the parent (but still within a Swing Ui element)?


Answer:

With regard to lightweight/heavyweight mixing, I suggest adding the canvas directly to the default content pane of the frame, which is a JPanel with BorderLayout. Also, the pack() call undoes the previous size_=.