blob: 75d5877950febeb7982f953a4c530317dc1f9a36 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2004, 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
*******************************************************************************/
/*
* $RCSfile: ImageCapture.java,v $
* $Revision: 1.8 $ $Date: 2010/06/18 00:17:02 $
*/
package org.eclipse.ve.internal.swt.targetvm.unix;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;
import org.eclipse.swt.SWT;
import org.eclipse.swt.custom.CCombo;
import org.eclipse.swt.graphics.GC;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.graphics.ImageData;
import org.eclipse.swt.graphics.PaletteData;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.graphics.RGB;
import org.eclipse.swt.graphics.Rectangle;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Decorations;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Menu;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.Text;
import org.eclipse.swt.widgets.Widget;
import org.eclipse.xwt.vex.swt.DisposeUtil;
/**
* GTK version of Image Capture
*
* @since 1.0.0
*/
public class ImageCapture extends org.eclipse.xwt.vex.swt.ImageCapture {
static Field Menu_handler;
static Field Control_handler;
static {
try {
Menu_handler = Menu.class.getField("handle");
Control_handler = Control.class.getField("handle");
System.loadLibrary("swt-gtk-print"); //$NON-NLS-1$
} catch (Exception error) {
error.printStackTrace();
} catch (UnsatisfiedLinkError error) {
error.printStackTrace();
}
}
static final int OBSCURED = 1 << 6; // Must be the same value as Widget.OBSCURED
static final String FIELD_STATE_NAME = "state"; //$NON-NLS-1$
private native int[] getPixels(int handle, int includeChildren, int maxWidth, int maxHeight, int arg4);
protected Point getTopLeftOfClientarea(Decorations decorations) {
Point trim = decorations.toControl(decorations.getLocation());
trim.x = -trim.x;
trim.y = -trim.y;
if (decorations.getMenuBar() != null) {
Menu menu = decorations.getMenuBar();
try {
Class<?> osClass = Class.forName("org.eclipse.swt.internal.gtk.OS"); //$NON-NLS-1$
Method method = osClass.getMethod("GTK_WIDGET_HEIGHT", new Class[] { int.class }); //$NON-NLS-1$
Object ret = method.invoke(menu, new Object[] { Menu_handler.getInt(menu)});
if (ret != null) {
int menuBarHeight = ((Integer) ret).intValue();
trim.y -= menuBarHeight;
}
} catch (Throwable t) {
}
}
return new Point(trim.x, trim.y);
}
protected Image getImageOfControl(Control control, int includeChildren, int maxWidth, int maxHeight) {
Image image = null;
if (control instanceof Shell) {
Shell shell = (Shell) control;
int handle = readIntFieldValue(shell.getClass(), shell, "shellHandle"); //$NON-NLS-1$
if (handle > 0) {
image = getImageOfHandle(handle, shell.getDisplay(), includeChildren, maxWidth, maxHeight);
}
}
try {
if (image == null) {
image = getImageOfHandle(Control_handler.getInt(control), control.getDisplay(), includeChildren, maxWidth, maxHeight);
}
if (control instanceof Decorations) {
Decorations decorations = (Decorations) control;
Rectangle shellBounds = decorations.getBounds();
Point topLeft = getTopLeftOfClientarea(decorations);
Image realShellImage = new Image(decorations.getDisplay(), shellBounds.width, shellBounds.height);
Image origImage = image;
try {
simulateDecoration(decorations, realShellImage, decorations.getBounds(), decorations.getClientArea(), topLeft);
GC gc = new GC(realShellImage);
gc.drawImage(image, topLeft.x, topLeft.y);
DisposeUtil.dispose(gc);
image = realShellImage;
} finally {
origImage.dispose();
}
}
} catch (Exception e) {
e.printStackTrace();
}
return image;
}
protected Image getImageOfHandle(int handle, Display display, int includeChildren, int maxWidth, int maxHeight) {
int[] tcData = getPixels(handle, includeChildren, maxWidth, maxHeight, 0);
int depth = display.getDepth();
if (depth == 15)
depth = 16; // SWT cant handle depth of 15. Similar to 16
if (depth > 24)
depth = 24;
if (tcData != null) {
int tcWidth = tcData[0];
int tcHeight = tcData[1];
int type = tcData[2];
if (type == 1) {
// Direct RGB values
int red_mask = tcData[3] == -1 ? 0x00FF : tcData[3];
int green_mask = tcData[4] == -1 ? 0x00FF00 : tcData[4];
int blue_mask = tcData[5] == -1 ? 0x00FF0000 : tcData[5];
// System.err.println("Masks: "+Integer.toHexString(red_mask)+","+Integer.toHexString(green_mask)+","+Integer.toHexString(blue_mask));
int[] tcPixels = new int[tcData.length - 6];
System.arraycopy(tcData, 6, tcPixels, 0, tcPixels.length);
ImageData tcImageData = new ImageData(tcWidth, tcHeight, depth, new PaletteData(red_mask, green_mask, blue_mask));
tcImageData.setPixels(0, 0, tcPixels.length, tcPixels, 0);
Image tcImage = new Image(display, tcImageData);
return tcImage;
} else if (type == 2) {
// Indexed values
int numColors = tcData[3];
RGB[] rgb = new RGB[numColors];
// System.err.println("### Num colors = "+numColors);
for (int colCount = 0; colCount < numColors; colCount++) {
int r = tcData[4 + (colCount * 3) + 0];
int g = tcData[4 + (colCount * 3) + 1];
int b = tcData[4 + (colCount * 3) + 2];
rgb[colCount] = new RGB(r, g, b);
}
PaletteData pd = new PaletteData(rgb);
ImageData id = new ImageData(tcWidth, tcHeight, depth, pd);
int offset = (4 + (rgb.length * 3));
int pixels[] = new int[tcData.length - offset];
System.arraycopy(tcData, offset, pixels, 0, pixels.length);
id.setPixels(0, 0, pixels.length, pixels, 0);
Image tcImage = new Image(display, id);
// System.err.println("### returning image");
return tcImage;
} else {
System.err.println("JNI Returned unknown image type"); //$NON-NLS-1$
}
}
return null;
}
/**
* @param decoration
* @param realShellImage
* @param bounds
* @param clientArea
* @param topLeft
*
* @since 1.0.0
*/
private void simulateDecoration(Decorations decoration, Image realShellImage, Rectangle bounds, Rectangle clientArea, Point topLeft) {
GC gc = new GC(realShellImage);
try {
gc.setBackground(decoration.getDisplay().getSystemColor(SWT.COLOR_WIDGET_BACKGROUND));
gc.fillRectangle(0, 0, bounds.width, bounds.height);
gc.setBackground(decoration.getDisplay().getSystemColor(SWT.COLOR_WIDGET_DARK_SHADOW));
gc.drawRectangle(topLeft.x - 1, topLeft.y - 1, clientArea.width + 2, clientArea.height + 2);
// little squares at bottom corners
gc.setBackground(decoration.getDisplay().getSystemColor(SWT.COLOR_TITLE_BACKGROUND));
gc.fillRectangle(0, bounds.height - topLeft.y, topLeft.y, bounds.height);
gc.fillRectangle(bounds.width - topLeft.y, bounds.height - topLeft.y, bounds.width, bounds.height);
// title bar
if ((decoration.getStyle() & (SWT.TITLE | SWT.CLOSE | SWT.MAX | SWT.MIN)) != 0 && topLeft.y > 2) {
int barHeight = topLeft.y - 2;
// There will be a title bar - draw the text
gc.setForeground(decoration.getDisplay().getSystemColor(SWT.COLOR_TITLE_BACKGROUND));
gc.setBackground(decoration.getDisplay().getSystemColor(SWT.COLOR_TITLE_FOREGROUND));
gc.fillGradientRectangle(0, 0, bounds.width, barHeight, false);
gc.setForeground(decoration.getDisplay().getSystemColor(SWT.COLOR_TITLE_FOREGROUND));
gc.drawText(decoration.getText(), topLeft.y, 2, true);
if (decoration.getImage() != null && !decoration.getImage().isDisposed()) {
Rectangle imageBounds = decoration.getImage().getBounds();
if (imageBounds.height <= barHeight) {
gc.drawImage(decoration.getImage(), 0, 0);
} else {
ImageData imageData = decoration.getImage().getImageData();
double factor = (double) barHeight / (double) imageBounds.height;
int newWidth = (int) (imageBounds.width * factor);
imageData = imageData.scaledTo(newWidth, barHeight);
Image newImage = new Image(decoration.getDisplay(), imageData);
gc.drawImage(newImage, 0, 0);
newImage.dispose();
}
}
int rightx = bounds.width - topLeft.y;
// title bar buttons
if ((decoration.getStyle() & SWT.CLOSE) != 0) {
gc.setBackground(decoration.getDisplay().getSystemColor(SWT.COLOR_WIDGET_BACKGROUND));
gc.fillRectangle(rightx, 0, topLeft.y, topLeft.y);
gc.setLineWidth(1);
gc.setForeground(decoration.getDisplay().getSystemColor(SWT.COLOR_WIDGET_DARK_SHADOW));
gc.drawRectangle(rightx, 0, topLeft.y, topLeft.y);
int lineWidth = topLeft.y / 6;
if (lineWidth < 1)
lineWidth = 1;
gc.setLineWidth(lineWidth);
lineWidth = lineWidth * 2;
gc.setForeground(decoration.getDisplay().getSystemColor(SWT.COLOR_WIDGET_BORDER));
gc.drawLine(rightx + lineWidth, lineWidth, rightx + topLeft.y - lineWidth, topLeft.y - lineWidth);
gc.drawLine(rightx + lineWidth, topLeft.y - lineWidth, rightx + topLeft.y - lineWidth, lineWidth);
rightx -= topLeft.y;
}
if ((decoration.getStyle() & SWT.MAX) != 0) {
gc.setBackground(decoration.getDisplay().getSystemColor(SWT.COLOR_WIDGET_BACKGROUND));
gc.fillRectangle(rightx, 0, topLeft.y, topLeft.y);
gc.setLineWidth(1);
gc.setForeground(decoration.getDisplay().getSystemColor(SWT.COLOR_WIDGET_DARK_SHADOW));
gc.drawRectangle(rightx, 0, topLeft.y, topLeft.y);
int lineWidth = topLeft.y / 6;
if (lineWidth < 1)
lineWidth = 1;
gc.setLineWidth(lineWidth);
lineWidth = lineWidth * 2;
gc.setForeground(decoration.getDisplay().getSystemColor(SWT.COLOR_WIDGET_BORDER));
gc.drawRectangle(rightx + lineWidth, lineWidth, topLeft.y - (2 * lineWidth), topLeft.y - (2 * lineWidth));
rightx -= topLeft.y;
}
if ((decoration.getStyle() & SWT.MIN) != 0) {
gc.setLineWidth(1);
gc.setBackground(decoration.getDisplay().getSystemColor(SWT.COLOR_WIDGET_BACKGROUND));
gc.fillRectangle(rightx, 0, topLeft.y - 1, topLeft.y - 1);
gc.setForeground(decoration.getDisplay().getSystemColor(SWT.COLOR_WIDGET_DARK_SHADOW));
gc.drawRectangle(rightx, 0, topLeft.y - 1, topLeft.y - 1);
int lineWidth = topLeft.y / 6;
if (lineWidth < 1)
lineWidth = 1;
gc.setLineWidth(lineWidth);
lineWidth = lineWidth * 2;
gc.setForeground(decoration.getDisplay().getSystemColor(SWT.COLOR_WIDGET_BORDER));
gc.drawLine(rightx + lineWidth, topLeft.y - lineWidth, rightx + topLeft.y - lineWidth, topLeft.y - lineWidth);
rightx -= topLeft.y;
}
gc.setLineWidth(1);
gc.setForeground(decoration.getDisplay().getSystemColor(SWT.COLOR_WIDGET_DARK_SHADOW));
gc.drawLine(0, topLeft.y - 1, bounds.width, topLeft.y - 1);
}
} finally {
gc.dispose();
}
}
protected Map<Class<?>, Map<String, Object>> fieldAccessors = new HashMap<Class<?>, Map<String, Object>>(); // Map of Class->fieldName->field reflect
/**
* @param object
* @param fieldName
* @return
*
* @since 1.0.0
*/
private int readIntFieldValue(Class<?> klass, Object object, String fieldName) {
try {
Field field = getField(klass, fieldName);
return field != null ? field.getInt(object) : 0;
} catch (IllegalArgumentException e) {
} catch (IllegalAccessException e) {
}
return -1;
}
private static final Object NO_FIELD = new Object();
private Field getField(Class<?> klass, String fieldName) {
Map<String, Object> nameToField = fieldAccessors.get(klass);
if (nameToField == null) {
fieldAccessors.put(klass, nameToField = new HashMap<String, Object>());
}
Object field = nameToField.get(fieldName);
if (field == null) {
try {
field = klass.getDeclaredField(fieldName);
((Field) field).setAccessible(true);
} catch (SecurityException e) {
field = NO_FIELD;
e.printStackTrace();
} catch (NoSuchFieldException e) {
field = NO_FIELD;
e.printStackTrace();
}
nameToField.put(fieldName, field);
}
return (Field) (field != NO_FIELD ? field : null);
}
/**
* @param object
* @param fieldName
* @return
*
* @since 1.0.0
*/
private void writeIntFieldValue(Class<?> klass, Object object, String fieldName, int newInt) {
try {
Field field = getField(klass, fieldName);
field.setInt(object, newInt);
} catch (IllegalArgumentException e) {
} catch (IllegalAccessException e) {
}
}
protected Image getImage(Control control, int maxWidth, int maxHeight, boolean includeChildren) {
int ic = includeChildren ? 1 : 0;
Map<Control, Integer> map = new HashMap<Control, Integer>();
changeObscured(control, map, false);
Image image = null;
try {
image = getImageOfControl(control, ic, maxWidth, maxHeight);
} finally {
changeObscured(control, map, true);
}
return image;
}
/**
* @param control
* @param map
*
* @since 1.0.0
*/
private void changeObscured(Control control, Map<Control, Integer> map, boolean on) {
if (on) {
// restoring the obscured flags
if (map.containsKey(control)) {
// control had obscured flag changed - reset it
Integer originalValue = (Integer) map.get(control);
writeIntFieldValue(Widget.class, control, FIELD_STATE_NAME, originalValue.intValue());
}
} else {
// disabling the obscure flags
int stateValue = readIntFieldValue(Widget.class, control, FIELD_STATE_NAME);
if ((stateValue & OBSCURED) != 0) {
// obscured - disable flag and remember
map.put(control, new Integer(stateValue));
stateValue &= ~OBSCURED;
writeIntFieldValue(Widget.class, control, FIELD_STATE_NAME, stateValue);
}
}
if (control instanceof CCombo) {
// CCombo has a text field whose OBSCURED field needs to be changed
CCombo ccombo = (CCombo) control;
Object val = readObjectFieldValue(CCombo.class, ccombo, "text"); //$NON-NLS-1$
if (val instanceof Text) {
Text text = (Text) val;
changeObscured(text, map, on);
}
} else if (control instanceof Composite) {
Composite composite = (Composite) control;
Control[] children = composite.getChildren();
for (int cc = 0; children != null && cc < children.length; cc++) {
changeObscured(children[cc], map, on);
}
}
}
/**
* @param object
* @param fieldName
* @return
*
* @since 1.1.0.1
*/
private Object readObjectFieldValue(Class<?> klass, Object object, String fieldName) {
try {
Field field = klass.getDeclaredField(fieldName);
field.setAccessible(true);
return field.get(object);
} catch (SecurityException e) {
} catch (NoSuchFieldException e) {
} catch (IllegalArgumentException e) {
} catch (IllegalAccessException e) {
}
return null;
}
}