Processing's windows overlap Windows's toolbar - avoidable?

How to avoid overlapping of windows created by Processing with Windows 8 toolbar?

  • App sets window size with size()
  • Makes window resizable with surface.setResizable(true)
  • Monitors Processing’s width/height variables and saves them in settings file
  • When run again, size is restored.

Unfortunately, if the user has previously maximized the window (which leaves the toolbar free), Processing opens the window at a slightly different position. It overlaps the toolbar.

To add to this, if I save the window’s position (to use my own positioning code, i.e. to save and restore window positions) with:

javax.swing.JFrame jframe = (javax.swing.JFrame)((processing.awt.PSurfaceAWT.SmoothCanvas)getSurface().getNative()).getFrame();

Window_X = jframe.getX(); // result -8 for window at top-left position
Window_Y = jframe.getY(); // result -8 for window at top-left position

… and restore it with surface.setLocation(), then the position is wrong. To have the window appear at the top-left position of the screen, I have to empirically do surface.setLocation(5, 5), not surface.setLocation(-8, -8); This upgrade …

Window_X = jframe.getX() + jframe.getInsets().left;
Window_Y = jframe.getY() + jframe.getInsets().top; 

doesn’t fix it (the insets are 8, 31).

[when window coordinates are read with jframe.getX/Y and restored with surface.setLocation()] the position is wrong

To clarify, this does not always lead to a wrong window position:

  • jframe.getX() and jframe.getY() return correct coordinates if the window is moved and resized with the mouse. Correct meaning that these coordinates (5|5) could be used with surface.setLocation to restore the position.

  • But if the window is maximized with a double click into the title bar, jframe.getX()/jframe.getY() return values that make no sense (-8|-8) and do not work with surface.setLocation.

void
setup()
{
    surface.setResizable(true);
}

void
draw()
{   
    javax.swing.JFrame jframe = (javax.swing.JFrame)((processing.awt.PSurfaceAWT.SmoothCanvas)getSurface().getNative()).getFrame();
    
    int Window_X = jframe.getX();
    int Window_Y = jframe.getY();
    
    println(Window_X, Window_Y, width, height);
}

This works (a bit crude, it’s just an example) for saving window position & size, including a maximized-to-the-toolbar window:

// Save window position and size in settings file, with special handling for maximized state

final int UNDEFINED = 0xffff;

boolean Run_Once         = true;
int     Skip_Frames      = 0;

// defaults (overridden by settings file)

boolean Window_Maximized = false;
int     Window_X         = UNDEFINED;
int     Window_Y         = UNDEFINED;
int     Window_W         = 640;
int     Window_H         = 400;

void
settings()
{
    // load settings but do not set window's size() here because size() uses a different coordinates system than jframe
  
    LoadSettings();
}

void
setup()
{ 
    // make window resizable
  
    surface.setResizable(true);
}

void
draw()
{    
    javax.swing.JFrame jframe = (javax.swing.JFrame)((processing.awt.PSurfaceAWT.SmoothCanvas)getSurface().getNative()).getFrame();
  
    // set window position/dimensions to saved state (once)
    
    if (Run_Once)
    {
        Run_Once = false;
        
        if ((Window_X != UNDEFINED) && (Window_Y != UNDEFINED))
      
            jframe.setLocation(Window_X, Window_Y);
 
        if ((Window_W!= UNDEFINED) && (Window_H != UNDEFINED))
      
            jframe.setSize(Window_W, Window_H);
            
        if (Window_Maximized)
        
            jframe.setExtendedState(jframe.getExtendedState() | javax.swing.JFrame.MAXIMIZED_BOTH);

        // do not monitor window for 2s (assuming framerate 60hz) to allow new state to be achieved - asynchronously
        
        Skip_Frames = 120;
    }
  
    // resume monitoring window's position and size? 
    
    if (Skip_Frames == 0)
    {  
        // get window position/size and compare to saved information
      
        boolean window_Maximized = ((jframe.getExtendedState() & javax.swing.JFrame.MAXIMIZED_BOTH) == javax.swing.JFrame.MAXIMIZED_BOTH);
        int     window_X;   
        int     window_Y;   
        int     window_W;   
        int     window_H;   
        
        // ignore coordinates of maxmized windows (keep recorded information, i.e. non-maximized values)

        if (window_Maximized)
        {
            window_X = Window_X;
            window_Y = Window_Y;
            window_W = Window_W;
            window_H = Window_H;
        }
        else
        {
            window_X = jframe.getX();   
            window_Y = jframe.getY();   
            window_W = jframe.getWidth();   
            window_H = jframe.getHeight();   
        }
        
        // re-save settings if changed 
        
        if ((Window_X != window_X) || (Window_Y != window_Y) || (Window_W != window_W) || (Window_H != window_H) || (Window_Maximized != window_Maximized))
        {
            Window_Maximized = window_Maximized;
            Window_X         = window_X;
            Window_Y         = window_Y;
            Window_W         = window_W;
            Window_H         = window_H;
            
            SaveSettings();
            
            // do not monitor window for 1s (assuming framerate 60hz), to allow user to resize/move without countless updates of settings file
            
            Skip_Frames = 120;
        }
    }
    else
        --Skip_Frames;
    
    text("Hello World!", 16, 16);
}

// load sttings from file

void
LoadSettings()
{
    // load configuration
    
    File file  = new File(sketchPath("settings.xml"));

    if (file.exists()) 
    {
        try
        {
            XML xml;
              
            // parse structure
            
            try
            {
                xml = loadXML(sketchPath("settings.xml"));
            }
            catch (Exception e)
            {
                xml = null;
            }
            
            if (xml != null)
            {
                if (xml.getName().equals("cfg"))
                {

                    XML window = xml.getChild("window");
                    
                    if (window != null)
                    {
                        String value;
                        
                        if ((value = window.getString("x")) != null)
    
                            Window_X = Integer.parseInt(value);
                            
                        if ((value = window.getString("y")) != null)
    
                            Window_Y = Integer.parseInt(value);
                        
                        if ((value = window.getString("width")) != null)
    
                            Window_W = Integer.parseInt(value);
                            
                        if ((value = window.getString("height")) != null)
    
                            Window_H = Integer.parseInt(value);           
                            
                        if ((value = window.getString("maximized")) != null)
                        {
                            Window_Maximized = Boolean.parseBoolean(value);
                        }
                    }
                }
            }
    
        }
        catch (Exception e)
        {
            println("Can not load settings!");
        }
    }
    else
        SaveSettings();
}

// save settings to file

void
SaveSettings()
{
    String xml[] = new String[1];

    xml[0]  = "<?xml version=\"1.0\"?><cfg><window";
    xml[0] += " x=\""         + Window_X         + "\"";
    xml[0] += " y=\""         + Window_Y         + "\"";
    xml[0] += " width=\""     + Window_W         + "\"";
    xml[0] += " height=\""    + Window_H         + "\"";
    xml[0] += " maximized=\"" + Window_Maximized + "\"";
    xml[0] +=  "></window></cfg>";

    try
    {
        saveStrings(sketchPath("settings.xml"), xml);
    }
    catch (Exception e)
    {
        println("Can not save settings!");
    }
}