Some Eclipse Foundation services are deprecated, or will be soon. Please ensure you've read this important communication.
Bug 219716 - GC.copyArea() does not work for capturing full desktop image if secondary monitor is at left or above the primary monitor
Summary: GC.copyArea() does not work for capturing full desktop image if secondary mon...
Status: RESOLVED WORKSFORME
Alias: None
Product: Platform
Classification: Eclipse Project
Component: SWT (show other bugs)
Version: 3.4   Edit
Hardware: PC Windows Vista
: P3 normal (vote)
Target Milestone: ---   Edit
Assignee: Silenio Quarti CLA
QA Contact:
URL:
Whiteboard:
Keywords:
Depends on:
Blocks:
 
Reported: 2008-02-20 20:01 EST by Willian Mitsuda CLA
Modified: 2008-04-18 09:54 EDT (History)
3 users (show)

See Also:


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Willian Mitsuda CLA 2008-02-20 20:01:34 EST
If you try to capture a screenshot image by using a GC built from a display, the secondary monitor is not captured correctly if it is at left or above the primary monitor.

Paste and run the following example:

public class MonitorTest {

	private static Image img;

	public static void main(String[] args) {
		final Display display = Display.getDefault();
		final Shell shell = new Shell(display);
		shell.setSize(800, 600);
		shell.setMaximized(true);
		shell.open();

		shell.setLayout(new GridLayout());
		Button capture = new Button(shell, SWT.PUSH);
		capture.setText("Capture!");
		capture.setLayoutData(new GridData());
		shell.layout();

		final ScrolledComposite composite = new ScrolledComposite(shell, SWT.H_SCROLL | SWT.V_SCROLL | SWT.BORDER);
		composite.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
		final Canvas canvas = new Canvas(composite, SWT.NONE);
		composite.setContent(canvas);
		canvas.addPaintListener(new PaintListener() {
			public void paintControl(PaintEvent e) {
				if (img != null) {
					e.gc.drawImage(img, 0, 0);
				}
			}
		});

		capture.addSelectionListener(new SelectionAdapter() {
			public void widgetSelected(SelectionEvent e) {
				if (img != null) {
					img.dispose();
				}
				Rectangle bounds = display.getBounds();
				img = new Image(display, bounds.width, bounds.height);
				GC gc = new GC(display);
				gc.copyArea(img, 0, 0);
				gc.dispose();
				canvas.setSize(bounds.width, bounds.height);
				canvas.redraw();
				shell.layout();
			}
		});

		while (!shell.isDisposed()) {
			if (!display.readAndDispatch()) {
				display.sleep();
			}
		}
		if (img != null) {
			img.dispose();
		}
	}

}

In this example, pressing the "Capture!" button, captures a full screenshot and displays it into a canvas bellow it.

In Windows control panel, video settings, drag the secondary monitor to the left of the primary monitor and run the capture. The resulting image will contain the primary monitor screenshot followed by a blank area to the right. A similar behavior happens when you move the secondary monitor on top of the primary.

I can reproduce this in Windows Vista, SWT 3.4 M5. There is at least 1 another case confirmed in Windows XP, where a user got into this through screenshot capture facility from Mylyn, which relies on this SWT facility (see bug#219171).
Comment 1 Mik Kersten CLA 2008-02-26 12:48:57 EST
*** Bug 219171 has been marked as a duplicate of this bug. ***
Comment 2 Eddie Galvez CLA 2008-02-26 15:31:46 EST
I got this using the mylyn feature, on eclipse 3.3.1:

Version: 3.3.1.1
Build id: M20071023-1652

mylyn feature:

org.eclipse.mylyn (2.2.0.I20071220-1700) "Mylyn"
Comment 3 Silenio Quarti CLA 2008-04-16 15:56:29 EDT
This is correct. The origin of the display is not 0,0 in that configuration. This is how APP code should look like.

import org.eclipse.swt.SWT;
import org.eclipse.swt.custom.ScrolledComposite;
import org.eclipse.swt.events.PaintEvent;
import org.eclipse.swt.events.PaintListener;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.graphics.GC;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.graphics.Rectangle;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Canvas;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Shell;

public class PR219716 {

        private static Image img;

        public static void main(String[] args) {
                final Display display = Display.getDefault();
                final Shell shell = new Shell(display);
                shell.setSize(800, 600);
                shell.setMaximized(true);
                shell.open();

                shell.setLayout(new GridLayout());
                Button capture = new Button(shell, SWT.PUSH);
                capture.setText("Capture!");
                capture.setLayoutData(new GridData());
                shell.layout();

                final ScrolledComposite composite = new ScrolledComposite(shell, SWT.H_SCROLL | SWT.V_SCROLL | SWT.BORDER);
                composite.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
                final Canvas canvas = new Canvas(composite, SWT.NONE);
                composite.setContent(canvas);
                canvas.addPaintListener(new PaintListener() {
                        public void paintControl(PaintEvent e) {
                                if (img != null) {
                                        e.gc.drawImage(img, 0, 0);
                                }
                        }
                });

                capture.addSelectionListener(new SelectionAdapter() {
                        public void widgetSelected(SelectionEvent e) {
                                if (img != null) {
                                        img.dispose();
                                }
                                Rectangle bounds = display.getBounds();
                                System.out.println(bounds);
                                img = new Image(display, bounds.width, bounds.height);
                                GC gc = new GC(display);
                                gc.copyArea(img, bounds.x, bounds.y);
                                gc.dispose();
                                canvas.setSize(bounds.width, bounds.height);
                                canvas.redraw();
                                shell.layout();
                        }
                });

                while (!shell.isDisposed()) {
                        if (!display.readAndDispatch()) {
                                display.sleep();
                        }
                }
                if (img != null) {
                        img.dispose();
                }
        }

}
Comment 4 Willian Mitsuda CLA 2008-04-18 03:37:54 EDT
Wow, this is surprising! I don't have 2 monitors set up right now, but I presume from the code modifications, the x/y values from Display.getBounds() come negative, right?

Silenio, it would be good if you can document this case in the Display.getBounds() javadoc, since this behavior is not intuitive.

Mik/Steffen, I'll reopen the original Mylyn bug and post a patch in there.
Comment 5 Silenio Quarti CLA 2008-04-18 09:54:49 EDT
Yes, I changed the javadoc of Display.getBounds() and Monitor.getBounds() to say that the origin can be negative.