Bug 1307 - GLCanvas is always drawn on top when using a JTabbedPane
Summary: GLCanvas is always drawn on top when using a JTabbedPane
Status: UNCONFIRMED
Alias: None
Product: Jogl
Classification: JogAmp
Component: awt (show other bugs)
Version: 2.4.0
Hardware: All macosx
: P4 critical
Assignee: Sven Gothel
URL:
Depends on:
Blocks:
 
Reported: 2016-05-13 12:33 CEST by Robin Stevens
Modified: 2016-05-17 14:51 CEST (History)
1 user (show)

See Also:
Type: DEFECT
SCM Refs:
Workaround: ---


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Robin Stevens 2016-05-13 12:33:33 CEST
Java version:
java version "1.8.0_91"
Java(TM) SE Runtime Environment (build 1.8.0_91-b14)
Java HotSpot(TM) 64-Bit Server VM (build 25.91-b14, mixed mode)

Operating system:
OS X El Capitan
10.11.4

When using a JTabbedPane with two tabs (one with regular JPanel, one with a GLCanvas), the GLCanvas is always painted on top. Even when selecting the tab with the regular JPanel, the GLCanvas is painted on the screen and you do not see the regular JPanel.

Code to reproduce this:

import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;

import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JTabbedPane;
import javax.swing.WindowConstants;

import com.jogamp.opengl.awt.GLCanvas;

public class JOGLTabbedPaneTest {
  public static void main(String[] args) {
    EventQueue.invokeLater(new Runnable() {
      @Override
      public void run() {
        showUI();
      }
    });
  }

  private static void showUI(){
    JFrame testFrame = new JFrame("TestFrame");

    JTabbedPane tabbedPane = new JTabbedPane();

    JPanel lightweight = new JPanel(){
      @Override
      protected void paintComponent(Graphics g) {
        super.paintComponent(g);
        g.setColor(Color.PINK);
        g.fillRect(0,0, getWidth(), getHeight());
      }

      @Override
      public Dimension getPreferredSize() {
        return new Dimension(200,200);
      }
    };
    tabbedPane.addTab("LW", lightweight);

    GLCanvas glCanvas = new GLCanvas();
    tabbedPane.addTab("HW", glCanvas);

    testFrame.getContentPane().add(tabbedPane);

    testFrame.pack();
    testFrame.setVisible(true);
    testFrame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
  }
}


This sounds very similar to bug 1277 (https://jogamp.org/bugzilla/show_bug.cgi?id=1277) as the problem disappears when you call the showUI method on the main thread instead of on the EDT.

The workaround posted in bug 1277 (removing and readding the GLCanvas from/to the Swing hierarchy) is not sufficient to fix this bug.

The only workaround I found for now is to remove the GLCanvas from the Swing hierarchy when its parent container is not showing, and re-add it when the parent is showing.
As you get no events when a container is showing/not showing, I use a timer to periodically poll the showing state of the parent container:

  private static void startRemoveHeavyWeightComponentFromContainerWhenContainerNotShowingTimer(final Container aContainer, final Component aComponent){
    Timer timer = new Timer(500, new ActionListener(){
      private final WeakReference<Container> fContainer = new WeakReference<Container>(aContainer);
      private final WeakReference<Component> fComponent = new WeakReference<Component>(aComponent);
      @Override
      public void actionPerformed(ActionEvent e) {
        Container container = fContainer.get();
        Component component = fComponent.get();
        if ( container == null || component == null ){
          ((Timer) e.getSource()).stop();
          return;
        }
        boolean containerContainsComponent = containerContains(container, component);
        if ( container.isShowing() && !containerContainsView ){
          container.add(component);
          container.revalidate();
          container.repaint();
        } else if ( !container.isShowing() && containerContainsView ){
          container.remove(component);
          container.revalidate();
          container.repaint();
        }
      }
    });

    timer.setRepeats(true);
    timer.start();
  }

  private static boolean containerContains( Container aContainer, Component aComponent ){
    Component[] components = aContainer.getComponents();
    for (Component component : components) {
      if (component == aComponent) {
        return true;
      }
    }
    return false;
  }
Comment 1 Robin Stevens 2016-05-17 14:51:33 CEST
I just created a new build locally from the master branch on Github with patch https://jogamp.org/bugzilla/attachment.cgi?id=786 applied.

After only replacing jogl-all-natives-macosx-universal.jar in my project with the build/jar/jogl-all-natives-macosx-universal.jar from the custom build, this issue goes away.