org.eclipse.wb.internal.os.win32.OSSupportWin32.java Source code

Java tutorial

Introduction

Here is the source code for org.eclipse.wb.internal.os.win32.OSSupportWin32.java

Source

/*******************************************************************************
 * Copyright (c) 2011 Google, Inc.
 * 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:
 *    Google, Inc. - initial API and implementation
 *******************************************************************************/
package org.eclipse.wb.internal.os.win32;

import org.eclipse.wb.internal.core.EnvironmentUtils;
import org.eclipse.wb.internal.core.utils.reflect.ReflectionUtils;
import org.eclipse.wb.os.OSSupport;

import org.eclipse.swt.SWT;
import org.eclipse.swt.graphics.GC;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.graphics.Point;
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.TabFolder;
import org.eclipse.swt.widgets.TabItem;
import org.eclipse.swt.widgets.Tree;
import org.eclipse.swt.widgets.TreeItem;

import org.apache.commons.lang.ArrayUtils;

import java.util.List;

/**
 * Win32 implementation for {@link OSSupport}.
 * 
 * @author mitin_aa
 * @coverage os.win32
 */
public abstract class OSSupportWin32<H extends Number> extends OSSupport {
    static {
        System.loadLibrary("wbp");
    }
    ////////////////////////////////////////////////////////////////////////////
    //
    // Instance
    //
    ////////////////////////////////////////////////////////////////////////////
    protected static final OSSupport INSTANCE = EnvironmentUtils.IS_64BIT_OS ? new Impl64() : new Impl32();

    ////////////////////////////////////////////////////////////////////////////
    //
    // Screen Shot
    //
    ////////////////////////////////////////////////////////////////////////////
    @Override
    public final void makeShots(Object controlObject) throws Exception {
        Control control = (Control) controlObject;
        try {
            reverseDrawingOrder(control);
            makeShotsHierarchy(control);
        } finally {
            reverseDrawingOrder(control);
        }
    }

    /**
     * For unknown reason, when we do screen shot using WM_PRINT, <em>last</em> {@link Control} is
     * displayed on the top of drawing order, however when we run application, Windows displays
     * <em>first</em> on the top of drawing order. So, we reverse drawing order before making screen
     * shot, and restore drawing order after this.
     */
    private static void reverseDrawingOrder(Control control) {
        // 20130423(scheglov) disabled because of http://www.eclipse.org/forums/index.php/t/476687/
        //    if (control instanceof Composite) {
        //      Composite composite = (Composite) control;
        //      for (Control child : composite.getChildren()) {
        //        child.moveAbove(null);
        //        reverseDrawingOrder(child);
        //      }
        //    }
    }

    /**
     * Creates screen shots for all {@link Control}'s in hierarchy marked with
     * <code>WBP_NEED_IMAGE</code>.
     */
    private void makeShotsHierarchy(Control control) throws Exception {
        if (control.getData(WBP_NEED_IMAGE) != null) {
            // check size
            Point size = control.getSize();
            if (size.x == 0 || size.y == 0) {
                return;
            }
            // set image
            control.setData(WBP_IMAGE, makeShot(control));
            // create images for children
            if (control instanceof Composite) {
                Composite composite = (Composite) control;
                for (Control child : composite.getChildren()) {
                    makeShotsHierarchy(child);
                }
            }
        }
    }

    @Override
    public final Image makeShot(Control control) throws Exception {
        Rectangle bounds = control.getBounds();
        if (bounds.width == 0 || bounds.height == 0) {
            return null;
        }
        Image image = new Image(Display.getCurrent(), bounds.width, bounds.height);
        GC gc = new GC(image);
        try {
            makeShotImpl(control, gc);
        } finally {
            gc.dispose();
        }
        //
        return image;
    }

    protected void makeShotImpl(Control control, GC gc) {
        _makeShot(getHandleField(control), getHandleField(gc));
    }

