blob: 510f836bd01695cf7fb2cf92e79d0ed1ccef3766 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2018 Red Hat and others. All rights reserved.
* The contents of this file are made available under the terms
* of the GNU Lesser General Public License (LGPL) Version 2.1 that
* accompanies this distribution (lgpl-v21.txt). The LGPL is also
* available at http://www.gnu.org/licenses/lgpl.html. If the version
* of the LGPL at http://www.gnu.org is different to the version of
* the LGPL accompanying this distribution and there is any conflict
* between the two license versions, the terms of the LGPL accompanying
* this distribution shall govern.
*
* Contributors:
* Red Hat - initial API and implementation
*******************************************************************************/
package org.eclipse.swt.tests.gtk.snippets;
import static org.junit.Assert.assertTrue;
import java.util.concurrent.atomic.AtomicInteger;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.ControlEvent;
import org.eclipse.swt.events.ControlListener;
import org.eclipse.swt.graphics.Rectangle;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Shell;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
/**
* Title: Bug 465280 – [GTK3] OS.gtk_widget_get_allocation returns (0,0) for invisible controls
* How to run: These are jUnits. Select the class and run as jUnits.
* Bug description: getBounds is not working properly in combination with setVisible.
* Expected results: All tests should pass, but on Gtk3.8+ the "fails_*" tests fail.
* GTK version(s): GTK3.8+
*
* This is a snippet to validate upcomming bug submission. These will be used to make new jUnits later.
*/
public class Bug497705_setBoundsAfterSetVisible {
boolean debugShowWidget = false; // true = see shell & widget. False = tests run without interaction.
Display display;
Shell shell ;
private StringBuilder log;
private int x;
private int y;
private int height;
private int width;
private boolean passed;
private Rectangle bounds;
Control testControl;
@Before
public void setUp() {
display = Display.getDefault();
shell = new Shell(display);
shell.setSize(400, 400);
log = new StringBuilder("");
x = 5;
y = 10;
height = 100;
width = 200;
passed = true;
testControl = new Button(shell, SWT.PUSH);
}
@Test
public void fails_test2_setBoundsAfterVisibility() { // Works on Gtk2, Fails on Gtk3.
testControl.setVisible(false);
testControl.setVisible(true);
testControl.setBounds(x, y, width, height);
bounds = testControl.getBounds();
verifyBounds();
}
@Test
public void fails_test2b_setBoundsInvisibleWidgets() { // Works on Gtk2, Fails on Gtk3.
testControl.setVisible(false);
testControl.setBounds(x, y, width, height);
bounds = testControl.getBounds();
verifyBounds();
}
@Test
public void fails_test3_setBoundsBetweenVisibility() { // Works on Gtk2, Fails on Gtk3.
testControl.setVisible(false);
testControl.setBounds(x, y, width, height);
testControl.setVisible(true);
bounds = testControl.getBounds();
verifyBounds();
}
@Test
public void fails_moveInnvisibleControl() {
testControl.setBounds(4, 4, 6, 6);
shell.open(); for (int i = 0; i < 500; i++) display.readAndDispatch();
testControl.setVisible(false);
shell.open(); for (int i = 0; i < 500; i++) display.readAndDispatch();
testControl.setBounds(x, y, width, height);
shell.open(); for (int i = 0; i < 500; i++) display.readAndDispatch();
testControl.setVisible(true);
shell.open(); for (int i = 0; i < 500; i++) display.readAndDispatch();
bounds = testControl.getBounds(); // Visually looks ok. (width/height), but programatically incorrect getBounds().
verifyBounds();
}
@Test
public void fails_unecessaryEvents() { // Breaks on Gtk3.8 & onwards
testControl.setVisible(false);
AtomicInteger resizeCount = new AtomicInteger(0);
AtomicInteger moveCount = new AtomicInteger(0);
testControl.addControlListener(new ControlListener() {
@Override
public void controlResized(ControlEvent e) {
resizeCount.incrementAndGet();
}
@Override
public void controlMoved(ControlEvent e) {
moveCount.incrementAndGet();
}
});
for (int i = 0; i < 10; i++) {
testControl.setBounds(x, y, width, height); // Once bounds set, calling same bounds shouldn't trigger SWT.MOVE events.
}
if (resizeCount.get() != 1 || moveCount.get() != 1) {
passed = false;
log.append("\nERROR:\nExpected only one Resize and one Move event.\nActually received R/M:" + resizeCount.get() + "/" + moveCount.get());
}
}
@Test
public void works_test1_setBoundsBeforeVisibility () {
// Note, here you can see that getBounds() does work for widgets that are set to be invisible, but
// only if setBounds was called before setVisible(false).
// The problem is inside setBounds, if it's called after setVisible(false), then getBounds() returns wrong output.
testControl.setBounds(x, y, width, height);
testControl.setVisible(false);
// testControl.setVisible(true); // commenting or uncommenting this doesn't change anything.
bounds = testControl.getBounds();
verifyBounds();
}
@Test
public void works_zeroSize() { // There has to be a mechanism by which we set with and height to 0.
testControl.setBounds(x, y, width, height);
x = y = width = height = 0;
testControl.setBounds(x, y, width, height);
bounds = testControl.getBounds();
verifyBounds();
}
@Test
public void works_drainingQueue() {
testControl.setVisible(false);
testControl.setVisible(true);
// doing readAndDispatch up *before* 'setBounds()' doesn't make a difference.
testControl.setBounds(x, y, width, height);
// doing readAndDispatch *After* setBounds *many times* gives gtk time to update it's cache, and getBounds() returns correct coordinates.
shell.open();
for (int i = 0; i < 1000; i++)
display.readAndDispatch();
bounds = testControl.getBounds();
verifyBounds();
}
@After
public void tearDown() {
if (debugShowWidget) {
if (!passed) System.err.println(log.toString());
shell.open();
while (!shell.isDisposed()) {
if (!display.readAndDispatch())
display.sleep();
}
display.dispose();
}
assertTrue(log.toString(), passed);
}
private void verifyBounds() {
if (bounds.x != x | bounds.y != y) {
passed = false;
log.append("\nERROR: x,y do not match. Expected:" + x + "/" + y + " Actual:" + bounds.x + "/" + bounds.y);
}
if (bounds.height != height | bounds.width != width) {
passed = false;
log.append("\nERROR: width,height do not match. Expected:" + width + "/" + height + " Actual:"
+ bounds.width + "/" + bounds.height);
}
}
}