Some Eclipse Foundation services are deprecated, or will be soon. Please ensure you've read this important communication.

Bug 91157

Summary: embedded SWT_AWT frames flicker when the SWT window is resized
Product: [Eclipse Project] Platform Reporter: Bruno Haible <haible>
Component: SWTAssignee: Silenio Quarti <Silenio_Quarti>
Status: CLOSED WORKSFORME QA Contact:
Severity: normal    
Priority: P3 CC: ericwill, gordon.hirsch, jan.krakora.cz, snorthov
Version: 3.1Keywords: triaged
Target Milestone: ---   
Hardware: Other   
OS: Linux-GTK   
Whiteboard:
Attachments:
Description Flags
sample application that uses embedded SWT frames
none
Sample without flickering, through a subclass of sun.awt.X11.XEmbeddedFrame none

Description Bruno Haible CLA 2005-04-12 12:19:38 EDT
With SWT from Eclipse 3.1M6 on Linux/x86 with the gtk window system, the 
attached application - which contains three SWT_AWT embedded frames - flickers 
when the SWT application window is resized (both when it is enlarged and also when 
it is shrinked). 
 
To reproduce: 
1) Unpack the attached application. 
2) $ export ECLIPSE_HOME=directory_of_your_eclipse_installation 
3) "ant" 
4) with a JDK 1.5: "ant run" 
5) resize the application window
Comment 1 Bruno Haible CLA 2005-04-12 12:20:36 EDT
Created attachment 19817 [details]
sample application that uses embedded SWT frames
Comment 2 Steve Northover CLA 2005-04-13 09:49:36 EDT
We believe strongly that the flickering is on the AWT/Swing side.  SSQ to 
provide strategies to reduce this.  Isn't there one on the SWT snippets page?
Comment 3 Bruno Haible CLA 2005-04-13 12:29:23 EDT
The strategy from Snippet 154 is already taken into account in the sample. It succeeds to fix the 
problem only on Windows, not on linux-gtk. 
 
Comment 4 Silenio Quarti CLA 2005-04-13 17:45:46 EDT
This is an AWT problem and I believe there is nothing SWT can do to work around
it. The problem does not happen on because of the AWT system property
"sun.awt.noerasebackground", but this property is only honoured on Windows.

        System.setProperty("sun.awt.noerasebackground", "true");

Here is a simple AWT only example that shows the problem:

public static void main(String[] args) {
    java.awt.Frame frame = new java.awt.Frame();
    java.awt.Panel panel =
        new java.awt.Panel(new BorderLayout()) {
            public void update(java.awt.Graphics g) {
                // Don't erase the background, to decrease flickering.
                paint(g);
            }
        };
    JRootPane root = new JRootPane();
    panel.add(root);
    java.awt.Container contentPane = root.getContentPane();
    JPanel blackPanel = new JPanel();
    blackPanel.setBackground(java.awt.Color.black);
    contentPane.add(blackPanel, BorderLayout.CENTER);
    frame.add(panel);
	frame.setVisible(true);
}
Comment 5 Bruno Haible CLA 2005-04-14 08:50:12 EDT
The AWT sample can be changed so that it doesn't show the problem any more: 
 
public static void main(String[] args) { 
    java.awt.Frame frame = 
        new java.awt.Frame() { 
            public void update(java.awt.Graphics g) { 
                // Don't erase the background, to decrease flickering. 
                paint(g); 
            } 
        }; 
    JRootPane root = new JRootPane(); 
    frame.add(root); 
    java.awt.Container contentPane = root.getContentPane(); 
    JPanel blackPanel = new JPanel(); 
    blackPanel.setBackground(java.awt.Color.black); 
    contentPane.add(blackPanel, BorderLayout.CENTER); 
    frame.setVisible(true); 
} 
 
The two tricks to get rid of the flickering are: 
   1) Not to use java.awt.Panel, 
   2) Override the update(Graphics) method of the java.awt.Frame class, to avoid 
      the clearRect call found in java.awt.Container:update(Graphics). 
 
These two tricks can be transposed to the SWT world. Find attached a sample with a class 
FixedXEmbeddedFrame, subclass of sun.awt.X11.XEmbeddedFrame, that overrides the 
update(Graphics) method as needed. This shows that the problem can indeed be fixed. 
 
However, this fix is not satisfactorily deployable on our side, because it is platform dependent: 
  - The class FixedXEmbeddedFrame cannot be compiled on non-X11 platforms. 
  - The comments in class SWT_AWT say that the constructor should take an 'int' on some 
    platforms and a 'long' on others. 
