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

Bug 294300

Summary: [GTK] Incorrect behaviour of tree rendering on GTK after removing paint listener
Product: [Eclipse Project] Platform Reporter: Yuri Strot <yuri>
Component: SWTAssignee: Eric Williams <ericwill>
Status: VERIFIED FIXED QA Contact: Praveen <pinnamur>
Severity: normal    
Priority: P3 CC: alex.panchenko, cocoakevin, ericwill, gautier.desaintmartinlacaze, ipun, pinnamur
Version: 4.8Keywords: triaged
Target Milestone: 4.12 M1   
Hardware: PC   
OS: Linux   
See Also: https://git.eclipse.org/r/137235
https://git.eclipse.org/c/platform/eclipse.platform.swt.git/commit/?id=eef687cb0ba0e614571caf5af7dc4ad829aeed1b
Whiteboard: RHT
Attachments:
Description Flags
Screenshot none

Description Yuri Strot CLA 2009-11-05 06:01:07 EST
If I'd like to add custom paint listener to my tree and than remove it, sometimes all text disappear. Actually, the problem is text foreground == white after removing paint listener.

Looks like the problem with Tree.drawForeground field: while custom rendering appear, Tree could cache this variable and then use invalid value when there are no custom painters (drawForeground value doesn't clear).

Following example reproduce my problem. You need to select the last one item in the tree, check "Enable custom painter" and then uncheck it -- all text will be white:

import org.eclipse.swt.SWT;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.graphics.Color;
import org.eclipse.swt.graphics.GC;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.graphics.Rectangle;
import org.eclipse.swt.graphics.TextLayout;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Event;
import org.eclipse.swt.widgets.Listener;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.Tree;
import org.eclipse.swt.widgets.TreeItem;

public class TreePainter implements Listener {

	private Tree tree;
	private TextLayout textLayout;

	TreePainter(Tree tree) {
		this.tree = tree;
	}

	public void setListeners(boolean add) {
		if (add) {
			tree.addListener(SWT.EraseItem, this);
			tree.addListener(SWT.PaintItem, this);
		} else {
			tree.removeListener(SWT.EraseItem, this);
			tree.removeListener(SWT.PaintItem, this);
		}
		redraw();
	}

	@Override
	public void handleEvent(Event event) {
		switch (event.type) {
		case SWT.PaintItem:
			paint(event);
			break;
		case SWT.EraseItem:
			erase(event);
			break;
		}
	}

	private void erase(Event event) {
		event.detail &= ~(SWT.BACKGROUND | SWT.FOREGROUND | SWT.SELECTED | SWT.HOT);
	}

	private void paint(Event event) {
		TreeItem item = (TreeItem) event.item;
		GC gc = event.gc;
		// remember colors to restore the GC later
		Color oldForeground = gc.getForeground();
		Color oldBackground = gc.getBackground();

		int index = event.index;

		Color foreground = item.getForeground(index);
		if (foreground != null) {
			gc.setForeground(foreground);
		}

		Color background = item.getBackground(index);
		if (background != null) {
			gc.setBackground(background);
		}

		if ((event.detail & SWT.SELECTED) != 0) {
			gc.fillRectangle(item.getBounds(index));
		}

		Image image = item.getImage(index);
		if (image != null) {
			Rectangle imageBounds = item.getImageBounds(index);
			if (imageBounds != null) {
				Rectangle bounds = image.getBounds();

				// center the image in the given space
				int x = imageBounds.x
						+ Math.max(0, (imageBounds.width - bounds.width) / 2);
				int y = imageBounds.y
						+ Math.max(0, (imageBounds.height - bounds.height) / 2);
				gc.drawImage(image, x, y);
			}
		}

		Rectangle textBounds = item.getTextBounds(index);
		if (textBounds != null) {
			TextLayout layout = getTextLayout();
			layout.setText(item.getText(index));
			layout.setFont(item.getFont(index));

			Rectangle layoutBounds = layout.getBounds();

			int x = textBounds.x;
			int avg = (textBounds.height - layoutBounds.height) / 2;
			int y = textBounds.y + Math.max(0, avg);

			layout.draw(gc, x, y);
		}

		gc.setForeground(oldForeground);
		gc.setBackground(oldBackground);
	}

	public void redraw() {
		Rectangle rect = tree.getClientArea();
		tree.redraw(rect.x, rect.y, rect.width, rect.height, true);
	}

	private TextLayout getTextLayout() {
		if (textLayout == null) {
			int orientation = tree.getStyle()
					& (SWT.LEFT_TO_RIGHT | SWT.RIGHT_TO_LEFT);
			textLayout = new TextLayout(tree.getDisplay());
			textLayout.setOrientation(orientation);
		} else {
			textLayout.setText("");
		}
		return textLayout;
	}

	public static void main(String[] args) {
		Display display = new Display();
		Shell shell = new Shell(display);
		shell.setBounds(10, 10, 800, 600);
		shell.setLayout(new GridLayout());
		final Tree tree = new Tree(shell, SWT.BORDER);
		tree.setLinesVisible(true);
		for (int i = 0; i < 5; i++) {
			TreeItem item = new TreeItem(tree, SWT.NONE);
			item.setText("item " + i);
			for (int j = 0; j < 5; j++) {
				TreeItem child = new TreeItem(item, SWT.NONE);
				child.setText("item " + i + "-" + j);
			}
		}
		tree.setLayoutData(new GridData(GridData.FILL_BOTH));

		final TreePainter painer = new TreePainter(tree);
		final Button button = new Button(shell, SWT.CHECK);
		button.setText("Enable custom painter");
		button.addSelectionListener(new SelectionAdapter() {
			@Override
			public void widgetSelected(SelectionEvent e) {
				painer.setListeners(button.getSelection());
			}
		});

		shell.open();
		while (!shell.isDisposed()) {
			if (!display.readAndDispatch())
				display.sleep();
		}
		display.dispose();
	}
}
Comment 1 Praveen CLA 2009-11-10 01:52:49 EST
which GTK version you are using ? I am not able to reproduce the problem on Ubuntu 9.04 (using GTK 2.16) - the text appears correctly after enabling/disabling the custom painter.
Comment 2 Kevin Barnes CLA 2010-01-06 11:57:41 EST
Created attachment 155426 [details]
Screenshot

I can reproduce this on RHEL 5 (gtk 2.10). Attaching a screenshot.
Comment 3 Eric Williams CLA 2016-12-20 14:06:20 EST
I can reproduce this on GTK3.22, Fedora 25.
Comment 4 Ian Pun CLA 2017-06-21 14:37:32 EDT
Bug has been triaged as it occurs from Erics tests, see https://wiki.eclipse.org/SWT/Devel/Triage for more information.
Comment 5 Eclipse Genie CLA 2019-02-19 15:18:04 EST
New Gerrit change created: https://git.eclipse.org/r/137235
Comment 7 Eric Williams CLA 2019-03-11 15:06:27 EDT
(In reply to Eclipse Genie from comment #6)
> Gerrit change https://git.eclipse.org/r/137235 was merged to [master].
> Commit:
> http://git.eclipse.org/c/platform/eclipse.platform.swt.git/commit/
> ?id=eef687cb0ba0e614571caf5af7dc4ad829aeed1b

In master now.
Comment 8 Eric Williams CLA 2019-04-09 10:04:57 EDT
Verified in I20190409-0600.