    ////////////////////////////////////////////////////////////////////////////
    //
    // TabItem
    //
    ////////////////////////////////////////////////////////////////////////////
    @Override
    public final Rectangle getTabItemBounds(Object tabItemObject) {
        TabFolder tabFolder = ((TabItem) tabItemObject).getParent();
        int index = ArrayUtils.indexOf(tabFolder.getItems(), tabItemObject);
        int[] bounds = new int[4];
        getTabItemBounds(tabFolder, index, bounds);
        // convert into Rectangle
        int borderOffset = (tabFolder.getStyle() & SWT.BORDER) != 0 ? 2 : 0;
        int x = bounds[0]/*itemRect.left*/ + borderOffset;
        int y = bounds[2]/*itemRect.top*/ + borderOffset;
        int width = bounds[1]/*itemRect.right*/ - bounds[0]/*itemRect.left*/;
        int height = bounds[3]/*itemRect.bottom*/ - bounds[2]/*itemRect.top*/;
        return new Rectangle(x, y, width, height);
    }

    private void getTabItemBounds(TabFolder tabFolder, int index, int[] bounds) {
        _getTabItemBounds(getHandleField(tabFolder), index, bounds);
    }

    ////////////////////////////////////////////////////////////////////////////
    //
    // Menu
    //
    ////////////////////////////////////////////////////////////////////////////
    @Override
    public final Rectangle getMenuBarBounds(Menu menu) {
        Decorations shell = getMenuParent(menu);
        int[] bounds = new int[4];
        if (getMenuBarOrItemBounds(shell, 0, bounds)) {
            int width = bounds[1] - bounds[0]; // info.right - info.left;
            int height = bounds[3] - bounds[2]; // info.bottom - info.top;
            //
            Point shellLocation = shell.getLocation();
            return new Rectangle(bounds[0] /*info.left*/ - shellLocation.x, bounds[2] /*info.top*/
                    - shellLocation.y, width, height);
        }
        throw new RuntimeException("OS function call failed.");
    }

    @Override
    public Image getMenuBarVisualData(Menu menu, List<Rectangle> dimensions) {
        Decorations shell = getMenuParent(menu);
        int[] offsetBounds = new int[4];
        if (!getMenuBarOrItemBounds(shell, 1, offsetBounds)) {
            throw new RuntimeException("OS function call failed.");
        }
        for (int index = 0; index < menu.getItemCount(); ++index) {
            int[] bounds = new int[4];
            if (!getMenuBarOrItemBounds(shell, index + 1, bounds)) {
                throw new IllegalStateException("OS function call failed.");
            }
            int x = bounds[0] - offsetBounds[0]; // barInfo.left - offsetBarInfo.left;
            int y = bounds[2] - offsetBounds[2]; // barInfo.top - offsetBarInfo.top;
            int width = bounds[1] - bounds[0]; // barInfo.right - barInfo.left;
            int height = bounds[3] - bounds[2]; // barInfo.bottom - barInfo.top;
            dimensions.add(new Rectangle(x, y, width, height));
        }
        return null;
    }

    /**
     * Checks this menu parent, it should have menu bar set for the given menu.
     */
    private Decorations getMenuParent(Menu menu) {
        Decorations shell = menu.getParent();
        if (shell.getMenuBar() != menu) {
            throw new IllegalArgumentException("Invalid menu parent.");
        }
        return shell;
    }

    private boolean getMenuBarOrItemBounds(Decorations shell, int index, int[] bounds) {
        return _getMenuBarOrItemBounds(getHandleField(shell), index, bounds);
    }

    @Override
    public Image getMenuPopupVisualData(Menu menu, int[] bounds) throws Exception {
        // create fake image
        Image image = new Image(Display.getCurrent(), 1, 1);
        // free system resource
        _DeleteObject(getHandleField(image));
        H handle = _fetchPopupMenuVisualData(getHandleField(menu.getShell()), getHandleField(menu), bounds);
        // set new handle to image
        ReflectionUtils.setField(image, "handle", handle);
        return image;
    }

    @Override
    public int getDefaultMenuBarHeight() {
        return _getDefaultMenuBarHeight();
    }

    ////////////////////////////////////////////////////////////////////////////
    //
    // Alpha
    //
    ////////////////////////////////////////////////////////////////////////////
    @Override
    public void setAlpha(Shell shell, int alpha) {
        _setAlpha(getHandleField(shell), alpha);
    }

    @Override
    public int getAlpha(Shell shell) {
        return _getAlpha(getHandleField(shell));
    }

    ////////////////////////////////////////////////////////////////////////////
    //
    // Tree click
    //
    ////////////////////////////////////////////////////////////////////////////
    @Override
    public boolean isPlusMinusTreeClick(Tree tree, int x, int y) {
        return _isPlusMinusTreeClick(getHandleField(tree), x, y);
    }