Therefore I believe this fix should best be integrated into SWT, so that code that uses SWT 
can remain platform independent. 
 
Comment 6 Bruno Haible CLA 2005-04-14 08:51:46 EDT
Created attachment 19906 [details]
Sample without flickering, through a subclass of sun.awt.X11.XEmbeddedFrame
Comment 7 Silenio Quarti CLA 2005-04-14 09:53:15 EDT
The extra java.awt.Panel is needed with JDK 1.4.2 (at least). The cursor will 
not change to the "resize cursor" when you try to resize the columns of the 
table without the panel (see Bug#58308).

Now, If I put the java.awt.Panel back, the example will still flicker even if 
I subclass XEmbeddedFrame and reimplement update().

sun.awt.X11.XEmbeddedFrame is not public API and there are binary 
incompatability between JREs for the same platform. So how can I have a 
subclass that will work on all JREs, since I have to decide between int or 
long at compile time. Right now, we use reflection to work around this problem.
Comment 8 Bruno Haible CLA 2005-04-14 11:41:36 EDT
To make a subclass that works on all JREs, you can either 
   a) Compile the subclass with the 'int' constructor on a platform where 
      sun.awt.X11.XEmbeddedFrame has 'int'; likewise with 'long' on a different 
      platform; then choose the appropriate one at runtime and load it through an 
      extra classloader. Or 
   b) Construct the appropriate subclass entirely at runtime using the Apache BCEL package, 
      parametrizing it with the information about sun.awt.X11.XEmbeddedFrame. 
      The class is converted from a byte[] to a Class object through a custom ClassLoader 
      whose findClass method just calls defineClass of the byte array. 
 
How to solve the conflict between Bug#58308 and this one regarding the extra java.awt.Panel, 
I don't know. 
 
Comment 9 Silenio Quarti CLA 2005-04-15 11:28:56 EDT
Having different classes at compile time for different platforms was not a 
option in JDK 1.3, because the same platform (Windows) had JREs with different 
WEmbeddedFrame classes. So if we compiled for one jre, we would not be able to 
run in the other jre. This may have change for newer JREs, I would have to 
check.

I believe adding dependence to Apache BCEL package is not a option (over kill).
Comment 10 Bruno Haible CLA 2008-04-21 16:31:07 EDT
This bug is still (in Eclipse 3.4M4) a major problem with SWT_AWT on Gtk.

You can easily reproduce it with Albireo: Install Albireo from http://wiki.eclipse.org/Albireo_Download, then launch the examples plugin, and open the "Resize Flickering" view. At every mouse drag events, it resizes 4 adjacent SWT_AWT instances, and the flickering is *heavy*.

You can see the flickering with the white color (#xffffff), although the background is set to grey.

You are right in comment #7 that a subclass of sun.awt.X11.XEmbeddedFrame does not fix the flickering, at least not with JDK 1.5.

Also, the following do not fix the problem:
  - Use of the SWT.NO_REDRAW_RESIZE flag in the constructor.
  - Use of the SWT.TRANSPARENT flag in the constructor.
  - OS.gtk_widget_set_redraw_on_allocate(composite.handle, false);
  - OS.gtk_fixed_set_has_window(composite.handle, false);

Single-stepping through the code, I found that the flickering occurs in
(or as a consequence of) the call
   OS.gtk_widget_size_allocate (topHandle, allocation);
in Control.java, method
setBounds (int x, int y, int width, int height, boolean move, boolean resize).

I've been looking at the source code of gtk_widget_size_allocate and
gtk_fixed_size_allocate (since the handle is an instance of SwtFixed,
subclass of GtkFixed), but I don't understand where the area is filled with
white color.

Is SwtFixed the right class at all for this? The SWT_AWT.new_Frame method
takes a Composite as argument. A Composite is meant to contain other widgets
and therefore normally paints a background. But here, the entire Composite's
area is covered by the Frame's area, therefore it should not paint a
background. Possibly this could be achieved by using the GTK_NO_WINDOW flag
- but this flag is not used by the implementation of Composite. - Is
SwtFixed or GtkFixed the right type to use here at all?
Comment 11 Bruno Haible CLA 2008-04-21 16:40:15 EDT
There's an old post by Havoc Pennington (you won't find a better expert
on Gtk)
  http://dev.eclipse.org/mhonarc/lists/platform-swt-dev/msg00260.html
who explains (AFAIU) that one should use NO_WINDOW in order to avoid flicker.

Comment 12 Eric Williams CLA 2018-07-06 13:44:29 EDT
I cannot reproduce this issue on SWT master as of today, GTK3.22, and Fedora 28.