blob: fcdbee094f59bc5bdea6a4ddcfbe34a9c9eaa242 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2003, 2009 IBM Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* IBM Corporation - initial API and implementation
*******************************************************************************/
package org.eclipse.xwt.vex.swt;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import org.eclipse.swt.browser.Browser;
import org.eclipse.swt.custom.CCombo;
import org.eclipse.swt.graphics.Font;
import org.eclipse.swt.graphics.GC;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.graphics.Rectangle;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Spinner;
import org.eclipse.swt.widgets.Table;
import org.eclipse.swt.widgets.Tree;
/**
* Image Capture for Win32 platforms.
*
* @since 1.1.0
*/
public class Win32ImageCapture extends org.eclipse.xwt.vex.swt.ImageCapture {
static protected Class<?> OleFrameClass;
static protected Method sendMessage;
static protected Method getParent;
static {
try {
OleFrameClass = GC.class.getClassLoader().loadClass("org.eclipse.swt.ole.win32.OleFrame");
Class<?> OSClass = GC.class.getClassLoader().loadClass("org.eclipse.swt.internal.win32.OS");
sendMessage = OSClass.getMethod("SendMessage", int.class, int.class, int.class, int.class);
getParent = OSClass.getMethod("GetParent", int.class);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
protected Image getImage(Control control, int maxWidth, int maxHeight, boolean includeChildren) {
Image myImage = getImage(control, maxWidth, maxHeight);
// We need to be able to handle right-to-left coordinates too. In that
// case the bounds rectangle will be reversed from what we
// think. We think the origin is upper-left, but the origin is really
// upper-right. To get out of this thinking we will
// instead convert all bounds to display bounds so that they will all be
// left-to-right.
if (myImage != null) {
// Get the images of all of the children
if (includeChildren && control instanceof Composite) {
Display display = control.getDisplay();
Rectangle parentBounds = control.getParent() == null ? control.getBounds() : display.map(control.getParent(), null, control.getBounds());
// Need to clip the bounds to the size of the image so we get
// just what we need.
Rectangle imgBounds = myImage.getBounds();
parentBounds.width = imgBounds.width;
parentBounds.height = imgBounds.height;
int parentRight = parentBounds.width + parentBounds.x;
int parentBottom = parentBounds.height + parentBounds.y;
Control[] children = ((Composite) control).getChildren();
GC myImageGC = new GC(myImage);
try {
int i = children.length;
while (--i >= 0) {
Control child = children[i];
// If the child is not visible then don't try and get
// its image
// An example of where this would cause a problem is
// TabFolder where all the controls
// for each page are children of the TabFolder, but only
// the visible one is being shown on the active page
if (!child.isVisible())
continue;
Rectangle childBounds = display.map(control, null, child.getBounds());
if (!parentBounds.intersects(childBounds))
continue; // Child is completely outside parent.
Image childImage = getImage(child, parentRight - childBounds.x, parentBottom - childBounds.y, true);
if (childImage != null) {
try {
// Paint the child image on top of our one
// Since the child bounds and parent bounds are
// both in display coors, the difference between
// the two is the offset of the child from the
// parent.
myImageGC.drawImage(childImage, childBounds.x - parentBounds.x, childBounds.y - parentBounds.y);
} finally {
childImage.dispose();
}
}
}
} finally {
myImageGC.dispose();
}
}
}
return myImage;
}
/**
* Return the image of the argument. This includes the client and non-client area, but does not include any child controls. To get child control use {@link Win32ImageCapture#getImage(Control, int, int, boolean)}.
*
* @param aControl
* @param maxWidth
* @param maxHeight
* @return image or <code>null</code> if not valid for some reason. (Like not yet sized).
*
* @since 1.1.0
*/
protected Image getImage(Control aControl, int maxWidth, int maxHeight) {
Rectangle rect = aControl.getBounds();
if (rect.width <= 0 || rect.height <= 0)
return null;
Image image = new Image(aControl.getDisplay(), Math.min(rect.width, maxWidth), Math.min(rect.height, maxHeight));
int WM_PRINT = 0x0317;
// int WM_PRINTCLIENT = 0x0318;
// int PRF_CHECKVISIBLE = 0x00000001;
int PRF_NONCLIENT = 0x00000002;
int PRF_CLIENT = 0x00000004;
int PRF_ERASEBKGND = 0x00000008;
int PRF_CHILDREN = 0x00000010;
// int PRF_OWNED = 0x00000020;
int print_bits = PRF_NONCLIENT | PRF_CLIENT | PRF_ERASEBKGND;
// This method does not print immediate children because the z-order
// doesn't work correctly and needs to be
// dealt with separately, however Table's TableColumn widgets are
// children so must be handled differently
boolean specialClass = aControl instanceof Table || aControl instanceof Browser || OleFrameClass.isInstance(aControl) || aControl instanceof CCombo;
try {
specialClass |= aControl instanceof Spinner;
} catch (NoClassDefFoundError e) {
} // might not be on 3.1 of SWT
if (specialClass) {
print_bits |= PRF_CHILDREN;
}
GC gc = new GC(image);
// Need to handle cases where the GC font isn't automatically set by the
// control's image (e.g. CLabel)
// see bug 98830 (https://bugs.eclipse.org/bugs/show_bug.cgi?id=98830)
Font f = aControl.getFont();
if (f != null)
gc.setFont(f);
try {
int hwnd = getIntHandle(aControl);
if (aControl instanceof Tree) {
int hwndParent = (Integer) getParent.invoke(null, hwnd);
if (hwndParent != getIntHandle(aControl.getParent())) {
hwnd = hwndParent;
print_bits |= PRF_CHILDREN;
}
}
sendMessage.invoke(null, hwnd, WM_PRINT, gc.handle, print_bits);
} catch (Exception e) {
throw new RuntimeException(e);
}
gc.dispose();
return image;
}
}