    ////////////////////////////////////////////////////////////////////////////
    //
    // Misc
    //
    ////////////////////////////////////////////////////////////////////////////
    @Override
    public void scroll(Control cursorControl, int count) {
        _scroll(getHandleField(cursorControl), count);
    }

    ////////////////////////////////////////////////////////////////////////////
    //
    // Utils
    //
    ////////////////////////////////////////////////////////////////////////////
    /**
     * @return the "handle" field value of given <code>object</code>.
     */
    protected abstract H getHandleField(Object object);

    ////////////////////////////////////////////////////////////////////////////
    //
    // Native
    //
    ////////////////////////////////////////////////////////////////////////////
    /**
     * Calls GetMenuBarInfo and fills the given array of int with bounds in a left, right, top, bottom
     * sequence.
     * 
     * @param shellHandle
     *          the handle of {@link Shell} which bar menu belongs to.
     * @param itemIndex
     *          the item index to fetch bounds of. Passing zero value returns the bounds of menu bar.
     * @param bounds
     *          the array of integer with size 4.
     */
    private static native <H extends Number> boolean _getMenuBarOrItemBounds(H shellHandle, int itemIndex,
            int[] bounds);

    /**
     * Fetches the menu data: returns item bounds as plain array and the HBITMAP of menu image.
     * 
     * @param shellHandle
     *          the handle of menu parent shell.
     * @param menuHandle
     *          the handle of menu.
     * @param bounds
     *          the array of integer with size 4 * menu item count.
     * @return the HBITMAP of menu widget.
     */
    private static native <H extends Number> H _fetchPopupMenuVisualData(H shellHandle, H menuHandle,
            int[] itemBounds);

    /**
     * @return the result of GetSystemMetrics(SM_CYMENU) invocation;
     */
    private static native int _getDefaultMenuBarHeight();

    /**
     * Scrolls by <code>count</code> positions.
     */
    private static native <H extends Number> void _scroll(H handle, int count);

    /**
     * Causes taking the screen shot.
     * 
     * @param windowHandle
     *          the handle of {@link Shell}.
     * @param dcHandle
     *          the handle {@link GC} to paint to.
     */
    private static native <H extends Number> void _makeShot(H windowHandle, H dcHandle);

    /**
     * @return <code>true</code> if pointer is over {@link TreeItem} plus/minus sign.
     */
    private static native <H extends Number> boolean _isPlusMinusTreeClick(H handle, int x, int y);

    /**
     * Sets the <code>alpha</code> value for given <code>shell</code>.
     * 
     * @param shellHandle
     *          the handle of {@link Shell}.
     * @param alpha
     *          the value of alpha, 0-255, not validated.
     */
    private static native <H extends Number> void _setAlpha(H shellHandle, int alpha);

    /**
     * Returns the current alpha value for given <code>shellHandle</code>.
     * 
     * @param shellHandle
     *          the handle of {@link Shell}.
     * @return the alpha value.
     */
    private static native <H extends Number> int _getAlpha(H shellHandle);

    /**
     * Fills the given array of int with bounds in a left, right, top, bottom sequence.
     * 
     * @param tabFolderHandle
     *          the handle of {@link TabFolder}.
     * @param itemIndex
     *          the {@link TabItem} index to fetch bounds of.
     * @param bounds
     *          the array of integer with size 4.
     */
    private static native <H extends Number> void _getTabItemBounds(H tabFolderHandle, int itemIndex, int[] bounds);

    /**
     * Simply calls DeleteObject() for given <code>handle</code>.
     */
    private static native <H extends Number> void _DeleteObject(H handle);

    ////////////////////////////////////////////////////////////////////////////
    //
    // Implementations
    //
    ////////////////////////////////////////////////////////////////////////////
    private static final class Impl32 extends OSSupportWin32<Integer> {
        @Override
        protected Integer getHandleField(Object object) {
            return ReflectionUtils.getFieldInt(object, "handle");
        }
    }

    private static final class Impl64 extends OSSupportWin32<Long> {
        @Override
        protected Long getHandleField(Object object) {
            return ReflectionUtils.getFieldLong(object, "handle");
        }
    }
}